|
11 | 11 | API_MOCK_RESPONSE = api_response_mock() |
12 | 12 | UPLOAD_MOCK_RESPONSE = uploader_response_mock() |
13 | 13 |
|
| 14 | +CONFIRM_ACTION_PATCH = "cloudinary_cli.utils.api_utils.confirm_action" |
| 15 | + |
14 | 16 |
|
15 | 17 | class TestCLIApi(unittest.TestCase): |
16 | 18 | runner = CliRunner() |
@@ -39,3 +41,87 @@ def test_provisioning(self, mocker): |
39 | 41 |
|
40 | 42 | self.assertEqual(0, result.exit_code, result.output) |
41 | 43 | self.assertIn('"foo": "bar"', result.output) |
| 44 | + |
| 45 | + |
| 46 | +class TestDestructiveBulkConfirmation(unittest.TestCase): |
| 47 | + runner = CliRunner() |
| 48 | + |
| 49 | + @patch(CONFIRM_ACTION_PATCH, return_value=False) |
| 50 | + @patch(URLLIB3_REQUEST) |
| 51 | + def test_delete_all_resources_decline_skips_call(self, http_mock, confirm_mock): |
| 52 | + http_mock.return_value = API_MOCK_RESPONSE |
| 53 | + result = self.runner.invoke(cli, ['admin', 'delete_all_resources']) |
| 54 | + |
| 55 | + self.assertEqual(0, result.exit_code, result.output) |
| 56 | + confirm_mock.assert_called_once() |
| 57 | + self.assertFalse(http_mock.called, "SDK should not be called when user declines") |
| 58 | + |
| 59 | + @patch(CONFIRM_ACTION_PATCH, return_value=True) |
| 60 | + @patch(URLLIB3_REQUEST) |
| 61 | + def test_delete_all_resources_accept_calls_sdk(self, http_mock, confirm_mock): |
| 62 | + http_mock.return_value = API_MOCK_RESPONSE |
| 63 | + result = self.runner.invoke(cli, ['admin', 'delete_all_resources']) |
| 64 | + |
| 65 | + self.assertEqual(0, result.exit_code, result.output) |
| 66 | + confirm_mock.assert_called_once() |
| 67 | + self.assertTrue(http_mock.called, "SDK should be called when user accepts") |
| 68 | + |
| 69 | + @patch(CONFIRM_ACTION_PATCH, return_value=False) |
| 70 | + @patch(URLLIB3_REQUEST) |
| 71 | + def test_delete_all_resources_force_skips_prompt(self, http_mock, confirm_mock): |
| 72 | + http_mock.return_value = API_MOCK_RESPONSE |
| 73 | + result = self.runner.invoke(cli, ['admin', '-F', 'delete_all_resources']) |
| 74 | + |
| 75 | + self.assertEqual(0, result.exit_code, result.output) |
| 76 | + self.assertFalse(confirm_mock.called, "--force should bypass the confirmation prompt") |
| 77 | + self.assertTrue(http_mock.called, "SDK should be called when --force is set") |
| 78 | + |
| 79 | + @patch(CONFIRM_ACTION_PATCH, return_value=False) |
| 80 | + @patch(URLLIB3_REQUEST) |
| 81 | + def test_delete_resources_by_tag_decline_skips_call(self, http_mock, confirm_mock): |
| 82 | + http_mock.return_value = API_MOCK_RESPONSE |
| 83 | + result = self.runner.invoke(cli, ['admin', 'delete_resources_by_tag', 'mytag']) |
| 84 | + |
| 85 | + self.assertEqual(0, result.exit_code, result.output) |
| 86 | + confirm_mock.assert_called_once() |
| 87 | + self.assertFalse(http_mock.called, "SDK should not be called when user declines") |
| 88 | + |
| 89 | + @patch(CONFIRM_ACTION_PATCH, return_value=False) |
| 90 | + @patch(URLLIB3_REQUEST) |
| 91 | + def test_delete_resources_explicit_ids_no_prompt(self, http_mock, confirm_mock): |
| 92 | + http_mock.return_value = API_MOCK_RESPONSE |
| 93 | + result = self.runner.invoke(cli, ['admin', 'delete_resources', 'public_id1', 'public_id2']) |
| 94 | + |
| 95 | + self.assertEqual(0, result.exit_code, result.output) |
| 96 | + self.assertFalse(confirm_mock.called, "Explicit-ID delete must not prompt") |
| 97 | + self.assertTrue(http_mock.called, "SDK should be called for explicit-ID delete") |
| 98 | + |
| 99 | + @patch(CONFIRM_ACTION_PATCH, return_value=False) |
| 100 | + @patch(URLLIB3_REQUEST) |
| 101 | + def test_uploader_add_tag_no_prompt(self, http_mock, confirm_mock): |
| 102 | + http_mock.return_value = UPLOAD_MOCK_RESPONSE |
| 103 | + result = self.runner.invoke(cli, ['uploader', 'add_tag', 'mytag', 'public_id1']) |
| 104 | + |
| 105 | + self.assertEqual(0, result.exit_code, result.output) |
| 106 | + self.assertFalse(confirm_mock.called, "Non-destructive bulk methods must not prompt") |
| 107 | + self.assertTrue(http_mock.called, "SDK should be called for non-destructive bulk methods") |
| 108 | + |
| 109 | + @patch(CONFIRM_ACTION_PATCH, return_value=False) |
| 110 | + @patch(URLLIB3_REQUEST) |
| 111 | + def test_admin_resources_read_no_prompt(self, http_mock, confirm_mock): |
| 112 | + http_mock.return_value = API_MOCK_RESPONSE |
| 113 | + result = self.runner.invoke(cli, ['admin', 'resources']) |
| 114 | + |
| 115 | + self.assertEqual(0, result.exit_code, result.output) |
| 116 | + self.assertFalse(confirm_mock.called, "Read commands must not prompt") |
| 117 | + self.assertTrue(http_mock.called, "SDK should be called for read commands") |
| 118 | + |
| 119 | + @patch(CONFIRM_ACTION_PATCH, return_value=False) |
| 120 | + @patch(URLLIB3_REQUEST) |
| 121 | + def test_admin_resources_read_with_force_no_prompt(self, http_mock, confirm_mock): |
| 122 | + http_mock.return_value = API_MOCK_RESPONSE |
| 123 | + result = self.runner.invoke(cli, ['admin', '-F', 'resources']) |
| 124 | + |
| 125 | + self.assertEqual(0, result.exit_code, result.output) |
| 126 | + self.assertFalse(confirm_mock.called, "Read commands must not prompt regardless of --force") |
| 127 | + self.assertTrue(http_mock.called) |
0 commit comments