kleinkram 0.38.1.dev20241212075157__py3-none-any.whl → 0.38.1.dev20250207122632__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kleinkram might be problematic. Click here for more details.

Files changed (58) hide show
  1. kleinkram/__init__.py +33 -2
  2. kleinkram/api/client.py +21 -16
  3. kleinkram/api/deser.py +165 -0
  4. kleinkram/api/file_transfer.py +13 -24
  5. kleinkram/api/pagination.py +56 -0
  6. kleinkram/api/query.py +111 -0
  7. kleinkram/api/routes.py +266 -97
  8. kleinkram/auth.py +21 -20
  9. kleinkram/cli/__init__.py +0 -0
  10. kleinkram/{commands/download.py → cli/_download.py} +18 -44
  11. kleinkram/cli/_endpoint.py +58 -0
  12. kleinkram/{commands/list.py → cli/_list.py} +25 -38
  13. kleinkram/cli/_mission.py +153 -0
  14. kleinkram/cli/_project.py +99 -0
  15. kleinkram/cli/_upload.py +84 -0
  16. kleinkram/cli/_verify.py +56 -0
  17. kleinkram/{app.py → cli/app.py} +57 -25
  18. kleinkram/cli/error_handling.py +67 -0
  19. kleinkram/config.py +141 -107
  20. kleinkram/core.py +251 -3
  21. kleinkram/errors.py +13 -45
  22. kleinkram/main.py +1 -1
  23. kleinkram/models.py +48 -149
  24. kleinkram/printing.py +325 -0
  25. kleinkram/py.typed +0 -0
  26. kleinkram/types.py +9 -0
  27. kleinkram/utils.py +88 -29
  28. kleinkram/wrappers.py +401 -0
  29. {kleinkram-0.38.1.dev20241212075157.dist-info → kleinkram-0.38.1.dev20250207122632.dist-info}/METADATA +3 -3
  30. kleinkram-0.38.1.dev20250207122632.dist-info/RECORD +49 -0
  31. {kleinkram-0.38.1.dev20241212075157.dist-info → kleinkram-0.38.1.dev20250207122632.dist-info}/WHEEL +1 -1
  32. {kleinkram-0.38.1.dev20241212075157.dist-info → kleinkram-0.38.1.dev20250207122632.dist-info}/top_level.txt +1 -0
  33. testing/__init__.py +0 -0
  34. testing/backend_fixtures.py +67 -0
  35. tests/conftest.py +7 -0
  36. tests/test_config.py +115 -0
  37. tests/test_core.py +165 -0
  38. tests/test_end_to_end.py +29 -39
  39. tests/test_error_handling.py +44 -0
  40. tests/test_fixtures.py +34 -0
  41. tests/test_printing.py +62 -0
  42. tests/test_query.py +138 -0
  43. tests/test_utils.py +46 -24
  44. tests/test_wrappers.py +71 -0
  45. kleinkram/api/parsing.py +0 -86
  46. kleinkram/commands/__init__.py +0 -1
  47. kleinkram/commands/endpoint.py +0 -62
  48. kleinkram/commands/mission.py +0 -69
  49. kleinkram/commands/project.py +0 -24
  50. kleinkram/commands/upload.py +0 -164
  51. kleinkram/commands/verify.py +0 -142
  52. kleinkram/consts.py +0 -8
  53. kleinkram/enums.py +0 -10
  54. kleinkram/resources.py +0 -158
  55. kleinkram-0.38.1.dev20241212075157.dist-info/LICENSE +0 -674
  56. kleinkram-0.38.1.dev20241212075157.dist-info/RECORD +0 -37
  57. tests/test_resources.py +0 -137
  58. {kleinkram-0.38.1.dev20241212075157.dist-info → kleinkram-0.38.1.dev20250207122632.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from pathlib import Path
5
+ from secrets import token_hex
6
+
7
+ import pytest
8
+
9
+ from kleinkram import create_mission
10
+ from kleinkram import create_project
11
+ from kleinkram import delete_project
12
+ from kleinkram import list_missions
13
+ from kleinkram import list_projects
14
+ from kleinkram import upload
15
+
16
+ # we expect the mission files to be in this folder that is not commited to the repo
17
+ DATA_PATH = Path(__file__).parent.parent / "data" / "testing"
18
+ DATA_FILES = [
19
+ DATA_PATH / "10_KB.bag",
20
+ DATA_PATH / "50_KB.bag",
21
+ DATA_PATH / "1_MB.bag",
22
+ DATA_PATH / "17_MB.bag",
23
+ DATA_PATH / "125_MB.bag",
24
+ ]
25
+
26
+ PROJECT_DESCRIPTION = "This is a test project"
27
+
28
+
29
+ WAIT_BEOFORE_DELETION = 5
30
+
31
+
32
+ @pytest.fixture(scope="session")
33
+ def project():
34
+ project_name = token_hex(8)
35
+
36
+ print("here")
37
+ create_project(project_name, description="This is a test project")
38
+
39
+ project = list_projects(project_names=[project_name])[0]
40
+
41
+ yield project
42
+
43
+ time.sleep(WAIT_BEOFORE_DELETION)
44
+ delete_project(project.id)
45
+
46
+
47
+ @pytest.fixture
48
+ def mission(project):
49
+ mission_name = token_hex(8)
50
+ upload(
51
+ mission_name=mission_name,
52
+ project_id=project.id,
53
+ files=DATA_FILES,
54
+ create=True,
55
+ )
56
+ mission = list_missions(project_ids=[project.id], mission_names=[mission_name])[0]
57
+
58
+ yield mission
59
+
60
+
61
+ @pytest.fixture
62
+ def empty_mission(project):
63
+ mission_name = token_hex(8)
64
+ create_mission(mission_name, project.id, metadata={})
65
+ mission = list_missions(project_ids=[project.id], mission_names=[mission_name])[0]
66
+
67
+ yield mission
tests/conftest.py ADDED
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ pytest_plugins = [
6
+ "testing.backend_fixtures",
7
+ ]
tests/test_config.py ADDED
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from tempfile import TemporaryDirectory
5
+
6
+ import pytest
7
+
8
+ from kleinkram.config import Config
9
+ from kleinkram.config import Endpoint
10
+ from kleinkram.config import _load_config
11
+ from kleinkram.config import add_endpoint
12
+ from kleinkram.config import check_config_compatibility
13
+ from kleinkram.config import endpoint_table
14
+ from kleinkram.config import get_config
15
+ from kleinkram.config import get_env
16
+ from kleinkram.config import get_shared_state
17
+ from kleinkram.config import save_config
18
+ from kleinkram.config import select_endpoint
19
+
20
+ CONFIG_FILENAME = "kleinkram.json"
21
+
22
+
23
+ @pytest.fixture
24
+ def config_path():
25
+ with TemporaryDirectory() as tmpdir:
26
+ yield Path(tmpdir) / CONFIG_FILENAME
27
+
28
+
29
+ def test_load_config_default(config_path):
30
+ config = _load_config(path=config_path)
31
+
32
+ assert not config_path.exists()
33
+ assert Config() == config
34
+
35
+
36
+ def test_save_and_load_config(config_path):
37
+
38
+ config = Config(version="foo")
39
+
40
+ assert not config_path.exists()
41
+ save_config(config, path=config_path)
42
+ assert config_path.exists()
43
+
44
+ loaded_config = _load_config(path=config_path)
45
+ assert loaded_config == config
46
+
47
+
48
+ def test_get_config_default(config_path):
49
+ config = get_config(path=config_path)
50
+
51
+ assert not config_path.exists()
52
+ assert Config() == config
53
+ assert config is get_config(path=config_path)
54
+
55
+
56
+ def test_get_config_after_save(config_path):
57
+ config = get_config(path=config_path)
58
+ config.version = "foo"
59
+ save_config(config, path=config_path)
60
+
61
+ assert config is get_config(path=config_path)
62
+
63
+
64
+ def test_get_shared_state():
65
+ state = get_shared_state()
66
+ assert state is get_shared_state()
67
+
68
+
69
+ def test_select_endpoint(config_path):
70
+ config = get_config(path=config_path)
71
+ save_config(config, path=config_path)
72
+ assert config.selected_endpoint == get_env().value
73
+
74
+ # select existing endpoint
75
+ select_endpoint(config, "prod", path=config_path)
76
+ assert config.selected_endpoint == "prod"
77
+ assert config == _load_config(path=config_path)
78
+
79
+ with pytest.raises(ValueError):
80
+ select_endpoint(config, "foo", path=config_path)
81
+
82
+
83
+ def test_add_endpoint(config_path):
84
+ config = get_config(path=config_path)
85
+ save_config(config, path=config_path)
86
+ assert config.selected_endpoint == get_env().value
87
+
88
+ with pytest.raises(ValueError):
89
+ select_endpoint(config, "foo", path=config_path)
90
+
91
+ ep = Endpoint("foo", "api", "s3")
92
+ add_endpoint(config, ep, path=config_path)
93
+ assert config.selected_endpoint == "foo"
94
+ assert config.endpoint == ep
95
+ assert config == _load_config(path=config_path)
96
+
97
+ select_endpoint(config, "dev", path=config_path)
98
+ assert config.selected_endpoint == "dev"
99
+ select_endpoint(config, "foo", path=config_path)
100
+ assert config.selected_endpoint == "foo"
101
+
102
+
103
+ def test_endpoint_table():
104
+ config = Config()
105
+ table = endpoint_table(config)
106
+
107
+ assert [c.header for c in table.columns] == ["Name", "API", "S3"]
108
+ assert len(table.rows) == 3
109
+
110
+
111
+ def test_check_config_compatiblity(config_path):
112
+ assert check_config_compatibility(path=config_path)
113
+ with open(config_path, "w") as f:
114
+ f.write("foo") # invalid config
115
+ assert not check_config_compatibility(path=config_path)
tests/test_core.py ADDED
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ from secrets import token_hex
4
+ from uuid import uuid4
5
+
6
+ import pytest
7
+
8
+ import kleinkram.api.routes
9
+ import kleinkram.core
10
+ import kleinkram.errors
11
+ from kleinkram import list_files
12
+ from kleinkram import list_missions
13
+ from kleinkram import list_projects
14
+ from kleinkram.api.client import AuthenticatedClient
15
+ from kleinkram.api.query import FileQuery
16
+ from kleinkram.api.query import MissionQuery
17
+ from kleinkram.api.query import ProjectQuery
18
+ from kleinkram.errors import MissionNotFound
19
+ from kleinkram.models import FileVerificationStatus
20
+ from testing.backend_fixtures import DATA_FILES
21
+
22
+
23
+ @pytest.mark.slow
24
+ def test_upload_create(project):
25
+ mission_name = token_hex(8)
26
+ mission_query = MissionQuery(
27
+ patterns=[mission_name], project_query=ProjectQuery(ids=[project.id])
28
+ )
29
+
30
+ client = AuthenticatedClient()
31
+ kleinkram.core.upload(
32
+ client=client, query=mission_query, file_paths=DATA_FILES, create=True
33
+ )
34
+
35
+ mission = list_missions(mission_names=[mission_name])[0]
36
+ assert mission.project_id == project.id
37
+ assert mission.name == mission_name
38
+
39
+ files = list_files(mission_ids=[mission.id])
40
+ assert set([file.name for file in files if file.name.endswith(".bag")]) == set(
41
+ [file.name for file in DATA_FILES]
42
+ )
43
+
44
+
45
+ @pytest.mark.slow
46
+ def test_upload_no_create(project):
47
+ mission_name = token_hex(8)
48
+ mission_query = MissionQuery(
49
+ patterns=[mission_name], project_query=ProjectQuery(ids=[project.id])
50
+ )
51
+
52
+ client = AuthenticatedClient()
53
+ with pytest.raises(MissionNotFound):
54
+ kleinkram.core.upload(
55
+ client=client, query=mission_query, file_paths=DATA_FILES, create=False
56
+ )
57
+
58
+
59
+ @pytest.mark.slow
60
+ def test_upload_to_existing_mission(empty_mission):
61
+ mission_query = MissionQuery(ids=[empty_mission.id])
62
+
63
+ client = AuthenticatedClient()
64
+ kleinkram.core.upload(client=client, query=mission_query, file_paths=DATA_FILES)
65
+
66
+ files = list_files(mission_ids=[empty_mission.id])
67
+ assert set([file.name for file in files if file.name.endswith(".bag")]) == set(
68
+ [file.name for file in DATA_FILES]
69
+ )
70
+
71
+
72
+ @pytest.mark.slow
73
+ def test_delete_existing_files(mission):
74
+ client = AuthenticatedClient()
75
+ files = list_files(mission_ids=[mission.id], file_names=["*.bag"])
76
+ kleinkram.core.delete_files(client=client, file_ids=[f.id for f in files])
77
+ assert not list_files(mission_ids=[mission.id], file_names=["*.bag"])
78
+
79
+
80
+ @pytest.mark.slow
81
+ def test_delete_non_existing_files():
82
+ client = AuthenticatedClient()
83
+
84
+ with pytest.raises(kleinkram.errors.FileNotFound):
85
+ kleinkram.core.delete_files(client=client, file_ids=[uuid4()])
86
+
87
+
88
+ @pytest.mark.slow
89
+ def test_create_update_delete_mission(project):
90
+ mission_name = token_hex(8)
91
+
92
+ client = AuthenticatedClient()
93
+ kleinkram.api.routes._create_mission(client, project.id, mission_name)
94
+
95
+ mission = list_missions(mission_names=[mission_name])[0]
96
+
97
+ assert mission.project_id == project.id
98
+ assert mission.name == mission_name
99
+
100
+ assert list_files(mission_ids=[mission.id]) == []
101
+
102
+ # TODO test update, for this we would need to add metadata types to the backend
103
+
104
+ kleinkram.core.delete_mission(client=client, mission_id=mission.id)
105
+
106
+
107
+ @pytest.mark.slow
108
+ def test_create_update_delete_project():
109
+ project_name = token_hex(8)
110
+
111
+ client = AuthenticatedClient()
112
+ project_id = kleinkram.api.routes._create_project(client, project_name, "test")
113
+ project = list_projects(project_ids=[project_id])[0]
114
+
115
+ assert list_missions(project_ids=[project.id]) == []
116
+ assert list_files(project_ids=[project.id]) == []
117
+
118
+ assert project.name == project_name
119
+ assert project.description == "test"
120
+
121
+ new_name = token_hex(8)
122
+ kleinkram.core.update_project(
123
+ client=client, project_id=project.id, new_name=new_name, description="new desc"
124
+ )
125
+
126
+ project = list_projects(project_ids=[project.id])[0]
127
+ assert project.name == new_name
128
+ assert project.description == "new desc"
129
+
130
+ kleinkram.core.delete_project(client=client, project_id=project.id)
131
+
132
+
133
+ @pytest.mark.slow
134
+ def test_download(mission, tmp_path):
135
+ client = AuthenticatedClient()
136
+
137
+ query = FileQuery(mission_query=MissionQuery(ids=[mission.id]), patterns=["*.bag"])
138
+ kleinkram.core.download(client=client, query=query, base_dir=tmp_path)
139
+ files = list_files(mission_ids=[mission.id], file_names=["*.bag"])
140
+
141
+ assert set([f.name for f in tmp_path.iterdir()]) == set([f.name for f in files])
142
+
143
+ for file in files:
144
+ assert (tmp_path / file.name).stat().st_size == file.size
145
+
146
+
147
+ @pytest.mark.slow
148
+ def test_verify(mission):
149
+ client = AuthenticatedClient()
150
+ query = MissionQuery(ids=[mission.id])
151
+
152
+ verify_status = kleinkram.core.verify(
153
+ client=client, query=query, file_paths=DATA_FILES, skip_hash=True
154
+ )
155
+
156
+ assert all(
157
+ status == FileVerificationStatus.UPLAODED for status in verify_status.values()
158
+ )
159
+
160
+
161
+ @pytest.mark.slow
162
+ def test_update_file():
163
+ client = AuthenticatedClient()
164
+ with pytest.raises(NotImplementedError):
165
+ kleinkram.core.update_file(client=client, file_id=uuid4())
tests/test_end_to_end.py CHANGED
@@ -6,18 +6,16 @@ import shutil
6
6
  from pathlib import Path
7
7
 
8
8
  import pytest
9
- from kleinkram.api.routes import _get_api_version
10
9
  from rich.console import Console
11
10
  from rich.text import Text
12
11
 
12
+ from kleinkram.api.routes import _get_api_version
13
+
13
14
  VERBOSE = True
14
15
 
15
16
  CLI = "klein"
16
17
  PROJECT_NAME = "automated-testing"
17
-
18
- DATA_DIR = Path(__file__).parent.parent / "data" / "testing"
19
- _IN_DIR = DATA_DIR / "in"
20
- _OUT_DIR = DATA_DIR / "out"
18
+ DATA_PATH = Path(__file__).parent.parent / "data" / "testing"
21
19
 
22
20
 
23
21
  @pytest.fixture(scope="session")
@@ -30,25 +28,6 @@ def api():
30
28
  return False
31
29
 
32
30
 
33
- @pytest.fixture(scope="session")
34
- def in_dir():
35
- return _IN_DIR
36
-
37
-
38
- @pytest.fixture(scope="session")
39
- def out_dir():
40
- try:
41
- _OUT_DIR.mkdir(exist_ok=True)
42
- yield _OUT_DIR
43
- finally:
44
- shutil.rmtree(_OUT_DIR)
45
-
46
-
47
- @pytest.fixture(scope="session")
48
- def name():
49
- return secrets.token_hex(8)
50
-
51
-
52
31
  def run_cmd(command, *, verbose=VERBOSE):
53
32
  msg = ("\n", "#" * 50, "\n\n", "running command:", Text(command, style="bold"))
54
33
  Console().print(*msg)
@@ -61,45 +40,56 @@ def run_cmd(command, *, verbose=VERBOSE):
61
40
 
62
41
 
63
42
  @pytest.mark.slow
64
- def test_upload_verify_update_download_mission(name, in_dir, out_dir, api):
43
+ def test_upload_verify_update_download_mission(project, tmp_path, api):
65
44
  assert api
66
45
 
67
- upload = (
68
- f"{CLI} upload -p {PROJECT_NAME} -m {name} --create {in_dir.absolute()}/*.bag"
46
+ mission_name = secrets.token_hex(8)
47
+ upload = f"{CLI} upload -p {project.name} -m {mission_name} --create {DATA_PATH.absolute()}/*.bag"
48
+ verify = (
49
+ f"{CLI} verify -p {project.name} -m {mission_name} {DATA_PATH.absolute()}/*.bag"
69
50
  )
70
- verify = f"{CLI} verify -p {PROJECT_NAME} -m {name} {in_dir.absolute()}/*.bag"
71
- update = f"{CLI} mission update -p {PROJECT_NAME} -m {name} --metadata {in_dir.absolute()}/metadata.yaml"
72
- download = f"{CLI} download -p {PROJECT_NAME} -m {name} --dest {out_dir.absolute()}"
51
+ # update = f"{CLI} mission update -p {project.name} -m {mission_name} --metadata {DATA_PATH.absolute()}/metadata.yaml"
52
+ download = f"{CLI} download -p {project.name} -m {mission_name} --dest {tmp_path.absolute()}"
73
53
 
74
54
  assert run_cmd(upload) == 0
75
55
  assert run_cmd(verify) == 0
76
- assert run_cmd(update) == 0
56
+ # assert run_cmd(update) == 0
77
57
  assert run_cmd(download) == 0
78
58
 
79
59
 
80
60
  @pytest.mark.slow
81
- def test_list_files(api):
61
+ def test_list_files(project, mission, api):
82
62
  assert api
83
- assert run_cmd(f"{CLI} list files -p {PROJECT_NAME}") == 0
84
- assert run_cmd(f"{CLI} list files -p {PROJECT_NAME} -m {secrets.token_hex(8)}") == 0
63
+ assert run_cmd(f"{CLI} list files -p {project.name}") == 0
64
+ assert run_cmd(f"{CLI} list files -p {project.name} -m {mission.name}") == 0
85
65
  assert run_cmd(f"{CLI} list files") == 0
86
- assert run_cmd(f"{CLI} list files -p {secrets.token_hex(8)}") == 0
66
+ assert run_cmd(f"{CLI} list files -p {mission.name}") == 0
87
67
  assert run_cmd(f'{CLI} list files -p "*" -m "*" "*"') == 0
88
68
 
89
69
 
90
70
  @pytest.mark.slow
91
- def test_list_missions(api):
71
+ def test_list_missions(api, project, mission):
92
72
  assert api
93
- assert run_cmd(f"{CLI} list missions -p {PROJECT_NAME}") == 0
73
+
74
+ assert run_cmd(f"{CLI} list missions -p {project.name} {mission.name}") == 0
75
+ assert run_cmd(f"{CLI} list missions -p {project.name} {secrets.token_hex(8)}") == 0
76
+ assert run_cmd(f"{CLI} list missions -p {project.name} {mission.id}") == 0
77
+ assert run_cmd(f"{CLI} list missions {secrets.token_hex(8)}") == 0
78
+ assert run_cmd(f"{CLI} list missions {mission.id}") == 0
79
+ assert run_cmd(f"{CLI} list missions {mission.name}") == 0
80
+
81
+ assert run_cmd(f"{CLI} list missions -p {project.name}") == 0
82
+ assert run_cmd(f"{CLI} list missions -p {project.id}") == 0
94
83
  assert run_cmd(f"{CLI} list missions -p {secrets.token_hex(8)}") == 0
95
84
  assert run_cmd(f"{CLI} list missions") == 0
96
85
  assert run_cmd(f'{CLI} list missions -p "*" "*"') == 0
97
86
 
98
87
 
99
88
  @pytest.mark.slow
100
- def test_list_projects(api):
89
+ def test_list_projects(api, project):
101
90
  assert api
102
91
  assert run_cmd(f"{CLI} list projects") == 0
103
- assert run_cmd(f"{CLI} list projects {PROJECT_NAME}") == 0
92
+ assert run_cmd(f"{CLI} list projects {project.name}") == 0
104
93
  assert run_cmd(f"{CLI} list projects {secrets.token_hex(8)}") == 0
94
+ assert run_cmd(f"{CLI} list projects {project.id}") == 0
105
95
  assert run_cmd(f'{CLI} list projects "*"') == 0
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ from kleinkram.cli.error_handling import display_error
6
+
7
+
8
+ class MyException(Exception):
9
+ pass
10
+
11
+
12
+ def test_display_error_not_verbose(capsys):
13
+ exc = MyException("hello")
14
+
15
+ display_error(exc=exc, verbose=False)
16
+
17
+ out, err = capsys.readouterr()
18
+
19
+ assert out == ""
20
+ assert err == "MyException: hello\n"
21
+
22
+ exc = MyException()
23
+
24
+ display_error(exc=exc, verbose=False)
25
+
26
+ out, err = capsys.readouterr()
27
+
28
+ assert out == ""
29
+ assert err == "MyException\n"
30
+
31
+
32
+ def test_display_error_verbose(capsys):
33
+ exc = MyException("hello")
34
+
35
+ display_error(exc=exc, verbose=True)
36
+
37
+ out, err = capsys.readouterr()
38
+
39
+ assert out == ""
40
+ assert err == (
41
+ "╭──────────────────────────────── My Exception ────────────────────────────────╮\n"
42
+ "│ hello │\n"
43
+ "╰──────────────────────────────────────────────────────────────────────────────╯\n"
44
+ )
tests/test_fixtures.py ADDED
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ from kleinkram import list_files
6
+ from kleinkram import list_missions
7
+ from kleinkram import list_projects
8
+ from testing.backend_fixtures import DATA_FILES
9
+ from testing.backend_fixtures import PROJECT_DESCRIPTION
10
+
11
+
12
+ @pytest.mark.slow
13
+ def test_project_fixture(project):
14
+ assert list_projects(project_ids=[project.id])[0].id == project.id
15
+ assert project.description == PROJECT_DESCRIPTION
16
+
17
+
18
+ @pytest.mark.slow
19
+ def test_mission_fixture(mission, project):
20
+ assert mission.project_id == project.id
21
+ assert list_missions(mission_ids=[mission.id])[0].id == mission.id
22
+
23
+ files = list_files(mission_ids=[mission.id])
24
+
25
+ assert set([file.name for file in files if file.name.endswith(".bag")]) == set(
26
+ [file.name for file in DATA_FILES]
27
+ )
28
+
29
+
30
+ @pytest.mark.slow
31
+ def test_empty_mission_fixture(empty_mission, project):
32
+ assert empty_mission.project_id == project.id
33
+ assert list_missions(mission_ids=[empty_mission.id])[0].id == empty_mission.id
34
+ assert not list_files(mission_ids=[empty_mission.id])
tests/test_printing.py ADDED
@@ -0,0 +1,62 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime
4
+
5
+ import pytest
6
+
7
+ from kleinkram.models import MetadataValue
8
+ from kleinkram.models import MetadataValueType
9
+ from kleinkram.printing import format_bytes
10
+ from kleinkram.printing import parse_metadata_value
11
+
12
+
13
+ def test_format_bytes():
14
+ assert format_bytes(0) == "0 B"
15
+ assert format_bytes(1) == "1 B"
16
+ assert format_bytes(1000) == "1000 B"
17
+ assert format_bytes(1024) == "1.00 KB"
18
+ assert format_bytes(1025) == "1.00 KB"
19
+ assert format_bytes(2048) == "2.00 KB"
20
+ assert format_bytes(2**20) == "1.00 MB"
21
+ assert format_bytes(2**30) == "1.00 GB"
22
+ assert format_bytes(2**40) == "1.00 TB"
23
+ assert format_bytes(2**50) == "1.00 PB"
24
+
25
+
26
+ def test_parse_metadata_value():
27
+ mv = MetadataValue(type_=MetadataValueType.STRING, value="foo")
28
+ assert parse_metadata_value(mv) == "foo"
29
+ mv = MetadataValue(type_=MetadataValueType.LINK, value="foo")
30
+ assert parse_metadata_value(mv) == "foo"
31
+ mv = MetadataValue(type_=MetadataValueType.LOCATION, value="foo")
32
+ assert parse_metadata_value(mv) == "foo"
33
+ mv = MetadataValue(type_=MetadataValueType.NUMBER, value="1")
34
+ assert parse_metadata_value(mv) == 1.0
35
+ mv = MetadataValue(type_=MetadataValueType.BOOLEAN, value="true")
36
+ assert parse_metadata_value(mv) is True # noqa
37
+ mv = MetadataValue(type_=MetadataValueType.BOOLEAN, value="false")
38
+ assert parse_metadata_value(mv) is False # noqa
39
+ mv = MetadataValue(type_=MetadataValueType.DATE, value="2021-01-01T00:00:00Z")
40
+ assert parse_metadata_value(mv) == datetime.datetime(
41
+ 2021, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc
42
+ )
43
+
44
+
45
+ @pytest.mark.skip
46
+ def test_projects_to_table(): ...
47
+
48
+
49
+ @pytest.mark.skip
50
+ def test_missions_to_table(): ...
51
+
52
+
53
+ @pytest.mark.skip
54
+ def test_files_to_table(): ...
55
+
56
+
57
+ @pytest.mark.skip
58
+ def test_mission_info_table(): ...
59
+
60
+
61
+ @pytest.mark.skip
62
+ def test_project_info_table(): ...