|
| 1 | +import json |
1 | 2 | import unittest |
2 | 3 | from datetime import datetime |
3 | 4 |
|
|
8 | 9 | from cloudinary.provisioning import account_config, reset_config |
9 | 10 | from cloudinary.exceptions import AuthorizationRequired, NotFound |
10 | 11 |
|
11 | | -from test.helper_test import UNIQUE_SUB_ACCOUNT_ID, UNIQUE_TEST_ID |
| 12 | +from test.helper_test import (UNIQUE_SUB_ACCOUNT_ID, UNIQUE_TEST_ID, URLLIB3_REQUEST, patch, api_response_mock, |
| 13 | + get_uri, get_method, get_params, get_headers) |
12 | 14 |
|
13 | 15 | disable_warnings() |
14 | 16 |
|
@@ -85,6 +87,7 @@ def test_update_sub_account(self): |
85 | 87 | @unittest.skipUnless(cloudinary.provisioning.account_config().provisioning_api_secret, |
86 | 88 | "requires provisioning_api_key/provisioning_api_secret") |
87 | 89 | def test_get_all_sub_accounts(self): |
| 90 | + |
88 | 91 | res = cloudinary.provisioning.sub_accounts(True) |
89 | 92 |
|
90 | 93 | sub_account_by_id = [sub_account for sub_account in res["sub_accounts"] |
@@ -264,5 +267,93 @@ def test_delete_access_key(self): |
264 | 267 | self.assertEqual("ok", named_key_del_res["message"]) |
265 | 268 |
|
266 | 269 |
|
| 270 | +class CreateAgentAccountTest(unittest.TestCase): |
| 271 | + """ |
| 272 | + The create agent account endpoint is public, unauthenticated and rate limited per IP, |
| 273 | + so it is verified against a mocked transport rather than the live API. |
| 274 | + """ |
| 275 | + |
| 276 | + def test_create_agent_account(self): |
| 277 | + with patch(URLLIB3_REQUEST) as mocker: |
| 278 | + mocker.return_value = api_response_mock() |
| 279 | + cloudinary.provisioning.create_agent_account( |
| 280 | + "jane@example.com", |
| 281 | + agent_framework="langchain", |
| 282 | + agent_llm_model="claude-opus-4-8", |
| 283 | + agent_goal="Build a product image gallery", |
| 284 | + sdk_framework="python", |
| 285 | + ) |
| 286 | + |
| 287 | + self.assertEqual("POST", get_method(mocker)) |
| 288 | + self.assertTrue(get_uri(mocker).endswith("/provisioning/agents/accounts")) |
| 289 | + |
| 290 | + params = get_params(mocker) |
| 291 | + self.assertEqual("jane@example.com", params["email"]) |
| 292 | + self.assertEqual("langchain", params["agent_framework"]) |
| 293 | + self.assertEqual("claude-opus-4-8", params["agent_llm_model"]) |
| 294 | + self.assertEqual("Build a product image gallery", params["agent_goal"]) |
| 295 | + self.assertEqual("python", params["sdk_framework"]) |
| 296 | + |
| 297 | + def test_create_agent_account_is_unauthenticated(self): |
| 298 | + with patch(URLLIB3_REQUEST) as mocker: |
| 299 | + mocker.return_value = api_response_mock() |
| 300 | + cloudinary.provisioning.create_agent_account( |
| 301 | + "jane@example.com", |
| 302 | + agent_framework="langchain", |
| 303 | + agent_llm_model="claude-opus-4-8", |
| 304 | + agent_goal="Build a product image gallery", |
| 305 | + ) |
| 306 | + |
| 307 | + # The endpoint is public - no authorization header must be sent. |
| 308 | + headers = get_headers(mocker) |
| 309 | + self.assertNotIn("authorization", {k.lower() for k in headers}) |
| 310 | + |
| 311 | + def test_create_agent_account_omits_unset_sdk_framework(self): |
| 312 | + with patch(URLLIB3_REQUEST) as mocker: |
| 313 | + mocker.return_value = api_response_mock() |
| 314 | + cloudinary.provisioning.create_agent_account( |
| 315 | + "jane@example.com", |
| 316 | + agent_framework="langchain", |
| 317 | + agent_llm_model="claude-opus-4-8", |
| 318 | + agent_goal="Build a product image gallery", |
| 319 | + ) |
| 320 | + |
| 321 | + self.assertNotIn("sdk_framework", get_params(mocker)) |
| 322 | + |
| 323 | + def test_create_agent_account_parses_response(self): |
| 324 | + body = json.dumps({ |
| 325 | + "external_id": "0aaaaa1bbbbb2ccccc3ddddd4eeeee5f", |
| 326 | + "email": "jane@example.com", |
| 327 | + "plan_name": "free", |
| 328 | + "product_environments": [{ |
| 329 | + "external_id": "abcde1fghij2klmno3pqrst4uvwxy5z", |
| 330 | + "cloud_name": "product1", |
| 331 | + "api_key": "123456789012345", |
| 332 | + "api_secret": "asdf1JKL2xyz3ABc4s3c5reT01DfaKez", |
| 333 | + "api_environment_variable": |
| 334 | + "CLOUDINARY_URL=cloudinary://123456789012345:asdf1JKL2xyz3ABc4s3c5reT01DfaKez@product1", |
| 335 | + }], |
| 336 | + "guidance": "A verification email has been sent to the supplied email address.", |
| 337 | + }) |
| 338 | + with patch(URLLIB3_REQUEST) as mocker: |
| 339 | + mocker.return_value = api_response_mock(body) |
| 340 | + res = cloudinary.provisioning.create_agent_account( |
| 341 | + "jane@example.com", |
| 342 | + agent_framework="langchain", |
| 343 | + agent_llm_model="claude-opus-4-8", |
| 344 | + agent_goal="Build a product image gallery", |
| 345 | + ) |
| 346 | + |
| 347 | + self.assertEqual("free", res["plan_name"]) |
| 348 | + self.assertEqual("jane@example.com", res["email"]) |
| 349 | + self.assertEqual(1, len(res["product_environments"])) |
| 350 | + product_environment = res["product_environments"][0] |
| 351 | + self.assertEqual("product1", product_environment["cloud_name"]) |
| 352 | + self.assertEqual("123456789012345", product_environment["api_key"]) |
| 353 | + self.assertEqual("asdf1JKL2xyz3ABc4s3c5reT01DfaKez", product_environment["api_secret"]) |
| 354 | + self.assertIn("CLOUDINARY_URL=cloudinary://", product_environment["api_environment_variable"]) |
| 355 | + self.assertIn("guidance", res) |
| 356 | + |
| 357 | + |
267 | 358 | if __name__ == '__main__': |
268 | 359 | unittest.main() |
0 commit comments