def test_givenADiscordNotificator_whenSendNotificationDoesNotWork_thenWaitTimer( self, requests_mock): discord_notificator = DiscordNotificator(self.a_fake_web_hook, on_error_sleep_time=1) with self.assertWarns(Warning): discord_notificator.send_notification(self.a_notification) expected_payload_message = { "content": self.default_subject_message + self.a_notification } post_call = [ call.post( url=self.a_fake_web_hook, data=json.dumps(expected_payload_message), headers=self.headers, ), call.post( url=self.a_fake_web_hook, data=json.dumps(expected_payload_message), headers=self.headers, ), ] requests_mock.assert_has_calls(post_call)
def test_get_tips_query_combinations(client_mock, config): """Use all the combinations to specify what's queried.""" store = Store(config.charmhub) client_mock.post.return_value = {"libraries": []} query_info = [ { "lib_id": "test-lib-id-1" }, { "lib_id": "test-lib-id-2", "api": 2 }, { "charm_name": "test-charm-name-3" }, { "charm_name": "test-charm-name-4", "api": 4 }, { "charm_name": "test-charm-name-5", "lib_name": "test-lib-name-5" }, { "charm_name": "test-charm-name-6", "lib_name": "test-lib-name-6", "api": 6 }, ] store.get_libraries_tips(query_info) payload = [ { "library-id": "test-lib-id-1" }, { "library-id": "test-lib-id-2", "api": 2 }, { "charm-name": "test-charm-name-3" }, { "charm-name": "test-charm-name-4", "api": 4 }, { "charm-name": "test-charm-name-5", "library-name": "test-lib-name-5" }, { "charm-name": "test-charm-name-6", "library-name": "test-lib-name-6", "api": 6, }, ] assert client_mock.mock_calls == [ call.post("/v1/charm/libraries/bulk", payload), ]
def test_release_multiple_channels(client_mock, config): """Releasing a revision into multiple channels.""" store = Store(config.charmhub) store.release("testname", 123, ["channel1", "channel2", "channel3"], []) expected_body = [ { "revision": 123, "channel": "channel1", "resources": [] }, { "revision": 123, "channel": "channel2", "resources": [] }, { "revision": 123, "channel": "channel3", "resources": [] }, ] assert client_mock.mock_calls == [ call.post("/v1/charm/testname/releases", expected_body), ]
def test_disconnect_request_sent_if_and_only_if_master_is_responsive( self, is_master_responsive): slave_creation_url = 'http://{}/v1/slave'.format(self._FAKE_MASTER_URL) master_connectivity_url = 'http://{}/v1'.format(self._FAKE_MASTER_URL) slave_info_url = 'http://{}/v1/slave/1'.format(self._FAKE_MASTER_URL) if not is_master_responsive: self.mock_network.get.side_effect = requests.ConnectionError # an offline master raises ConnectionError slave = self._create_cluster_slave() slave.connect_to_master(self._FAKE_MASTER_URL) slave._disconnect_from_master() # expect a connect call and a connectivity call, and if the master is responsive also expect a disconnect call expected_network_calls = [ call.post(slave_creation_url, data=ANY), call.get(master_connectivity_url), ] if is_master_responsive: expected_network_calls.append( call.put_with_digest(slave_info_url, request_params=ANY, secret=ANY, error_on_failure=ANY)) self.mock_network.assert_has_calls(expected_network_calls, any_order=True) self.assertEqual(len(self.mock_network.method_calls), len(expected_network_calls), 'All requests should be accounted for in the test.')
def test_release_with_resources(client_mock, config): """Releasing with resources attached.""" store = Store(config.charmhub) r1 = ResourceOption(name="foo", revision=3) r2 = ResourceOption(name="bar", revision=17) store.release("testname", 123, ["channel1", "channel2"], [r1, r2]) expected_body = [ { "revision": 123, "channel": "channel1", "resources": [ {"name": "foo", "revision": 3}, {"name": "bar", "revision": 17}, ], }, { "revision": 123, "channel": "channel2", "resources": [ {"name": "foo", "revision": 3}, {"name": "bar", "revision": 17}, ], }, ] assert client_mock.mock_calls == [ call.post("/v1/charm/testname/releases", expected_body), ]
def test_release_multiple_channels(client_mock, config): """Releasing a revision into multiple channels.""" store = Store(config.charmhub) store.release('testname', 123, ['channel1', 'channel2', 'channel3'], []) expected_body = [ { 'revision': 123, 'channel': 'channel1', 'resources': [] }, { 'revision': 123, 'channel': 'channel2', 'resources': [] }, { 'revision': 123, 'channel': 'channel3', 'resources': [] }, ] assert client_mock.mock_calls == [ call.post('/v1/charm/testname/releases', expected_body), ]
def test_get_tips_query_combinations(client_mock, config): """Use all the combinations to specify what's queried.""" store = Store(config.charmhub) client_mock.post.return_value = {'libraries': []} query_info = [ {'lib_id': 'test-lib-id-1'}, {'lib_id': 'test-lib-id-2', 'api': 2}, {'charm_name': 'test-charm-name-3'}, {'charm_name': 'test-charm-name-4', 'api': 4}, {'charm_name': 'test-charm-name-5', 'lib_name': 'test-lib-name-5'}, {'charm_name': 'test-charm-name-6', 'lib_name': 'test-lib-name-6', 'api': 6}, ] store.get_libraries_tips(query_info) payload = [ {'library-id': 'test-lib-id-1'}, {'library-id': 'test-lib-id-2', 'api': 2}, {'charm-name': 'test-charm-name-3'}, {'charm-name': 'test-charm-name-4', 'api': 4}, {'charm-name': 'test-charm-name-5', 'library-name': 'test-lib-name-5'}, {'charm-name': 'test-charm-name-6', 'library-name': 'test-lib-name-6', 'api': 6}, ] assert client_mock.mock_calls == [ call.post('/v1/charm/libraries/bulk', payload), ]
def test_release_with_resources(client_mock, config): """Releasing with resources attached.""" store = Store(config.charmhub) r1 = ResourceOption(name='foo', revision=3) r2 = ResourceOption(name='bar', revision=17) store.release('testname', 123, ['channel1', 'channel2'], [r1, r2]) expected_body = [ { 'revision': 123, 'channel': 'channel1', 'resources': [ {'name': 'foo', 'revision': 3}, {'name': 'bar', 'revision': 17}, ] }, { 'revision': 123, 'channel': 'channel2', 'resources': [ {'name': 'foo', 'revision': 3}, {'name': 'bar', 'revision': 17}, ] } ] assert client_mock.mock_calls == [ call.post('/v1/charm/testname/releases', expected_body), ]
def test_get_tips_several(client_mock, config): """Get info for multiple libs at once.""" test_charm_name_1 = 'test-charm-name-1' test_lib_name_1 = 'test-lib-name-1' test_lib_id_1 = 'test-lib-id-1' test_api_1 = 'test-api-version-1' test_patch_1 = 'test-patch-version-1' test_content_1 = 'test content with quite a lot of funny Python code :p' test_hash_1 = '1234' test_charm_name_2 = 'test-charm-name-2' test_lib_name_2 = 'test-lib-name-2' test_lib_id_2 = 'test-lib-id-2' test_api_2 = 'test-api-version-2' test_patch_2 = 'test-patch-version-2' test_content_2 = 'more awesome Python code :)' test_hash_2 = '5678' store = Store(config.charmhub) client_mock.post.return_value = {'libraries': [{ 'api': test_api_1, 'content': test_content_1, 'hash': test_hash_1, 'library-id': test_lib_id_1, 'library-name': test_lib_name_1, 'charm-name': test_charm_name_1, 'patch': test_patch_1, }, { 'api': test_api_2, 'content': test_content_2, 'hash': test_hash_2, 'library-id': test_lib_id_2, 'library-name': test_lib_name_2, 'charm-name': test_charm_name_2, 'patch': test_patch_2, }]} query_info = [ {'lib_id': test_lib_id_1}, {'lib_id': test_lib_id_2}, ] result = store.get_libraries_tips(query_info) payload = [ {'library-id': test_lib_id_1}, {'library-id': test_lib_id_2}, ] assert client_mock.mock_calls == [ call.post('/v1/charm/libraries/bulk', payload), ] expected = { (test_lib_id_1, test_api_1): Library( api=test_api_1, content=test_content_1, content_hash=test_hash_1, lib_id=test_lib_id_1, lib_name=test_lib_name_1, charm_name=test_charm_name_1, patch=test_patch_1), (test_lib_id_2, test_api_2): Library( api=test_api_2, content=test_content_2, content_hash=test_hash_2, lib_id=test_lib_id_2, lib_name=test_lib_name_2, charm_name=test_charm_name_2, patch=test_patch_2), } assert result == expected
def test_register_name(client_mock, config): """Simple register case.""" store = Store(config.charmhub) result = store.register_name("testname", "stuff") assert client_mock.mock_calls == [ call.post("/v1/charm", {"name": "testname", "type": "stuff"}), ] assert result is None
def test_release_simple(client_mock, config): """Releasing a revision into one channel.""" store = Store(config.charmhub) store.release("testname", 123, ["somechannel"], []) expected_body = [{"revision": 123, "channel": "somechannel", "resources": []}] assert client_mock.mock_calls == [ call.post("/v1/charm/testname/releases", expected_body), ]
def test_register_name(client_mock, config): """Simple register case.""" store = Store(config.charmhub) result = store.register_name('testname', 'stuff') assert client_mock.mock_calls == [ call.post('/v1/charm', {'name': 'testname', 'type': 'stuff'}), ] assert result is None
def test_release_simple(client_mock, config): """Releasing a revision into one channel.""" store = Store(config.charmhub) store.release('testname', 123, ['somechannel']) expected_body = [{'revision': 123, 'channel': 'somechannel'}] assert client_mock.mock_calls == [ call.post('/v1/charm/testname/releases', expected_body), ]
def test_register_name(client_mock): """Simple register case.""" store = Store() result = store.register_name('testname') assert client_mock.mock_calls == [ call.post('/v1/charm', {'name': 'testname'}), ] assert result is None
def test_post_json(self): self.mock_sess.post.side_effect = [ MockResponse(201, 'Created', _json={'list': ['three']}) ] res = self.api._post_json('http://jive.example.com/foo', {'foo': 'bar'}) assert res == {'list': ['three']} assert self.mock_sess.mock_calls == [ call.post('http://jive.example.com/foo', json={'foo': 'bar'}) ]
def test_create_library_id(client_mock, config): """Create a new library in the store.""" store = Store(config.charmhub) client_mock.post.return_value = {'library-id': 'test-lib-id'} result = store.create_library_id('test-charm-name', 'test-lib-name') assert client_mock.mock_calls == [ call.post('/v1/charm/libraries/test-charm-name', {'library-name': 'test-lib-name'}), ] assert result == 'test-lib-id'
def test_demo(mock_requests): demo() assert (mock_requests.mock_calls == [ call.get("http://127.0.0.1:5000/openapi.json"), call.post("http://127.0.0.1:5000/roll", json={"dice": 5}, headers={}), call.get("http://127.0.0.1:5000/roll/mockity-mock-mock", headers={}), call.get("http://mocked/roll/mockity-mock-mock", headers={}), call.patch("http://mocked/roll/mockity-mock-mock", json={"keep": [0, 1]}, headers={}), ])
def test_create_library_id(client_mock, config): """Create a new library in the store.""" store = Store(config.charmhub) client_mock.post.return_value = {"library-id": "test-lib-id"} result = store.create_library_id("test-charm-name", "test-lib-name") assert client_mock.mock_calls == [ call.post("/v1/charm/libraries/test-charm-name", {"library-name": "test-lib-name"}), ] assert result == "test-lib-id"
def test_upload_straightforward(client_mock, caplog, config): """The full and successful upload case.""" caplog.set_level(logging.DEBUG, logger="charmcraft.commands") store = Store(config.charmhub) # the first response, for when pushing bytes test_upload_id = 'test-upload-id' client_mock.push.return_value = test_upload_id # the second response, for telling the store it was pushed test_status_url = 'https://store.c.c/status' client_mock.post.return_value = {'status-url': test_status_url} # the third response, status ok (note the patched UPLOAD_ENDING_STATUSES below) test_revision = 123 test_status_ok = 'test-status' status_response = { 'revisions': [{ 'status': test_status_ok, 'revision': test_revision, 'errors': None }] } client_mock.get.return_value = status_response test_status_resolution = 'test-ok-or-not' fake_statuses = {test_status_ok: test_status_resolution} test_charm_name = 'test-name' test_filepath = 'test-filepath' with patch.dict('charmcraft.commands.store.store.UPLOAD_ENDING_STATUSES', fake_statuses): result = store.upload(test_charm_name, test_filepath) # check all client calls assert client_mock.mock_calls == [ call.push(test_filepath), call.post('/v1/charm/{}/revisions'.format(test_charm_name), {'upload-id': test_upload_id}), call.get(test_status_url), ] # check result (build after patched ending struct) assert result.ok == test_status_resolution assert result.status == test_status_ok assert result.revision == test_revision # check logs expected = [ "Upload test-upload-id started, got status url https://store.c.c/status", "Status checked: " + str(status_response), ] assert expected == [rec.message for rec in caplog.records]
def test_release_multiple(client_mock): """Releasing a revision into multiple channels.""" store = Store() store.release('testname', 123, ['channel1', 'channel2', 'channel3']) expected_body = [ {'revision': 123, 'channel': 'channel1'}, {'revision': 123, 'channel': 'channel2'}, {'revision': 123, 'channel': 'channel3'}, ] assert client_mock.mock_calls == [ call.post('/v1/charm/testname/releases', expected_body), ]
def test_upload_straightforward(client_mock, caplog, config): """The full and successful upload case.""" caplog.set_level(logging.DEBUG, logger="charmcraft.commands") store = Store(config.charmhub) # the first response, for when pushing bytes test_upload_id = "test-upload-id" client_mock.push.return_value = test_upload_id # the second response, for telling the store it was pushed test_status_url = "https://store.c.c/status" client_mock.post.return_value = {"status-url": test_status_url} # the third response, status ok (note the patched UPLOAD_ENDING_STATUSES below) test_revision = 123 test_status_ok = "test-status" status_response = { "revisions": [{ "status": test_status_ok, "revision": test_revision, "errors": None }] } client_mock.get.return_value = status_response test_status_resolution = "test-ok-or-not" fake_statuses = {test_status_ok: test_status_resolution} test_filepath = "test-filepath" test_endpoint = "/v1/test/revisions/endpoint/" with patch.dict("charmcraft.commands.store.store.UPLOAD_ENDING_STATUSES", fake_statuses): result = store._upload(test_endpoint, test_filepath) # check all client calls assert client_mock.mock_calls == [ call.push(test_filepath), call.post(test_endpoint, {"upload-id": test_upload_id}), call.get(test_status_url), ] # check result (build after patched ending struct) assert result.ok == test_status_resolution assert result.status == test_status_ok assert result.revision == test_revision # check logs expected = [ "Upload test-upload-id started, got status url https://store.c.c/status", "Status checked: " + str(status_response), ] assert expected == [rec.message for rec in caplog.records]
def test_get_tips_simple(client_mock, config): """Get info for a lib, simple case with successful result.""" test_charm_name = "test-charm-name" test_lib_name = "test-lib-name" test_lib_id = "test-lib-id" test_api = "test-api-version" test_patch = "test-patch-version" test_content = "test content with quite a lot of funny Python code :p" test_hash = "1234" store = Store(config.charmhub) client_mock.post.return_value = { "libraries": [{ "api": test_api, "content": test_content, "hash": test_hash, "library-id": test_lib_id, "library-name": test_lib_name, "charm-name": test_charm_name, "patch": test_patch, }] } query_info = [ { "lib_id": test_lib_id }, ] result = store.get_libraries_tips(query_info) payload = [ { "library-id": test_lib_id }, ] assert client_mock.mock_calls == [ call.post("/v1/charm/libraries/bulk", payload), ] expected = { (test_lib_id, test_api): Library( api=test_api, content=test_content, content_hash=test_hash, lib_id=test_lib_id, lib_name=test_lib_name, charm_name=test_charm_name, patch=test_patch, ), } assert result == expected
def test_get_tips_simple(client_mock): """Get info for a lib, simple case with successful result.""" test_charm_name = 'test-charm-name' test_lib_name = 'test-lib-name' test_lib_id = 'test-lib-id' test_api = 'test-api-version' test_patch = 'test-patch-version' test_content = 'test content with quite a lot of funny Python code :p' test_hash = '1234' store = Store() client_mock.post.return_value = { 'libraries': [{ 'api': test_api, 'content': test_content, 'hash': test_hash, 'library-id': test_lib_id, 'library-name': test_lib_name, 'charm-name': test_charm_name, 'patch': test_patch, }] } query_info = [ { 'lib_id': test_lib_id }, ] result = store.get_libraries_tips(query_info) payload = [ { 'library-id': test_lib_id }, ] assert client_mock.mock_calls == [ call.post('/v1/charm/libraries/bulk', payload), ] expected = { (test_lib_id, test_api): Library(api=test_api, content=test_content, content_hash=test_hash, lib_id=test_lib_id, lib_name=test_lib_name, charm_name=test_charm_name, patch=test_patch), } assert result == expected
def test_get_oci_image_blob(client_mock, config): """Get the blob generated by Charmhub to refer to the OCI image.""" store = Store(config.charmhub) client_mock.post.return_value = "some opaque stuff" result = store.get_oci_image_blob("charm-name", "resource-name", "a-very-specific-digest") assert client_mock.mock_calls == [ call.post( "/v1/charm/charm-name/resources/resource-name/oci-image/blob", {"image-digest": "a-very-specific-digest"}, parse_json=False, ) ] assert result == "some opaque stuff"
def test_success(self): api = JiveApi('http://jive.example.com/', 'jiveuser', 'jivepass') mock_sess = MagicMock(spec_set=Session) api._requests = mock_sess mock_sess.post.return_value = MockResponse( 201, 'Created', _json={'foo': 'bar'}, headers={'Location': 'http://some.location/'}) res = api.upload_image(b'1234', 'img.jpg', 'image/jpeg') assert res == ('http://some.location/', {'foo': 'bar'}) assert mock_sess.mock_calls == [ call.post('http://jive.example.com/core/v3/images', files={'file': ('img.jpg', b'1234', 'image/jpeg')}, allow_redirects=False) ]
def test_givenASlackNotificator_whenSendNotification_thenSendMessageDefaultSubject( self, requests_mock): slack_notificator = SlackNotificator(self.a_fake_web_hook) slack_notificator.send_notification(self.a_notification) expected_payload_message = { "text": self.default_subject_message + self.a_notification } post_call = [ call.post( url=self.a_fake_web_hook, data=json.dumps(expected_payload_message), headers=self.headers, ) ] requests_mock.assert_has_calls(post_call)
def test_upload_including_extra_parameters(client_mock, caplog, config): """Verify that the upload includes extra parameters if given.""" caplog.set_level(logging.DEBUG, logger="charmcraft.commands") store = Store(config.charmhub) # the first response, for when pushing bytes test_upload_id = "test-upload-id" client_mock.push.return_value = test_upload_id # the second response, for telling the store it was pushed test_status_url = "https://store.c.c/status" client_mock.post.return_value = {"status-url": test_status_url} # the third response, status ok (note the patched UPLOAD_ENDING_STATUSES below) test_revision = 123 test_status_ok = "test-status" status_response = { "revisions": [{ "status": test_status_ok, "revision": test_revision, "errors": None }] } client_mock.get.return_value = status_response test_status_resolution = "test-ok-or-not" fake_statuses = {test_status_ok: test_status_resolution} test_filepath = "test-filepath" test_endpoint = "/v1/test/revisions/endpoint/" extra_fields = {"extra-key": "1", "more": "2"} with patch.dict("charmcraft.commands.store.store.UPLOAD_ENDING_STATUSES", fake_statuses): store._upload(test_endpoint, test_filepath, extra_fields=extra_fields) # check all client calls assert client_mock.mock_calls == [ call.push(test_filepath), call.post(test_endpoint, { "upload-id": test_upload_id, "extra-key": "1", "more": "2" }), call.get(test_status_url), ]
def test_get_tips_empty(client_mock, config): """Get info for a lib, with an empty response.""" test_lib_id = 'test-lib-id' store = Store(config.charmhub) client_mock.post.return_value = {'libraries': []} query_info = [ {'lib_id': test_lib_id}, ] result = store.get_libraries_tips(query_info) payload = [ {'library-id': test_lib_id}, ] assert client_mock.mock_calls == [ call.post('/v1/charm/libraries/bulk', payload), ] assert result == {}
def test_create_library_revision(client_mock): """Create a new library revision in the store.""" test_charm_name = 'test-charm-name' test_lib_name = 'test-lib-name' test_lib_id = 'test-lib-id' test_api = 'test-api-version' test_patch = 'test-patch-version' test_content = 'test content with quite a lot of funny Python code :p' test_hash = '1234' store = Store() client_mock.post.return_value = { 'api': test_api, 'content': test_content, 'hash': test_hash, 'library-id': test_lib_id, 'library-name': test_lib_name, 'charm-name': test_charm_name, 'patch': test_patch, } result_lib = store.create_library_revision(test_charm_name, test_lib_id, test_api, test_patch, test_content, test_hash) payload = { 'api': test_api, 'patch': test_patch, 'content': test_content, 'hash': test_hash, } assert client_mock.mock_calls == [ call.post('/v1/charm/libraries/test-charm-name/' + test_lib_id, payload), ] assert result_lib.api == test_api assert result_lib.content == test_content assert result_lib.content_hash == test_hash assert result_lib.lib_id == test_lib_id assert result_lib.lib_name == test_lib_name assert result_lib.charm_name == test_charm_name assert result_lib.patch == test_patch
def test_create_library_revision(client_mock, config): """Create a new library revision in the store.""" test_charm_name = "test-charm-name" test_lib_name = "test-lib-name" test_lib_id = "test-lib-id" test_api = "test-api-version" test_patch = "test-patch-version" test_content = "test content with quite a lot of funny Python code :p" test_hash = "1234" store = Store(config.charmhub) client_mock.post.return_value = { "api": test_api, "content": test_content, "hash": test_hash, "library-id": test_lib_id, "library-name": test_lib_name, "charm-name": test_charm_name, "patch": test_patch, } result_lib = store.create_library_revision(test_charm_name, test_lib_id, test_api, test_patch, test_content, test_hash) payload = { "api": test_api, "patch": test_patch, "content": test_content, "hash": test_hash, } assert client_mock.mock_calls == [ call.post("/v1/charm/libraries/test-charm-name/" + test_lib_id, payload), ] assert result_lib.api == test_api assert result_lib.content == test_content assert result_lib.content_hash == test_hash assert result_lib.lib_id == test_lib_id assert result_lib.lib_name == test_lib_name assert result_lib.charm_name == test_charm_name assert result_lib.patch == test_patch
def test_disconnect_request_sent_if_and_only_if_master_is_responsive(self, is_master_responsive): slave_creation_url = 'http://{}/v1/slave'.format(self._FAKE_MASTER_URL) master_connectivity_url = 'http://{}/v1'.format(self._FAKE_MASTER_URL) slave_info_url = 'http://{}/v1/slave/1'.format(self._FAKE_MASTER_URL) if not is_master_responsive: self.mock_network.get.side_effect = requests.ConnectionError # an offline master raises ConnectionError slave = self._create_cluster_slave() slave.connect_to_master(self._FAKE_MASTER_URL) slave._disconnect_from_master() # expect a connect call and a connectivity call, and if the master is responsive also expect a disconnect call expected_network_calls = [ call.post(slave_creation_url, data=ANY), call.get(master_connectivity_url), ] if is_master_responsive: expected_network_calls.append(call.put_with_digest(slave_info_url, request_params=ANY, secret=ANY, error_on_failure=ANY)) self.mock_network.assert_has_calls(expected_network_calls, any_order=True) self.assertEqual(len(self.mock_network.method_calls), len(expected_network_calls), 'All requests should be accounted for in the test.')