cumulusci-plus 5.0.21__py3-none-any.whl → 5.0.43__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 (135) hide show
  1. cumulusci/__about__.py +1 -1
  2. cumulusci/cli/logger.py +2 -2
  3. cumulusci/cli/service.py +20 -0
  4. cumulusci/cli/task.py +19 -3
  5. cumulusci/cli/tests/test_error.py +3 -1
  6. cumulusci/cli/tests/test_flow.py +279 -2
  7. cumulusci/cli/tests/test_org.py +5 -0
  8. cumulusci/cli/tests/test_service.py +15 -12
  9. cumulusci/cli/tests/test_task.py +122 -2
  10. cumulusci/cli/tests/utils.py +1 -4
  11. cumulusci/core/config/__init__.py +1 -0
  12. cumulusci/core/config/base_task_flow_config.py +26 -1
  13. cumulusci/core/config/org_config.py +2 -1
  14. cumulusci/core/config/project_config.py +14 -20
  15. cumulusci/core/config/scratch_org_config.py +12 -0
  16. cumulusci/core/config/tests/test_config.py +1 -0
  17. cumulusci/core/config/tests/test_config_expensive.py +9 -3
  18. cumulusci/core/config/universal_config.py +3 -4
  19. cumulusci/core/dependencies/base.py +5 -1
  20. cumulusci/core/dependencies/dependencies.py +1 -1
  21. cumulusci/core/dependencies/github.py +1 -2
  22. cumulusci/core/dependencies/resolvers.py +1 -1
  23. cumulusci/core/dependencies/tests/test_dependencies.py +1 -1
  24. cumulusci/core/dependencies/tests/test_resolvers.py +1 -1
  25. cumulusci/core/flowrunner.py +90 -6
  26. cumulusci/core/github.py +1 -1
  27. cumulusci/core/sfdx.py +3 -1
  28. cumulusci/core/source_transforms/tests/test_transforms.py +1 -1
  29. cumulusci/core/source_transforms/transforms.py +1 -1
  30. cumulusci/core/tasks.py +13 -2
  31. cumulusci/core/tests/test_flowrunner.py +100 -0
  32. cumulusci/core/tests/test_tasks.py +65 -0
  33. cumulusci/core/utils.py +3 -1
  34. cumulusci/core/versions.py +1 -1
  35. cumulusci/cumulusci.yml +73 -1
  36. cumulusci/oauth/client.py +1 -1
  37. cumulusci/plugins/plugin_base.py +5 -3
  38. cumulusci/robotframework/pageobjects/ObjectManagerPageObject.py +1 -1
  39. cumulusci/salesforce_api/rest_deploy.py +1 -1
  40. cumulusci/schema/cumulusci.jsonschema.json +69 -0
  41. cumulusci/tasks/apex/anon.py +1 -1
  42. cumulusci/tasks/apex/testrunner.py +421 -144
  43. cumulusci/tasks/apex/tests/test_apex_tasks.py +917 -1
  44. cumulusci/tasks/bulkdata/extract.py +0 -1
  45. cumulusci/tasks/bulkdata/extract_dataset_utils/extract_yml.py +1 -1
  46. cumulusci/tasks/bulkdata/extract_dataset_utils/synthesize_extract_declarations.py +1 -1
  47. cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_extract_yml.py +1 -1
  48. cumulusci/tasks/bulkdata/generate_and_load_data.py +136 -12
  49. cumulusci/tasks/bulkdata/mapping_parser.py +139 -44
  50. cumulusci/tasks/bulkdata/select_utils.py +1 -1
  51. cumulusci/tasks/bulkdata/snowfakery.py +100 -25
  52. cumulusci/tasks/bulkdata/tests/test_generate_and_load.py +159 -0
  53. cumulusci/tasks/bulkdata/tests/test_load.py +0 -2
  54. cumulusci/tasks/bulkdata/tests/test_mapping_parser.py +763 -1
  55. cumulusci/tasks/bulkdata/tests/test_select_utils.py +46 -0
  56. cumulusci/tasks/bulkdata/tests/test_snowfakery.py +133 -0
  57. cumulusci/tasks/create_package_version.py +190 -16
  58. cumulusci/tasks/datadictionary.py +1 -1
  59. cumulusci/tasks/metadata_etl/__init__.py +2 -0
  60. cumulusci/tasks/metadata_etl/applications.py +256 -0
  61. cumulusci/tasks/metadata_etl/base.py +7 -3
  62. cumulusci/tasks/metadata_etl/layouts.py +1 -1
  63. cumulusci/tasks/metadata_etl/permissions.py +1 -1
  64. cumulusci/tasks/metadata_etl/remote_site_settings.py +2 -2
  65. cumulusci/tasks/metadata_etl/tests/test_applications.py +710 -0
  66. cumulusci/tasks/push/README.md +15 -17
  67. cumulusci/tasks/release_notes/README.md +13 -13
  68. cumulusci/tasks/release_notes/generator.py +13 -8
  69. cumulusci/tasks/robotframework/tests/test_robotframework.py +6 -1
  70. cumulusci/tasks/salesforce/Deploy.py +53 -2
  71. cumulusci/tasks/salesforce/SfPackageCommands.py +363 -0
  72. cumulusci/tasks/salesforce/__init__.py +1 -0
  73. cumulusci/tasks/salesforce/assign_ps_psg.py +448 -0
  74. cumulusci/tasks/salesforce/composite.py +1 -1
  75. cumulusci/tasks/salesforce/custom_settings_wait.py +1 -1
  76. cumulusci/tasks/salesforce/enable_prediction.py +5 -1
  77. cumulusci/tasks/salesforce/getPackageVersion.py +89 -0
  78. cumulusci/tasks/salesforce/insert_record.py +18 -19
  79. cumulusci/tasks/salesforce/sourcetracking.py +1 -1
  80. cumulusci/tasks/salesforce/tests/test_Deploy.py +316 -1
  81. cumulusci/tasks/salesforce/tests/test_SfPackageCommands.py +554 -0
  82. cumulusci/tasks/salesforce/tests/test_assign_ps_psg.py +1055 -0
  83. cumulusci/tasks/salesforce/tests/test_enable_prediction.py +4 -2
  84. cumulusci/tasks/salesforce/tests/test_getPackageVersion.py +651 -0
  85. cumulusci/tasks/salesforce/tests/test_update_dependencies.py +1 -1
  86. cumulusci/tasks/salesforce/tests/test_update_external_auth_identity_provider.py +927 -0
  87. cumulusci/tasks/salesforce/tests/test_update_external_credential.py +1427 -0
  88. cumulusci/tasks/salesforce/tests/test_update_named_credential.py +1042 -0
  89. cumulusci/tasks/salesforce/tests/test_update_record.py +512 -0
  90. cumulusci/tasks/salesforce/update_dependencies.py +2 -2
  91. cumulusci/tasks/salesforce/update_external_auth_identity_provider.py +551 -0
  92. cumulusci/tasks/salesforce/update_external_credential.py +647 -0
  93. cumulusci/tasks/salesforce/update_named_credential.py +441 -0
  94. cumulusci/tasks/salesforce/update_profile.py +17 -13
  95. cumulusci/tasks/salesforce/update_record.py +217 -0
  96. cumulusci/tasks/salesforce/users/permsets.py +62 -5
  97. cumulusci/tasks/salesforce/users/tests/test_permsets.py +237 -11
  98. cumulusci/tasks/sfdmu/__init__.py +0 -0
  99. cumulusci/tasks/sfdmu/sfdmu.py +376 -0
  100. cumulusci/tasks/sfdmu/tests/__init__.py +1 -0
  101. cumulusci/tasks/sfdmu/tests/test_runner.py +212 -0
  102. cumulusci/tasks/sfdmu/tests/test_sfdmu.py +1012 -0
  103. cumulusci/tasks/tests/test_create_package_version.py +716 -1
  104. cumulusci/tasks/tests/test_util.py +42 -0
  105. cumulusci/tasks/util.py +37 -1
  106. cumulusci/tasks/utility/copyContents.py +402 -0
  107. cumulusci/tasks/utility/credentialManager.py +302 -0
  108. cumulusci/tasks/utility/directoryRecreator.py +30 -0
  109. cumulusci/tasks/utility/env_management.py +1 -1
  110. cumulusci/tasks/utility/secretsToEnv.py +135 -0
  111. cumulusci/tasks/utility/tests/test_copyContents.py +1719 -0
  112. cumulusci/tasks/utility/tests/test_credentialManager.py +1150 -0
  113. cumulusci/tasks/utility/tests/test_directoryRecreator.py +439 -0
  114. cumulusci/tasks/utility/tests/test_secretsToEnv.py +1118 -0
  115. cumulusci/tests/test_integration_infrastructure.py +3 -1
  116. cumulusci/tests/test_utils.py +70 -6
  117. cumulusci/utils/__init__.py +54 -9
  118. cumulusci/utils/classutils.py +5 -2
  119. cumulusci/utils/http/tests/cassettes/ManualEditTestCompositeParallelSalesforce.test_http_headers.yaml +31 -30
  120. cumulusci/utils/options.py +23 -1
  121. cumulusci/utils/parallel/task_worker_queues/parallel_worker.py +1 -1
  122. cumulusci/utils/yaml/cumulusci_yml.py +8 -3
  123. cumulusci/utils/yaml/model_parser.py +2 -2
  124. cumulusci/utils/yaml/tests/test_cumulusci_yml.py +1 -1
  125. cumulusci/utils/yaml/tests/test_model_parser.py +3 -3
  126. cumulusci/vcs/base.py +23 -15
  127. cumulusci/vcs/bootstrap.py +5 -4
  128. cumulusci/vcs/utils/list_modified_files.py +189 -0
  129. cumulusci/vcs/utils/tests/test_list_modified_files.py +588 -0
  130. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/METADATA +11 -10
  131. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/RECORD +135 -104
  132. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/WHEEL +1 -1
  133. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/entry_points.txt +0 -0
  134. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/licenses/AUTHORS.rst +0 -0
  135. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,927 @@
