From 100b00cbb0020ef5cff53b4be0e587900d0ab771 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Thu, 24 Apr 2025 18:45:58 -0300 Subject: [PATCH] remove login method Signed-off-by: Leonardo Rossetti --- .../corellium/api.py | 34 ++-------- .../corellium/api_test.py | 42 +----------- .../corellium/types.py | 19 +----- .../jumpstarter_driver_corellium/driver.py | 21 +----- .../driver_test.py | 64 ++++++++----------- 5 files changed, 34 insertions(+), 146 deletions(-) diff --git a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api.py b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api.py index 44d85ae27..f33407d89 100644 --- a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api.py +++ b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api.py @@ -3,24 +3,24 @@ import requests from .exceptions import CorelliumApiException -from .types import Device, Instance, Project, Session +from .types import Device, Instance, Project class ApiClient: """ Corellium ReST API client used by the Corellium driver. """ - session: Session req: requests.Session def __init__(self, host: str, token: str) -> None: """ - Initializes a new client, containing a + Initializes a new client using the API token + in all HTTP requests. """ self.host = host self.token = token - self.session = None self.req = requests.Session() + self.req.headers.update({'Authorization': f'Bearer {self.token}'}) @property def baseurl(self) -> str: @@ -29,32 +29,6 @@ def baseurl(self) -> str: """ return f'https://{self.host}/api' - def login(self) -> None: - """ - Login against Corellium's ReST API. - - Set an internal Session object instance to be used - in other API calls that require authentication. - - It uses the global requests objects so a new session can be generated. - """ - data = None - req_data = { - 'apiToken': self.token - } - - try: - res = requests.post(f'{self.baseurl}/v1/auth/login', json=req_data) - data = res.json() - res.raise_for_status() - except (requests.exceptions.RequestException, requests.exceptions.HTTPError) as e: - msgerr = data.get('error') if data is not None else str(e) - - raise CorelliumApiException(msgerr) from e - - self.session = Session(**data) - self.req.headers.update(self.session.as_header()) - def get_project(self, project_ref: str = 'Default Project') -> Optional[Project]: """ Retrieve a project based on project_ref, which is either its id or name. diff --git a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api_test.py b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api_test.py index 7825b2460..5e514d42b 100644 --- a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api_test.py +++ b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/api_test.py @@ -5,7 +5,7 @@ # import websockets from .api import ApiClient from .exceptions import CorelliumApiException -from .types import Device, Instance, Project, Session +from .types import Device, Instance, Project def fixture(path): @@ -19,34 +19,6 @@ def fixture(path): return f.read() -def test_login_ok(requests_mock): - requests_mock.post('https://api-host/api/v1/auth/login', text=fixture('http/login-200.json')) - - api = ApiClient('api-host', 'api-token') - api.login() - - assert 'session-token' == api.session.token - assert '2022-03-20T01:50:10.000Z' == api.session.expiration - assert {'Authorization': 'Bearer session-token'} == api.session.as_header() - - -@pytest.mark.parametrize( - 'status_code,data,msg', - [ - (403, fixture('http/403.json'), 'Invalid or missing authorization token'), - (200, fixture('http/json-error.json'), 'Invalid control character at'), - ]) -def test_login_error(requests_mock, status_code, data, msg): - requests_mock.post('https://api-host/api/v1/auth/login', status_code=status_code, text=data) - api = ApiClient('api-host', 'api-token') - - with pytest.raises(CorelliumApiException) as e: - api.login() - - assert msg in str(e.value) - assert api.session is None - - @pytest.mark.parametrize('project_name,data,has_results', [ ('OtherProject', fixture('http/get-projects-200.json'), True), (None, fixture('http/get-projects-200.json'), True), @@ -55,7 +27,6 @@ def test_login_error(requests_mock, status_code, data, msg): def test_get_project_ok(requests_mock, project_name, data, has_results): requests_mock.get('https://api-host/api/v1/projects', status_code=200, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') args = [] if project_name: @@ -78,7 +49,6 @@ def test_get_project_ok(requests_mock, project_name, data, has_results): def test_get_project_error(requests_mock, status_code, data, msg): requests_mock.get('https://api-host/api/v1/projects', status_code=status_code, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') with pytest.raises(CorelliumApiException) as e: api.get_project() @@ -93,7 +63,6 @@ def test_get_project_error(requests_mock, status_code, data, msg): def test_get_device_ok(requests_mock, model, data, has_results): requests_mock.get('https://api-host/api/v1/models', status_code=200, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') device = api.get_device(model) @@ -112,7 +81,6 @@ def test_get_device_ok(requests_mock, model, data, has_results): def test_get_device_error(requests_mock, status_code, data, msg): requests_mock.get('https://api-host/api/v1/models', status_code=status_code, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') with pytest.raises(CorelliumApiException) as e: api.get_device('mymodel') @@ -124,7 +92,6 @@ def test_create_instance_ok(requests_mock): data = fixture('http/create-instance-200.json') requests_mock.post('https://api-host/api/v1/instances', status_code=200, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') project = Project('d59db33d-27bd-4b22-878d-49e4758a648e', 'Default Project') device = Device(name='rd1ae', type='automotive', flavor='kronos', @@ -144,7 +111,6 @@ def test_create_instance_ok(requests_mock): def test_create_instance_error(requests_mock, status_code, data, msg): requests_mock.post('https://api-host/api/v1/instances', status_code=status_code, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') with pytest.raises(CorelliumApiException) as e: project = Project('d59db33d-27bd-4b22-878d-49e4758a648e', 'Default Project') @@ -160,7 +126,6 @@ def test_destroy_instance_state_ok(requests_mock): requests_mock.delete(f'https://api-host/api/v1/instances/{instance.id}', status_code=204, text='') api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') api.destroy_instance(instance) @@ -175,7 +140,6 @@ def test_destroy_instance_error(requests_mock, status_code, data, msg): requests_mock.delete(f'https://api-host/api/v1/instances/{instance.id}', status_code=status_code, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') with pytest.raises(CorelliumApiException) as e: api.destroy_instance(instance) @@ -195,7 +159,6 @@ def test_get_instance_console_id_ok(requests_mock, console_name, console_id): instance = Instance(id='d59db33d-27bd-4b22-878d-49e4758a648e') requests_mock.get(f'https://api-host/api/v1/instances/{instance.id}', status_code=200, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') current = api.get_instance_console_id(instance, console_name) @@ -213,7 +176,6 @@ def test_get_instance_console_id_error(requests_mock, status_code, data, msg): requests_mock.get(f'https://api-host/api/v1/instances/{instance.id}', status_code=status_code, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') with pytest.raises(CorelliumApiException) as e: api.get_instance_console_id(instance, 'Console 1') @@ -228,7 +190,6 @@ def test_get_instance_console_url_ok(requests_mock): requests_mock.get(f'https://api-host/api/v1/instances/{instance.id}/console?type=1-cons', status_code=200, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') current = api.get_instance_console_url(instance, console_id) expected = 'wss://api-host/port-cons-1' @@ -249,7 +210,6 @@ def test_get_instance_console_url_error(requests_mock, status_code, data, msg): requests_mock.get(f'https://api-host/api/v1/instances/{instance.id}/console?type=1-cons', status_code=status_code, text=data) api = ApiClient('api-host', 'api-token') - api.session = Session('session-token', '2022-03-20T01:50:10.000Z') with pytest.raises(CorelliumApiException) as e: api.get_instance_console_url(instance, console_id) diff --git a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/types.py b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/types.py index 88716e2ee..e4699df98 100644 --- a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/types.py +++ b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/types.py @@ -2,24 +2,7 @@ Corellium API types. """ from dataclasses import dataclass, field -from typing import Dict, Optional - - -@dataclass -class Session: - """ - Session data class to hold Corellium's API session data. - """ - token: str - expiration: str - - def as_header(self) -> Dict[str, str]: - """ - Return a dict to be used as HTTP header for authenticated requests. - """ - return { - 'Authorization': f'Bearer {self.token}' - } +from typing import Optional @dataclass diff --git a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver.py b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver.py index 8058f2001..226a1f01f 100644 --- a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver.py +++ b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver.py @@ -5,7 +5,6 @@ import time from collections.abc import AsyncGenerator from dataclasses import dataclass, field -from datetime import datetime, timedelta from typing import Dict, Optional from jumpstarter_driver_network.driver import WebsocketNetwork @@ -81,26 +80,10 @@ def get_env_var(self, name: str) -> str: return value @property - def api(self): + def api(self) -> ApiClient: """ - Return the internal Corellium API client instance from `self._api`. - - It will also be responsible for creating/refreshing the session token used - across different API methods that require authentication. + Return the Corellium API client object. """ - # session does not exist, just login and return - if self._api.session is None: - self._api.login() - - return self._api - - # check if session is about to expire - # currently depends on the magic number of 60 seconds - now = datetime.utcnow() - diff = datetime.strptime(self._api.session.expiration, '%Y-%m-%dT%H:%M:%S.%fZ') - now - if diff > timedelta(seconds=1): - self._api.login() - return self._api diff --git a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver_test.py b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver_test.py index acc55c4a9..bfe33295a 100644 --- a/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver_test.py +++ b/packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/driver_test.py @@ -3,7 +3,7 @@ import pytest from .corellium.exceptions import CorelliumApiException -from .corellium.types import Device, Instance, Project, Session +from .corellium.types import Device, Instance, Project from .driver import Corellium, CorelliumConsole, CorelliumPower from jumpstarter.common import exceptions as jmp_exceptions @@ -18,8 +18,8 @@ def test_driver_corellium_init_ok(monkeypatch): assert 'jmp' == c.device_name assert 'kronos' == c.device_flavor assert '1.0' == c.device_os - assert 'api-host' == c._api.host - assert 'api-token' == c._api.token + assert 'api-host' == c.api.host + assert 'api-token' == c.api.token @pytest.mark.parametrize( @@ -63,7 +63,7 @@ def test_driver_api_client_ok(monkeypatch, requests_mock): c = Corellium(project_id='1', device_name='jmp', device_flavor='kronos', device_os='1.0') - assert Session('token', '2022-03-20T01:50:10.000Z') == c.api.session + assert c.api.req.headers['Authorization'] == 'Bearer api-token' def test_driver_power_on_ok(monkeypatch): @@ -77,16 +77,14 @@ def test_driver_power_on_ok(monkeypatch): root = Corellium(project_id='1', device_name='jmp', device_flavor='kronos', device_os='1.0') power = CorelliumPower(parent=root) - with (patch.object(root._api, 'login', return_value=None), - patch.object(root._api, 'get_project', return_value=project), - patch.object(root._api, 'get_device', return_value=device), - patch.object(root._api, 'get_instance', side_effect=[None, instance]), - patch.object(root._api, 'create_instance', return_value=instance)): + with (patch.object(root.api, 'get_project', return_value=project), + patch.object(root.api, 'get_device', return_value=device), + patch.object(root.api, 'get_instance', side_effect=[None, instance]), + patch.object(root.api, 'create_instance', return_value=instance)): power.on() @pytest.mark.parametrize('mock_data', [ - ({'login': {'side_effect': CorelliumApiException('login error')}}), ({'get_project': {'return_value': None}}), ({'get_instance': {'return_value': None}}), ({'create_instance': {'side_effect': CorelliumApiException('create error')}}), @@ -101,15 +99,13 @@ def test_driver_power_on_error(monkeypatch, mock_data): power = CorelliumPower(parent=root) with pytest.raises((CorelliumApiException, ValueError)): - with (patch.object(root._api, 'login', - **mock_data.get('login', {'return_value': None})), - patch.object(root._api, 'get_project', + with (patch.object(root.api, 'get_project', **mock_data.get('get_project', {'return_value': project})), - patch.object(root._api, 'get_instance', + patch.object(root.api, 'get_instance', **mock_data.get('get_instance', {'return_value': instance})), - patch.object(root._api, 'create_instance', + patch.object(root.api, 'create_instance', **mock_data.get('create_instance', {'return_value': instance}))): - power.off() + power.on() def test_driver_power_off_ok(monkeypatch): @@ -121,16 +117,14 @@ def test_driver_power_off_ok(monkeypatch): root = Corellium(project_id='1', device_name='jmp', device_flavor='kronos', device_os='1.0') power = CorelliumPower(parent=root) - with (patch.object(root._api, 'login', return_value=None), - patch.object(root._api, 'get_project', return_value=project), - patch.object(root._api, 'set_instance_state', return_value=None), - patch.object(root._api, 'get_instance', + with (patch.object(root.api, 'get_project', return_value=project), + patch.object(root.api, 'set_instance_state', return_value=None), + patch.object(root.api, 'get_instance', side_effect=[instance, Instance(id=instance.id, state='off')])): power.off() @pytest.mark.parametrize('mock_data',[ - ({'login': {'side_effect': CorelliumApiException('login error')}}), ({'get_project': {'return_value': None}}), ({'get_instance': {'return_value': None}}), ({'destroy_instance': {'side_effect': CorelliumApiException('destroy error')}}), @@ -145,13 +139,11 @@ def test_driver_power_off_error(monkeypatch, mock_data): power = CorelliumPower(parent=root) with pytest.raises((CorelliumApiException, ValueError)): - with (patch.object(root._api, 'login', - **mock_data.get('login', {'return_value': None})), - patch.object(root._api, 'get_project', + with (patch.object(root.api, 'get_project', **mock_data.get('get_project', {'return_value': project})), - patch.object(root._api, 'get_instance', + patch.object(root.api, 'get_instance', **mock_data.get('get_instance', {'side_effect': [instance, None]})), - patch.object(root._api, 'destroy_instance', + patch.object(root.api, 'destroy_instance', **mock_data.get('destroy_instance', {'return_value': instance}))): power.off() @@ -165,16 +157,14 @@ def test_driver_console_get_url_ok(monkeypatch): root = Corellium(project_id='1', device_name='jmp', device_flavor='kronos', device_os='1.0') console = CorelliumConsole(parent=root, url='') - with (patch.object(root._api, 'login', return_value=None), - patch.object(root._api, 'get_project', return_value=project), - patch.object(root._api, 'get_instance', return_value=instance), - patch.object(root._api, 'get_instance_console_id', return_value='uart7-cons'), - patch.object(root._api, 'get_instance_console_url', return_value='wss://mock')): + with (patch.object(root.api, 'get_project', return_value=project), + patch.object(root.api, 'get_instance', return_value=instance), + patch.object(root.api, 'get_instance_console_id', return_value='uart7-cons'), + patch.object(root.api, 'get_instance_console_url', return_value='wss://mock')): assert 'wss://mock' == console.url @pytest.mark.parametrize('mock_data',[ - ({'login': {'side_effect': CorelliumApiException('login error')}}), ({'get_project': {'return_value': None}}), ({'get_instance': {'return_value': None}}), ({'get_instance_console_id': {'side_effect': ValueError('x')}}), @@ -190,14 +180,12 @@ def test_driver_console_get_url_error(monkeypatch, mock_data): console = CorelliumConsole(parent=root, url='') with pytest.raises((CorelliumApiException, ValueError)): - with (patch.object(root._api, 'login', - **mock_data.get('login', {'return_value': None})), - patch.object(root._api, 'get_project', + with (patch.object(root.api, 'get_project', **mock_data.get('get_project', {'return_value': project})), - patch.object(root._api, 'get_instance', + patch.object(root.api, 'get_instance', **mock_data.get('get_instance', {'side_effect': [instance, None]})), - patch.object(root._api, 'get_instance_console_id', + patch.object(root.api, 'get_instance_console_id', **mock_data.get('get_instance_console_id', {'return_value': 'uart7-cons'})), - patch.object(root._api, 'get_instance_console_id', + patch.object(root.api, 'get_instance_console_id', **mock_data.get('get_instance_console_url', {'return_value': 'ws://mock'}))): assert console.url