Skip to content

Commit 91b29a4

Browse files
committed
Fixing all tests!
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
1 parent 5579f54 commit 91b29a4

12 files changed

Lines changed: 187 additions & 262 deletions

File tree

arcsecond/api/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def login(self, username, access_key=None, upload_key=None):
5757

5858
endpoint = ArcsecondAPIEndpoint(self.config, API_AUTH_PATH_VERIFY)
5959
_, error = endpoint.create(
60-
{"username": username, "key": access_key or upload_key}
60+
json={"username": username, "key": access_key or upload_key}
6161
)
6262
if error:
6363
click.echo(click.style(error, fg="red"))

arcsecond/cloud/uploader/allskycameraimages/uploader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def _prepare_upload(self):
1111
# Camera validation was already done in the context
1212
pass
1313

14-
def _get_upload_data_fields(self, **kwargs):
14+
def _get_upload_data(self, **kwargs):
1515
fields = {
1616
"camera": self._context.camera_uuid
1717
}

arcsecond/cloud/uploader/context.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from arcsecond.api.constants import API_AUTH_PATH_VERIFY_PORTAL
66
from arcsecond.api.endpoint import ArcsecondAPIEndpoint
77
from arcsecond.api.main import ArcsecondAPI
8-
98
from .errors import (
109
InvalidAstronomerError,
1110
InvalidOrgMembershipError,
@@ -92,7 +91,7 @@ def _validate_remote_organisation(self):
9291
def _validate_astronomer_role_in_remote_organisation(self):
9392
endpoint = ArcsecondAPIEndpoint(self.config, API_AUTH_PATH_VERIFY_PORTAL)
9493
_, error = endpoint.create(
95-
{
94+
json={
9695
"username": self._config.username,
9796
"key": self._config.access_key or self._config.upload_key,
9897
"organisation": self._subdomain,

arcsecond/cloud/uploader/datafiles/uploader.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def _prepare_upload(self):
2323
f"{self.log_prefix} Creating dataset with name {dataset_name}..."
2424
)
2525
endpoint = ArcsecondAPIEndpoint(self._context.config, 'datasets', self._context.subdomain)
26-
dataset, error = endpoint.create(data=data)
26+
dataset, error = endpoint.create(json=data)
2727

2828
if error:
2929
error_msg = f"Dataset {dataset_name} could not be created: {error}"
@@ -40,8 +40,11 @@ def _get_upload_data(self, **kwargs):
4040
"dataset": self._context.dataset_uuid,
4141
"is_raw": str(self._context.is_raw_data),
4242
}
43-
if self._context.custom_tags:
44-
fields["tags"] = ",".join(self._context.custom_tags or []) # will be split back in backend
43+
if self._context.custom_tags and len(self._context.custom_tags) > 0:
44+
raw_tags = self._context.custom_tags if isinstance(self._context.custom_tags, list) \
45+
else self._context.custom_tags.split(',')
46+
tags = [t.strip() for t in raw_tags if len(t.strip()) > 0]
47+
fields["tags"] = ",".join(tags)
4548
clean_kwargs = {k: kwargs[k] for k in ('is_raw', 'tags', 'dataset') if k in kwargs}
4649
if 'tags' in clean_kwargs and not clean_kwargs['tags']:
4750
# Tags must really be provided only when non-blank/null/empty

tests/api/test_api.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import responses
1+
import respx
22

33
from arcsecond import ArcsecondAPI, ArcsecondConfig
44
from arcsecond.api.constants import ARCSECOND_API_URL_DEV
@@ -10,24 +10,24 @@
1010
)
1111

1212

13-
@responses.activate
13+
@respx.mock
1414
def test_login_basic():
1515
random_api_name = random_string()
1616
config = ArcsecondConfig(api_name=random_api_name)
1717
config.api_server = ARCSECOND_API_URL_DEV
1818
assert config.access_key == ""
19-
prepare_successful_login(random_api_name)
19+
prepare_successful_login(config)
2020
ArcsecondAPI(config).login(TEST_LOGIN_USERNAME, access_key=TEST_API_KEY)
2121
assert config.access_key == TEST_API_KEY
2222
assert config.upload_key == ""
2323

2424

25-
@responses.activate
25+
@respx.mock
2626
def test_login_upload_key():
2727
random_api_name = random_string()
2828
config = ArcsecondConfig(api_name=random_api_name)
2929
config.api_server = ARCSECOND_API_URL_DEV
30-
prepare_successful_login(random_api_name)
30+
prepare_successful_login(config)
3131
ArcsecondAPI(config).login(username=TEST_LOGIN_USERNAME, upload_key=TEST_UPLOAD_KEY)
3232
assert config.access_key == ""
3333
assert config.upload_key == TEST_UPLOAD_KEY
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import random
2+
import shutil
3+
import tempfile
4+
import uuid
5+
from datetime import datetime, timezone
6+
from pathlib import Path
7+
from unittest.mock import MagicMock
8+
9+
import pytest
10+
import respx
11+
from httpx import Response
12+
13+
from arcsecond import (
14+
AllSkyCameraImageFileUploader,
15+
AllSkyCameraImageUploadContext,
16+
)
17+
from arcsecond.cloud.uploader.constants import Status, Substatus
18+
from tests.utils import (
19+
prepare_successful_login,
20+
prepare_upload_allskyimages,
21+
random_string,
22+
)
23+
24+
25+
@pytest.fixture
26+
def mock_config():
27+
"""Create a mock ArcsecondConfig."""
28+
config = MagicMock()
29+
config.username = "test_user"
30+
config.upload_key = "test_key"
31+
config.api_name = random_string()
32+
config.api_server = "http://mock.example.com"
33+
config.access_key = None # very important, because access_key takes precedence on upload_key in headers setting.
34+
config.upload_key = '1234567890'
35+
return config
36+
37+
38+
@respx.mock
39+
def test_full_upload_process_allskyimages(mock_config):
40+
camera_uuid = str(uuid.uuid4())
41+
org_subdomain = "test-portal"
42+
43+
prepare_successful_login(mock_config, org_subdomain)
44+
prepare_upload_allskyimages(mock_config, camera_uuid, org_subdomain)
45+
46+
# file upload
47+
image_id = random.randint(1, 1000)
48+
respx.post(
49+
"/".join([mock_config.api_server, org_subdomain, "allskycameras", camera_uuid, "images"]) + "/"
50+
).mock(Response(201, json={"status": "success", "id": image_id}))
51+
52+
context = AllSkyCameraImageUploadContext(
53+
mock_config,
54+
input_camera_uuid=camera_uuid,
55+
org_subdomain=org_subdomain
56+
)
57+
58+
context.validate() # important step to perform before uploading.
59+
fixtures_dir = Path(__file__).parent.parent.parent.parent / "fixtures"
60+
fixture_files = list(fixtures_dir.glob("*.jpeg"))
61+
62+
for fixture_file in fixture_files:
63+
# Create a temporary directory and copy the fixture file there
64+
with tempfile.TemporaryDirectory() as temp_dir:
65+
temp_path = Path(temp_dir) / fixture_file.name
66+
shutil.copy(fixture_file, temp_path)
67+
68+
# Use the actual file for uploading
69+
uploader = AllSkyCameraImageFileUploader(
70+
context, str(temp_path), display_progress=False
71+
)
72+
73+
status, substatus, error = uploader.upload_file(datetime.now(timezone.utc).timestamp())
74+
assert status.value == Status.OK.value
75+
assert substatus.value == Substatus.DONE.value
76+
assert error is None

tests/cloud/uploader/datafiles/test_uploader_errors.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_upload_file_skipped(file_uploader):
2828
mock_perform.assert_called_once()
2929

3030
# Verify result
31-
assert result == [Status.OK, Substatus.DONE, None]
31+
assert result == [Status.SKIPPED, Substatus.ALREADY_SYNCED, None]
3232

3333

3434
def test_upload_file_invalid_context(file_uploader):
@@ -102,6 +102,5 @@ def test_upload_file_retry_on_error(file_uploader):
102102
# Verify each method was called twice (initial + retry)
103103
assert prepare_mock.call_count == 2
104104
assert perform_mock.call_count == 2
105-
assert update_mock.call_count == 2
106105

107106

tests/cloud/uploader/datafiles/test_uploader_full_process.py

Lines changed: 30 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,62 +3,56 @@
33
import tempfile
44
import uuid
55
from pathlib import Path
6+
from unittest.mock import MagicMock
67

7-
import responses
8+
import pytest
9+
import respx
10+
from httpx import Response
811

9-
from api.constants import ARCSECOND_API_URL_DEV
1012
from arcsecond import (
11-
AllSkyCameraImageFileUploader,
12-
AllSkyCameraImageUploadContext,
13-
ArcsecondConfig,
1413
DatasetFileUploader,
1514
DatasetUploadContext,
1615
)
1716
from arcsecond.cloud.uploader.constants import Status, Substatus
18-
from arcsecond.options import State
1917
from tests.utils import (
2018
prepare_successful_login,
21-
prepare_upload_allskyimage,
22-
prepare_upload_files,
19+
prepare_upload_files, random_string,
2320
)
2421

2522

26-
@responses.activate
27-
def test_full_upload_process_datafiles():
23+
@pytest.fixture
24+
def mock_config():
25+
"""Create a mock ArcsecondConfig."""
26+
config = MagicMock()
27+
config.username = "test_user"
28+
config.upload_key = "test_key"
29+
config.api_name = random_string()
30+
config.api_server = "http://mock.example.com"
31+
config.access_key = None # very important, because access_key takes precedence on upload_key in headers setting.
32+
config.upload_key = '1234567890'
33+
return config
34+
35+
36+
@respx.mock
37+
def test_full_upload_process_datafiles(mock_config):
2838
dataset_uuid = str(uuid.uuid4())
2939
telescope_uuid = str(uuid.uuid4())
3040
org_subdomain = "test-portal"
3141

32-
prepare_successful_login(org_subdomain)
33-
prepare_upload_files(dataset_uuid, telescope_uuid, org_subdomain)
42+
prepare_successful_login(mock_config, org_subdomain)
43+
prepare_upload_files(mock_config, dataset_uuid, telescope_uuid, org_subdomain)
3444

35-
# file upload
36-
datafile_id = random.randint(1, 1000)
37-
responses.post(
38-
"/".join([ARCSECOND_API_URL_DEV, org_subdomain, "datafiles"]) + "/",
39-
status=201,
40-
json={"status": "success", "id": datafile_id},
41-
)
42-
# update metadata
43-
responses.patch(
44-
"/".join([ARCSECOND_API_URL_DEV, org_subdomain, "datafiles", str(datafile_id)])
45-
+ "/",
46-
status=200,
47-
json={"id": datafile_id},
48-
)
45+
respx.get(
46+
"/".join([mock_config.api_server, org_subdomain, "datasets", dataset_uuid]) + "/"
47+
).mock(Response(201, json={"name": "dummy", "uuid": dataset_uuid}))
4948

50-
state = State(verbose=False, api_name="cloud")
51-
config = {
52-
"cloud": {
53-
"username": "dummy",
54-
"upload_key": "1234",
55-
"api_server": ARCSECOND_API_URL_DEV,
56-
}
57-
}
58-
config = ArcsecondConfig(state, config) # it will read your config file.
49+
datafile_id = random.randint(1, 1000)
50+
respx.post(
51+
"/".join([mock_config.api_server, org_subdomain, "datafiles"]) + "/"
52+
).mock(Response(201, json={"status": "success", "id": datafile_id}))
5953

6054
context = DatasetUploadContext(
61-
config,
55+
mock_config,
6256
input_dataset_uuid_or_name=dataset_uuid,
6357
input_telescope_uuid=telescope_uuid,
6458
is_raw_data=True,
@@ -84,54 +78,3 @@ def test_full_upload_process_datafiles():
8478
assert status.value == Status.OK.value
8579
assert substatus.value == Substatus.DONE.value
8680
assert error is None
87-
88-
89-
@responses.activate
90-
def test_full_upload_process_allskyimages():
91-
camera_uuid = str(uuid.uuid4())
92-
org_subdomain = "test-portal"
93-
94-
prepare_successful_login(org_subdomain)
95-
prepare_upload_allskyimage(camera_uuid, org_subdomain)
96-
97-
# file upload
98-
image_id = random.randint(1, 1000)
99-
responses.post(
100-
"/".join([ARCSECOND_API_URL_DEV, org_subdomain, "allskycameras", camera_uuid, "images"]) + "/",
101-
status=201,
102-
json={"status": "success", "id": image_id},
103-
)
104-
105-
state = State(verbose=False, api_name="cloud")
106-
config = {
107-
"cloud": {
108-
"username": "dummy",
109-
"upload_key": "1234",
110-
"api_server": ARCSECOND_API_URL_DEV,
111-
}
112-
}
113-
config = ArcsecondConfig(state, config) # it will read your config file.
114-
115-
context = AllSkyCameraImageUploadContext(
116-
config, input_camera_uuid=camera_uuid, org_subdomain=org_subdomain
117-
)
118-
119-
context.validate() # important step to perform before uploading.
120-
fixtures_dir = Path(__file__).parent.parent.parent.parent / "fixtures"
121-
fixture_files = list(fixtures_dir.glob("*.fits"))
122-
123-
for fixture_file in fixture_files:
124-
# Create a temporary directory and copy the fixture file there
125-
with tempfile.TemporaryDirectory() as temp_dir:
126-
temp_path = Path(temp_dir) / fixture_file.name
127-
shutil.copy(fixture_file, temp_path)
128-
129-
# Use the actual file for uploading
130-
uploader = AllSkyCameraImageFileUploader(
131-
context, str(temp_path), display_progress=False
132-
)
133-
134-
status, substatus, error = uploader.upload_file()
135-
assert status.value == Status.OK.value
136-
assert substatus.value == Substatus.DONE.value
137-
assert error is None

tests/cloud/uploader/datafiles/test_uploader_prepare.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def test_prepare_upload_with_new_dataset(file_uploader):
3434
"name": file_uploader._context.dataset_name,
3535
"telescope": file_uploader._context.telescope_uuid,
3636
}
37-
mock_func_create.assert_called_once_with(data=expected_data)
37+
mock_func_create.assert_called_once_with(json=expected_data)
3838
mock_func_update.assert_not_called()
3939

4040

0 commit comments

Comments
 (0)