def test_get_workspace_handles_error_responses(client: StructurizrClient, mocker: MockerFixture): """Test that response code other than 200 raise an exception.""" mocker.patch.object(client._client, "send", return_value=Response(403)) with pytest.raises( StructurizrClientException, match="Failed .* workspace 19.\nResponse 403 - Forbidden", ): client.get_workspace()
def test_suppressing_archive(mock_settings, mocker): """Test that when the archive location is None then no archive is written.""" old_settings = mock_settings._asdict() old_settings["workspace_archive_location"] = None new_mock_settings = MockSettings(**old_settings) client = StructurizrClient(settings=new_mock_settings) mocked_open = mocker.mock_open(mock=mocker.Mock(spec_set=GzipFile)) mocker.patch("gzip.open", mocked_open) client._archive_workspace('{"mock_key":"mock_value"}') assert not mocked_open.called
def test_failed_unlock_raises_exception(client: StructurizrClient, mocker: MockerFixture): """Check failing to unlock raises an exception. Not quite sure how this could occur, but check the handling anyway. """ def fake_send(request: Request): if request.method == "PUT": return Response( 200, content='{"success": true, "message": "OK"}'.encode("ascii"), request=request, ) else: return Response( 200, content='{"success": false, "message": "Not OK"}'.encode( "ascii"), request=request, ) mocker.patch.object(client._client, "send", new=fake_send) with pytest.raises(StructurizrClientException, match="Failed to unlock"): with client.lock(): pass
def test_init(mock_settings): """Expect proper initialization from arguments.""" client = StructurizrClient(settings=mock_settings) assert client.url == "https://api.structurizr.com" assert client.workspace_id == 19 assert client.api_key == "7f4e4edc-f61c-4ff2-97c9-ea4bc2a7c98c" assert client.api_secret == "ae140655-da7c-4a8d-9467-5a7d9792fca0" assert client.user == "astley@localhost" assert client.agent == "structurizr-python/1.0.0" assert str(client.workspace_archive_location) == "."
def test_add_headers_authentication(client: StructurizrClient, mocker): """Validate the headers are added correctly, including authentication.""" mocker.patch.object(client, "_number_once", return_value="1529225966174") request = client._client.build_request("GET", client._workspace_url) headers = client._add_headers(request) assert headers["Nonce"] == "1529225966174" assert headers["X-Authorization"] == ( "7f4e4edc-f61c-4ff2-97c9-ea4bc2a7c98c:" "ZmJhNTVkMDM2NGEwN2I5YjRhMDgwZWNhMjA0ODIzZD" "kyMTg3YzliMzVhMjBlNmM4ZjAxMDAwOGU4OGJlODEwMQ==") assert "Content-MD5" not in headers assert "Content-Type" not in headers # Check the additional headers needed for PUTs request = client._client.build_request("PUT", client._workspace_url) headers = client._add_headers(request, content="Hello", content_type="World") assert headers[ "Content-MD5"] == "OGIxYTk5NTNjNDYxMTI5NmE4MjdhYmY4YzQ3ODA0ZDc=" assert headers["Content-Type"] == "World"
def test_failed_lock_bad_http_code(client: StructurizrClient, mocker: MockerFixture): """Check getting a non-200 HTTP response raises an HTTPX exception. Trying to lock a workspace which is already locked by someone else actually returns a 200 status, but with success as false in the message. """ def fake_send(request: Request): msg = "Server failure" return Response( 500, content=msg.encode("ascii"), request=request, ) mocker.patch.object(client._client, "send", new=fake_send) with pytest.raises(httpx.HTTPStatusError): with client.lock(): pass
def test_failed_lock_raises_exception(client: StructurizrClient, mocker: MockerFixture): """Check failing to lock raises an exception. Trying to lock a workspace which is already locked by someone else actually returns a 200 status, but with success as false in the message. """ def fake_send(request: Request): msg = '{"success": false, "message": "The workspace is already locked"}' return Response( 200, content=msg.encode("ascii"), request=request, ) mocker.patch.object(client._client, "send", new=fake_send) with pytest.raises(StructurizrClientException, match="Failed to lock"): with client.lock(): pass
def test_failed_lock_on_free_plan_doesnt_attempt_unlock( client: StructurizrClient, mocker: MockerFixture): """Check that if lock failed because on free plan then unlock isn't called.""" requests: List[Request] = [] def fake_send(request: Request): nonlocal requests requests.append(request) return Response( 200, content='{"success": false, "message": "Cannot lock on free plan"}' .encode("ascii"), request=request, ) mocker.patch.object(client._client, "send", new=fake_send) with client.lock(): pass assert len(requests) == 1
def test_locking_and_unlocking_with_context_manager(client: StructurizrClient, mocker: MockerFixture): """Check new-style locking using .lock().""" requests: List[Request] = [] def fake_send(request: Request): nonlocal requests requests.append(request) return Response( 200, content='{"success": true, "message": "OK"}'.encode("ascii"), request=request, ) mocker.patch.object(client._client, "send", new=fake_send) with client.lock(): pass assert len(requests) == 2 assert requests[0].method == "PUT" assert requests[0].url.path == "/workspace/19/lock" assert requests[1].method == "DELETE" assert requests[1].url.path == "/workspace/19/lock"
def client(mock_settings) -> StructurizrClient: """Provide a client instance with the mock settings.""" return StructurizrClient(settings=mock_settings)