def test_get_service_calls(lob: lobotomy.Lobotomy): """Should correctly retrieve service calls made.""" lob.data = { "clients": { "sts": { "get_caller_identity": { "Account": "123" } } } } session = lob() client = session.client("sts") assert client.get_caller_identity()["Account"] == "123" assert client.get_caller_identity( )["Account"] == "123", "Expected to work twice." assert len(lob.service_calls) == 2 assert len(lob.get_service_calls("sts", "get_caller_identity")) == 2 assert lob.get_service_call("sts", "get_caller_identity", 0) assert lob.get_service_call("sts", "get_caller_identity", 1) with pytest.raises(IndexError): lob.get_service_call("sts", "get_caller_identity", 2)
def test_missing_request_arguments(lobotomized: lobotomy.Lobotomy): """Should fail due to missing "Bucket" request argument.""" lobotomized.add_call("s3", "list_objects", {}) session = boto3.Session() client = session.client("s3") with pytest.raises(lobotomy.RequestValidationError): client.list_objects()
def test_unknown_request_arguments(lobotomized: lobotomy.Lobotomy): """Should fail due to presence of unknown "Foo" argument.""" lobotomized.add_call("s3", "list_objects", {}) session = boto3.Session() client = session.client("s3") with pytest.raises(lobotomy.RequestValidationError): client.list_objects(Bucket="foo", Foo="bar")
def test_bad_casting(lobotomized: lobotomy.Lobotomy): """Should fail to cast dictionary as string.""" lobotomized.add_call("s3", "list_objects", {"Contents": ["should-be-dict"]}) session = boto3.Session() client = session.client("s3") with pytest.raises(lobotomy.DataTypeError): client.list_objects(Bucket="foo")
def test_dynamodb_get_item(lobotomized: lobotomy.Lobotomy): """Should handle dynamodb.get_item without recursion errors.""" lobotomized.data = {"clients": {"dynamodb": {"get_item": {}}}} session = lobotomized() client = session.client("dynamodb") client.get_item(TableName="foo", Key={"pk": {"S": "spam"}, "sk": {"S": "ham"}}) call = lobotomized.get_service_calls("dynamodb", "get_item")[0] assert call.request["TableName"] == "foo"
def test_timestamp_formats(lobotomized: lobotomy.Lobotomy, value: typing.Any): """Should cast timestamp values correctly.""" lobotomized.add_call("iam", "get_role", response={"Role": {"CreateDate": value}}) response = boto3.Session().client("iam").get_role(RoleName="foo") observed: datetime.datetime = response["Role"]["CreateDate"] assert isinstance(observed, datetime.datetime) assert observed.date() == datetime.date(2020, 1, 1) assert observed.hour in (0, 12) assert observed.minute in (0, 23) assert observed.second in (0, 34)
def test_client_error_convenience(lobotomized: lobotomy.Lobotomy): """Should create an error response.""" lobotomized.add_error_call("s3", "list_objects", "NoSuchBucket", "Hello...") client = lobotomized().client("s3") session = boto3.Session() client = session.client("s3") with pytest.raises(client.exceptions.NoSuchBucket): client.list_objects(Bucket="foo")
def test_s3_download_file(lobotomized: lobotomy.Lobotomy): """Should handle s3.download_file correctly despite it being an augmentation.""" lobotomized.data = {"clients": {"s3": {"download_file": {}}}} session = lobotomized() client = session.client("s3") client.download_file(Filename="foo", Bucket="bar", Key="baz") call = lobotomized.get_service_calls("s3", "download_file")[0] assert call.request["Filename"] == "foo" assert call.request["Bucket"] == "bar" assert call.request["Key"] == "baz"
def test_s3_select(lobotomized: lobotomy.Lobotomy): """Should correctly return S3 Select results.""" lobotomized.add_call( "s3", "select_object_content", { "Payload": [ { "Records": { "Payload": "a" } }, { "Records": { "Payload": "b" } }, { "Records": { "Payload": "c" } }, ] }, ) response = (lobotomized().client("s3").select_object_content( Bucket="foo", Key="bar/baz.file", InputSerialization={"Parquet": {}}, Expression="SELECT * FROM S3Object LIMIT 100", ExpressionType="SQL", OutputSerialization={"JSON": { "RecordDelimiter": "\n" }}, )) observed = list(response["Payload"]) assert observed == [ { "Records": { "Payload": b"a" } }, { "Records": { "Payload": b"b" } }, { "Records": { "Payload": b"c" } }, ]
def test_sqs_delete_message(lobotomized: lobotomy.Lobotomy): """ Should handle sqs.delete_message without error despite edge case configuration in botocore service method definitions where the return structure has no members. """ lobotomized.add_call("sqs", "delete_message") lobotomized().client("sqs").delete_message( QueueUrl="https://sqs.us-west-2.amazonaws.com/123/my-queue", ReceiptHandle="fake-receipt-handle", ) assert lobotomized.get_service_call("sqs", "delete_message") is not None
def test_pagination(lobotomized: lobotomy.Lobotomy): """Should paginate correctly by using only the first response.""" lobotomized.add_call("s3", "list_objects_v2", {"Contents": [{"Key": "a"}]}) lobotomized.add_call("s3", "list_objects_v2", {"Contents": [{"Key": "b"}]}) session = lobotomized() client = session.client("s3") paginator = client.get_paginator("list_objects_v2") pages = [] for page in paginator.paginate(Bucket="my-bucket"): pages.append(page) assert pages == [{"Contents": [{"Key": "a"}]}]
def test_eks_describe_cluster(lobotomized: lobotomy.Lobotomy): """Should return result without error.""" lobotomized.add_call( "eks", "describe_cluster", response={ "name": "cluster-name", "arn": "arn:aws:eks:us-west-2:123456:cluster/cluster-name", "certificateAuthority": { "data": "fakecertificatedata=" }, }, ) response = lobotomized().client("eks").describe_cluster("cluster-name") assert response[ "arn"] == "arn:aws:eks:us-west-2:123456:cluster/cluster-name"
def test_creation_empty_patched(lob: lobotomy.Lobotomy): """Should patch an empty lobotomy and then work after setting data manually.""" lob.data = { "clients": { "sts": { "get_caller_identity": { "Account": "123" } } } } session = lob() client = session.client("sts") assert client.get_caller_identity()["Account"] == "123" assert len(lob.service_calls) == 1 assert len(lob.get_service_calls("sts", "get_caller_identity")) == 1
def test_client_errors(lobotomized: lobotomy.Lobotomy): """Should raise the specified error.""" lobotomized.add_call( service_name="s3", method_name="list_objects", response={"Error": { "Code": "NoSuchBucket", "Message": "Hello..." }}, ) session = boto3.Session() client = session.client("s3") with pytest.raises(client.exceptions.NoSuchBucket): client.list_objects(Bucket="foo") with pytest.raises(lobotomy.ClientError) as exception_info: client.list_objects(Bucket="foo") assert exception_info.value.response["Error"]["Code"] == "NoSuchBucket"
def test_session_properties(lob: lobotomy.Lobotomy): """Should return the expected values for session properties.""" session_data = { "profile_name": "foo-bar", "region_name": "us-north-1", "available_profiles": ["foo-bar", "baz"], } lob.data = {"session": session_data} session = lob() assert session.profile_name == "foo-bar" assert session.region_name == "us-north-1" assert session.available_profiles == ["foo-bar", "baz"]
def _process_action( lobotomized: lobotomy.Lobotomy, action: typing.Dict[str, typing.Any], ) -> None: """Mutates the lobotomized data according the specified action.""" kind = action.get("kind") data = lobotomized.data clients = data.get("clients", {}) if kind == "remove_service_calls": service = action["service"] method = action["method"] del clients[service][method] elif kind == "remove_service": service = action["service"] del clients[service] elif kind == "add_service_call": lobotomized.add_call( service_name=action["service"], method_name=action["method"], response=action.get("response"), )
def test_credentials(lob: lobotomy.Lobotomy): """Should return the expected values for session credentials.""" credentials = { "method": "foo", "access_key": "A123", "secret_key": "123abc", "token": "foobar", } lob.data = {"session": {"credentials": credentials}} session = lob() observed = session.get_credentials() assert observed.method == "foo" assert observed.access_key == "A123" assert observed.secret_key == "123abc" assert observed.token == "foobar" frozen = observed.get_frozen_credentials() assert frozen.access_key == "A123" assert frozen.secret_key == "123abc" assert frozen.token == "foobar"
def test_override_manual(lob: lobotomy.Lobotomy): """Should return the override dictionary for the STS client.""" session = lob.add_client_override("sts", {"foo": "bar"})() assert session.client("sts") == {"foo": "bar"}
def test_override_removed(lob: lobotomy.Lobotomy): """Should not return the override dictionary for the STS client if removed.""" session = lob.remove_client_override("sts")() assert session.client("sts") != {"foo": "bar"} assert isinstance(session.client("sts"), lobotomy.Client)
def test_creation_empty_added(lob: lobotomy.Lobotomy): """Should patch an empty lobotomy and then work after setting data manually.""" lob.add_call("sts", "get_caller_identity", {"Account": "123"}) session = lob() client = session.client("sts") assert client.get_caller_identity()["Account"] == "123"
def test_lambda_invoke(lobotomized: lobotomy.Lobotomy): """Should return a StreamingBody for the payload.""" lobotomized.add_call("lambda", "invoke") response = lobotomized().client("lambda").invoke(FunctionName="foo") assert b"..." == response["Payload"].read()