qontract-reconcile 0.10.1rc1201__py3-none-any.whl → 0.10.2.dev1__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.
Files changed (140) hide show
  1. qontract_reconcile-0.10.2.dev1.dist-info/METADATA +500 -0
  2. {qontract_reconcile-0.10.1rc1201.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/RECORD +14 -132
  3. {qontract_reconcile-0.10.1rc1201.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.10.1rc1201.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/entry_points.txt +1 -0
  5. reconcile/aws_account_manager/README.md +5 -0
  6. reconcile/change_owners/README.md +34 -0
  7. reconcile/external_resources/manager.py +12 -1
  8. reconcile/external_resources/model.py +11 -0
  9. reconcile/glitchtip/README.md +150 -0
  10. reconcile/gql_definitions/introspection.json +51176 -0
  11. reconcile/run_integration.py +293 -0
  12. reconcile/utils/binary.py +2 -2
  13. reconcile/utils/mr/README.md +198 -0
  14. reconcile/utils/oc_map.py +2 -2
  15. tools/qontract_cli.py +0 -0
  16. qontract_reconcile-0.10.1rc1201.dist-info/METADATA +0 -64
  17. qontract_reconcile-0.10.1rc1201.dist-info/top_level.txt +0 -3
  18. reconcile/test/__init__.py +0 -0
  19. reconcile/test/conftest.py +0 -157
  20. reconcile/test/fixtures.py +0 -24
  21. reconcile/test/saas_auto_promotions_manager/__init__.py +0 -0
  22. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -170
  23. reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py +0 -0
  24. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py +0 -0
  25. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -115
  26. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -19
  27. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py +0 -66
  28. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -86
  29. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py +0 -352
  30. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py +0 -494
  31. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/__init__.py +0 -0
  32. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -25
  33. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -37
  34. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -81
  35. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -61
  36. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_json_path_selector.py +0 -74
  37. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -52
  38. reconcile/test/saas_auto_promotions_manager/utils/__init__.py +0 -0
  39. reconcile/test/test_acs_notifiers.py +0 -393
  40. reconcile/test/test_acs_policies.py +0 -497
  41. reconcile/test/test_acs_rbac.py +0 -865
  42. reconcile/test/test_aggregated_list.py +0 -237
  43. reconcile/test/test_amtool.py +0 -37
  44. reconcile/test/test_aws_ami_cleanup.py +0 -230
  45. reconcile/test/test_aws_ami_share.py +0 -68
  46. reconcile/test/test_aws_cloudwatch_log_retention.py +0 -434
  47. reconcile/test/test_aws_iam_keys.py +0 -70
  48. reconcile/test/test_aws_iam_password_reset.py +0 -35
  49. reconcile/test/test_aws_support_cases_sos.py +0 -23
  50. reconcile/test/test_checkpoint.py +0 -178
  51. reconcile/test/test_cli.py +0 -41
  52. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  53. reconcile/test/test_dashdotdb_dora.py +0 -245
  54. reconcile/test/test_database_access_manager.py +0 -660
  55. reconcile/test/test_deadmanssnitch.py +0 -290
  56. reconcile/test/test_gabi_authorized_users.py +0 -72
  57. reconcile/test/test_gcr_mirror.py +0 -14
  58. reconcile/test/test_github_org.py +0 -156
  59. reconcile/test/test_github_repo_invites.py +0 -119
  60. reconcile/test/test_gitlab_housekeeping.py +0 -333
  61. reconcile/test/test_gitlab_labeler.py +0 -126
  62. reconcile/test/test_gitlab_members.py +0 -219
  63. reconcile/test/test_gitlab_permissions.py +0 -164
  64. reconcile/test/test_instrumented_wrappers.py +0 -18
  65. reconcile/test/test_integrations_manager.py +0 -1252
  66. reconcile/test/test_jenkins_worker_fleets.py +0 -57
  67. reconcile/test/test_jira_permissions_validator.py +0 -519
  68. reconcile/test/test_jump_host.py +0 -114
  69. reconcile/test/test_ldap_users.py +0 -125
  70. reconcile/test/test_make.py +0 -28
  71. reconcile/test/test_ocm_additional_routers.py +0 -133
  72. reconcile/test/test_ocm_clusters.py +0 -798
  73. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -87
  74. reconcile/test/test_ocm_machine_pools.py +0 -1103
  75. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  76. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -125
  77. reconcile/test/test_openshift_base.py +0 -1269
  78. reconcile/test/test_openshift_cluster_bots.py +0 -240
  79. reconcile/test/test_openshift_namespace_labels.py +0 -344
  80. reconcile/test/test_openshift_namespaces.py +0 -256
  81. reconcile/test/test_openshift_resource.py +0 -443
  82. reconcile/test/test_openshift_resources_base.py +0 -478
  83. reconcile/test/test_openshift_saas_deploy.py +0 -188
  84. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -308
  85. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +0 -65
  86. reconcile/test/test_openshift_serviceaccount_tokens.py +0 -282
  87. reconcile/test/test_openshift_tekton_resources.py +0 -265
  88. reconcile/test/test_openshift_upgrade_watcher.py +0 -223
  89. reconcile/test/test_prometheus_rules_tester.py +0 -151
  90. reconcile/test/test_quay_membership.py +0 -86
  91. reconcile/test/test_quay_mirror.py +0 -172
  92. reconcile/test/test_quay_mirror_org.py +0 -82
  93. reconcile/test/test_quay_repos.py +0 -59
  94. reconcile/test/test_queries.py +0 -53
  95. reconcile/test/test_repo_owners.py +0 -47
  96. reconcile/test/test_requests_sender.py +0 -139
  97. reconcile/test/test_saasherder.py +0 -1611
  98. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -125
  99. reconcile/test/test_secret_reader.py +0 -153
  100. reconcile/test/test_slack_base.py +0 -183
  101. reconcile/test/test_slack_usergroups.py +0 -785
  102. reconcile/test/test_sql_query.py +0 -316
  103. reconcile/test/test_status_board.py +0 -258
  104. reconcile/test/test_terraform_aws_route53.py +0 -29
  105. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  106. reconcile/test/test_terraform_cloudflare_resources.py +0 -408
  107. reconcile/test/test_terraform_cloudflare_users.py +0 -747
  108. reconcile/test/test_terraform_repo.py +0 -440
  109. reconcile/test/test_terraform_resources.py +0 -519
  110. reconcile/test/test_terraform_tgw_attachments.py +0 -1295
  111. reconcile/test/test_terraform_users.py +0 -152
  112. reconcile/test/test_terraform_vpc_peerings.py +0 -576
  113. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1434
  114. reconcile/test/test_three_way_diff_strategy.py +0 -131
  115. reconcile/test/test_utils_jinja2.py +0 -130
  116. reconcile/test/test_vault_replication.py +0 -534
  117. reconcile/test/test_vault_utils.py +0 -47
  118. reconcile/test/test_version_bump.py +0 -18
  119. reconcile/test/test_vpc_peerings_validator.py +0 -194
  120. reconcile/test/test_wrong_region.py +0 -78
  121. release/__init__.py +0 -0
  122. release/test_version.py +0 -50
  123. release/version.py +0 -104
  124. tools/cli_commands/test/__init__.py +0 -0
  125. tools/cli_commands/test/conftest.py +0 -332
  126. tools/cli_commands/test/test_aws_cost_report.py +0 -258
  127. tools/cli_commands/test/test_cost_management_api.py +0 -326
  128. tools/cli_commands/test/test_gpg_encrypt.py +0 -235
  129. tools/cli_commands/test/test_openshift_cost_optimization_report.py +0 -255
  130. tools/cli_commands/test/test_openshift_cost_report.py +0 -295
  131. tools/cli_commands/test/test_util.py +0 -70
  132. tools/test/__init__.py +0 -0
  133. tools/test/conftest.py +0 -77
  134. tools/test/test_app_interface_metrics_exporter.py +0 -48
  135. tools/test/test_erv2.py +0 -80
  136. tools/test/test_get_container_images.py +0 -230
  137. tools/test/test_qontract_cli.py +0 -197
  138. tools/test/test_saas_promotion_state.py +0 -187
  139. tools/test/test_sd_app_sre_alert_report.py +0 -74
  140. tools/test/test_sre_checkpoints.py +0 -79
@@ -1,1269 +0,0 @@
1
- import logging
2
- from collections.abc import Mapping
3
- from typing import Any
4
- from unittest.mock import patch
5
-
6
- import pytest
7
- import yaml
8
- from kubernetes.dynamic import Resource
9
- from pydantic import BaseModel
10
- from pytest_mock import MockerFixture
11
-
12
- import reconcile.openshift_base as sut
13
- import reconcile.utils.openshift_resource as resource
14
- from reconcile.test.fixtures import Fixtures
15
- from reconcile.utils import oc
16
- from reconcile.utils.differ import (
17
- DiffPair,
18
- DiffResult,
19
- )
20
- from reconcile.utils.semver_helper import make_semver
21
-
22
- fxt = Fixtures("namespaces")
23
-
24
-
25
- TEST_INT = "test_openshift_resources"
26
- TEST_INT_VER = make_semver(1, 9, 2)
27
-
28
-
29
- def build_resource(kind: str, api_version: str, name: str) -> dict[str, Any]:
30
- return {
31
- "kind": kind,
32
- "apiVersion": api_version,
33
- "metadata": {
34
- "name": name,
35
- },
36
- }
37
-
38
-
39
- @pytest.fixture
40
- def resource_inventory() -> resource.ResourceInventory:
41
- return resource.ResourceInventory()
42
-
43
-
44
- @pytest.fixture
45
- def namespaces() -> list[dict[str, Any]]:
46
- return [fxt.get_anymarkup("valid-ns.yml")]
47
-
48
-
49
- @pytest.fixture
50
- @patch("reconcile.utils.oc.OCNative")
51
- def oc_cs1(self) -> oc.OCClient:
52
- return oc.OCNative(cluster_name="cs1", server="server", token="token", local=True)
53
-
54
-
55
- @pytest.fixture
56
- def oc_map(mocker, oc_cs1: oc.OCNative) -> oc.OC_Map:
57
- def get_cluster(cluster: str, privileged: bool = False):
58
- if cluster == "cs1":
59
- return oc_cs1
60
-
61
- return (
62
- oc.OCLogMsg(
63
- log_level=logging.DEBUG, message=f"[{cluster}] cluster skipped"
64
- ),
65
- )
66
-
67
- oc_map = mocker.patch("reconcile.utils.oc.OC_Map", autospec=True).return_value
68
- oc_map.get.side_effect = get_cluster
69
- return oc_map
70
-
71
-
72
- #
73
- # init_specs_to_fetch tests
74
- #
75
-
76
-
77
- def test_only_cluster_or_namespace(
78
- resource_inventory: resource.ResourceInventory, oc_map: oc.OC_Map
79
- ) -> None:
80
- with pytest.raises(KeyError):
81
- sut.init_specs_to_fetch(
82
- ri=resource_inventory,
83
- oc_map=oc_map,
84
- namespaces=[{"foo": "bar"}],
85
- clusters=[{"name": "cs1"}],
86
- )
87
-
88
-
89
- def test_no_cluster_or_namespace(
90
- resource_inventory: resource.ResourceInventory, oc_map: oc.OC_Map
91
- ) -> None:
92
- with pytest.raises(KeyError):
93
- sut.init_specs_to_fetch(
94
- ri=resource_inventory, oc_map=oc_map, namespaces=None, clusters=None
95
- )
96
-
97
-
98
- def test_namespaces_managed_types(
99
- resource_inventory: resource.ResourceInventory,
100
- oc_map: oc.OC_Map,
101
- oc_cs1: oc.OCNative,
102
- ) -> None:
103
- namespace = yaml.safe_load(
104
- """
105
- name: ns1
106
- cluster:
107
- name: cs1
108
- managedResourceTypes:
109
- - Template
110
- managedResourceNames:
111
- - resource: Template
112
- resourceNames:
113
- - tp1
114
- - tp2
115
- openshiftResources:
116
- - provider: resource
117
- path: /some/path.yml
118
- """
119
- )
120
- expected: list[sut.StateSpec] = [
121
- sut.CurrentStateSpec(
122
- oc=oc_cs1,
123
- cluster="cs1",
124
- namespace="ns1",
125
- kind="Template",
126
- resource_names=["tp1", "tp2"],
127
- ),
128
- sut.DesiredStateSpec(
129
- oc=oc_cs1,
130
- cluster="cs1",
131
- namespace="ns1",
132
- resource={"provider": "resource", "path": "/some/path.yml"},
133
- parent=namespace,
134
- ),
135
- ]
136
-
137
- rs = sut.init_specs_to_fetch(
138
- resource_inventory,
139
- oc_map,
140
- namespaces=[namespace],
141
- )
142
- assert rs == expected
143
-
144
-
145
- def test_namespaces_managed_types_with_resoruce_type_overrides(
146
- resource_inventory: resource.ResourceInventory,
147
- oc_map: oc.OC_Map,
148
- oc_cs1: oc.OCNative,
149
- ) -> None:
150
- namespace = yaml.safe_load(
151
- """
152
- name: ns1
153
- cluster:
154
- name: cs1
155
- managedResourceTypes:
156
- - Template
157
- managedResourceNames:
158
- - resource: Template
159
- resourceNames:
160
- - tp1
161
- - tp2
162
- managedResourceTypeOverrides:
163
- - resource: Template
164
- "override": "Template.something.something"
165
- openshiftResources:
166
- - provider: resource
167
- path: /some/path.yml
168
- """
169
- )
170
- expected: list[sut.StateSpec] = [
171
- sut.CurrentStateSpec(
172
- oc=oc_cs1,
173
- cluster="cs1",
174
- namespace="ns1",
175
- kind="Template.something.something",
176
- resource_names=["tp1", "tp2"],
177
- ),
178
- sut.DesiredStateSpec(
179
- oc=oc_cs1,
180
- cluster="cs1",
181
- namespace="ns1",
182
- resource={"provider": "resource", "path": "/some/path.yml"},
183
- parent=namespace,
184
- ),
185
- ]
186
- rs = sut.init_specs_to_fetch(
187
- resource_inventory,
188
- oc_map,
189
- namespaces=[namespace],
190
- )
191
-
192
- assert rs == expected
193
-
194
-
195
- def test_namespaces_managed_types_no_managed_resource_names(
196
- resource_inventory: resource.ResourceInventory,
197
- oc_map: oc.OC_Map,
198
- oc_cs1: oc.OCNative,
199
- ) -> None:
200
- namespace = yaml.safe_load(
201
- """
202
- name: ns1
203
- cluster:
204
- name: cs1
205
- managedResourceTypes:
206
- - Template
207
- openshiftResources:
208
- - provider: resource
209
- path: /some/path.yml
210
- """
211
- )
212
- expected: list[sut.StateSpec] = [
213
- sut.CurrentStateSpec(
214
- oc=oc_cs1,
215
- cluster="cs1",
216
- namespace="ns1",
217
- kind="Template",
218
- resource_names=None,
219
- ),
220
- sut.DesiredStateSpec(
221
- oc=oc_cs1,
222
- cluster="cs1",
223
- namespace="ns1",
224
- resource={"provider": "resource", "path": "/some/path.yml"},
225
- parent=namespace,
226
- ),
227
- ]
228
- rs = sut.init_specs_to_fetch(
229
- resource_inventory,
230
- oc_map,
231
- namespaces=[namespace],
232
- )
233
- assert rs == expected
234
-
235
-
236
- def test_namespaces_no_managed_resource_types(
237
- resource_inventory: resource.ResourceInventory,
238
- oc_map: oc.OC_Map,
239
- ) -> None:
240
- namespace = yaml.safe_load(
241
- """
242
- name: ns1
243
- cluster:
244
- name: cs1
245
- openshiftResources:
246
- - provider: resource
247
- path: /some/path.yml
248
- """
249
- )
250
- rs = sut.init_specs_to_fetch(
251
- resource_inventory,
252
- oc_map,
253
- namespaces=[namespace],
254
- )
255
-
256
- assert not rs
257
-
258
-
259
- def test_namespaces_resources_names_for_unmanaged_type(
260
- resource_inventory: resource.ResourceInventory,
261
- oc_map: oc.OC_Map,
262
- ) -> None:
263
- namespace = yaml.safe_load(
264
- """
265
- name: ns1
266
- cluster:
267
- name: cs1
268
- managedResourceTypes:
269
- - Template
270
- managedResourceNames:
271
- - resource: Template
272
- resourceNames:
273
- - tp1
274
- - tp2
275
- - resource: Secret
276
- resourceNames:
277
- - s1
278
- - s2
279
- openshiftResources:
280
- - provider: resource
281
- path: /some/path.yml
282
- """
283
- )
284
-
285
- with pytest.raises(KeyError):
286
- sut.init_specs_to_fetch(
287
- resource_inventory,
288
- oc_map,
289
- namespaces=[namespace],
290
- )
291
-
292
-
293
- def test_namespaces_type_override_for_unmanaged_type(
294
- resource_inventory: resource.ResourceInventory,
295
- oc_map: oc.OC_Map,
296
- ) -> None:
297
- namespace = yaml.safe_load(
298
- """
299
- name: ns1
300
- cluster:
301
- name: cs1
302
- managedResourceTypes:
303
- - Template
304
- managedResourceTypeOverrides:
305
- - resource: UnmanagedType
306
- override: UnmanagedType.unmanagedapi
307
- openshiftResources:
308
- - provider: resource
309
- path: /some/path.yml
310
- """
311
- )
312
- with pytest.raises(KeyError):
313
- sut.init_specs_to_fetch(resource_inventory, oc_map, namespaces=[namespace])
314
-
315
-
316
- def test_namespaces_override_managed_type(
317
- resource_inventory: resource.ResourceInventory,
318
- oc_map: oc.OC_Map,
319
- oc_cs1: oc.OCNative,
320
- ) -> None:
321
- """
322
- test that the override_managed_types parameter for init_specs_to_fetch takes
323
- precedence over what might be defined on the namespace. this is relevant for
324
- integrations that specifically handle only a subset of types e.g. terraform-resources
325
- only managing Secrets
326
- """
327
- namespace = yaml.safe_load(
328
- """
329
- name: ns1
330
- cluster:
331
- name: cs1
332
- managedResourceTypes:
333
- - Template
334
- managedResourceNames:
335
- - resource: Template
336
- resourceNames:
337
- - tp1
338
- - tp2
339
- openshiftResources:
340
- - provider: resource
341
- path: /some/path.yml
342
- """
343
- )
344
- expected: list[sut.StateSpec] = [
345
- sut.CurrentStateSpec(
346
- oc=oc_cs1,
347
- cluster="cs1",
348
- namespace="ns1",
349
- kind="LimitRanges",
350
- resource_names=None,
351
- ),
352
- sut.DesiredStateSpec(
353
- oc=oc_cs1,
354
- cluster="cs1",
355
- namespace="ns1",
356
- resource={"provider": "resource", "path": "/some/path.yml"},
357
- parent=namespace,
358
- ),
359
- ]
360
-
361
- rs = sut.init_specs_to_fetch(
362
- resource_inventory,
363
- oc_map=oc_map,
364
- namespaces=[namespace],
365
- override_managed_types=["LimitRanges"],
366
- )
367
- assert rs == expected
368
-
369
- registrations = list(resource_inventory)
370
- # make sure only the override_managed_type LimitRange is present
371
- # and not the Template from the namespace
372
- assert len(registrations) == 1
373
- cluster, ns, kind, _ = registrations[0]
374
- assert (cluster, ns, kind) == ("cs1", "ns1", "LimitRanges")
375
-
376
-
377
- def test_namespaces_managed_fully_qualified_types(
378
- resource_inventory: resource.ResourceInventory,
379
- oc_map: oc.OC_Map,
380
- oc_cs1: oc.OCNative,
381
- ) -> None:
382
- namespace = yaml.safe_load(
383
- """
384
- name: ns1
385
- cluster:
386
- name: cs1
387
- managedResourceTypes:
388
- - Kind.fully.qualified
389
- openshiftResources:
390
- - provider: resource
391
- path: /some/path.yml
392
- """
393
- )
394
- expected: list[sut.StateSpec] = [
395
- sut.CurrentStateSpec(
396
- oc=oc_cs1,
397
- cluster="cs1",
398
- namespace="ns1",
399
- kind="Kind.fully.qualified",
400
- resource_names=None,
401
- ),
402
- sut.DesiredStateSpec(
403
- oc=oc_cs1,
404
- cluster="cs1",
405
- namespace="ns1",
406
- resource={"provider": "resource", "path": "/some/path.yml"},
407
- parent=namespace,
408
- ),
409
- ]
410
-
411
- rs = sut.init_specs_to_fetch(
412
- resource_inventory,
413
- oc_map,
414
- namespaces=[namespace],
415
- )
416
- assert rs == expected
417
-
418
-
419
- def test_namespaces_managed_fully_qualified_types_with_resource_names(
420
- resource_inventory: resource.ResourceInventory,
421
- oc_map: oc.OC_Map,
422
- oc_cs1: oc.OCNative,
423
- ) -> None:
424
- namespace = yaml.safe_load(
425
- """
426
- name: ns1
427
- cluster:
428
- name: cs1
429
- managedResourceTypes:
430
- - Kind.fully.qualified
431
- managedResourceNames:
432
- - resource: Kind.fully.qualified
433
- resourceNames:
434
- - n1
435
- - n2
436
- openshiftResources:
437
- - provider: resource
438
- path: /some/path.yml
439
- """
440
- )
441
- expected: list[sut.StateSpec] = [
442
- sut.CurrentStateSpec(
443
- oc=oc_cs1,
444
- cluster="cs1",
445
- namespace="ns1",
446
- kind="Kind.fully.qualified",
447
- resource_names=["n1", "n2"],
448
- ),
449
- sut.DesiredStateSpec(
450
- oc=oc_cs1,
451
- cluster="cs1",
452
- namespace="ns1",
453
- resource={"provider": "resource", "path": "/some/path.yml"},
454
- parent=namespace,
455
- ),
456
- ]
457
-
458
- rs = sut.init_specs_to_fetch(
459
- resource_inventory,
460
- oc_map,
461
- namespaces=[namespace],
462
- )
463
- assert rs == expected
464
-
465
-
466
- def test_namespaces_managed_mixed_qualified_types_with_resource_names(
467
- resource_inventory: resource.ResourceInventory,
468
- oc_map: oc.OC_Map,
469
- oc_cs1: oc.OCNative,
470
- ) -> None:
471
- namespace = yaml.safe_load(
472
- """
473
- name: ns1
474
- cluster:
475
- name: cs1
476
- managedResourceTypes:
477
- - Kind.fully.qualified
478
- - Kind
479
- managedResourceNames:
480
- - resource: Kind.fully.qualified
481
- resourceNames:
482
- - fname
483
- - resource: Kind
484
- resourceNames:
485
- - name
486
- openshiftResources:
487
- - provider: resource
488
- path: /some/path.yml
489
- """
490
- )
491
- expected: list[sut.StateSpec] = [
492
- sut.CurrentStateSpec(
493
- oc=oc_cs1,
494
- cluster="cs1",
495
- namespace="ns1",
496
- kind="Kind.fully.qualified",
497
- resource_names=["fname"],
498
- ),
499
- sut.CurrentStateSpec(
500
- oc=oc_cs1,
501
- cluster="cs1",
502
- namespace="ns1",
503
- kind="Kind",
504
- resource_names=["name"],
505
- ),
506
- sut.DesiredStateSpec(
507
- oc=oc_cs1,
508
- cluster="cs1",
509
- namespace="ns1",
510
- resource={"provider": "resource", "path": "/some/path.yml"},
511
- parent=namespace,
512
- ),
513
- ]
514
-
515
- rs = sut.init_specs_to_fetch(
516
- resource_inventory,
517
- oc_map,
518
- namespaces=[namespace],
519
- )
520
-
521
- assert len(expected) == len(rs)
522
- for e in expected:
523
- assert e in rs
524
-
525
-
526
- #
527
- # populate state tests
528
- #
529
-
530
-
531
- @pytest.fixture
532
- def api_resources():
533
- r1 = Resource(
534
- prefix="",
535
- kind="Kind",
536
- group="fully.qualified",
537
- api_version="v1",
538
- namespaced=True,
539
- )
540
- r2 = Resource(
541
- prefix="",
542
- kind="Kind",
543
- group="another.group",
544
- api_version="v1",
545
- namespaced=True,
546
- )
547
- return {"Kind": [r1, r2]}
548
-
549
-
550
- def test_populate_current_state(
551
- api_resources, resource_inventory: resource.ResourceInventory, oc_cs1: oc.OCNative
552
- ):
553
- """
554
- test that populate_current_state properly populates the resource inventory
555
- """
556
- # prepare client and resource inventory
557
- oc_cs1.init_api_resources = True
558
- oc_cs1.api_resources = api_resources
559
- oc_cs1.get_items = lambda kind, **kwargs: [
560
- build_resource("Kind", "fully.qualified/v1", "name")
561
- ]
562
- resource_inventory.initialize_resource_type("cs1", "ns1", "Kind.fully.qualified")
563
-
564
- # process
565
- spec = sut.CurrentStateSpec(
566
- oc=oc_cs1,
567
- cluster="cs1",
568
- namespace="ns1",
569
- kind="Kind.fully.qualified",
570
- resource_names=["name"],
571
- )
572
- sut.populate_current_state(spec, resource_inventory, TEST_INT, TEST_INT_VER)
573
-
574
- # verify
575
- cluster, namespace, kind, data = next(iter(resource_inventory))
576
- assert (cluster, namespace, kind) == ("cs1", "ns1", "Kind.fully.qualified")
577
- assert data["current"]["name"] == resource.OpenshiftResource(
578
- build_resource("Kind", "fully.qualified/v1", "name"), TEST_INT, TEST_INT_VER
579
- )
580
-
581
-
582
- def test_populate_current_state_unknown_kind(
583
- resource_inventory: resource.ResourceInventory, oc_cs1: oc.OCNative, mocker
584
- ):
585
- """
586
- test that a missing kind in the cluster is catched early on
587
- """
588
- oc_cs1.init_api_resources = True
589
- k1 = Resource(prefix="", group="some.other.group", api_version="v1", kind="Kind")
590
- oc_cs1.api_resources = {"Kind": [k1]}
591
- get_item_mock = mocker.patch.object(oc.OCNative, "get_items", autospec=True)
592
-
593
- spec = sut.CurrentStateSpec(
594
- oc=oc_cs1,
595
- cluster="cs1",
596
- namespace="ns1",
597
- kind="Kind.fully.qualified",
598
- resource_names=["name"],
599
- )
600
- sut.populate_current_state(spec, resource_inventory, TEST_INT, TEST_INT_VER)
601
-
602
- assert len(list(iter(resource_inventory))) == 0
603
- get_item_mock.assert_not_called()
604
-
605
-
606
- def test_populate_current_state_resource_name_filtering(
607
- resource_inventory: resource.ResourceInventory, oc_cs1: oc.OCNative, mocker
608
- ):
609
- """
610
- test if the resource names are passed properly to the oc client when fetching items
611
- """
612
- spec = sut.CurrentStateSpec(
613
- oc=oc_cs1,
614
- cluster="cs1",
615
- namespace="ns1",
616
- kind="Kind.fully.qualified",
617
- resource_names=["name1", "name2"],
618
- )
619
- sut.populate_current_state(spec, resource_inventory, TEST_INT, TEST_INT_VER)
620
-
621
- oc_cs1.get_items.assert_called_with(
622
- "Kind.fully.qualified",
623
- namespace="ns1",
624
- resource_names=["name1", "name2"],
625
- )
626
-
627
-
628
- #
629
- # determine_user_keys_for_access tests
630
- #
631
-
632
-
633
- class OpenshiftBaseAuthService(BaseModel):
634
- service: str
635
-
636
-
637
- class OpenshiftBaseCluster(BaseModel):
638
- name: str
639
- auth: list[OpenshiftBaseAuthService]
640
-
641
-
642
- class OpenshiftBaseUser(BaseModel):
643
- org_username: str
644
- github_username: str
645
-
646
-
647
- @pytest.mark.parametrize(
648
- "auth, expected",
649
- [
650
- # dicts
651
- ([{"service": "github-org"}], ["github_username"]),
652
- ([{"service": "github-org-team"}], ["github_username"]),
653
- ([{"service": "oidc"}], ["org_username"]),
654
- (
655
- [{"service": "oidc"}, {"service": "github-org-team"}],
656
- ["org_username", "github_username"],
657
- ),
658
- (
659
- [{"service": "github-org"}, {"service": "github-org-team"}],
660
- ["github_username"],
661
- ),
662
- # class
663
- ([OpenshiftBaseAuthService(service="github-org")], ["github_username"]),
664
- ([OpenshiftBaseAuthService(service="github-org-team")], ["github_username"]),
665
- ([OpenshiftBaseAuthService(service="oidc")], ["org_username"]),
666
- (
667
- [
668
- OpenshiftBaseAuthService(service="oidc"),
669
- OpenshiftBaseAuthService(service="github-org-team"),
670
- ],
671
- ["org_username", "github_username"],
672
- ),
673
- (
674
- [
675
- OpenshiftBaseAuthService(service="github-org"),
676
- OpenshiftBaseAuthService(service="github-org-team"),
677
- ],
678
- ["github_username"],
679
- ),
680
- # backward_compatibility
681
- ([], ["github_username"]),
682
- ],
683
- )
684
- def test_determine_user_keys_for_access(auth, expected):
685
- assert sut.determine_user_keys_for_access("cluster-name", auth) == expected
686
-
687
-
688
- def test_determine_user_keys_enforced_user_keys():
689
- assert sut.determine_user_keys_for_access(
690
- "cluster-name",
691
- [{"service": "github-org"}],
692
- enforced_user_keys=["my-enforced-key"],
693
- ) == ["my-enforced-key"]
694
-
695
-
696
- def test_determine_user_keys_for_access_not_implemented():
697
- auth = {"service": "not-implemented"}
698
- with pytest.raises(NotImplementedError):
699
- sut.determine_user_keys_for_access("cluster-name", [auth])
700
-
701
-
702
- def test_is_namespace_deleted_true():
703
- ns = {"delete": True}
704
- assert sut.is_namespace_deleted(ns) is True
705
-
706
-
707
- def test_is_namespace_deleted_false():
708
- ns = {"delete": False}
709
- assert sut.is_namespace_deleted(ns) is False
710
-
711
-
712
- def test_is_namespace_deleted_none():
713
- ns = {"delete": None}
714
- assert sut.is_namespace_deleted(ns) is False
715
-
716
-
717
- def test_is_namespace_deleted_empty():
718
- assert sut.is_namespace_deleted({}) is False
719
-
720
-
721
- def test_user_has_cluster_access(mocker: MockerFixture):
722
- mocker.patch.object(
723
- sut, "determine_user_keys_for_access", return_value=["org_username"]
724
- )
725
- user = OpenshiftBaseUser(org_username="user_org", github_username="user_github")
726
- cluster = OpenshiftBaseCluster(
727
- name="cluster", auth=[OpenshiftBaseAuthService(service="oidc")]
728
- )
729
- assert sut.user_has_cluster_access(user, cluster, ["user_org"])
730
- assert not sut.user_has_cluster_access(user, cluster, ["another_user"])
731
-
732
-
733
- @pytest.fixture
734
- def apply_options() -> sut.ApplyOptions:
735
- options = sut.ApplyOptions(
736
- dry_run=True,
737
- no_dry_run_skip_compare=False,
738
- wait_for_namespace=True,
739
- recycle_pods=True,
740
- take_over=False,
741
- override_enable_deletion=False,
742
- caller="saas-test",
743
- all_callers=["saas-test"],
744
- privileged=False,
745
- enable_deletion=False,
746
- )
747
- return options
748
-
749
-
750
- def build_openshift_resource(
751
- kind: str,
752
- api_version: str,
753
- name: str,
754
- extra_body: dict[str, Any] | None,
755
- integration: str = "",
756
- integration_version: str = "",
757
- error_details: str = "",
758
- caller_name: str = "",
759
- ) -> resource.OpenshiftResource:
760
- body = {
761
- "kind": kind,
762
- "apiVersion": api_version,
763
- "metadata": {"name": name},
764
- }
765
- if extra_body:
766
- body |= extra_body
767
-
768
- return resource.OpenshiftResource(
769
- body=body,
770
- integration=integration,
771
- integration_version=integration_version,
772
- error_details=error_details,
773
- caller_name=caller_name,
774
- validate_k8s_object=False,
775
- )
776
-
777
-
778
- def build_openshift_resource_1() -> resource.OpenshiftResource:
779
- spec = {"spec": {"test-attr": "test-value-1"}}
780
- return build_openshift_resource(
781
- kind="test-kind",
782
- api_version="v1",
783
- name="test-resource",
784
- extra_body=spec,
785
- caller_name="saas-test",
786
- )
787
-
788
-
789
- def build_openshift_resource_2() -> resource.OpenshiftResource:
790
- spec = {"spec": {"test-attr": "test-value-2"}}
791
- return build_openshift_resource(
792
- kind="test-kind",
793
- api_version="v1",
794
- name="test-resource",
795
- extra_body=spec,
796
- caller_name="saas-test",
797
- )
798
-
799
-
800
- @pytest.fixture
801
- def diff_result() -> DiffResult:
802
- r1 = build_openshift_resource_1()
803
- r2 = build_openshift_resource_2()
804
- return DiffResult(
805
- add={"test-resource": r1},
806
- change={"test-resource": DiffPair(r1, r2)},
807
- delete={"test-resource": r1},
808
- identical={"test-resource": DiffPair(r1, r1)},
809
- )
810
-
811
-
812
- def test_handle_new_resources(
813
- mocker: MockerFixture,
814
- oc_map: oc.OC_Map,
815
- resource_inventory: resource.ResourceInventory,
816
- diff_result: DiffResult,
817
- apply_options: sut.ApplyOptions,
818
- ):
819
- apply_mock = mocker.patch.object(sut, "apply", autospec=True)
820
- cluster = "test-cluster"
821
- namespace = "test-namespace"
822
- resource_type = "test-Kind"
823
- data = {"use_admin_token": {"test-resource": False}}
824
-
825
- actions = sut.handle_new_resources(
826
- oc_map=oc_map,
827
- ri=resource_inventory,
828
- new_resources=diff_result.add,
829
- cluster=cluster,
830
- namespace=namespace,
831
- resource_type=resource_type,
832
- data=data,
833
- options=apply_options,
834
- )
835
-
836
- assert len(actions) == 1
837
- apply_expected_args = {
838
- "dry_run": True,
839
- "oc_map": oc_map,
840
- "cluster": "test-cluster",
841
- "namespace": "test-namespace",
842
- "resource_type": "test-Kind",
843
- "resource": diff_result.add["test-resource"],
844
- "wait_for_namespace": True,
845
- "recycle_pods": True,
846
- "privileged": False,
847
- }
848
- apply_mock.assert_called_with(**apply_expected_args)
849
-
850
-
851
- @pytest.mark.parametrize(
852
- "apply_options, should_apply, should_error_ri",
853
- [
854
- ( # Same Caller. The resource should be updated
855
- sut.ApplyOptions(
856
- dry_run=True,
857
- no_dry_run_skip_compare=False,
858
- wait_for_namespace=True,
859
- recycle_pods=True,
860
- take_over=False,
861
- override_enable_deletion=False,
862
- caller="saas-test",
863
- all_callers=["saas-test"],
864
- privileged=False,
865
- enable_deletion=False,
866
- ),
867
- True,
868
- False,
869
- ),
870
- ( # The resource is owned by "saas-test" but is present in "different".
871
- # An error must be raised
872
- sut.ApplyOptions(
873
- dry_run=True,
874
- no_dry_run_skip_compare=False,
875
- wait_for_namespace=True,
876
- recycle_pods=True,
877
- take_over=False,
878
- override_enable_deletion=False,
879
- caller="different",
880
- all_callers=["saas-test", "different"],
881
- privileged=False,
882
- enable_deletion=False,
883
- ),
884
- False,
885
- True,
886
- ),
887
- ( # The Resource is owned by "saas-test" and is being deployed by "different"
888
- # Since "saas-test" is not in all_callers it means it has been
889
- # deprecated. The Resource needs to be taken over by "different"
890
- sut.ApplyOptions(
891
- dry_run=True,
892
- no_dry_run_skip_compare=False,
893
- wait_for_namespace=True,
894
- recycle_pods=True,
895
- take_over=False,
896
- override_enable_deletion=False,
897
- caller="different",
898
- all_callers=["different"],
899
- privileged=False,
900
- enable_deletion=False,
901
- ),
902
- True,
903
- False,
904
- ),
905
- ( # Take over resources from another Saas-file
906
- sut.ApplyOptions(
907
- dry_run=True,
908
- no_dry_run_skip_compare=False,
909
- wait_for_namespace=True,
910
- recycle_pods=True,
911
- take_over=True,
912
- override_enable_deletion=False,
913
- caller="different",
914
- all_callers=["saas-test", "different"],
915
- privileged=False,
916
- enable_deletion=False,
917
- ),
918
- True,
919
- False,
920
- ),
921
- ],
922
- )
923
- def test_handle_modified_resources(
924
- mocker: MockerFixture,
925
- oc_map: oc.OC_Map,
926
- resource_inventory: resource.ResourceInventory,
927
- diff_result: DiffResult,
928
- apply_options: sut.ApplyOptions,
929
- should_apply: bool,
930
- should_error_ri: bool,
931
- ):
932
- apply_mock = mocker.patch.object(sut, "apply", autospec=True)
933
- cluster = "test-cluster"
934
- namespace = "test-namespace"
935
- resource_type = "test-Kind"
936
- data = {"use_admin_token": {"test-resource": False}}
937
-
938
- modified_resources = diff_result.change
939
-
940
- actions = sut.handle_modified_resources(
941
- oc_map=oc_map,
942
- ri=resource_inventory,
943
- modified_resources=modified_resources,
944
- cluster=cluster,
945
- namespace=namespace,
946
- resource_type=resource_type,
947
- data=data,
948
- options=apply_options,
949
- )
950
-
951
- if should_apply:
952
- assert len(actions) == 1
953
- apply_expected_args = {
954
- "dry_run": True,
955
- "oc_map": oc_map,
956
- "cluster": "test-cluster",
957
- "namespace": "test-namespace",
958
- "resource_type": "test-Kind",
959
- "resource": diff_result.change["test-resource"].desired,
960
- "wait_for_namespace": True,
961
- "recycle_pods": True,
962
- "privileged": False,
963
- }
964
- apply_mock.assert_called_with(**apply_expected_args)
965
- else:
966
- assert len(actions) == 0
967
-
968
- if should_error_ri:
969
- assert resource_inventory._error_registered
970
-
971
-
972
- @pytest.mark.parametrize(
973
- "apply_options, should_take_over, should_error_ri",
974
- [
975
- ( # Same Caller and Identical Resource. Nothing should happen
976
- sut.ApplyOptions(
977
- dry_run=True,
978
- no_dry_run_skip_compare=False,
979
- wait_for_namespace=True,
980
- recycle_pods=True,
981
- take_over=False,
982
- override_enable_deletion=False,
983
- caller="saas-test",
984
- all_callers=["saas-test"],
985
- privileged=False,
986
- enable_deletion=False,
987
- ),
988
- False,
989
- False,
990
- ),
991
- ( # The resource is owned by "saas-test" but is present in "different".
992
- # An error must be raised
993
- sut.ApplyOptions(
994
- dry_run=True,
995
- no_dry_run_skip_compare=False,
996
- wait_for_namespace=True,
997
- recycle_pods=True,
998
- take_over=False,
999
- override_enable_deletion=False,
1000
- caller="different",
1001
- all_callers=["saas-test", "different"],
1002
- privileged=False,
1003
- enable_deletion=False,
1004
- ),
1005
- False,
1006
- True,
1007
- ),
1008
- ( # The Resource is owned by "saas-test" and is being deployed by "different"
1009
- # Since "saas-test" is not in all_callers it means it has been
1010
- # deprecated. The Resource needs to be taken over by "different"
1011
- sut.ApplyOptions(
1012
- dry_run=True,
1013
- no_dry_run_skip_compare=False,
1014
- wait_for_namespace=True,
1015
- recycle_pods=True,
1016
- take_over=False,
1017
- override_enable_deletion=False,
1018
- caller="different",
1019
- all_callers=["different"],
1020
- privileged=False,
1021
- enable_deletion=False,
1022
- ),
1023
- True,
1024
- False,
1025
- ),
1026
- ( # Take over resources from another Saas-file
1027
- sut.ApplyOptions(
1028
- dry_run=True,
1029
- no_dry_run_skip_compare=False,
1030
- wait_for_namespace=True,
1031
- recycle_pods=True,
1032
- take_over=True,
1033
- override_enable_deletion=False,
1034
- caller="different",
1035
- all_callers=["saas-test", "different"],
1036
- privileged=False,
1037
- enable_deletion=False,
1038
- ),
1039
- True,
1040
- False,
1041
- ),
1042
- ],
1043
- )
1044
- def test_handle_identical_resources(
1045
- mocker: MockerFixture,
1046
- oc_map: oc.OC_Map,
1047
- resource_inventory: resource.ResourceInventory,
1048
- diff_result: DiffResult,
1049
- apply_options: sut.ApplyOptions,
1050
- should_take_over: bool,
1051
- should_error_ri: bool,
1052
- ):
1053
- apply_mock = mocker.patch.object(sut, "apply", autospec=True)
1054
- cluster = "test-cluster"
1055
- namespace = "test-namespace"
1056
- resource_type = "test-Kind"
1057
- data = {"use_admin_token": {"test-resource": False}}
1058
-
1059
- actions = sut.handle_identical_resources(
1060
- oc_map=oc_map,
1061
- ri=resource_inventory,
1062
- identical_resources=diff_result.identical,
1063
- cluster=cluster,
1064
- namespace=namespace,
1065
- resource_type=resource_type,
1066
- data=data,
1067
- options=apply_options,
1068
- )
1069
-
1070
- if should_take_over:
1071
- assert len(actions) == 1
1072
- apply_expected_args = {
1073
- "dry_run": True,
1074
- "oc_map": oc_map,
1075
- "cluster": "test-cluster",
1076
- "namespace": "test-namespace",
1077
- "resource_type": "test-Kind",
1078
- "resource": diff_result.identical["test-resource"].desired,
1079
- "wait_for_namespace": True,
1080
- "recycle_pods": True,
1081
- "privileged": False,
1082
- }
1083
- apply_mock.assert_called_with(**apply_expected_args)
1084
- else:
1085
- assert len(actions) == 0
1086
- if should_error_ri:
1087
- assert resource_inventory._error_registered
1088
-
1089
-
1090
- def test_handle_deleted_resources(
1091
- mocker: MockerFixture,
1092
- oc_map: oc.OC_Map,
1093
- resource_inventory: resource.ResourceInventory,
1094
- diff_result: DiffResult,
1095
- apply_options: sut.ApplyOptions,
1096
- ):
1097
- delete_mock = mocker.patch.object(sut, "delete", autospec=True)
1098
-
1099
- # mock has_qontract_annotations to own the resource
1100
- hqa = mocker.patch.object(
1101
- resource.OpenshiftResource, "has_qontract_annotations", autospec=True
1102
- )
1103
- hqa.return_value = True
1104
-
1105
- cluster = "test-cluster"
1106
- namespace = "test-namespace"
1107
- resource_type = "test-Kind"
1108
- data = {"use_admin_token": {"test-resource": False}}
1109
-
1110
- actions = sut.handle_deleted_resources(
1111
- oc_map=oc_map,
1112
- ri=resource_inventory,
1113
- deleted_resources=diff_result.delete,
1114
- cluster=cluster,
1115
- namespace=namespace,
1116
- resource_type=resource_type,
1117
- data=data,
1118
- options=apply_options,
1119
- )
1120
-
1121
- assert len(actions) == 1
1122
- delete_expected_args = {
1123
- "dry_run": True,
1124
- "oc_map": oc_map,
1125
- "cluster": "test-cluster",
1126
- "namespace": "test-namespace",
1127
- "resource_type": "test-Kind",
1128
- "name": "test-resource",
1129
- "enable_deletion": False,
1130
- "privileged": False,
1131
- }
1132
- delete_mock.assert_called_with(**delete_expected_args)
1133
-
1134
-
1135
- # Fixtures does not work with parametrize
1136
- # functions are used to build resources instead
1137
- @pytest.mark.parametrize(
1138
- "data, len_actions, apply_calls, delete_calls",
1139
- [
1140
- (
1141
- {
1142
- "current": {},
1143
- "desired": {"test-resource": build_openshift_resource_1()},
1144
- "use_admin_token": {},
1145
- },
1146
- 1,
1147
- 1,
1148
- 0,
1149
- ),
1150
- (
1151
- {
1152
- "current": {"test-resource": build_openshift_resource_1()},
1153
- "desired": {"test-resource": build_openshift_resource_2()},
1154
- "use_admin_token": {},
1155
- },
1156
- 1,
1157
- 1,
1158
- 0,
1159
- ),
1160
- (
1161
- {
1162
- "current": {"test-resource": build_openshift_resource_1()},
1163
- "desired": {},
1164
- "use_admin_token": {},
1165
- },
1166
- 1,
1167
- 0,
1168
- 1,
1169
- ),
1170
- ],
1171
- )
1172
- def test_realize_resource_data_3way_diff(
1173
- mocker: MockerFixture,
1174
- oc_map: oc.OC_Map,
1175
- resource_inventory: resource.ResourceInventory,
1176
- apply_options: sut.ApplyOptions,
1177
- data: Mapping[str, Any],
1178
- len_actions: int,
1179
- apply_calls: int,
1180
- delete_calls: int,
1181
- ):
1182
- apply_mock = mocker.patch.object(sut, "apply", autospec=True)
1183
- delete_mock = mocker.patch.object(sut, "delete", autospec=True)
1184
- # Patch has_qontract_annotations to own the resource
1185
- mocker.patch.object(
1186
- resource.OpenshiftResource, "has_qontract_annotations", autospec=True
1187
- ).return_value = True
1188
-
1189
- ri_item = ("test-cluster", "test-namespace", "test-kind", data)
1190
- actions = sut._realize_resource_data_3way_diff(
1191
- ri_item=ri_item, oc_map=oc_map, ri=resource_inventory, options=apply_options
1192
- )
1193
- assert len(actions) == len_actions
1194
- assert apply_mock.call_count == apply_calls
1195
- assert delete_mock.call_count == delete_calls
1196
-
1197
-
1198
- def test_get_state_count_combinations():
1199
- state = [
1200
- {"cluster": "c1"},
1201
- {"cluster": "c2"},
1202
- {"cluster": "c1"},
1203
- {"cluster": "c3"},
1204
- {"cluster": "c2"},
1205
- ]
1206
- expected = {"c1": 2, "c2": 2, "c3": 1}
1207
- assert expected == sut.get_state_count_combinations(state)
1208
-
1209
-
1210
- def test_aggregate_shared_resources_typed_openshift_service_resources() -> None:
1211
- class OpenShiftResourcesStub(BaseModel):
1212
- openshift_resources: list | None
1213
-
1214
- class OpenShiftResourcesAndSharedResourcesStub(OpenShiftResourcesStub, BaseModel):
1215
- shared_resources: list[OpenShiftResourcesStub] | None
1216
-
1217
- namespace = OpenShiftResourcesAndSharedResourcesStub(
1218
- openshift_resources=[1], shared_resources=None
1219
- )
1220
- sut.aggregate_shared_resources_typed(namespace=namespace)
1221
- assert namespace.openshift_resources == [1]
1222
-
1223
- namespace = OpenShiftResourcesAndSharedResourcesStub(
1224
- openshift_resources=None,
1225
- shared_resources=[OpenShiftResourcesStub(openshift_resources=[2])],
1226
- )
1227
- sut.aggregate_shared_resources_typed(namespace=namespace)
1228
- assert namespace.openshift_resources == [2]
1229
-
1230
- namespace = OpenShiftResourcesAndSharedResourcesStub(
1231
- openshift_resources=[1],
1232
- shared_resources=[OpenShiftResourcesStub(openshift_resources=[2])],
1233
- )
1234
- sut.aggregate_shared_resources_typed(namespace=namespace)
1235
- assert namespace.openshift_resources == [1, 2]
1236
-
1237
-
1238
- def test_aggregate_shared_resources_typed_openshift_service_account_token() -> None:
1239
- class OpenshiftServiceAccountTokensStub(BaseModel):
1240
- openshift_service_account_tokens: list | None
1241
-
1242
- class OpenshiftServiceAccountTokensAndSharedResourcesStub(
1243
- OpenshiftServiceAccountTokensStub, BaseModel
1244
- ):
1245
- shared_resources: list[OpenshiftServiceAccountTokensStub] | None
1246
-
1247
- namespace = OpenshiftServiceAccountTokensAndSharedResourcesStub(
1248
- openshift_service_account_tokens=[1], shared_resources=None
1249
- )
1250
- sut.aggregate_shared_resources_typed(namespace=namespace)
1251
- assert namespace.openshift_service_account_tokens == [1]
1252
-
1253
- namespace = OpenshiftServiceAccountTokensAndSharedResourcesStub(
1254
- openshift_service_account_tokens=None,
1255
- shared_resources=[
1256
- OpenshiftServiceAccountTokensStub(openshift_service_account_tokens=[2])
1257
- ],
1258
- )
1259
- sut.aggregate_shared_resources_typed(namespace=namespace)
1260
- assert namespace.openshift_service_account_tokens == [2]
1261
-
1262
- namespace = OpenshiftServiceAccountTokensAndSharedResourcesStub(
1263
- openshift_service_account_tokens=[1],
1264
- shared_resources=[
1265
- OpenshiftServiceAccountTokensStub(openshift_service_account_tokens=[2])
1266
- ],
1267
- )
1268
- sut.aggregate_shared_resources_typed(namespace=namespace)
1269
- assert namespace.openshift_service_account_tokens == [1, 2]