1
+ import os
2
+
3
+ import pytest
4
+ import responses
5
+
6
+ from cumulusci.core.exceptions import SalesforceDXException
7
+ from cumulusci.tasks.salesforce.update_external_auth_identity_provider import (
8
+ ExternalAuthIdentityProviderCredential,
9
+ ExternalAuthIdentityProviderParameter,
10
+ ExtParameter,
11
+ TransformExternalAuthIdentityProviderParameter,
12
+ UpdateExternalAuthIdentityProvider,
13
+ )
14
+ from cumulusci.tests.util import CURRENT_SF_API_VERSION
15
+
16
+ from .util import create_task
17
+
18
+
19
+ class TestExtParameter:
20
+ """Test ExtParameter model"""
21
+
22
+ def test_ext_parameter_defaults(self):
23
+ """Test default values for ext parameter"""
24
+ param = ExtParameter(name="test-param", value="test-value")
25
+ assert param.name == "test-param"
26
+ assert param.value == "test-value"
27
+ assert param.sequence_number is None
28
+
29
+ def test_ext_parameter_with_sequence_number(self):
30
+ """Test ext parameter with sequence number"""
31
+ param = ExtParameter(name="test-param", value="test-value", sequence_number=1)
32
+ assert param.name == "test-param"
33
+ assert param.value == "test-value"
34
+ assert param.sequence_number == 1
35
+
36
+
37
+ class TestExternalAuthIdentityProviderCredential:
38
+ """Test ExternalAuthIdentityProviderCredential model"""
39
+
40
+ def test_credential_defaults(self):
41
+ """Test default values for credential"""
42
+ cred = ExternalAuthIdentityProviderCredential(
43
+ name="test-cred", client_id="client123", client_secret="secret456"
44
+ )
45
+ assert cred.name == "test-cred"
46
+ assert cred.client_id == "client123"
47
+ assert cred.client_secret == "secret456"
48
+ assert cred.auth_protocol == "OAuth"
49
+
50
+ def test_credential_with_custom_protocol(self):
51
+ """Test credential with custom auth protocol"""
52
+ cred = ExternalAuthIdentityProviderCredential(
53
+ name="test-cred",
54
+ client_id="client123",
55
+ client_secret="secret456",
56
+ auth_protocol="OpenIdConnect",
57
+ )
58
+ assert cred.auth_protocol == "OpenIdConnect"
59
+
60
+
61
+ class TestExternalAuthIdentityProviderParameter:
62
+ """Test ExternalAuthIdentityProviderParameter model"""
63
+
64
+ def test_parameter_with_authorize_url(self):
65
+ """Test parameter with authorize URL"""
66
+ param = ExternalAuthIdentityProviderParameter(
67
+ authorize_url="https://auth.example.com/authorize"
68
+ )
69
+ assert param.authorize_url == "https://auth.example.com/authorize"
70
+
71
+ def test_parameter_with_token_url(self):
72
+ """Test parameter with token URL"""
73
+ param = ExternalAuthIdentityProviderParameter(
74
+ token_url="https://auth.example.com/token"
75
+ )
76
+ assert param.token_url == "https://auth.example.com/token"
77
+
78
+ def test_parameter_with_user_info_url(self):
79
+ """Test parameter with user info URL"""
80
+ param = ExternalAuthIdentityProviderParameter(
81
+ user_info_url="https://auth.example.com/userinfo"
82
+ )
83
+ assert param.user_info_url == "https://auth.example.com/userinfo"
84
+
85
+ def test_parameter_with_jwks_url(self):
86
+ """Test parameter with JWKS URL"""
87
+ param = ExternalAuthIdentityProviderParameter(
88
+ jwks_url="https://auth.example.com/.well-known/jwks.json"
89
+ )
90
+ assert param.jwks_url == "https://auth.example.com/.well-known/jwks.json"
91
+
92
+ def test_parameter_with_issuer_url(self):
93
+ """Test parameter with issuer URL"""
94
+ param = ExternalAuthIdentityProviderParameter(
95
+ issuer_url="https://auth.example.com"
96
+ )
97
+ assert param.issuer_url == "https://auth.example.com"
98
+
99
+ def test_parameter_with_client_authentication(self):
100
+ """Test parameter with client authentication"""
101
+ param = ExternalAuthIdentityProviderParameter(
102
+ client_authentication="ClientSecretBasic"
103
+ )
104
+ assert param.client_authentication == "ClientSecretBasic"
105
+
106
+ def test_parameter_with_custom_parameter(self):
107
+ """Test parameter with custom parameter"""
108
+ custom_param = ExtParameter(name="scope", value="openid profile email")
109
+ param = ExternalAuthIdentityProviderParameter(custom_parameter=custom_param)
110
+ assert param.custom_parameter == custom_param
111
+
112
+ def test_parameter_with_identity_provider_option(self):
113
+ """Test parameter with identity provider option"""
114
+ option = ExtParameter(name="PkceEnabled", value="true")
115
+ param = ExternalAuthIdentityProviderParameter(identity_provider_option=option)
116
+ assert param.identity_provider_option == option
117
+
118
+ def test_parameter_with_credential(self):
119
+ """Test parameter with credential"""
120
+ cred = ExternalAuthIdentityProviderCredential(
121
+ name="test-cred", client_id="client123", client_secret="secret456"
122
+ )
123
+ param = ExternalAuthIdentityProviderParameter(credential=cred)
124
+ assert param.credential == cred
125
+
126
+ def test_parameter_validation_no_parameters(self):
127
+ """Test validation when no parameters are provided"""
128
+ with pytest.raises(ValueError, match="At least and only one parameter"):
129
+ ExternalAuthIdentityProviderParameter()
130
+
131
+ def test_parameter_validation_multiple_parameters(self):
132
+ """Test validation when multiple parameters are provided"""
133
+ with pytest.raises(ValueError, match="At least and only one parameter"):
134
+ ExternalAuthIdentityProviderParameter(
135
+ authorize_url="https://auth.example.com/authorize",
136
+ token_url="https://auth.example.com/token",
137
+ )
138
+
139
+ def test_get_parameter_authorize_url(self):
140
+ """Test getting parameter for authorize URL"""
141
+ param = ExternalAuthIdentityProviderParameter(
142
+ authorize_url="https://auth.example.com/authorize"
143
+ )
144
+ result = param.get_external_auth_identity_provider_parameter()
145
+ assert result["parameterType"] == "AuthorizeUrl"
146
+ assert result["parameterName"] == "AuthorizeUrl"
147
+ assert result["parameterValue"] == "https://auth.example.com/authorize"
148
+
149
+ def test_get_parameter_token_url(self):
150
+ """Test getting parameter for token URL"""
151
+ param = ExternalAuthIdentityProviderParameter(
152
+ token_url="https://auth.example.com/token"
153
+ )
154
+ result = param.get_external_auth_identity_provider_parameter()
155
+ assert result["parameterType"] == "TokenUrl"
156
+ assert result["parameterName"] == "TokenUrl"
157
+ assert result["parameterValue"] == "https://auth.example.com/token"
158
+
159
+ def test_get_parameter_user_info_url(self):
160
+ """Test getting parameter for user info URL"""
161
+ param = ExternalAuthIdentityProviderParameter(
162
+ user_info_url="https://auth.example.com/userinfo"
163
+ )
164
+ result = param.get_external_auth_identity_provider_parameter()
165
+ assert result["parameterType"] == "UserInfoUrl"
166
+ assert result["parameterName"] == "UserInfoUrl"
167
+ assert result["parameterValue"] == "https://auth.example.com/userinfo"
168
+
169
+ def test_get_parameter_client_authentication(self):
170
+ """Test getting parameter for client authentication"""
171
+ param = ExternalAuthIdentityProviderParameter(
172
+ client_authentication="ClientSecretBasic"
173
+ )
174
+ result = param.get_external_auth_identity_provider_parameter()
175
+ assert result["parameterType"] == "ClientAuthentication"
176
+ assert result["parameterName"] == "ClientAuthentication"
177
+ assert result["parameterValue"] == "ClientSecretBasic"
178
+
179
+ def test_get_parameter_custom_parameter(self):
180
+ """Test getting custom parameter"""
181
+ custom_param = ExtParameter(name="scope", value="openid profile")
182
+ param = ExternalAuthIdentityProviderParameter(custom_parameter=custom_param)
183
+ result = param.get_external_auth_identity_provider_parameter()
184
+ assert result["parameterType"] == "CustomParameter"
185
+ assert result["parameterName"] == "scope"
186
+ assert result["parameterValue"] == "openid profile"
187
+
188
+ def test_get_parameter_identity_provider_option(self):
189
+ """Test getting identity provider option"""
190
+ option = ExtParameter(name="PkceEnabled", value="true")
191
+ param = ExternalAuthIdentityProviderParameter(identity_provider_option=option)
192
+ result = param.get_external_auth_identity_provider_parameter()
193
+ assert result["parameterType"] == "IdentityProviderOptions"
194
+ assert result["parameterName"] == "PkceEnabled"
195
+ assert result["parameterValue"] == "true"
196
+
197
+ def test_get_parameter_jwks_url(self):
198
+ """Test getting parameter for JWKS URL"""
199
+ param = ExternalAuthIdentityProviderParameter(
200
+ jwks_url="https://auth.example.com/.well-known/jwks.json"
201
+ )
202
+ result = param.get_external_auth_identity_provider_parameter()
203
+ assert result["parameterType"] == "JwksUrl"
204
+ assert result["parameterName"] == "JwksUrl"
205
+ assert (
206
+ result["parameterValue"] == "https://auth.example.com/.well-known/jwks.json"
207
+ )
208
+
209
+ def test_get_parameter_issuer_url(self):
210
+ """Test getting parameter for issuer URL"""
211
+ param = ExternalAuthIdentityProviderParameter(
212
+ issuer_url="https://auth.example.com"
213
+ )
214
+ result = param.get_external_auth_identity_provider_parameter()
215
+ assert result["parameterType"] == "IssuerUrl"
216
+ assert result["parameterName"] == "IssuerUrl"
217
+ assert result["parameterValue"] == "https://auth.example.com"
218
+
219
+ def test_get_parameter_custom_parameter_with_sequence_number(self):
220
+ """Test getting custom parameter with sequence number"""
221
+ custom_param = ExtParameter(
222
+ name="scope", value="openid profile", sequence_number=5
223
+ )
224
+ param = ExternalAuthIdentityProviderParameter(custom_parameter=custom_param)
225
+ result = param.get_external_auth_identity_provider_parameter()
226
+ assert result["parameterType"] == "CustomParameter"
227
+ assert result["parameterName"] == "scope"
228
+ assert result["parameterValue"] == "openid profile"
229
+ assert result["sequenceNumber"] == 5
230
+
231
+ def test_get_credential(self):
232
+ """Test getting credential"""
233
+ cred = ExternalAuthIdentityProviderCredential(
234
+ name="test-cred", client_id="client123", client_secret="secret456"
235
+ )
236
+ param = ExternalAuthIdentityProviderParameter(credential=cred)
237
+ result = param.get_credential("TestProvider")
238
+ assert result["credentials"] is not None
239
+ assert len(result["credentials"]) == 2
240
+ client_id_cred = next(
241
+ c for c in result["credentials"] if c["credentialName"] == "clientId"
242
+ )
243
+ client_secret_cred = next(
244
+ c for c in result["credentials"] if c["credentialName"] == "clientSecret"
245
+ )
246
+ assert client_id_cred["credentialValue"] == "client123"
247
+ assert client_secret_cred["credentialValue"] == "secret456"
248
+
249
+ def test_get_credential_none(self):
250
+ """Test getting credential when none is set"""
251
+ param = ExternalAuthIdentityProviderParameter(
252
+ authorize_url="https://auth.example.com/authorize"
253
+ )
254
+ result = param.get_credential("TestProvider")
255
+ assert result is None
256
+
257
+
258
+ class TestTransformExternalAuthIdentityProviderParameter:
259
+ """Test TransformExternalAuthIdentityProviderParameter model"""
260
+
261
+ def test_transform_parameter_value(self):
262
+ """Test transforming parameter value from environment variable"""
263
+ os.environ["TEST_AUTH_URL"] = "https://auth.example.com/authorize"
264
+ param = TransformExternalAuthIdentityProviderParameter(
265
+ authorize_url="TEST_AUTH_URL"
266
+ )
267
+ result = param.get_external_auth_identity_provider_parameter()
268
+ assert result["parameterValue"] == "https://auth.example.com/authorize"
269
+ del os.environ["TEST_AUTH_URL"]
270
+
271
+ def test_transform_credential(self):
272
+ """Test transforming credential from environment variables"""
273
+ os.environ["TEST_CLIENT_ID"] = "client123"
274
+ os.environ["TEST_CLIENT_SECRET"] = "secret456"
275
+ cred = ExternalAuthIdentityProviderCredential(
276
+ name="test-cred",
277
+ client_id="TEST_CLIENT_ID",
278
+ client_secret="TEST_CLIENT_SECRET",
279
+ )
280
+ param = TransformExternalAuthIdentityProviderParameter(credential=cred)
281
+ result = param.get_credential("TestProvider")
282
+ assert result["credentials"] is not None
283
+ assert len(result["credentials"]) == 2
284
+ client_id_cred = next(
285
+ c for c in result["credentials"] if c["credentialName"] == "clientId"
286
+ )
287
+ client_secret_cred = next(
288
+ c for c in result["credentials"] if c["credentialName"] == "clientSecret"
289
+ )
290
+ assert client_id_cred["credentialValue"] == "client123"
291
+ assert client_secret_cred["credentialValue"] == "secret456"
292
+ del os.environ["TEST_CLIENT_ID"]
293
+ del os.environ["TEST_CLIENT_SECRET"]
294
+
295
+ def test_transform_credential_none(self):
296
+ """Test transforming when credential returns None"""
297
+ param = TransformExternalAuthIdentityProviderParameter(authorize_url="TEST_URL")
298
+ result = param.get_credential("TestProvider")
299
+ assert result is None
300
+
301
+
302
+ class TestUpdateExternalAuthIdentityProvider:
303
+ """Test UpdateExternalAuthIdentityProvider task"""
304
+
305
+ @responses.activate
306
+ def test_run_task_success(self):
307
+ """Test successful task execution"""
308
+ task = create_task(
309
+ UpdateExternalAuthIdentityProvider,
310
+ {
311
+ "name": "TestProvider",
312
+ "parameters": [
313
+ {
314
+ "authorize_url": "https://auth.example.com/authorize",
315
+ }
316
+ ],
317
+ },
318
+ )
319
+
320
+ # Mock query response
321
+ responses.add(
322
+ method=responses.GET,
323
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
324
+ json={
325
+ "size": 1,
326
+ "records": [{"Id": "0soxx0000000001AAA"}],
327
+ },
328
+ status=200,
329
+ )
330
+
331
+ # Mock get external auth identity provider
332
+ responses.add(
333
+ method=responses.GET,
334
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
335
+ json={
336
+ "Metadata": {
337
+ "externalAuthIdentityProviderParameters": [
338
+ {
339
+ "parameterType": "AuthorizeUrl",
340
+ "parameterName": "AuthorizeUrl",
341
+ "parameterValue": "https://old.example.com/authorize",
342
+ }
343
+ ]
344
+ }
345
+ },
346
+ status=200,
347
+ )
348
+
349
+ # Mock update external auth identity provider
350
+ responses.add(
351
+ method=responses.PATCH,
352
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
353
+ json={},
354
+ status=200,
355
+ )
356
+
357
+ task()
358
+
359
+ @responses.activate
360
+ def test_run_task_not_found(self):
361
+ """Test task execution when provider is not found"""
362
+ task = create_task(
363
+ UpdateExternalAuthIdentityProvider,
364
+ {
365
+ "name": "NonExistentProvider",
366
+ "parameters": [
367
+ {
368
+ "authorize_url": "https://auth.example.com/authorize",
369
+ }
370
+ ],
371
+ },
372
+ )
373
+
374
+ # Mock query response with no results
375
+ responses.add(
376
+ method=responses.GET,
377
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
378
+ json={"size": 0, "records": []},
379
+ status=200,
380
+ )
381
+
382
+ with pytest.raises(
383
+ SalesforceDXException,
384
+ match="External auth identity provider 'NonExistentProvider' not found",
385
+ ):
386
+ task()
387
+
388
+ @responses.activate
389
+ def test_run_task_with_namespace(self):
390
+ """Test task execution with namespace"""
391
+ task = create_task(
392
+ UpdateExternalAuthIdentityProvider,
393
+ {
394
+ "name": "TestProvider",
395
+ "namespace": "testns",
396
+ "parameters": [
397
+ {
398
+ "token_url": "https://auth.example.com/token",
399
+ }
400
+ ],
401
+ },
402
+ )
403
+
404
+ # Mock query response
405
+ responses.add(
406
+ method=responses.GET,
407
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
408
+ json={
409
+ "size": 1,
410
+ "records": [{"Id": "0soxx0000000001AAA"}],
411
+ },
412
+ status=200,
413
+ )
414
+
415
+ # Mock get external auth identity provider
416
+ responses.add(
417
+ method=responses.GET,
418
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
419
+ json={
420
+ "Metadata": {
421
+ "externalAuthIdentityProviderParameters": [
422
+ {
423
+ "parameterType": "TokenUrl",
424
+ "parameterName": "TokenUrl",
425
+ "parameterValue": "https://old.example.com/token",
426
+ }
427
+ ]
428
+ }
429
+ },
430
+ status=200,
431
+ )
432
+
433
+ # Mock update external auth identity provider
434
+ responses.add(
435
+ method=responses.PATCH,
436
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
437
+ json={},
438
+ status=200,
439
+ )
440
+
441
+ task()
442
+
443
+ # Verify query includes namespace (URL encoded)
444
+ assert "NamespacePrefix" in responses.calls[0].request.url
445
+ assert "testns" in responses.calls[0].request.url
446
+
447
+ @responses.activate
448
+ def test_run_task_retrieve_error(self):
449
+ """Test task execution when retrieve fails"""
450
+ task = create_task(
451
+ UpdateExternalAuthIdentityProvider,
452
+ {
453
+ "name": "TestProvider",
454
+ "parameters": [
455
+ {
456
+ "authorize_url": "https://auth.example.com/authorize",
457
+ }
458
+ ],
459
+ },
460
+ )
461
+
462
+ # Mock query response
463
+ responses.add(
464
+ method=responses.GET,
465
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
466
+ json={
467
+ "size": 1,
468
+ "records": [{"Id": "0soxx0000000001AAA"}],
469
+ },
470
+ status=200,
471
+ )
472
+
473
+ # Mock get external auth identity provider with error
474
+ responses.add(
475
+ method=responses.GET,
476
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
477
+ json={"error": "Not found"},
478
+ status=404,
479
+ )
480
+
481
+ with pytest.raises(
482
+ SalesforceDXException,
483
+ match="Failed to retrieve external auth identity provider object for 'TestProvider'",
484
+ ):
485
+ task()
486
+
487
+ @responses.activate
488
+ def test_run_task_update_error(self):
489
+ """Test task execution when update fails"""
490
+ task = create_task(
491
+ UpdateExternalAuthIdentityProvider,
492
+ {
493
+ "name": "TestProvider",
494
+ "parameters": [
495
+ {
496
+ "authorize_url": "https://auth.example.com/authorize",
497
+ }
498
+ ],
499
+ },
500
+ )
501
+
502
+ # Mock query response
503
+ responses.add(
504
+ method=responses.GET,
505
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
506
+ json={
507
+ "size": 1,
508
+ "records": [{"Id": "0soxx0000000001AAA"}],
509
+ },
510
+ status=200,
511
+ )
512
+
513
+ # Mock get external auth identity provider
514
+ responses.add(
515
+ method=responses.GET,
516
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
517
+ json={
518
+ "Metadata": {
519
+ "externalAuthIdentityProviderParameters": [
520
+ {
521
+ "parameterType": "AuthorizeUrl",
522
+ "parameterName": "AuthorizeUrl",
523
+ "parameterValue": "https://old.example.com/authorize",
524
+ }
525
+ ]
526
+ }
527
+ },
528
+ status=200,
529
+ )
530
+
531
+ # Mock update external auth identity provider with error
532
+ responses.add(
533
+ method=responses.PATCH,
534
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
535
+ json={"error": "Update failed"},
536
+ status=400,
537
+ )
538
+
539
+ with pytest.raises(
540
+ SalesforceDXException,
541
+ match="Failed to update external auth identity provider object for 'TestProvider'",
542
+ ):
543
+ task()
544
+
545
+ @responses.activate
546
+ def test_run_task_with_credential_update(self):
547
+ """Test task execution with credential update"""
548
+ task = create_task(
549
+ UpdateExternalAuthIdentityProvider,
550
+ {
551
+ "name": "TestProvider",
552
+ "parameters": [
553
+ {
554
+ "credential": {
555
+ "name": "TestCred",
556
+ "client_id": "client123",
557
+ "client_secret": "secret456",
558
+ }
559
+ }
560
+ ],
561
+ },
562
+ )
563
+
564
+ # Mock query response
565
+ responses.add(
566
+ method=responses.GET,
567
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
568
+ json={
569
+ "size": 1,
570
+ "records": [{"Id": "0soxx0000000001AAA"}],
571
+ },
572
+ status=200,
573
+ )
574
+
575
+ # Mock get external auth identity provider
576
+ responses.add(
577
+ method=responses.GET,
578
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
579
+ json={
580
+ "Metadata": {
581
+ "externalAuthIdentityProviderParameters": [
582
+ {
583
+ "parameterType": "AuthorizeUrl",
584
+ "parameterName": "AuthorizeUrl",
585
+ "parameterValue": "https://auth.example.com/authorize",
586
+ }
587
+ ]
588
+ }
589
+ },
590
+ status=200,
591
+ )
592
+
593
+ # Mock update external auth identity provider
594
+ responses.add(
595
+ method=responses.PATCH,
596
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
597
+ json={},
598
+ status=200,
599
+ )
600
+
601
+ # Mock get credential
602
+ responses.add(
603
+ method=responses.GET,
604
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/named-credentials/external-auth-identity-provider-credentials/TestProvider",
605
+ json={
606
+ "externalAuthIdentityProvider": "TestProvider",
607
+ "credentials": None,
608
+ },
609
+ status=200,
610
+ )
611
+
612
+ # Mock update credential
613
+ responses.add(
614
+ method=responses.POST,
615
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/named-credentials/external-auth-identity-provider-credentials/TestProvider",
616
+ json={},
617
+ status=200,
618
+ )
619
+
620
+ task()
621
+
622
+ @responses.activate
623
+ def test_run_task_with_multiple_parameters(self):
624
+ """Test task execution with multiple parameters"""
625
+ task = create_task(
626
+ UpdateExternalAuthIdentityProvider,
627
+ {
628
+ "name": "TestProvider",
629
+ "parameters": [
630
+ {
631
+ "authorize_url": "https://auth.example.com/authorize",
632
+ },
633
+ {
634
+ "token_url": "https://auth.example.com/token",
635
+ },
636
+ ],
637
+ },
638
+ )
639
+
640
+ # Mock query response
641
+ responses.add(
642
+ method=responses.GET,
643
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
644
+ json={
645
+ "size": 1,
646
+ "records": [{"Id": "0soxx0000000001AAA"}],
647
+ },
648
+ status=200,
649
+ )
650
+
651
+ # Mock get external auth identity provider
652
+ responses.add(
653
+ method=responses.GET,
654
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
655
+ json={
656
+ "Metadata": {
657
+ "externalAuthIdentityProviderParameters": [
658
+ {
659
+ "parameterType": "AuthorizeUrl",
660
+ "parameterName": "AuthorizeUrl",
661
+ "parameterValue": "https://old.example.com/authorize",
662
+ }
663
+ ]
664
+ }
665
+ },
666
+ status=200,
667
+ )
668
+
669
+ # Mock update external auth identity provider
670
+ responses.add(
671
+ method=responses.PATCH,
672
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
673
+ json={},
674
+ status=200,
675
+ )
676
+
677
+ task()
678
+
679
+ @responses.activate
680
+ def test_run_task_with_transform_parameters(self):
681
+ """Test task execution with transform parameters"""
682
+ os.environ["TEST_AUTH_URL"] = "https://auth.example.com/authorize"
683
+
684
+ task = create_task(
685
+ UpdateExternalAuthIdentityProvider,
686
+ {
687
+ "name": "TestProvider",
688
+ "transform_parameters": [
689
+ {
690
+ "authorize_url": "TEST_AUTH_URL",
691
+ }
692
+ ],
693
+ },
694
+ )
695
+
696
+ # Mock query response
697
+ responses.add(
698
+ method=responses.GET,
699
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
700
+ json={
701
+ "size": 1,
702
+ "records": [{"Id": "0soxx0000000001AAA"}],
703
+ },
704
+ status=200,
705
+ )
706
+
707
+ # Mock get external auth identity provider
708
+ responses.add(
709
+ method=responses.GET,
710
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
711
+ json={
712
+ "Metadata": {
713
+ "externalAuthIdentityProviderParameters": [
714
+ {
715
+ "parameterType": "AuthorizeUrl",
716
+ "parameterName": "AuthorizeUrl",
717
+ "parameterValue": "https://old.example.com/authorize",
718
+ }
719
+ ]
720
+ }
721
+ },
722
+ status=200,
723
+ )
724
+
725
+ # Mock update external auth identity provider
726
+ responses.add(
727
+ method=responses.PATCH,
728
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
729
+ json={},
730
+ status=200,
731
+ )
732
+
733
+ task()
734
+
735
+ del os.environ["TEST_AUTH_URL"]
736
+
737
+ @responses.activate
738
+ def test_run_task_query_exception(self):
739
+ """Test task execution when query raises exception"""
740
+ task = create_task(
741
+ UpdateExternalAuthIdentityProvider,
742
+ {
743
+ "name": "TestProvider",
744
+ "parameters": [
745
+ {
746
+ "authorize_url": "https://auth.example.com/authorize",
747
+ }
748
+ ],
749
+ },
750
+ )
751
+
752
+ # Mock query response with exception
753
+ responses.add(
754
+ method=responses.GET,
755
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
756
+ body=Exception("Query failed"),
757
+ )
758
+
759
+ with pytest.raises(
760
+ SalesforceDXException,
761
+ match="External auth identity provider 'TestProvider' not found",
762
+ ):
763
+ task()
764
+
765
+ @responses.activate
766
+ def test_run_task_retrieve_exception(self):
767
+ """Test task execution when retrieve raises exception"""
768
+ task = create_task(
769
+ UpdateExternalAuthIdentityProvider,
770
+ {
771
+ "name": "TestProvider",
772
+ "parameters": [
773
+ {
774
+ "authorize_url": "https://auth.example.com/authorize",
775
+ }
776
+ ],
777
+ },
778
+ )
779
+
780
+ # Mock query response
781
+ responses.add(
782
+ method=responses.GET,
783
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
784
+ json={
785
+ "size": 1,
786
+ "records": [{"Id": "0soxx0000000001AAA"}],
787
+ },
788
+ status=200,
789
+ )
790
+
791
+ # Mock get external auth identity provider with exception
792
+ responses.add(
793
+ method=responses.GET,
794
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
795
+ body=Exception("Retrieve failed"),
796
+ )
797
+
798
+ with pytest.raises(
799
+ SalesforceDXException,
800
+ match="Failed to retrieve external auth identity provider object for 'TestProvider'",
801
+ ):
802
+ task()
803
+
804
+ @responses.activate
805
+ def test_run_task_add_new_parameter_to_empty_list(self):
806
+ """Test adding parameter when no parameters exist"""
807
+ task = create_task(
808
+ UpdateExternalAuthIdentityProvider,
809
+ {
810
+ "name": "TestProvider",
811
+ "parameters": [
812
+ {
813
+ "authorize_url": "https://auth.example.com/authorize",
814
+ }
815
+ ],
816
+ },
817
+ )
818
+
819
+ # Mock query response
820
+ responses.add(
821
+ method=responses.GET,
822
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
823
+ json={
824
+ "size": 1,
825
+ "records": [{"Id": "0soxx0000000001AAA"}],
826
+ },
827
+ status=200,
828
+ )
829
+
830
+ # Mock get external auth identity provider with no parameters
831
+ responses.add(
832
+ method=responses.GET,
833
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
834
+ json={"Metadata": {"externalAuthIdentityProviderParameters": []}},
835
+ status=200,
836
+ )
837
+
838
+ # Mock update external auth identity provider
839
+ responses.add(
840
+ method=responses.PATCH,
841
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
842
+ json={},
843
+ status=200,
844
+ )
845
+
846
+ task()
847
+
848
+ @responses.activate
849
+ def test_run_task_credential_update_failure(self):
850
+ """Test task execution when credential update fails"""
851
+ task = create_task(
852
+ UpdateExternalAuthIdentityProvider,
853
+ {
854
+ "name": "TestProvider",
855
+ "parameters": [
856
+ {
857
+ "credential": {
858
+ "name": "TestCred",
859
+ "client_id": "client123",
860
+ "client_secret": "secret456",
861
+ }
862
+ }
863
+ ],
864
+ },
865
+ )
866
+
867
+ # Mock query response
868
+ responses.add(
869
+ method=responses.GET,
870
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/query/",
871
+ json={
872
+ "size": 1,
873
+ "records": [{"Id": "0soxx0000000001AAA"}],
874
+ },
875
+ status=200,
876
+ )
877
+
878
+ # Mock get external auth identity provider
879
+ responses.add(
880
+ method=responses.GET,
881
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
882
+ json={
883
+ "Metadata": {
884
+ "externalAuthIdentityProviderParameters": [
885
+ {
886
+ "parameterType": "AuthorizeUrl",
887
+ "parameterName": "AuthorizeUrl",
888
+ "parameterValue": "https://auth.example.com/authorize",
889
+ }
890
+ ]
891
+ }
892
+ },
893
+ status=200,
894
+ )
895
+
896
+ # Mock update external auth identity provider
897
+ responses.add(
898
+ method=responses.PATCH,
899
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/tooling/sobjects/ExternalAuthIdentityProvider/0soxx0000000001AAA",
900
+ json={},
901
+ status=200,
902
+ )
903
+
904
+ # Mock get credential
905
+ responses.add(
906
+ method=responses.GET,
907
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/named-credentials/external-auth-identity-provider-credentials/TestProvider",
908
+ json={
909
+ "externalAuthIdentityProvider": "TestProvider",
910
+ "credentials": None,
911
+ },
912
+ status=200,
913
+ )
914
+
915
+ # Mock update credential failure
916
+ responses.add(
917
+ method=responses.POST,
918
+ url=f"https://test.salesforce.com/services/data/v{CURRENT_SF_API_VERSION}/named-credentials/external-auth-identity-provider-credentials/TestProvider",
919
+ json={"error": "Credential update failed"},
920
+ status=400,
921
+ )
922
+
923
+ with pytest.raises(
924
+ SalesforceDXException,
925
+ match="Failed to update credentials for external auth identity provider 'TestProvider'",
926
+ ):
927
+ task()