qontract-reconcile 0.10.1rc1202__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 (138) hide show
  1. qontract_reconcile-0.10.2.dev1.dist-info/METADATA +500 -0
  2. {qontract_reconcile-0.10.1rc1202.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/RECORD +12 -130
  3. {qontract_reconcile-0.10.1rc1202.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.10.1rc1202.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/glitchtip/README.md +150 -0
  8. reconcile/gql_definitions/introspection.json +51176 -0
  9. reconcile/run_integration.py +293 -0
  10. reconcile/utils/binary.py +2 -2
  11. reconcile/utils/mr/README.md +198 -0
  12. reconcile/utils/oc_map.py +2 -2
  13. tools/qontract_cli.py +0 -0
  14. qontract_reconcile-0.10.1rc1202.dist-info/METADATA +0 -64
  15. qontract_reconcile-0.10.1rc1202.dist-info/top_level.txt +0 -3
  16. reconcile/test/__init__.py +0 -0
  17. reconcile/test/conftest.py +0 -157
  18. reconcile/test/fixtures.py +0 -24
  19. reconcile/test/saas_auto_promotions_manager/__init__.py +0 -0
  20. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -170
  21. reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py +0 -0
  22. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py +0 -0
  23. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -115
  24. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -19
  25. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py +0 -66
  26. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -86
  27. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py +0 -352
  28. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py +0 -494
  29. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/__init__.py +0 -0
  30. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -25
  31. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -37
  32. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -81
  33. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -61
  34. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_json_path_selector.py +0 -74
  35. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -52
  36. reconcile/test/saas_auto_promotions_manager/utils/__init__.py +0 -0
  37. reconcile/test/test_acs_notifiers.py +0 -393
  38. reconcile/test/test_acs_policies.py +0 -497
  39. reconcile/test/test_acs_rbac.py +0 -865
  40. reconcile/test/test_aggregated_list.py +0 -237
  41. reconcile/test/test_amtool.py +0 -37
  42. reconcile/test/test_aws_ami_cleanup.py +0 -230
  43. reconcile/test/test_aws_ami_share.py +0 -68
  44. reconcile/test/test_aws_cloudwatch_log_retention.py +0 -434
  45. reconcile/test/test_aws_iam_keys.py +0 -70
  46. reconcile/test/test_aws_iam_password_reset.py +0 -35
  47. reconcile/test/test_aws_support_cases_sos.py +0 -23
  48. reconcile/test/test_checkpoint.py +0 -178
  49. reconcile/test/test_cli.py +0 -41
  50. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  51. reconcile/test/test_dashdotdb_dora.py +0 -245
  52. reconcile/test/test_database_access_manager.py +0 -660
  53. reconcile/test/test_deadmanssnitch.py +0 -290
  54. reconcile/test/test_gabi_authorized_users.py +0 -72
  55. reconcile/test/test_gcr_mirror.py +0 -14
  56. reconcile/test/test_github_org.py +0 -156
  57. reconcile/test/test_github_repo_invites.py +0 -119
  58. reconcile/test/test_gitlab_housekeeping.py +0 -333
  59. reconcile/test/test_gitlab_labeler.py +0 -126
  60. reconcile/test/test_gitlab_members.py +0 -219
  61. reconcile/test/test_gitlab_permissions.py +0 -164
  62. reconcile/test/test_instrumented_wrappers.py +0 -18
  63. reconcile/test/test_integrations_manager.py +0 -1252
  64. reconcile/test/test_jenkins_worker_fleets.py +0 -57
  65. reconcile/test/test_jira_permissions_validator.py +0 -519
  66. reconcile/test/test_jump_host.py +0 -114
  67. reconcile/test/test_ldap_users.py +0 -125
  68. reconcile/test/test_make.py +0 -28
  69. reconcile/test/test_ocm_additional_routers.py +0 -133
  70. reconcile/test/test_ocm_clusters.py +0 -798
  71. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -87
  72. reconcile/test/test_ocm_machine_pools.py +0 -1103
  73. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  74. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -125
  75. reconcile/test/test_openshift_base.py +0 -1269
  76. reconcile/test/test_openshift_cluster_bots.py +0 -240
  77. reconcile/test/test_openshift_namespace_labels.py +0 -344
  78. reconcile/test/test_openshift_namespaces.py +0 -256
  79. reconcile/test/test_openshift_resource.py +0 -443
  80. reconcile/test/test_openshift_resources_base.py +0 -478
  81. reconcile/test/test_openshift_saas_deploy.py +0 -188
  82. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -308
  83. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +0 -65
  84. reconcile/test/test_openshift_serviceaccount_tokens.py +0 -282
  85. reconcile/test/test_openshift_tekton_resources.py +0 -265
  86. reconcile/test/test_openshift_upgrade_watcher.py +0 -223
  87. reconcile/test/test_prometheus_rules_tester.py +0 -151
  88. reconcile/test/test_quay_membership.py +0 -86
  89. reconcile/test/test_quay_mirror.py +0 -172
  90. reconcile/test/test_quay_mirror_org.py +0 -82
  91. reconcile/test/test_quay_repos.py +0 -59
  92. reconcile/test/test_queries.py +0 -53
  93. reconcile/test/test_repo_owners.py +0 -47
  94. reconcile/test/test_requests_sender.py +0 -139
  95. reconcile/test/test_saasherder.py +0 -1611
  96. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -125
  97. reconcile/test/test_secret_reader.py +0 -153
  98. reconcile/test/test_slack_base.py +0 -183
  99. reconcile/test/test_slack_usergroups.py +0 -785
  100. reconcile/test/test_sql_query.py +0 -316
  101. reconcile/test/test_status_board.py +0 -258
  102. reconcile/test/test_terraform_aws_route53.py +0 -29
  103. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  104. reconcile/test/test_terraform_cloudflare_resources.py +0 -408
  105. reconcile/test/test_terraform_cloudflare_users.py +0 -747
  106. reconcile/test/test_terraform_repo.py +0 -440
  107. reconcile/test/test_terraform_resources.py +0 -519
  108. reconcile/test/test_terraform_tgw_attachments.py +0 -1295
  109. reconcile/test/test_terraform_users.py +0 -152
  110. reconcile/test/test_terraform_vpc_peerings.py +0 -576
  111. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1434
  112. reconcile/test/test_three_way_diff_strategy.py +0 -131
  113. reconcile/test/test_utils_jinja2.py +0 -130
  114. reconcile/test/test_vault_replication.py +0 -534
  115. reconcile/test/test_vault_utils.py +0 -47
  116. reconcile/test/test_version_bump.py +0 -18
  117. reconcile/test/test_vpc_peerings_validator.py +0 -194
  118. reconcile/test/test_wrong_region.py +0 -78
  119. release/__init__.py +0 -0
  120. release/test_version.py +0 -50
  121. release/version.py +0 -104
  122. tools/cli_commands/test/__init__.py +0 -0
  123. tools/cli_commands/test/conftest.py +0 -332
  124. tools/cli_commands/test/test_aws_cost_report.py +0 -258
  125. tools/cli_commands/test/test_cost_management_api.py +0 -326
  126. tools/cli_commands/test/test_gpg_encrypt.py +0 -235
  127. tools/cli_commands/test/test_openshift_cost_optimization_report.py +0 -255
  128. tools/cli_commands/test/test_openshift_cost_report.py +0 -295
  129. tools/cli_commands/test/test_util.py +0 -70
  130. tools/test/__init__.py +0 -0
  131. tools/test/conftest.py +0 -77
  132. tools/test/test_app_interface_metrics_exporter.py +0 -48
  133. tools/test/test_erv2.py +0 -80
  134. tools/test/test_get_container_images.py +0 -230
  135. tools/test/test_qontract_cli.py +0 -197
  136. tools/test/test_saas_promotion_state.py +0 -187
  137. tools/test/test_sd_app_sre_alert_report.py +0 -74
  138. tools/test/test_sre_checkpoints.py +0 -79
@@ -1,86 +0,0 @@
1
- from unittest.mock import patch
2
-
3
- from reconcile import quay_membership
4
- from reconcile.utils import (
5
- config,
6
- gql,
7
- )
8
- from reconcile.utils.aggregated_list import AggregatedList
9
-
10
- from .fixtures import Fixtures
11
-
12
- fxt = Fixtures("quay_membership")
13
-
14
-
15
- def get_items_by_params(state, params):
16
- h = AggregatedList.hash_params(params)
17
- for group in state:
18
- this_h = AggregatedList.hash_params(group["params"])
19
-
20
- if h == this_h:
21
- return sorted(group["items"])
22
- return False
23
-
24
-
25
- class QuayApiMock:
26
- def __init__(self, list_team_members_response):
27
- self.list_team_members_response = list_team_members_response
28
-
29
- def list_team_members(self, team):
30
- return self.list_team_members_response[team]
31
-
32
-
33
- class TestQuayMembership:
34
- @staticmethod
35
- def setup_method(method):
36
- config.init_from_toml(fxt.path("config.toml"))
37
- gql.init_from_config(autodetect_sha=False)
38
-
39
- @staticmethod
40
- def do_current_state_test(path):
41
- fixture = fxt.get_anymarkup(path)
42
-
43
- quay_org_catalog = fixture["quay_org_catalog"]
44
- quay_org_teams = fixture["quay_org_teams"]
45
-
46
- store = {}
47
- for org_data in quay_org_catalog:
48
- name = org_data["name"]
49
- store[name] = {
50
- "api": QuayApiMock(quay_org_teams[name]),
51
- "teams": org_data["managedTeams"],
52
- }
53
-
54
- current_state = quay_membership.fetch_current_state(store)
55
- current_state = current_state.dump()
56
-
57
- expected_current_state = fixture["state"]
58
-
59
- assert len(current_state) == len(expected_current_state)
60
- for group in current_state:
61
- params = group["params"]
62
- items = sorted(group["items"])
63
- assert items == get_items_by_params(expected_current_state, params)
64
-
65
- @staticmethod
66
- def do_desired_state_test(path):
67
- fixture = fxt.get_anymarkup(path)
68
-
69
- with patch("reconcile.utils.gql.GqlApi.query") as m_gql:
70
- m_gql.return_value = fixture["gql_response"]
71
-
72
- desired_state = quay_membership.fetch_desired_state().dump()
73
-
74
- expected_desired_state = fixture["state"]
75
-
76
- assert len(desired_state) == len(expected_desired_state)
77
- for group in desired_state:
78
- params = group["params"]
79
- items = sorted(group["items"])
80
- assert items == get_items_by_params(expected_desired_state, params)
81
-
82
- def test_current_state_simple(self):
83
- self.do_current_state_test("current_state_simple.yml")
84
-
85
- def test_desired_state_simple(self):
86
- self.do_desired_state_test("desired_state_simple.yml")
@@ -1,172 +0,0 @@
1
- import os
2
- import tempfile
3
- from unittest.mock import create_autospec, patch
4
-
5
- import pytest
6
- import requests
7
-
8
- from reconcile.quay_mirror import (
9
- CONTROL_FILE_NAME,
10
- OrgKey,
11
- QuayMirror,
12
- queries,
13
- )
14
-
15
- from .fixtures import Fixtures
16
-
17
- NOW = 1662124612.995397
18
-
19
- fxt = Fixtures("quay_mirror")
20
-
21
-
22
- @patch("reconcile.utils.gql.get_api", autospec=True)
23
- @patch("reconcile.queries.get_app_interface_settings", return_value={})
24
- class TestControlFile:
25
- def test_check_compare_tags_no_control_file(self, mock_gql, mock_settings):
26
- assert QuayMirror.check_compare_tags_elapsed_time("/no-such-file", 100)
27
-
28
- @patch("time.time", return_value=NOW)
29
- def test_check_compare_tags_with_file(self, mock_gql, mock_settings, mock_time):
30
- with tempfile.NamedTemporaryFile() as fp:
31
- fp.write(str(NOW - 100.0).encode())
32
- fp.seek(0)
33
-
34
- assert QuayMirror.check_compare_tags_elapsed_time(fp.name, 10)
35
- assert not QuayMirror.check_compare_tags_elapsed_time(fp.name, 1000)
36
-
37
- def test_control_file_dir_does_not_exist(self, mock_gql, mock_settings):
38
- with pytest.raises(FileNotFoundError):
39
- QuayMirror(control_file_dir="/no-such-dir")
40
-
41
- def test_control_file_path_from_given_dir(self, mock_gql, mock_settings):
42
- with tempfile.TemporaryDirectory() as tmp_dir_name:
43
- qm = QuayMirror(control_file_dir=tmp_dir_name)
44
- assert qm.control_file_path == os.path.join(tmp_dir_name, CONTROL_FILE_NAME)
45
-
46
-
47
- @patch("reconcile.utils.gql.get_api", autospec=True)
48
- @patch("reconcile.queries.get_app_interface_settings", return_value={})
49
- @patch("time.time", return_value=NOW)
50
- class TestIsCompareTags:
51
- def setup_method(self):
52
- self.tmp_dir = (
53
- tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
54
- )
55
- with open(
56
- os.path.join(self.tmp_dir.name, CONTROL_FILE_NAME), "w", encoding="locale"
57
- ) as fh:
58
- fh.write(str(NOW - 100.0))
59
-
60
- def teardown_method(self):
61
- self.tmp_dir.cleanup()
62
-
63
- # Last run was in NOW - 100s, we run compare tags every 10s.
64
- def test_is_compare_tags_elapsed(self, mock_gql, mock_settings, mock_time):
65
- qm = QuayMirror(control_file_dir=self.tmp_dir.name, compare_tags_interval=10)
66
- assert qm.is_compare_tags
67
-
68
- # Same as before, but now we force no compare with the option.
69
- def test_is_compare_tags_force_no_compare(self, mock_gql, mock_settings, mock_time):
70
- qm = QuayMirror(
71
- control_file_dir=self.tmp_dir.name,
72
- compare_tags_interval=10,
73
- compare_tags=False,
74
- )
75
- assert not qm.is_compare_tags
76
-
77
- # Last run was in NOW - 100s, we run compare tags every 1000s.
78
- def test_is_compare_tags_not_elapsed(self, mock_gql, mock_settings, mock_time):
79
- qm = QuayMirror(control_file_dir=self.tmp_dir.name, compare_tags_interval=1000)
80
- assert not qm.is_compare_tags
81
-
82
- # Same as before, but now we force compare with the option.
83
- def test_is_compare_tags_force_compare(self, mock_gql, mock_settings, mock_time):
84
- qm = QuayMirror(
85
- control_file_dir=self.tmp_dir.name,
86
- compare_tags_interval=1000,
87
- compare_tags=True,
88
- )
89
- assert qm.is_compare_tags
90
-
91
-
92
- @pytest.mark.parametrize(
93
- "tags, tags_exclude, candidate, result",
94
- [
95
- # Tags include tests.
96
- (["^sha256-.+sig$", "^main-.+"], None, "main-755781cc", True),
97
- (["^sha256-.+sig$", "^main-.+"], None, "sha256-8b5.sig", True),
98
- (["^sha256-.+sig$", "^main-.+"], None, "1.2.3", False),
99
- # # Tags exclude tests.
100
- (None, ["^sha256-.+sig$", "^main-.+"], "main-755781cc", False),
101
- (None, ["^sha256-.+sig$", "^main-.+"], "sha256-8b5.sig", False),
102
- (None, ["^sha256-.+sig$", "^main-.+"], "1.2.3", True),
103
- # When both includes and excludes are explicitly given, exclude take precedence.
104
- (["^sha256-.+sig$", "^main-.+"], ["main-755781cc"], "main-755781cc", False),
105
- (["^sha256-.+sig$", "^main-.+"], ["main-755781cc"], "sha256-8b5.sig", True),
106
- # both include and exclude are not set
107
- (None, None, "main-755781cc", True),
108
- ],
109
- )
110
- def test_sync_tag(tags, tags_exclude, candidate, result):
111
- assert QuayMirror.sync_tag(tags, tags_exclude, candidate) == result
112
-
113
-
114
- def test_process_repos_query_ok(mocker):
115
- repos_query = mocker.patch.object(queries, "get_quay_repos")
116
- repos_query.return_value = fxt.get_anymarkup("get_quay_repos_ok.yaml")
117
-
118
- cloudservices = OrgKey(instance="quay.io", org_name="cloudservices")
119
- app_sre = OrgKey(instance="quay.io", org_name="app-sre")
120
- session = create_autospec(requests.Session)
121
- timeout = 30
122
-
123
- summary = QuayMirror.process_repos_query()
124
- assert len(summary) == 2
125
- assert len(summary[cloudservices]) == 2
126
- assert len(summary[app_sre]) == 1
127
-
128
- mosquitto = "docker.io/library/eclipse-mosquitto"
129
- redis = "docker.io/redis"
130
-
131
- summary = QuayMirror.process_repos_query(
132
- repository_urls=[mosquitto, redis],
133
- session=session,
134
- timeout=timeout,
135
- )
136
- cl = summary[cloudservices]
137
- ap = summary[app_sre]
138
- assert len(cl) == 2
139
- assert len(ap) == 0
140
- assert cl[0]["mirror"]["url"] == mosquitto
141
- assert cl[1]["mirror"]["url"] == redis
142
-
143
- summary = QuayMirror.process_repos_query(
144
- exclude_repository_urls=[mosquitto, redis],
145
- session=session,
146
- timeout=timeout,
147
- )
148
- cl = summary[cloudservices]
149
- ap = summary[app_sre]
150
- assert len(cl) == 0
151
- assert len(summary[app_sre]) == 1
152
-
153
-
154
- def test_process_repos_query_public_dockerhub(mocker, caplog):
155
- repos_query = mocker.patch.object(queries, "get_quay_repos")
156
- repos_query.return_value = fxt.get_anymarkup("get_quay_repos_public_dockerhub.yaml")
157
-
158
- with pytest.raises(SystemExit):
159
- QuayMirror.process_repos_query()
160
-
161
- assert "can't be mirrored to a public quay repository" in caplog.text
162
-
163
-
164
- def test_quay_mirror_session(mocker):
165
- mocker.patch("reconcile.quay_mirror.gql")
166
- mocker.patch("reconcile.quay_mirror.queries")
167
- mocked_request = mocker.patch("reconcile.quay_mirror.requests")
168
-
169
- with QuayMirror() as quay_mirror:
170
- assert quay_mirror.session == mocked_request.Session.return_value
171
-
172
- mocked_request.Session.return_value.close.assert_called_once_with()
@@ -1,82 +0,0 @@
1
- import os
2
- import tempfile
3
- from unittest.mock import patch
4
-
5
- import pytest
6
-
7
- from reconcile.quay_mirror_org import (
8
- CONTROL_FILE_NAME,
9
- QuayMirrorOrg,
10
- )
11
-
12
- NOW = 1662124612.995397
13
-
14
-
15
- @patch("reconcile.utils.gql.get_api", autospec=True)
16
- @patch("reconcile.queries.get_app_interface_settings", return_value={})
17
- class TestControlFile:
18
- def test_control_file_dir_does_not_exist(self, mock_gql, mock_settings):
19
- with pytest.raises(FileNotFoundError):
20
- QuayMirrorOrg(control_file_dir="/no-such-dir")
21
-
22
- def test_control_file_path_from_given_dir(self, mock_gql, mock_settings):
23
- with tempfile.TemporaryDirectory() as tmp_dir_name:
24
- qm = QuayMirrorOrg(control_file_dir=tmp_dir_name)
25
- assert qm.control_file_path == os.path.join(tmp_dir_name, CONTROL_FILE_NAME)
26
-
27
-
28
- @patch("reconcile.utils.gql.get_api", autospec=True)
29
- @patch("reconcile.queries.get_app_interface_settings", return_value={})
30
- @patch("time.time", return_value=NOW)
31
- class TestIsCompareTags:
32
- def setup_method(self):
33
- self.tmp_dir = (
34
- tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
35
- )
36
- with open(
37
- os.path.join(self.tmp_dir.name, CONTROL_FILE_NAME), "w", encoding="locale"
38
- ) as fh:
39
- fh.write(str(NOW - 100.0))
40
-
41
- def teardown_method(self):
42
- self.tmp_dir.cleanup()
43
-
44
- # Last run was in NOW - 100s, we run compare tags every 10s.
45
- def test_is_compare_tags_elapsed(self, mock_gql, mock_settings, mock_time):
46
- qm = QuayMirrorOrg(control_file_dir=self.tmp_dir.name, compare_tags_interval=10)
47
- assert qm.is_compare_tags
48
-
49
- # Same as before, but now we force no compare with the option.
50
- def test_is_compare_tags_force_no_compare(self, mock_gql, mock_settings, mock_time):
51
- qm = QuayMirrorOrg(
52
- control_file_dir=self.tmp_dir.name,
53
- compare_tags_interval=10,
54
- compare_tags=False,
55
- )
56
- assert not qm.is_compare_tags
57
-
58
- # Last run was in NOW - 100s, we run compare tags every 1000s.
59
- def test_is_compare_tags_not_elapsed(self, mock_gql, mock_settings, mock_time):
60
- qm = QuayMirrorOrg(
61
- control_file_dir=self.tmp_dir.name, compare_tags_interval=1000
62
- )
63
- assert not qm.is_compare_tags
64
-
65
- # Same as before, but now we force compare with the option.
66
- def test_is_compare_tags_force_compare(self, mock_gql, mock_settings, mock_time):
67
- qm = QuayMirrorOrg(
68
- control_file_dir=self.tmp_dir.name,
69
- compare_tags_interval=1000,
70
- compare_tags=True,
71
- )
72
- assert qm.is_compare_tags
73
-
74
-
75
- def test_quay_mirror_org_session(mocker):
76
- mocker.patch("reconcile.quay_mirror_org.get_quay_api_store")
77
- mocked_request = mocker.patch("reconcile.quay_mirror_org.requests")
78
-
79
- with QuayMirrorOrg() as quay_mirror_org:
80
- assert quay_mirror_org.session == mocked_request.Session.return_value
81
-
82
- mocked_request.Session.return_value.close.assert_called_once_with()
@@ -1,59 +0,0 @@
1
- from unittest.mock import patch
2
-
3
- from reconcile.quay_base import OrgKey
4
- from reconcile.quay_repos import (
5
- RepoInfo,
6
- act,
7
- )
8
-
9
- from .fixtures import Fixtures
10
-
11
- fxt = Fixtures("quay_repos")
12
-
13
-
14
- def build_state(fixture_state):
15
- return [
16
- RepoInfo(
17
- org_key=OrgKey("instance", "org"),
18
- name=item[0],
19
- public=item[1],
20
- description=item[2],
21
- )
22
- for item in fixture_state
23
- ]
24
-
25
-
26
- def get_test_repo_from_state(state, name):
27
- for item in state:
28
- if item.name == name:
29
- return item
30
- return None
31
-
32
-
33
- class TestQuayRepos:
34
- @staticmethod
35
- @patch("reconcile.quay_repos.act_public")
36
- @patch("reconcile.quay_repos.act_description")
37
- @patch("reconcile.quay_repos.act_delete")
38
- @patch("reconcile.quay_repos.act_create")
39
- def test_act(act_create, act_delete, act_description, act_public):
40
- fixture = fxt.get_anymarkup("state.yml")
41
-
42
- current_state = build_state(fixture["current_state"])
43
- desired_state = build_state(fixture["desired_state"])
44
-
45
- quay_api_store = {}
46
- dry_run = True
47
- act(dry_run, quay_api_store, current_state, desired_state)
48
-
49
- repo_delete = get_test_repo_from_state(current_state, "repo_delete")
50
- act_delete.assert_called_once_with(dry_run, quay_api_store, repo_delete)
51
-
52
- repo_create = get_test_repo_from_state(desired_state, "repo_create")
53
- act_create.assert_called_once_with(dry_run, quay_api_store, repo_create)
54
-
55
- repo_desc = get_test_repo_from_state(desired_state, "repo_desc")
56
- act_description.assert_called_once_with(dry_run, quay_api_store, repo_desc)
57
-
58
- repo_public = get_test_repo_from_state(desired_state, "repo_public")
59
- act_public.assert_called_once_with(dry_run, quay_api_store, repo_public)
@@ -1,53 +0,0 @@
1
- from copy import deepcopy
2
- from typing import Any
3
- from unittest.mock import (
4
- create_autospec,
5
- patch,
6
- )
7
-
8
- from reconcile import queries
9
- from reconcile.utils import gql
10
-
11
- from .fixtures import Fixtures
12
-
13
-
14
- class TestQueries:
15
- def setup_method(self) -> None:
16
- """This starts a patch on gql.query method which will answer with the
17
- contents of self.fixture_data."""
18
-
19
- # Resetting this to make sure it is set from every test
20
- self.fixture_data: dict[str, Any] = {}
21
-
22
- self.gql_patcher = patch.object(gql, "get_api", autospec=True)
23
- self.gql = self.gql_patcher.start()
24
- gqlapi_mock = create_autospec(gql.GqlApi)
25
- self.gql.return_value = gqlapi_mock
26
- gqlapi_mock.query.side_effect = self.mock_gql_query
27
-
28
- def teardown_method(self) -> None:
29
- """Cleanup patches created in self.setup_method"""
30
- self.gql_patcher.stop()
31
-
32
- def mock_gql_query(self, query: str) -> dict[str, Any]:
33
- return self.fixture_data
34
-
35
- def test_get_pipelines_providers_all_defaults(self) -> None:
36
- data = Fixtures("queries").get_json("pipelines_providers_all_defaults.json")
37
- self.fixture_data = deepcopy(data)
38
- pps = queries.get_pipelines_providers()
39
-
40
- for k in ["retention", "taskTemplates", "pipelineTemplates", "deployResources"]:
41
- assert data["pipelines_providers"][0]["defaults"][k] == pps[0][k]
42
-
43
- def test_get_pipelines_providers_mixed(self) -> None:
44
- data = Fixtures("queries").get_json("pipelines_providers_mixed.json")
45
- self.fixture_data = deepcopy(data)
46
- pps = queries.get_pipelines_providers()
47
-
48
- # the fixture has some keys overriden from the defaults
49
- for k in ["taskTemplates", "pipelineTemplates"]:
50
- assert data["pipelines_providers"][0]["defaults"][k] == pps[0][k]
51
-
52
- for k in ["retention", "deployResources"]:
53
- assert data["pipelines_providers"][0][k] == pps[0][k]
@@ -1,47 +0,0 @@
1
- from reconcile.utils import repo_owners
2
-
3
-
4
- def test_repo_owners_subpath() -> None:
5
- def _mock_get_owners_map():
6
- return {
7
- "/foo": {
8
- "approvers": ["foo_approver"],
9
- "reviewers": ["foo_reviewer"],
10
- },
11
- "/foobar": {
12
- "approvers": ["foobar_approver"],
13
- "reviewers": ["foobar_reviewer"],
14
- },
15
- "/bar": {
16
- "approvers": ["bar_approver"],
17
- "reviewers": ["bar_reviewer"],
18
- },
19
- }
20
-
21
- owners = repo_owners.RepoOwners(None)
22
- owners._get_owners_map = _mock_get_owners_map # type: ignore
23
- assert owners.get_path_owners("/foobar/baz") == {
24
- "approvers": ["foobar_approver"],
25
- "reviewers": ["foobar_reviewer"],
26
- }
27
-
28
-
29
- def test_repo_owners_subpath_closest() -> None:
30
- def _mock_get_owners_map():
31
- return {
32
- "/": {
33
- "approvers": ["root_approver"],
34
- "reviewers": ["root_reviewer"],
35
- },
36
- "/foo": {
37
- "approvers": ["foo_approver"],
38
- "reviewers": ["foo_reviewer"],
39
- },
40
- }
41
-
42
- owners = repo_owners.RepoOwners(None)
43
- owners._get_owners_map = _mock_get_owners_map # type: ignore
44
- assert owners.get_path_closest_owners("/foobar/baz") == {
45
- "approvers": ["root_approver"],
46
- "reviewers": ["root_reviewer"],
47
- }
@@ -1,139 +0,0 @@
1
- import os
2
- import sys
3
- from subprocess import CalledProcessError
4
- from unittest import TestCase
5
- from unittest.mock import patch
6
-
7
- import reconcile.requests_sender as integ
8
- from reconcile import (
9
- queries,
10
- typed_queries,
11
- )
12
-
13
-
14
- class TestRunInteg(TestCase):
15
- def setUp(self):
16
- os.environ["APP_INTERFACE_STATE_BUCKET_ACCOUNT"] = "anaccount"
17
- self.user = {
18
- "org_username": "myorg",
19
- "public_gpg_key": "mykey",
20
- }
21
-
22
- self.requests = [
23
- {
24
- "user": self.user,
25
- "credentials": "credentials_name",
26
- "name": "aname",
27
- }
28
- ]
29
-
30
- self.exit_patcher = patch.object(sys, "exit", autospec=True)
31
- self.get_encrypted_creds_patcher = patch.object(
32
- integ, "get_encrypted_credentials"
33
- )
34
- self.smtpclient_patcher = patch.object(integ, "SmtpClient", autospec=True)
35
- self.get_settings_patcher = patch.object(
36
- queries, "get_app_interface_settings", autospec=True
37
- )
38
- self.get_smtp_credentials_patcher = patch.object(
39
- integ, "get_smtp_server_connection", autospec=True
40
- )
41
- self.smtp_settings_patcher = patch.object(
42
- typed_queries.smtp, "settings", autospec=True
43
- )
44
- self.get_aws_accounts_patcher = patch.object(
45
- queries, "get_aws_accounts", autospec=True
46
- )
47
- self.get_credentials_requests_patcher = patch.object(
48
- queries, "get_credentials_requests", autospec=True
49
- )
50
- self.state_patcher = patch.object(integ, "init_state", autospec=True)
51
- self.vault_settings_patcher = patch.object(
52
- integ,
53
- "get_app_interface_vault_settings",
54
- autospec=True,
55
- )
56
-
57
- self.do_exit = self.exit_patcher.start()
58
- self.get_encrypted_credentials = self.get_encrypted_creds_patcher.start()
59
- self.smtpclient = self.smtpclient_patcher.start()
60
- self.get_app_interface_settings = self.get_settings_patcher.start()
61
- self.get_smtp_credentials = self.get_smtp_credentials_patcher.start()
62
- self.smtp_settings = self.smtp_settings_patcher.start()
63
- self.get_aws_accounts = self.get_aws_accounts_patcher.start()
64
- self.get_credentials_requests = self.get_credentials_requests_patcher.start()
65
- self.get_credentials_requests.return_value = self.requests
66
- self.get_encrypted_credentials.return_value = "anencryptedcred"
67
- self.state = self.state_patcher.start()
68
- self.vault_settings_patcher.start()
69
- self.settings = {
70
- "smtp": {
71
- "secret_path": "asecretpath",
72
- "server": "aserver",
73
- "password": "apassword",
74
- "port": 993,
75
- "require_tls": True,
76
- "username": "asmtpuser",
77
- }
78
- }
79
- self.get_app_interface_settings.return_value = self.settings
80
- self.get_aws_accounts.return_value = ["anaccount"]
81
-
82
- def tearDown(self):
83
- for p in (
84
- self.exit_patcher,
85
- self.get_encrypted_creds_patcher,
86
- self.smtpclient_patcher,
87
- self.get_settings_patcher,
88
- self.get_smtp_credentials_patcher,
89
- self.smtp_settings_patcher,
90
- self.get_credentials_requests_patcher,
91
- self.get_aws_accounts_patcher,
92
- self.state_patcher,
93
- self.vault_settings_patcher,
94
- ):
95
- p.stop()
96
-
97
- def test_valid_credentials(self):
98
- # Yeah, yeah, whatever
99
- self.state.return_value.exists.return_value = False
100
- integ.run(False)
101
- # This has succeeded
102
- self.do_exit.assert_not_called()
103
- self.get_encrypted_credentials.assert_called_once_with(
104
- "credentials_name", self.user, self.settings
105
- )
106
- calls = self.smtpclient.return_value.send_mail.call_args_list
107
- self.assertEqual(len(calls), 1)
108
- # I don't care too much about the body of the email, TBH
109
- self.assertEqual(calls[0][0][:-1], (["myorg"], "aname"))
110
- # Just check that we're still sending the encrypted credential
111
- # in the body. This assertion is backwards with regards to all
112
- # other assertions :(
113
- self.assertIn("anencryptedcred", calls[0][0][-1])
114
-
115
- def test_existing_credentials(self):
116
- self.state.return_value.exists.return_value = True
117
- integ.run(False)
118
- self.do_exit.assert_not_called()
119
- self.get_encrypted_credentials.assert_not_called()
120
- self.smtpclient.return_value.send_mail.assert_not_called()
121
-
122
- def test_invalid_credentials(self):
123
- self.get_encrypted_credentials.side_effect = CalledProcessError(
124
- stderr="iadaiada", returncode=1, cmd="a command"
125
- )
126
- self.state.return_value.exists.return_value = False
127
- integ.run(False)
128
- self.do_exit.assert_called_once()
129
- self.get_encrypted_credentials.assert_called_once()
130
- self.smtpclient.return_value.send_mail.assert_not_called()
131
-
132
- def test_dry_run_honored(self):
133
- self.state.return_value.exists.return_value = False
134
- integ.run(True)
135
-
136
- self.get_encrypted_credentials.assert_called_once()
137
- self.do_exit.assert_not_called()
138
- self.smtpclient.return_value.send_mail.assert_not_called()
139
- self.state.return_value.add.assert_not_called()