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,785 +0,0 @@
1
- import copy
2
- from collections.abc import (
3
- Iterable,
4
- Sequence,
5
- )
6
- from datetime import (
7
- datetime,
8
- timedelta,
9
- )
10
- from typing import Any
11
- from unittest.mock import (
12
- Mock,
13
- call,
14
- create_autospec,
15
- )
16
-
17
- import pytest
18
- from pytest_mock import MockerFixture
19
-
20
- import reconcile.slack_base as slackbase
21
- import reconcile.slack_usergroups as integ
22
- from reconcile.gql_definitions.slack_usergroups.clusters import ClusterAuthV1, ClusterV1
23
- from reconcile.gql_definitions.slack_usergroups.permissions import (
24
- PagerDutyInstanceV1,
25
- PagerDutyTargetV1,
26
- PermissionSlackUsergroupV1,
27
- ScheduleEntryV1,
28
- )
29
- from reconcile.gql_definitions.slack_usergroups.users import (
30
- AccessV1,
31
- NamespaceV1,
32
- NamespaceV1_ClusterV1,
33
- RoleV1,
34
- UserV1,
35
- )
36
- from reconcile.gql_definitions.slack_usergroups.users import ClusterV1 as AccessCluster
37
- from reconcile.slack_usergroups import (
38
- SlackMap,
39
- SlackState,
40
- State,
41
- WorkspaceSpec,
42
- act,
43
- get_clusters,
44
- get_permissions,
45
- get_users,
46
- )
47
- from reconcile.utils import repo_owners
48
- from reconcile.utils.github_api import GithubRepositoryApi
49
- from reconcile.utils.pagerduty_api import PagerDutyMap
50
- from reconcile.utils.slack_api import SlackApi
51
-
52
- from .fixtures import Fixtures
53
-
54
-
55
- @pytest.fixture
56
- def base_state():
57
- state = SlackState({
58
- "slack-workspace": {
59
- "usergroup-1": State(
60
- workspace="slack-workspace",
61
- usergroup="usergroup-1",
62
- usergroup_id="USERGA",
63
- user_names={"username"},
64
- channel_names={"channelname"},
65
- description="Some description",
66
- )
67
- }
68
- })
69
-
70
- return state
71
-
72
-
73
- @pytest.fixture
74
- def user() -> UserV1:
75
- return UserV1(
76
- org_username="org",
77
- slack_username="slack",
78
- github_username="github",
79
- name="name",
80
- pagerduty_username="pagerduty",
81
- tag_on_cluster_updates=None,
82
- tag_on_merge_requests=None,
83
- roles=None,
84
- )
85
-
86
-
87
- @pytest.fixture
88
- def fxt() -> Fixtures:
89
- return Fixtures("slack_usergroups")
90
-
91
-
92
- @pytest.fixture
93
- def permissions(fxt: Fixtures) -> list[PermissionSlackUsergroupV1]:
94
- def q(*args: Any, **kwargs: Any) -> dict[Any, Any]:
95
- return fxt.get_anymarkup("permissions.yml")
96
-
97
- return get_permissions(q)
98
-
99
-
100
- @pytest.fixture
101
- def slack_client_mock() -> SlackApi:
102
- api = create_autospec(SlackApi)
103
- api.channel = "channel"
104
- return api
105
-
106
-
107
- @pytest.fixture
108
- def slack_map(slack_client_mock: Mock) -> SlackMap:
109
- return {
110
- "slack-workspace": WorkspaceSpec(
111
- slack=slack_client_mock, managed_usergroups=[]
112
- ),
113
- "coreos": WorkspaceSpec(slack=slack_client_mock, managed_usergroups=[]),
114
- }
115
-
116
-
117
- def test_get_permissions(permissions: Sequence[PermissionSlackUsergroupV1]) -> None:
118
- assert len(permissions) == 2
119
- p = permissions[0]
120
- assert p.channels and len(p.channels) == 2
121
- assert p.roles and p.roles[0].users == []
122
-
123
- p = permissions[1]
124
- assert p.roles and p.roles[0].users and p.roles[0].users[0].name == "Rafael"
125
-
126
-
127
- def test_get_users(fxt: Fixtures) -> None:
128
- def q(*args: Any, **kwargs: Any) -> dict[Any, Any]:
129
- return fxt.get_anymarkup("users.yml")
130
-
131
- users = get_users(q)
132
- assert len(users) == 2
133
- assert users[0].org_username == "user1-org-username"
134
- assert users[0].roles
135
- assert len(users[0].roles) == 1
136
- assert (
137
- users[1].roles
138
- and users[1].roles[0].access
139
- and users[1].roles[0].access[0].namespace
140
- and users[1].roles[0].access[0].namespace.cluster.name == "cluster-1"
141
- )
142
-
143
-
144
- def test_get_clusters(fxt: Fixtures) -> None:
145
- def q(*args: Any, **kwargs: Any) -> dict[Any, Any]:
146
- return fxt.get_anymarkup("clusters.yml")
147
-
148
- clusters = get_clusters(q)
149
- assert len(clusters) == 2
150
- assert clusters[0].name == "cluster-1"
151
- assert clusters[0].disable
152
-
153
-
154
- def test_get_slack_usernames_from_schedule_none() -> None:
155
- result = integ.get_slack_usernames_from_schedule([])
156
- assert not result
157
-
158
-
159
- def test_get_slack_usernames_from_schedule(user: UserV1) -> None:
160
- now = datetime.utcnow()
161
- schedule = ScheduleEntryV1(
162
- start=(now - timedelta(hours=1)).strftime(integ.DATE_FORMAT),
163
- end=(now + timedelta(hours=1)).strftime(integ.DATE_FORMAT),
164
- users=[user],
165
- )
166
- result = integ.get_slack_usernames_from_schedule([schedule])
167
- assert result == [user.slack_username]
168
-
169
-
170
- def test_get_slack_username_org_username(user: UserV1) -> None:
171
- user.slack_username = None
172
- result = integ.get_slack_username(user)
173
- assert result == user.org_username
174
-
175
-
176
- def test_get_slack_username_slack_username(user: UserV1) -> None:
177
- result = integ.get_slack_username(user)
178
- assert result == user.slack_username
179
-
180
-
181
- def test_get_pagerduty_username_org_username(user: UserV1) -> None:
182
- user.pagerduty_username = None
183
- result = integ.get_pagerduty_name(user)
184
- assert result == user.org_username
185
-
186
-
187
- def test_get_pagerduty_username_slack_username(user: UserV1) -> None:
188
- result = integ.get_pagerduty_name(user)
189
- assert result == user.pagerduty_username
190
-
191
-
192
- def test_get_usernames_from_pagerduty(user: UserV1) -> None:
193
- pagerduties = [
194
- PagerDutyTargetV1(
195
- name="app-sre-pagerduty-primary-oncall",
196
- instance=PagerDutyInstanceV1(name="redhat"),
197
- scheduleID="PHS3079",
198
- escalationPolicyID=None,
199
- )
200
- ]
201
- mock_pagerduty_map = create_autospec(PagerDutyMap)
202
- mock_pagerduty_map.get.return_value.get_pagerduty_users.return_value = [
203
- "pagerduty+foobar",
204
- "nobody",
205
- "nobody+foobar",
206
- ]
207
- result = integ.get_usernames_from_pagerduty(
208
- pagerduties=pagerduties,
209
- users=[user],
210
- usergroup="usergroup",
211
- pagerduty_map=mock_pagerduty_map,
212
- )
213
- assert result == [user.slack_username]
214
-
215
-
216
- def test_get_slack_usernames_from_owners(mocker: MockerFixture, user: UserV1) -> None:
217
- mocker.patch(
218
- "reconcile.slack_usergroups.get_git_api"
219
- ).return_value.__enter__.return_value = create_autospec(GithubRepositoryApi)
220
- mock_repo_owner = create_autospec(repo_owners.RepoOwners)
221
- mock_repo_owner.return_value.get_root_owners.return_value = {
222
- "approvers": ["approver1"],
223
- "reviewers": ["github"], # <- the test user
224
- }
225
- result = integ.get_slack_usernames_from_owners(
226
- owners_from_repo=["https://github.com/owner/repo"],
227
- users=[user],
228
- usergroup="usergroup",
229
- repo_owner_class=mock_repo_owner,
230
- )
231
- assert result == [user.slack_username]
232
-
233
-
234
- def test_include_user_to_cluster_usergroup_user_has_cluster_access(
235
- mocker: MockerFixture, user: UserV1
236
- ) -> None:
237
- mocker.patch(
238
- "reconcile.openshift_base.user_has_cluster_access",
239
- autospec=True,
240
- return_value=False,
241
- )
242
- cluster = ClusterV1(name="cluster", auth=[], disable={"integrations": []})
243
- # user_has_cluster_access -> False
244
- assert not integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
245
-
246
-
247
- def test_user_has_cluster_access(mocker: MockerFixture, user: UserV1) -> None:
248
- cluster = ClusterV1(
249
- name="cluster",
250
- auth=[ClusterAuthV1(service="oidc")],
251
- disable={"integrations": []},
252
- )
253
- assert integ.user_has_cluster_access(user, cluster, [user.org_username])
254
- assert not integ.user_has_cluster_access(user, cluster, ["just-another-user"])
255
-
256
-
257
- def test_include_user_to_cluster_usergroup(mocker: MockerFixture, user: UserV1) -> None:
258
- mocker.patch.object(
259
- integ,
260
- "user_has_cluster_access",
261
- autospec=True,
262
- return_value=True,
263
- )
264
- cluster = ClusterV1(name="cluster", auth=[], disable={"integrations": []})
265
-
266
- # user.tag_on_cluster_updates
267
- user.tag_on_cluster_updates = False
268
- assert not integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
269
- user.tag_on_cluster_updates = True
270
- assert integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
271
-
272
- # no roles
273
- user.tag_on_cluster_updates = None
274
- user.roles = []
275
- assert not integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
276
-
277
- # role: cluster and tag_on_cluster_updates = True & False
278
- user.roles = [
279
- RoleV1(
280
- tag_on_cluster_updates=True,
281
- access=[AccessV1(cluster=AccessCluster(name=cluster.name), namespace=None)],
282
- ),
283
- RoleV1(
284
- tag_on_cluster_updates=False,
285
- access=[AccessV1(cluster=AccessCluster(name=cluster.name), namespace=None)],
286
- ),
287
- ]
288
- assert integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
289
- # role: cluster and tag_on_cluster_updates = None & False
290
- user.roles = [
291
- RoleV1(
292
- tag_on_cluster_updates=None,
293
- access=[AccessV1(cluster=AccessCluster(name=cluster.name), namespace=None)],
294
- ),
295
- RoleV1(
296
- tag_on_cluster_updates=False,
297
- access=[AccessV1(cluster=AccessCluster(name=cluster.name), namespace=None)],
298
- ),
299
- ]
300
- assert integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
301
-
302
- # role: cluster and tag_on_cluster_updates = False & False
303
- user.roles = [
304
- RoleV1(
305
- tag_on_cluster_updates=False,
306
- access=[AccessV1(cluster=AccessCluster(name=cluster.name), namespace=None)],
307
- ),
308
- RoleV1(
309
- tag_on_cluster_updates=False,
310
- access=[AccessV1(cluster=AccessCluster(name=cluster.name), namespace=None)],
311
- ),
312
- ]
313
- assert not integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
314
-
315
- # role: namespace and tag_on_cluster_updates = True & False
316
- user.roles = [
317
- RoleV1(
318
- tag_on_cluster_updates=True,
319
- access=[
320
- AccessV1(
321
- cluster=None,
322
- namespace=NamespaceV1(
323
- name="namespace",
324
- cluster=NamespaceV1_ClusterV1(name=cluster.name),
325
- ),
326
- )
327
- ],
328
- ),
329
- RoleV1(
330
- tag_on_cluster_updates=False,
331
- access=[
332
- AccessV1(
333
- cluster=None,
334
- namespace=NamespaceV1(
335
- name="namespace",
336
- cluster=NamespaceV1_ClusterV1(name=cluster.name),
337
- ),
338
- )
339
- ],
340
- ),
341
- ]
342
- assert integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
343
- # role: namespace and tag_on_cluster_updates = None & False
344
- user.roles = [
345
- RoleV1(
346
- tag_on_cluster_updates=None,
347
- access=[
348
- AccessV1(
349
- cluster=None,
350
- namespace=NamespaceV1(
351
- name="namespace",
352
- cluster=NamespaceV1_ClusterV1(name=cluster.name),
353
- ),
354
- )
355
- ],
356
- ),
357
- RoleV1(
358
- tag_on_cluster_updates=False,
359
- access=[
360
- AccessV1(
361
- cluster=None,
362
- namespace=NamespaceV1(
363
- name="namespace",
364
- cluster=NamespaceV1_ClusterV1(name=cluster.name),
365
- ),
366
- )
367
- ],
368
- ),
369
- ]
370
- assert integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
371
-
372
- # role: namespace and tag_on_cluster_updates = False & False
373
- user.roles = [
374
- RoleV1(
375
- tag_on_cluster_updates=False,
376
- access=[
377
- AccessV1(
378
- cluster=None,
379
- namespace=NamespaceV1(
380
- name="namespace",
381
- cluster=NamespaceV1_ClusterV1(name=cluster.name),
382
- ),
383
- )
384
- ],
385
- ),
386
- RoleV1(
387
- tag_on_cluster_updates=False,
388
- access=[
389
- AccessV1(
390
- cluster=None,
391
- namespace=NamespaceV1(
392
- name="namespace",
393
- cluster=NamespaceV1_ClusterV1(name=cluster.name),
394
- ),
395
- )
396
- ],
397
- ),
398
- ]
399
- assert not integ.include_user_to_cluster_usergroup(user, cluster, ["user1"])
400
-
401
-
402
- def test_get_desired_state(
403
- mocker: MockerFixture,
404
- permissions: Sequence[PermissionSlackUsergroupV1],
405
- user: UserV1,
406
- ) -> None:
407
- mocker.patch(
408
- "reconcile.slack_usergroups.get_usernames_from_pagerduty"
409
- ).return_value = ["user1"]
410
- mocker.patch(
411
- "reconcile.slack_usergroups.get_slack_usernames_from_owners"
412
- ).return_value = ["repo-user"]
413
- mock_pagerduty_map = create_autospec(PagerDutyMap)
414
- result = integ.get_desired_state(
415
- mock_pagerduty_map,
416
- permissions[1:],
417
- [user],
418
- desired_workspace_name=None,
419
- desired_usergroup_name=None,
420
- )
421
-
422
- assert result == {
423
- "coreos": {
424
- "saas-osd-operators": State(
425
- workspace="coreos",
426
- usergroup="saas-osd-operators",
427
- description="SREP managed-cluster-config owners (managed via app-interface)",
428
- users=set(),
429
- user_names={"repo-user", "user1", "slack_username"},
430
- channels=set(),
431
- channel_names={"sre-operators", "sd-sre-platform"},
432
- usergroup_id="ugid",
433
- )
434
- }
435
- }
436
-
437
-
438
- def test_get_desired_state_with_error(
439
- mocker: MockerFixture,
440
- permissions: Sequence[PermissionSlackUsergroupV1],
441
- user: UserV1,
442
- ) -> None:
443
- mocker.patch(
444
- "reconcile.slack_usergroups.get_usernames_from_pagerduty"
445
- ).return_value = ["user1"]
446
- mocker.patch(
447
- "reconcile.slack_usergroups.get_slack_usernames_from_owners"
448
- ).side_effect = Exception("some error")
449
- mock_pagerduty_map = create_autospec(PagerDutyMap)
450
- result = integ.get_desired_state(
451
- mock_pagerduty_map,
452
- permissions[1:],
453
- [user],
454
- desired_workspace_name=None,
455
- desired_usergroup_name=None,
456
- )
457
-
458
- assert result == {}
459
-
460
-
461
- def test_get_desired_state_cluster_usergroups(
462
- mocker: MockerFixture, slack_map: SlackMap, user: UserV1
463
- ) -> None:
464
- mocker.patch("reconcile.openshift_users.fetch_desired_state", autospec=True)
465
- mocker.patch(
466
- "reconcile.slack_usergroups.include_user_to_cluster_usergroup"
467
- ).return_value = True
468
-
469
- cluster = ClusterV1(name="cluster1", auth=[], disable={"integrations": []})
470
- result = integ.get_desired_state_cluster_usergroups(
471
- slack_map, [cluster], [user], None, None
472
- )
473
-
474
- assert result == {
475
- "coreos": {
476
- "cluster1-cluster": State(
477
- workspace="coreos",
478
- usergroup="cluster1-cluster",
479
- description="Users with access to the cluster1 cluster",
480
- users=set(),
481
- user_names={"slack"},
482
- channels=set(),
483
- channel_names={"channel"},
484
- usergroup_id="ugid",
485
- )
486
- },
487
- "slack-workspace": {
488
- "cluster1-cluster": State(
489
- workspace="slack-workspace",
490
- usergroup="cluster1-cluster",
491
- description="Users with access to the cluster1 cluster",
492
- users=set(),
493
- user_names={"slack"},
494
- channels=set(),
495
- channel_names={"channel"},
496
- usergroup_id="ugid",
497
- )
498
- },
499
- }
500
-
501
-
502
- def test_get_desired_state_non_existing_usergroup(
503
- mocker: MockerFixture, slack_map: SlackMap, user: UserV1
504
- ) -> None:
505
- mocker.patch("reconcile.openshift_users.fetch_desired_state", autospec=True)
506
- mocker.patch(
507
- "reconcile.slack_usergroups.include_user_to_cluster_usergroup"
508
- ).return_value = True
509
-
510
- cluster = ClusterV1(name="cluster1", auth=[], disable={"integrations": []})
511
- result = integ.get_desired_state_cluster_usergroups(
512
- slack_map, [cluster], [user], None, None
513
- )
514
-
515
- assert result == {
516
- "coreos": {
517
- "cluster1-cluster": State(
518
- workspace="coreos",
519
- usergroup="cluster1-cluster",
520
- description="Users with access to the cluster1 cluster",
521
- users=set(),
522
- user_names={"slack"},
523
- channels=set(),
524
- channel_names={"channel"},
525
- usergroup_id=None,
526
- )
527
- },
528
- "slack-workspace": {
529
- "cluster1-cluster": State(
530
- workspace="slack-workspace",
531
- usergroup="cluster1-cluster",
532
- description="Users with access to the cluster1 cluster",
533
- users=set(),
534
- user_names={"slack"},
535
- channels=set(),
536
- channel_names={"channel"},
537
- usergroup_id=None,
538
- )
539
- },
540
- }
541
-
542
-
543
- def test_get_slack_map_return_expected(
544
- mocker: MockerFixture, permissions: Iterable[PermissionSlackUsergroupV1]
545
- ) -> None:
546
- mock_slack_api = mocker.patch.object(slackbase, "SlackApi", autospec=True)
547
- mock_secretreader = mocker.patch(
548
- "reconcile.utils.secret_reader.SecretReader", autospec=True
549
- )
550
- mock_secretreader.return_value.read.return_value = "secret"
551
-
552
- result = integ.get_slack_map(mock_secretreader, permissions)
553
- mock_slack_api.assert_called_once()
554
- # just one workspace in the permissions
555
- assert len(result) == 1
556
- assert isinstance(result["coreos"].slack, SlackApi)
557
- assert result["coreos"].managed_usergroups == [
558
- "app-sre-team",
559
- "app-sre-ic",
560
- "backplane-team",
561
- ]
562
-
563
-
564
- def test_act_no_changes_detected(
565
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
566
- ) -> None:
567
- """No changes should be made when the states are identical."""
568
- current_state = base_state
569
- desired_state = base_state
570
-
571
- act(current_state, desired_state, slack_map, dry_run=False)
572
-
573
- slack_client_mock.update_usergroup.assert_not_called()
574
- slack_client_mock.update_usergroup_users.assert_not_called()
575
-
576
-
577
- def test_act_dryrun_no_changes_made(
578
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
579
- ) -> None:
580
- """No changes should be made when dryrun mode is enabled."""
581
-
582
- current_state = base_state
583
- desired_state = copy.deepcopy(base_state)
584
-
585
- desired_state["slack-workspace"]["usergroup-1"].user_names = {"foo"}
586
-
587
- act(current_state, desired_state, slack_map, dry_run=True)
588
-
589
- slack_client_mock.update_usergroup.assert_not_called()
590
- slack_client_mock.update_usergroup_users.assert_not_called()
591
-
592
-
593
- def test_act_empty_current_state(
594
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
595
- ) -> None:
596
- """
597
- An empty current state should be able to be handled properly (watching for
598
- TypeErrors, etc).
599
- """
600
-
601
- current_state: SlackState = {}
602
- desired_state = base_state
603
-
604
- slack_client_mock.create_usergroup.return_value = "USERGA"
605
- slack_client_mock.get_usergroup_id.return_value = "USERGA"
606
- slack_client_mock.get_active_users_by_names.return_value = {"USERA": "username"}
607
- slack_client_mock.get_channels_by_names.return_value = {"CHANA": "someotherchannel"}
608
-
609
- act(current_state, desired_state, slack_map, dry_run=False)
610
-
611
- assert slack_client_mock.create_usergroup.call_args_list == [call("usergroup-1")]
612
- assert slack_client_mock.update_usergroup.call_args_list == [
613
- call(id="USERGA", channels_list=["CHANA"], description="Some description")
614
- ]
615
- assert slack_client_mock.update_usergroup_users.call_args_list == [
616
- call(id="USERGA", users_list=["USERA"])
617
- ]
618
-
619
-
620
- def test_act_update_usergroup_users(
621
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
622
- ) -> None:
623
- current_state = base_state
624
- desired_state = copy.deepcopy(base_state)
625
-
626
- desired_state["slack-workspace"]["usergroup-1"].user_names = {
627
- "someotherusername",
628
- "anotheruser",
629
- }
630
-
631
- slack_client_mock.get_usergroup_id.return_value = "USERGA"
632
- slack_client_mock.get_active_users_by_names.return_value = {
633
- "USERB": "someotherusername",
634
- "USERC": "anotheruser",
635
- }
636
- slack_client_mock.get_channels_by_names.return_value = {"CHANA": "channelname"}
637
-
638
- act(current_state, desired_state, slack_map, dry_run=False)
639
-
640
- slack_client_mock.update_usergroup.assert_not_called()
641
- slack_client_mock.update_usergroup_users.assert_called_once()
642
- assert slack_client_mock.update_usergroup_users.call_args_list == [
643
- call(id="USERGA", users_list=["USERB", "USERC"])
644
- ]
645
-
646
-
647
- def test_act_update_usergroup_channels(
648
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
649
- ) -> None:
650
- current_state = base_state
651
- desired_state = copy.deepcopy(base_state)
652
-
653
- desired_state["slack-workspace"]["usergroup-1"].channel_names = {"CHANB"}
654
-
655
- slack_client_mock.get_usergroup_id.return_value = "USERGA"
656
- slack_client_mock.get_active_users_by_names.return_value = {"USERA": "username"}
657
- slack_client_mock.get_channels_by_names.return_value = {"CHANB": "channel"}
658
-
659
- act(current_state, desired_state, slack_map, dry_run=False)
660
-
661
- assert slack_client_mock.update_usergroup.call_args_list == [
662
- call(id="USERGA", channels_list=["CHANB"], description="Some description")
663
- ]
664
- slack_client_mock.update_usergroup_users.assert_not_called()
665
-
666
-
667
- def test_act_update_usergroup_description(
668
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
669
- ) -> None:
670
- current_state = base_state
671
- desired_state = copy.deepcopy(base_state)
672
-
673
- desired_state["slack-workspace"][
674
- "usergroup-1"
675
- ].description = "A different description"
676
-
677
- slack_client_mock.get_usergroup_id.return_value = "USERGA"
678
- slack_client_mock.get_active_users_by_names.return_value = {"USERA": "username"}
679
- slack_client_mock.get_channels_by_names.return_value = {"CHANA": "channel"}
680
-
681
- act(current_state, desired_state, slack_map, dry_run=False)
682
-
683
- assert slack_client_mock.update_usergroup.call_args_list == [
684
- call(
685
- id="USERGA", channels_list=["CHANA"], description="A different description"
686
- )
687
- ]
688
- slack_client_mock.update_usergroup_users.assert_not_called()
689
-
690
-
691
- def test_act_update_usergroup_desc_and_channels(
692
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
693
- ) -> None:
694
- current_state = base_state
695
- desired_state = copy.deepcopy(base_state)
696
-
697
- desired_state["slack-workspace"][
698
- "usergroup-1"
699
- ].description = "A different description"
700
-
701
- slack_client_mock.get_usergroup_id.return_value = "USERGA"
702
- slack_client_mock.get_active_users_by_names.return_value = {"USERA": "username"}
703
- slack_client_mock.get_channels_by_names.return_value = {"CHANB": "someotherchannel"}
704
-
705
- act(current_state, desired_state, slack_map, dry_run=False)
706
-
707
- assert slack_client_mock.update_usergroup.call_args_list == [
708
- call(
709
- id="USERGA", channels_list=["CHANB"], description="A different description"
710
- )
711
- ]
712
- slack_client_mock.update_usergroup_users.assert_not_called()
713
-
714
-
715
- def test_act_add_new_usergroups(
716
- base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
717
- ) -> None:
718
- def get_users(users: set[str]) -> dict[str, str]:
719
- if "username" in users:
720
- return {"USERA": "username"}
721
- if "userb" in users:
722
- return {"USERB": "userb", "USERC": "userc"}
723
- return {"USERF": "userf", "USERG": "userg"}
724
-
725
- def get_channels(channels: set[str]) -> dict[str, str]:
726
- if "channelname" in channels:
727
- return {"CHANA": "channelname"}
728
- if "channelb" in channels:
729
- return {"CHANB": "channelb", "CHANC": "channelc"}
730
- return {"CHANF": "channelf", "CHANG": "channelg"}
731
-
732
- def get_ugid(usergroup: str) -> str:
733
- if usergroup == "usergroup-1":
734
- return "USERGA"
735
- if usergroup == "usergroup-2":
736
- return "USERGB"
737
- return "USERGC"
738
-
739
- current_state = base_state
740
- desired_state = copy.deepcopy(base_state)
741
-
742
- slack_client_mock.get_usergroup_id.side_effect = get_ugid
743
- slack_client_mock.get_active_users_by_names.side_effect = get_users
744
- slack_client_mock.get_channels_by_names.side_effect = get_channels
745
-
746
- desired_state["slack-workspace"]["usergroup-2"] = State(
747
- workspace="slack-workspace",
748
- usergroup="usergroup-2",
749
- usergroup_id="USERGB",
750
- user_names={"userb", "userc"},
751
- channel_names={"channelb", "channelc"},
752
- description="A new usergroup",
753
- )
754
-
755
- desired_state["slack-workspace"]["usergroup-3"] = State(
756
- workspace="slack-workspace",
757
- usergroup="usergroup-3",
758
- usergroup_id="USERGC",
759
- user_names={"userf", "userg"},
760
- channel_names={"channelf", "channelg"},
761
- description="Another new usergroup",
762
- )
763
- slack_client_mock.create_usergroup.side_effect = ["USERGB", "USERGC"]
764
-
765
- act(current_state, desired_state, slack_map, dry_run=False)
766
-
767
- assert slack_client_mock.create_usergroup.call_args_list == [
768
- call("usergroup-2"),
769
- call("usergroup-3"),
770
- ]
771
-
772
- assert slack_client_mock.update_usergroup.call_args_list == [
773
- call(
774
- id="USERGB", channels_list=["CHANB", "CHANC"], description="A new usergroup"
775
- ),
776
- call(
777
- id="USERGC",
778
- channels_list=["CHANF", "CHANG"],
779
- description="Another new usergroup",
780
- ),
781
- ]
782
- assert slack_client_mock.update_usergroup_users.call_args_list == [
783
- call(id="USERGB", users_list=["USERB", "USERC"]),
784
- call(id="USERGC", users_list=["USERF", "USERG"]),
785
- ]