Repository: getmoto/moto (python)

Issue:
s3 copy_from w/ CopySourceIfNoneMatch with same etag does not result in a PreconditionFailed error when mocked
Given a bucket with an existing object's e_tag, *xyz*, with the following bits of code:

```
s3 = boto3.resource("s3")
obj = s3.Object("bucketName", "keyOfObject") # keyOfObject has etag "xyz"; bucketName has versioning enabled
copy_from_kwargs = {
            "CopySource": {
                "Bucket": "anotherBucketName",
                "Key": "aDifferentKey",
            },
            "CopySourceIfNoneMatch": "xyz"
        }

obj.copy_from(**copy_from_kwargs)
```

Boto3 will return a `PreconditionFailed` error.  However, when I use moto when mocking the  copy_from response, there is no `PreconditionFailed` exception returned.  It proceeds to "create" a new object with *a different version ID*.  The intent of my code here is to prevent creation of a new version ID **if** the e tag value is the same. It appears there is some deviation between what happens server side and what moto is doing.

In the above example, **xyz** is used for illustrative purposes and is not a valid etag. A etag will contain a string with double quotes prefixing and suffixing the hash - I tried calling copy_from using moto with and without the double quotes and the same behaviour occurs as described above. e.g.:

```
copy_from_kwargs = {
            "CopySource": {
                "Bucket": "anotherBucketName",
                "Key": "aDifferentKey",
            },
            "CopySourceIfNoneMatch": '"xyx"'
        }
```


 Note, boto3 itself seems to not care if they are or are not included.

I am using moto 5.0.9.

Boto docs: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3/objectsummary/copy_from.html

Pull request:
S3: copy_object() now respects the CopySourceIfNoneMatch-parameter
Fixes #7868 

All modified tests are verified against AWS.

Patch:
diff --git a/docs/docs/configuration/index.rst b/docs/docs/configuration/index.rst
index 9466d7497..ba0b50358 100644
--- a/docs/docs/configuration/index.rst
+++ b/docs/docs/configuration/index.rst
@@ -20,6 +20,7 @@ If you are using the decorators, some options are configurable within the decora
                 "services": ["dynamodb"]
             },
             "reset_boto3_session": True,
+            "service_whitelist": None,
         },
         "iam": {"load_aws_managed_policies": False},
         "stepfunctions": {"execute_state_machine": True},
@@ -52,6 +53,17 @@ That is why Moto resets the `boto3-Session`, to make sure that it is recreated w
 
 If all of your tests use Moto, and you never want to reach out to AWS, you can choose to _not_ reset the `boto3-session`. New boto3-clients that are created will reuse the `boto3-Session` (with fake credentials), making Moto much more performant.
 
+Whitelist Services
+-------------------
+The `mock_aws` decorator will allow requests to all supported services. If you want to restrict this to only specific services, you can configure a service whitelist.
+For example, if you only want your application to use DynamoDB and S3:
+
+```
+mock_aws(config={"core": {"service_whitelist": ["dynamodb", "s3"]}})
+```
+
+If the application under test tries to access any other services, Moto will throw a `ServiceNotWhitelisted`-exception.
+
 AWS Managed Policies
 --------------------
 Moto comes bundled with all Managed Policies that AWS exposes, which are updated regularly. However, they are not loaded unless specifically requested for performance reasons.
diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py
index ce66fef66..7943659cc 100644
--- a/moto/awslambda/models.py
+++ b/moto/awslambda/models.py
@@ -1150,9 +1150,9 @@ class LambdaFunction(CloudFormationModel, DockerModel):
         spec = {
             "Code": properties["Code"],
             "FunctionName": resource_name,
-            "Handler": properties["Handler"],
+            "Handler": properties.get("Handler"),
             "Role": properties["Role"],
-            "Runtime": properties["Runtime"],
+            "Runtime": properties.get("Runtime"),
         }
 
         # NOTE: Not doing `properties.get(k, DEFAULT)` to avoid duplicating the
diff --git a/moto/core/botocore_stubber.py b/moto/core/botocore_stubber.py
index 929326168..0872fc8f3 100644
--- a/moto/core/botocore_stubber.py
+++ b/moto/core/botocore_stubber.py
@@ -7,7 +7,8 @@ from botocore.awsrequest import AWSResponse
 import moto.backend_index as backend_index
 from moto.core.base_backend import BackendDict
 from moto.core.common_types import TYPE_RESPONSE
-from moto.core.config import passthrough_service, passthrough_url
+from moto.core.config import passthrough_service, passthrough_url, service_whitelisted
+from moto.core.exceptions import ServiceNotWhitelisted
 from moto.core.utils import get_equivalent_url_in_aws_domain
 
 
@@ -56,6 +57,9 @@ class BotocoreStubber:
                 if passthrough_service(service):
                     return None
 
+                if not service_whitelisted(service):
+                    raise ServiceNotWhitelisted(service)
+
                 import moto.backends as backends
                 from moto.core import DEFAULT_ACCOUNT_ID
                 from moto.core.exceptions import HTTPException
diff --git a/moto/core/config.py b/moto/core/config.py
index 1b6cfa72b..47a3e27ee 100644
--- a/moto/core/config.py
+++ b/moto/core/config.py
@@ -1,5 +1,5 @@
 import re
-from typing import List, TypedDict
+from typing import List, Optional, TypedDict
 
 
 class _docker_config(TypedDict, total=False):
@@ -15,6 +15,7 @@ class _core_config(TypedDict, total=False):
     mock_credentials: bool
     passthrough: _passthrough_config
     reset_boto3_session: bool
+    service_whitelist: Optional[List[str]]
 
 
 class _iam_config(TypedDict, total=False):
@@ -49,6 +50,7 @@ default_user_config: DefaultConfig = {
         "mock_credentials": True,
         "passthrough": {"urls": [], "services": []},
         "reset_boto3_session": True,
+        "service_whitelist": None,
     },
     "iam": {"load_aws_managed_policies": False},
     "stepfunctions": {"execute_state_machine": False},
@@ -56,6 +58,11 @@ default_user_config: DefaultConfig = {
 }
 
 
+def service_whitelisted(service: str) -> bool:
+    services_whitelisted = default_user_config.get("core", {}).get("service_whitelist")
+    return services_whitelisted is None or service in services_whitelisted
+
+
 def passthrough_service(service: str) -> bool:
     passthrough_services = (
         default_user_config.get("core", {}).get("passthrough", {}).get("services", [])
diff --git a/moto/core/exceptions.py b/moto/core/exceptions.py
index 69a5ae457..86595bc8e 100644
--- a/moto/core/exceptions.py
+++ b/moto/core/exceptions.py
@@ -200,3 +200,15 @@ class InvalidToken(AWSError):
 
     def __init__(self, message: str = "Invalid token"):
         super().__init__(f"Invalid Token: {message}", "InvalidToken")
+
+
+class ServiceNotWhitelisted(Exception):
+    def __init__(self, service_name: str):
+        from moto.settings import default_user_config
+
+        services_whitelisted = default_user_config.get("core", {}).get(
+            "service_whitelist"
+        )
+        super().__init__(
+            f"Service {service_name} not whitelisted. Only services {services_whitelisted} are allowed."
+        )
diff --git a/moto/s3/models.py b/moto/s3/models.py
index 155261282..a6b931604 100644
--- a/moto/s3/models.py
+++ b/moto/s3/models.py
@@ -2836,6 +2836,7 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
         lock_mode: Optional[str] = None,
         lock_legal_status: Optional[str] = None,
         lock_until: Optional[str] = None,
+        provided_version_id: Optional[str] = None,
     ) -> None:
         bucket = self.get_bucket(dest_bucket_name)
         if src_key.name == dest_key_name and src_key.bucket_name == dest_bucket_name:
@@ -2851,11 +2852,11 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
                     encryption,
                     mdirective == "REPLACE",
                     website_redirect_location,
-                    bucket.encryption,  # S3 will allow copy in place if the bucket has encryption configured
-                    src_key._version_id and bucket.is_versioned,
+                    bucket.encryption,
                 )
             ):
-                raise CopyObjectMustChangeSomething
+                if not bucket.is_versioned or not provided_version_id:
+                    raise CopyObjectMustChangeSomething
 
         new_key = self.put_object(
             bucket_name=dest_bucket_name,
diff --git a/moto/s3/responses.py b/moto/s3/responses.py
index c9c899776..e4035fa80 100644
--- a/moto/s3/responses.py
+++ b/moto/s3/responses.py
@@ -1683,6 +1683,13 @@ class S3Response(BaseResponse):
             )
 
             if key_to_copy is not None:
+                if "x-amz-copy-source-if-none-match" in request.headers:
+                    requested_etag = request.headers["x-amz-copy-source-if-none-match"]
+                    if requested_etag in [key_to_copy.etag, key_to_copy.etag[1:-1]]:
+                        raise PreconditionFailed(
+                            failed_condition="x-amz-copy-source-If-None-Match"
+                        )
+
                 if key_to_copy.storage_class in ARCHIVE_STORAGE_CLASSES:
                     if (
                         key_to_copy.response_dict.get("x-amz-restore") is None
@@ -1713,8 +1720,11 @@ class S3Response(BaseResponse):
                     lock_mode=lock_mode,
                     lock_legal_status=legal_hold,
                     lock_until=lock_until,
+                    provided_version_id=src_version_id,
                 )
             else:
+                if src_version_id:
+                    raise MissingVersion()
                 raise MissingKey(key=src_key)
 
             new_key: FakeKey = self.backend.get_object(bucket_name, key_name)  # type: ignore
diff --git a/moto/sqs/exceptions.py b/moto/sqs/exceptions.py
index d2f483c4e..7207d4488 100644
--- a/moto/sqs/exceptions.py
+++ b/moto/sqs/exceptions.py
@@ -18,7 +18,7 @@ class MessageAttributesInvalid(RESTError):
 
 
 class QueueDoesNotExist(RESTError):
-    code = 400
+    code = 404
 
     def __init__(self) -> None:
         super().__init__(
diff --git a/moto/sqs/responses.py b/moto/sqs/responses.py
index 3c84d2710..8a9e077f5 100644
--- a/moto/sqs/responses.py
+++ b/moto/sqs/responses.py
@@ -136,10 +136,18 @@ class SQSResponse(BaseResponse):
     def call_action(self) -> TYPE_RESPONSE:
         status_code, headers, body = super().call_action()
         if status_code == 404:
-            queue_name = self.querystring.get("QueueName", [""])[0]
-            template = self.response_template(ERROR_INEXISTENT_QUEUE)
-            response = template.render(queue_name=queue_name)
-            return 404, headers, response
+            if self.is_json():
+                err = {
+                    "__type": "com.amazonaws.sqs#QueueDoesNotExist",
+                    "message": "The specified queue does not exist.",
+                }
+                headers["x-amzn-query-error"] = (
+                    "AWS.SimpleQueueService.NonExistentQueue;Sender"
+                )
+                body = json.dumps(err)
+            else:
+                body = self.response_template(ERROR_INEXISTENT_QUEUE).render()
+            status_code = 400
         return status_code, headers, body
 
     def _error(self, code: str, message: str, status: int = 400) -> TYPE_RESPONSE:


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 000000000..f723cf5f3
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,18 @@
+import boto3
+import pytest
+
+from moto import mock_aws
+
+
+@pytest.fixture(scope="function")
+def account_id():
+    """Return the current Account ID. Will reach out to AWS if so configured."""
+    from . import allow_aws_request
+
+    if allow_aws_request():
+        identity = boto3.client("sts", "us-east-1").get_caller_identity()
+        yield identity["Account"]
+    else:
+        with mock_aws():
+            identity = boto3.client("sts", "us-east-1").get_caller_identity()
+            yield identity["Account"]
diff --git a/tests/test_awslambda/test_awslambda_cloudformation.py b/tests/test_awslambda/test_awslambda_cloudformation.py
index 09e3edf8c..6e1198a0f 100644
--- a/tests/test_awslambda/test_awslambda_cloudformation.py
+++ b/tests/test_awslambda/test_awslambda_cloudformation.py
@@ -1,4 +1,5 @@
 import io
+import json
 import re
 import zipfile
 from string import Template
@@ -54,6 +55,26 @@ template = Template(
 }"""
 )
 
+
+code_image_template = {
+    "AWSTemplateFormatVersion": "2010-09-09",
+    "Resources": {
+        "LambdaFunction": {
+            "Type": "AWS::Lambda::Function",
+            "Properties": {
+                "FunctionName": "ContainerLambdaFunction",
+                "Role": "dummy-role-arn",
+                "Code": {
+                    "ImageUri": "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-lambda-container:latest"
+                },
+                "PackageType": "Image",
+                "MemorySize": 128,
+                "Timeout": 30,
+            },
+        }
+    },
+}
+
 event_source_mapping_template = Template(
     """{
     "AWSTemplateFormatVersion": "2010-09-09",
@@ -114,6 +135,25 @@ def test_lambda_can_be_deleted_by_cloudformation():
     assert e.value.response["Error"]["Code"] == "ResourceNotFoundException"
 
 
+@mock_aws
+def test_lambda_with_code_image_can_be_created():
+    our_template = code_image_template.copy()
+    our_template["Resources"]["LambdaFunction"]["Properties"]["Role"] = get_role_arn()
+    stack_name = f"stack{str(uuid4())[0:6]}"
+    cf = boto3.client("cloudformation", region_name="us-east-1")
+    cf.create_stack(StackName=stack_name, TemplateBody=json.dumps(code_image_template))
+
+    lmbda = boto3.client("lambda", region_name="us-east-1")
+    functions = lmbda.list_functions()["Functions"]
+    function_names = [f["FunctionName"] for f in functions]
+    assert "ContainerLambdaFunction" in function_names
+
+    cf.delete_stack(StackName=stack_name)
+    functions = lmbda.list_functions()["Functions"]
+    function_names = [f["FunctionName"] for f in functions]
+    assert "ContainerLambdaFunction" not in function_names
+
+
 @mock_aws
 def test_event_source_mapping_create_from_cloudformation_json():
     sqs = boto3.resource("sqs", region_name="us-east-1")
diff --git a/tests/test_core/test_config.py b/tests/test_core/test_config.py
index 63ba387ff..20b2d5939 100644
--- a/tests/test_core/test_config.py
+++ b/tests/test_core/test_config.py
@@ -1,3 +1,7 @@
+from unittest import SkipTest
+
+import boto3
+import pytest
 import requests
 
 from moto import mock_aws, settings
@@ -6,6 +10,7 @@ from moto.awslambda.utils import get_backend
 from moto.awslambda_simple.models import LambdaSimpleBackend
 from moto.core import DEFAULT_ACCOUNT_ID
 from moto.core.config import default_user_config
+from moto.core.exceptions import ServiceNotWhitelisted
 
 
 @mock_aws
@@ -50,3 +55,33 @@ def test_change_configuration_using_api() -> None:
         f"http://{base_url}/moto-api/config",
         json={"batch": {"use_docker": True}, "lambda": {"use_docker": True}},
     )
+
+
+def test_whitelist() -> None:
+    if not settings.TEST_DECORATOR_MODE:
+        raise SkipTest("No point in testing this anywhere else")
+
+    with mock_aws(config={"core": {"service_whitelist": ["s3"]}}):
+        dynamodb = boto3.client("dynamodb", "us-east-1")
+        s3 = boto3.client("s3", "us-east-1")
+
+        # S3 is whitelisted, so all calls are allowed
+        s3.list_buckets()
+
+        # DynamoDB is not whitelisted
+        with pytest.raises(ServiceNotWhitelisted):
+            dynamodb.list_tables()
+
+    # Empty whitelist, so no calls are allowed
+    with mock_aws(config={"core": {"service_whitelist": []}}):
+        with pytest.raises(ServiceNotWhitelisted):
+            s3.list_buckets()
+
+        with pytest.raises(ServiceNotWhitelisted):
+            dynamodb.list_tables()
+
+    # Both are whitelisted, so both are allowed
+    with mock_aws(config={"core": {"service_whitelist": ["dynamodb", "s3"]}}):
+        s3.list_buckets()
+
+        dynamodb.list_tables()
diff --git a/tests/test_logs/test_export_tasks.py b/tests/test_logs/test_export_tasks.py
index dd29adbc0..97146899a 100644
--- a/tests/test_logs/test_export_tasks.py
+++ b/tests/test_logs/test_export_tasks.py
@@ -47,19 +47,6 @@ S3_POLICY = {
 }
 
 
-@pytest.fixture()
-def account_id():
-    if allow_aws_request:
-        identity = boto3.client("sts", region_name="us-east-1").get_caller_identity()
-        yield identity["Account"]
-    else:
-        with mock_aws():
-            identity = boto3.client(
-                "sts", region_name="us-east-1"
-            ).get_caller_identity()
-            yield identity["Account"]
-
-
 @pytest.fixture()
 def logs():
     if allow_aws_request:
diff --git a/tests/test_s3/test_s3_copyobject.py b/tests/test_s3/test_s3_copyobject.py
index 1dd900f13..08ea47521 100644
--- a/tests/test_s3/test_s3_copyobject.py
+++ b/tests/test_s3/test_s3_copyobject.py
@@ -1,4 +1,5 @@
 import datetime
+from uuid import uuid4
 
 import boto3
 import pytest
@@ -6,6 +7,7 @@ from botocore.client import ClientError
 
 from moto import mock_aws
 from moto.s3.responses import DEFAULT_REGION_NAME
+from tests.test_s3.test_s3 import enable_versioning
 
 from . import s3_aws_verified
 
@@ -226,15 +228,14 @@ def test_copy_key_replace_metadata():
     assert resp["ETag"] == initial["ETag"]
 
 
-@mock_aws
-def test_copy_key_without_changes_should_error():
+@s3_aws_verified
+@pytest.mark.aws_verified
+def test_copy_key_without_changes_should_error(bucket_name=None):
     client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
-    bucket_name = "my_bucket"
     s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
     key_name = "my_key"
     key = s3_resource.Object(bucket_name, key_name)
 
-    s3_resource.create_bucket(Bucket=bucket_name)
     key.put(Body=b"some value")
 
     with pytest.raises(ClientError) as exc:
@@ -250,15 +251,14 @@ def test_copy_key_without_changes_should_error():
         )
 
 
-@mock_aws
-def test_copy_key_without_changes_should_not_error():
+@s3_aws_verified
+@pytest.mark.aws_verified
+def test_copy_key_without_changes_should_not_error(bucket_name=None):
     client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
-    bucket_name = "my_bucket"
     s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
     key_name = "my_key"
     key = s3_resource.Object(bucket_name, key_name)
 
-    s3_resource.create_bucket(Bucket=bucket_name)
     key.put(Body=b"some value")
 
     client.copy_object(
@@ -295,85 +295,95 @@ def test_copy_key_reduced_redundancy():
     assert keys["the-key"].storage_class == "STANDARD"
 
 
-@mock_aws
-def test_copy_non_existing_file():
+@s3_aws_verified
+@pytest.mark.aws_verified
+def test_copy_non_existing_file(bucket_name=None):
     s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
-    src = "srcbucket"
-    target = "target"
-    s3_resource.create_bucket(Bucket=src)
+    target = str(uuid4())
     s3_resource.create_bucket(Bucket=target)
 
-    s3_client = boto3.client("s3")
-    with pytest.raises(ClientError) as exc:
-        s3_client.copy_object(
-            Bucket=target, CopySource={"Bucket": src, "Key": "foofoofoo"}, Key="newkey"
-        )
-    err = exc.value.response["Error"]
-    assert err["Code"] == "NoSuchKey"
-    assert err["Message"] == "The specified key does not exist."
-    assert err["Key"] == "foofoofoo"
+    try:
+        s3_client = boto3.client("s3", "us-east-1")
+        with pytest.raises(ClientError) as exc:
+            s3_client.copy_object(
+                Bucket=target,
+                CopySource={"Bucket": bucket_name, "Key": "foofoofoo"},
+                Key="newkey",
+            )
+        err = exc.value.response["Error"]
+        assert err["Code"] == "NoSuchKey"
+        assert err["Message"] == "The specified key does not exist."
+        assert err["Key"] == "foofoofoo"
+    finally:
+        s3_client.delete_bucket(Bucket=target)
 
 
-@mock_aws
-def test_copy_object_with_versioning():
+@s3_aws_verified
+@pytest.mark.aws_verified
+def test_copy_object_with_versioning(bucket_name=None):
     client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
 
-    client.create_bucket(
-        Bucket="blah", CreateBucketConfiguration={"LocationConstraint": "eu-west-1"}
-    )
-    client.put_bucket_versioning(
-        Bucket="blah", VersioningConfiguration={"Status": "Enabled"}
-    )
+    enable_versioning(bucket_name, client)
 
-    client.put_object(Bucket="blah", Key="test1", Body=b"test1")
-    client.put_object(Bucket="blah", Key="test2", Body=b"test2")
+    client.put_object(Bucket=bucket_name, Key="test1", Body=b"test1")
+    client.put_object(Bucket=bucket_name, Key="test2", Body=b"test2")
 
-    _ = client.get_object(Bucket="blah", Key="test1")["VersionId"]
-    obj2_version = client.get_object(Bucket="blah", Key="test2")["VersionId"]
+    _ = client.get_object(Bucket=bucket_name, Key="test1")["VersionId"]
+    obj2_version = client.get_object(Bucket=bucket_name, Key="test2")["VersionId"]
 
     client.copy_object(
-        CopySource={"Bucket": "blah", "Key": "test1"}, Bucket="blah", Key="test2"
+        CopySource={"Bucket": bucket_name, "Key": "test1"},
+        Bucket=bucket_name,
+        Key="test2",
     )
-    obj2_version_new = client.get_object(Bucket="blah", Key="test2")["VersionId"]
+    obj2_version_new = client.get_object(Bucket=bucket_name, Key="test2")["VersionId"]
 
     # Version should be different to previous version
     assert obj2_version_new != obj2_version
 
     client.copy_object(
-        CopySource={"Bucket": "blah", "Key": "test2", "VersionId": obj2_version},
-        Bucket="blah",
+        CopySource={"Bucket": bucket_name, "Key": "test2", "VersionId": obj2_version},
+        Bucket=bucket_name,
         Key="test3",
     )
-    obj3_version_new = client.get_object(Bucket="blah", Key="test3")["VersionId"]
+    obj3_version_new = client.get_object(Bucket=bucket_name, Key="test3")["VersionId"]
     assert obj3_version_new != obj2_version_new
 
     # Copy file that doesn't exist
     with pytest.raises(ClientError) as exc:
         client.copy_object(
-            CopySource={"Bucket": "blah", "Key": "test4", "VersionId": obj2_version},
-            Bucket="blah",
+            CopySource={
+                "Bucket": bucket_name,
+                "Key": "test4",
+                "VersionId": obj2_version,
+            },
+            Bucket=bucket_name,
             Key="test5",
         )
-    assert exc.value.response["Error"]["Code"] == "NoSuchKey"
+    assert exc.value.response["Error"]["Code"] == "NoSuchVersion"
 
-    response = client.create_multipart_upload(Bucket="blah", Key="test4")
+    response = client.create_multipart_upload(Bucket=bucket_name, Key="test4")
     upload_id = response["UploadId"]
     response = client.upload_part_copy(
-        Bucket="blah",
+        Bucket=bucket_name,
         Key="test4",
-        CopySource={"Bucket": "blah", "Key": "test3", "VersionId": obj3_version_new},
+        CopySource={
+            "Bucket": bucket_name,
+            "Key": "test3",
+            "VersionId": obj3_version_new,
+        },
         UploadId=upload_id,
         PartNumber=1,
     )
     etag = response["CopyPartResult"]["ETag"]
     client.complete_multipart_upload(
-        Bucket="blah",
+        Bucket=bucket_name,
         Key="test4",
         UploadId=upload_id,
         MultipartUpload={"Parts": [{"ETag": etag, "PartNumber": 1}]},
     )
 
-    response = client.get_object(Bucket="blah", Key="test4")
+    response = client.get_object(Bucket=bucket_name, Key="test4")
     data = response["Body"].read()
     assert data == b"test2"
 
@@ -605,15 +615,13 @@ def test_copy_object_does_not_copy_acl():
     assert default_acl["Grants"] == dest_acl["Grants"]
 
 
-@mock_aws
-def test_copy_object_in_place_with_metadata():
+@s3_aws_verified
+@pytest.mark.aws_verified
+def test_copy_object_in_place_with_metadata(bucket_name=None):
     s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
     client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
-    bucket_name = "testbucket"
-    bucket = s3_resource.Bucket(bucket_name)
-    bucket.create()
     key_name = "source-key"
-    bucket.put_object(Key=key_name, Body=b"somedata")
+    s3_resource.Object(bucket_name, key_name).put(Body=b"somedata")
 
     # test that giving metadata is not enough and should provide
     # MetadataDirective=REPLACE on top.
@@ -783,34 +791,18 @@ def test_copy_object_in_place_with_bucket_encryption():
     assert response["ServerSideEncryption"] == "AES256"
 
 
-@mock_aws
-def test_copy_object_in_place_with_versioning():
+@s3_aws_verified
+@pytest.mark.aws_verified
+def test_copy_object_in_place_with_versioning(bucket_name=None):
     # If a bucket has versioning enabled, it will allow copy in place
     client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
-    bucket_name = "testbucket"
-    client.create_bucket(Bucket=bucket_name)
     key = "source-key"
 
-    response = client.put_object(
-        Body=b"",
-        Bucket=bucket_name,
-        Key=key,
-    )
+    client.put_object(Body=b"", Bucket=bucket_name, Key=key)
 
-    response = client.put_bucket_versioning(
-        Bucket=bucket_name,
-        VersioningConfiguration={
-            "MFADelete": "Disabled",
-            "Status": "Enabled",
-        },
-    )
-    assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
+    enable_versioning(bucket_name, client)
 
-    response = client.put_object(
-        Body=b"",
-        Bucket=bucket_name,
-        Key=key,
-    )
+    response = client.put_object(Body=b"", Bucket=bucket_name, Key=key)
     version_id = response["ResponseMetadata"]["HTTPHeaders"]["x-amz-version-id"]
     assert version_id and version_id != "null"
 
@@ -834,6 +826,28 @@ def test_copy_object_in_place_with_versioning():
     )
     assert len(response["Versions"]) == 4
 
+    # Copy-In-Place does not work if no other parameters are set
+    with pytest.raises(ClientError) as exc:
+        client.copy_object(
+            Bucket=bucket_name,
+            CopySource={"Bucket": bucket_name, "Key": key},
+            Key=key,
+        )
+    err = exc.value.response["Error"]
+    assert err["Code"] == "InvalidRequest"
+    assert (
+        err["Message"]
+        == "This copy request is illegal because it is trying to copy an object to itself without changing the object's metadata, storage class, website redirect location or encryption attributes."
+    )
+
+    # It does work when any other property is set
+    client.copy_object(
+        Bucket=bucket_name,
+        CopySource={"Bucket": bucket_name, "Key": key},
+        Key=key,
+        StorageClass="STANDARD",
+    )
+
 
 @mock_aws
 @pytest.mark.parametrize(
@@ -949,3 +963,72 @@ def test_copy_object_keeps_checksum():
     # assert that it kept the checksum from the source key
     assert "ChecksumSHA256" in resp["CopyObjectResult"]
     assert resp["CopyObjectResult"]["ChecksumSHA256"] == expected_checksum
+
+
+@s3_aws_verified
+@pytest.mark.aws_verified
+def test_copy_source_if_none_match(bucket_name=None):
+    client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
+    s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
+
+    enable_versioning(bucket_name, client)
+
+    obj = s3.Object(bucket_name, "orig")
+
+    etag = obj.put(Body=b"n/a")["ETag"]
+
+    # Exact match
+    copy_from_kwargs = {
+        "CopySource": {"Bucket": bucket_name, "Key": "orig"},
+        "CopySourceIfNoneMatch": etag,
+        "StorageClass": "STANDARD",
+    }
+
+    with pytest.raises(ClientError) as exc:
+        obj.copy_from(**copy_from_kwargs)
+    err = exc.value.response["Error"]
+    assert err["Code"] == "PreconditionFailed"
+    assert (
+        err["Message"]
+        == "At least one of the pre-conditions you specified did not hold"
+    )
+    assert err["Condition"] == "x-amz-copy-source-If-None-Match"
+
+    r = client.list_object_versions(Bucket=bucket_name)["Versions"]
+    assert len(r) == 1
+    assert r[0]["ETag"] == etag
+
+    # Match without quotes
+    copy_from_kwargs = {
+        "CopySource": {"Bucket": bucket_name, "Key": "orig"},
+        "CopySourceIfNoneMatch": etag[1:-1],
+        "StorageClass": "STANDARD",
+    }
+
+    with pytest.raises(ClientError) as exc:
+        obj.copy_from(**copy_from_kwargs)
+    err = exc.value.response["Error"]
+    assert err["Code"] == "PreconditionFailed"
+    assert (
+        err["Message"]
+        == "At least one of the pre-conditions you specified did not hold"
+    )
+    assert err["Condition"] == "x-amz-copy-source-If-None-Match"
+
+    r = client.list_object_versions(Bucket=bucket_name)["Versions"]
+    assert len(r) == 1
+    assert r[0]["ETag"] == etag
+
+    # No match - completely different etag
+    copy_from_kwargs = {
+        "CopySource": {"Bucket": bucket_name, "Key": "orig"},
+        "CopySourceIfNoneMatch": "unknown etag",
+        "StorageClass": "STANDARD",
+    }
+
+    obj.copy_from(**copy_from_kwargs)
+
+    r = client.list_object_versions(Bucket=bucket_name)["Versions"]
+    assert len(r) == 2
+    assert r[0]["ETag"] == r[1]["ETag"] == etag
+    assert r[0]["VersionId"] != r[1]["VersionId"]
diff --git a/tests/test_sqs/__init__.py b/tests/test_sqs/__init__.py
index e69de29bb..d2cf7d8a1 100644
--- a/tests/test_sqs/__init__.py
+++ b/tests/test_sqs/__init__.py
@@ -0,0 +1,50 @@
+from functools import wraps
+from uuid import uuid4
+
+import boto3
+
+from moto import mock_aws
+from tests import allow_aws_request
+
+
+def sqs_aws_verified():
+    """
+    Function that is verified to work against AWS.
+    Can be run against AWS at any time by setting:
+      MOTO_TEST_ALLOW_AWS_REQUEST=true
+
+    If this environment variable is not set, the function runs in a `mock_aws` context.
+
+    This decorator will:
+      - Create an SQS queue
+      - Run the test and pass the queue_name as an argument
+      - Delete the queue
+    """
+
+    def inner(func):
+        @wraps(func)
+        def pagination_wrapper(**kwargs):
+            queue_name = "q" + str(uuid4())[0:6]
+            kwargs["queue_name"] = queue_name
+
+            def create_queue_and_test():
+                client = boto3.client("sqs", region_name="us-east-1")
+
+                queue_url = client.create_queue(QueueName=queue_name)["QueueUrl"]
+                kwargs["queue_url"] = queue_url
+                try:
+                    resp = func(**kwargs)
+                finally:
+                    client.delete_queue(QueueUrl=queue_url)
+
+                return resp
+
+            if allow_aws_request():
+                return create_queue_and_test()
+            else:
+                with mock_aws():
+                    return create_queue_and_test()
+
+        return pagination_wrapper
+
+    return inner
diff --git a/tests/test_sqs/test_sqs.py b/tests/test_sqs/test_sqs.py
index b6294ff82..7e5410d9f 100644
--- a/tests/test_sqs/test_sqs.py
+++ b/tests/test_sqs/test_sqs.py
@@ -23,6 +23,7 @@ from moto.sqs.models import (
 )
 from moto.utilities.distutils_version import LooseVersion
 from tests import aws_verified
+from tests.test_sqs import sqs_aws_verified
 
 TEST_POLICY = """
 {
@@ -278,6 +279,15 @@ def test_create_queue_with_policy():
     }
 
 
+@aws_verified
+@pytest.mark.aws_verified
+def test_get_unknown_queue_by_name():
+    sqs = boto3.resource("sqs", "us-east-1")
+    with pytest.raises(sqs.meta.client.exceptions.QueueDoesNotExist) as exc:
+        sqs.get_queue_by_name(QueueName="doesnotexist")
+    _verify_unknown_queue_error(exc)
+
+
 @mock_aws
 def test_set_queue_attribute_empty_policy_removes_attr():
     client = boto3.client("sqs", region_name=REGION)
@@ -355,37 +365,35 @@ def test_get_queue_url():
     assert q_name in response["QueueUrl"]
 
 
-@mock_aws
+@aws_verified
+@pytest.mark.aws_verified
 def test_get_queue_url_error_not_exists():
-    # given
     client = boto3.client("sqs", region_name=REGION)
+    sqs = boto3.resource("sqs", region_name=REGION)
 
-    # when
     with pytest.raises(ClientError) as e:
         client.get_queue_url(QueueName="not-exists")
+    _verify_unknown_queue_error(e)
 
-    # then
-    ex = e.value
-    assert ex.operation_name == "GetQueueUrl"
-    assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
-    assert "AWS.SimpleQueueService.NonExistentQueue" in ex.response["Error"]["Code"]
-    assert ex.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
+    with pytest.raises(ClientError) as err:
+        sqs.Queue("http://whatever-incorrect-queue-address").load()
+    _verify_unknown_queue_error(err, "GetQueueAttributes")
 
 
-@mock_aws
-def test_get_nonexistent_queue():
-    sqs = boto3.resource("sqs", region_name=REGION)
+def _verify_unknown_queue_error(e, op_name="GetQueueUrl", status_code=400):
+    response = e.value.response
+    assert e.value.operation_name == op_name
+    assert response["ResponseMetadata"]["HTTPStatusCode"] == status_code
+    assert "AWS.SimpleQueueService.NonExistentQueue" == response["Error"]["Code"]
 
-    with pytest.raises(ClientError) as err:
-        sqs.Queue("http://whatever-incorrect-queue-address").load()
-    ex = err.value
-    assert ex.operation_name == "GetQueueAttributes"
-    assert ex.response["Error"]["Code"] == "AWS.SimpleQueueService.NonExistentQueue"
-    assert ex.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
+    botocore_version = sys.modules["botocore"].__version__
+    if LooseVersion(botocore_version) >= LooseVersion("1.34.90"):
+        assert response["Error"]["Message"] == "The specified queue does not exist."
+    else:
+        assert (
+            response["Error"]["Message"]
+            == "The specified queue does not exist for this wsdl version."
+        )
 
 
 @mock_aws
@@ -742,22 +750,16 @@ def test_delete_queue():
     assert q_name not in [u[u.rfind("/") + 1 :] for u in all_urls]
 
 
-@mock_aws
-def test_delete_queue_error_not_exists():
+@aws_verified
+@pytest.mark.aws_verified
+def test_delete_queue_error_not_exists(account_id):
     client = boto3.client("sqs", region_name=REGION)
 
     with pytest.raises(ClientError) as e:
         client.delete_queue(
-            QueueUrl=f"https://queue.amazonaws.com/{ACCOUNT_ID}/not-exists"
+            QueueUrl=f"https://queue.amazonaws.com/{account_id}/unknown"
         )
-
-    ex = e.value
-    assert ex.operation_name == "DeleteQueue"
-    assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
-    assert "AWS.SimpleQueueService.NonExistentQueue" in ex.response["Error"]["Code"]
-    assert ex.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
+    _verify_unknown_queue_error(e, op_name="DeleteQueue")
 
 
 @mock_aws
@@ -850,25 +852,20 @@ def test_get_queue_attributes_errors():
     assert client_error.value.response["Error"]["Message"] == "Unknown Attribute ."
 
 
-@mock_aws
-def test_get_queue_attributes_error_not_exists():
+@aws_verified
+@pytest.mark.aws_verified
+def test_get_queue_attributes_error_not_exists(account_id):
     # given
     client = boto3.client("sqs", region_name=REGION)
 
     # when
     with pytest.raises(ClientError) as e:
         client.get_queue_attributes(
-            QueueUrl=f"https://queue.amazonaws.com/{ACCOUNT_ID}/not-exists"
+            QueueUrl=f"https://queue.amazonaws.com/{account_id}/unknown"
         )
 
     # then
-    ex = e.value
-    assert ex.operation_name == "GetQueueAttributes"
-    assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
-    assert "AWS.SimpleQueueService.NonExistentQueue" in ex.response["Error"]["Code"]
-    assert ex.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
+    _verify_unknown_queue_error(e, op_name="GetQueueAttributes")
 
 
 @mock_aws
@@ -1768,16 +1765,7 @@ def test_delete_message_errors():
     response = client.create_queue(QueueName=str(uuid4())[0:6])
     queue_url = response["QueueUrl"]
     client.send_message(QueueUrl=queue_url, MessageBody="body")
-    response = client.receive_message(QueueUrl=queue_url)
-    receipt_handle = response["Messages"][0]["ReceiptHandle"]
-
-    with pytest.raises(ClientError) as client_error:
-        client.delete_message(
-            QueueUrl=queue_url + "-not-existing", ReceiptHandle=receipt_handle
-        )
-    assert client_error.value.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
+    client.receive_message(QueueUrl=queue_url)
 
     with pytest.raises(ClientError) as client_error:
         client.delete_message(QueueUrl=queue_url, ReceiptHandle="not-existing")
@@ -1787,6 +1775,18 @@ def test_delete_message_errors():
     )
 
 
+@aws_verified
+@pytest.mark.aws_verified
+def test_delete_message_from_unknown_url(account_id):
+    client = boto3.client("sqs", region_name=REGION)
+    with pytest.raises(ClientError) as client_error:
+        client.delete_message(
+            QueueUrl=f"https://sqs.us-east-1.amazonaws.com/{account_id}/unknown",
+            ReceiptHandle="unknown",
+        )
+    _verify_unknown_queue_error(client_error, op_name="DeleteMessage")
+
+
 @mock_aws
 def test_delete_message_twice_using_same_receipt_handle():
     client = boto3.client("sqs", region_name=REGION)
@@ -2037,21 +2037,17 @@ def test_message_attributes_in_receive_message():
     }
 
 
-@mock_aws
-def test_send_message_batch_errors():
+@sqs_aws_verified()
+@pytest.mark.aws_verified
+def test_send_message_batch_errors(queue_name=None, queue_url=None):
     client = boto3.client("sqs", region_name=REGION)
 
-    response = client.create_queue(QueueName="test-queue")
-    queue_url = response["QueueUrl"]
-
     with pytest.raises(ClientError) as client_error:
         client.send_message_batch(
             QueueUrl=queue_url + "-not-existing",
             Entries=[{"Id": "id_1", "MessageBody": "body_1"}],
         )
-    assert client_error.value.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
+    _verify_unknown_queue_error(client_error, op_name="SendMessageBatch")
 
     with pytest.raises(ClientError) as client_error:
         client.send_message_batch(QueueUrl=queue_url, Entries=[])
@@ -2454,20 +2450,28 @@ def test_tags():
     assert client.list_queue_tags(QueueUrl=queue_url)["Tags"] == {"test1": "value1"}
 
 
-@mock_aws
-def test_list_queue_tags_errors():
+@aws_verified
+@pytest.mark.aws_verified
+def test_list_queue_tags_errors(account_id):
     client = boto3.client("sqs", region_name=REGION)
 
-    response = client.create_queue(
-        QueueName=str(uuid4())[0:6], tags={"tag_key_1": "tag_value_X"}
-    )
-    queue_url = response["QueueUrl"]
+    with pytest.raises(ClientError) as client_error:
+        client.list_queue_tags(
+            QueueUrl=f"https://sqs.us-east-1.amazonaws.com/{account_id}/not-existing"
+        )
+    _verify_unknown_queue_error(client_error, op_name="ListQueueTags")
+
 
+@aws_verified
+@pytest.mark.aws_verified
+def test_tag_unknown_queue(account_id):
+    client = boto3.client("sqs", region_name=REGION)
     with pytest.raises(ClientError) as client_error:
-        client.list_queue_tags(QueueUrl=queue_url + "-not-existing")
-    assert client_error.value.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
+        client.tag_queue(
+            QueueUrl=f"https://sqs.us-east-1.amazonaws.com/{account_id}/unknown",
+            Tags={"t": "v"},
+        )
+    _verify_unknown_queue_error(client_error, op_name="TagQueue")
 
 
 @mock_aws
@@ -2478,14 +2482,6 @@ def test_tag_queue_errors():
     response = client.create_queue(QueueName=q_name, tags={"tag_key_1": "tag_value_X"})
     queue_url = response["QueueUrl"]
 
-    with pytest.raises(ClientError) as client_error:
-        client.tag_queue(
-            QueueUrl=queue_url + "-not-existing", Tags={"tag_key_1": "tag_value_1"}
-        )
-    assert client_error.value.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
-
     with pytest.raises(ClientError) as client_error:
         client.tag_queue(QueueUrl=queue_url, Tags={})
     assert client_error.value.response["Error"]["Message"] == (
@@ -2505,6 +2501,18 @@ def test_tag_queue_errors():
     )
 
 
+@aws_verified
+@pytest.mark.aws_verified
+def test_untag_unknown_queue(account_id):
+    client = boto3.client("sqs", region_name=REGION)
+    with pytest.raises(ClientError) as client_error:
+        client.untag_queue(
+            QueueUrl=f"https://sqs.us-east-1.amazonaws.com/{account_id}/unknown",
+            TagKeys=["tag1"],
+        )
+    _verify_unknown_queue_error(client_error, op_name="UntagQueue")
+
+
 @mock_aws
 def test_untag_queue_errors():
     client = boto3.client("sqs", region_name=REGION)
@@ -2514,12 +2522,6 @@ def test_untag_queue_errors():
     )
     queue_url = response["QueueUrl"]
 
-    with pytest.raises(ClientError) as client_error:
-        client.untag_queue(QueueUrl=queue_url + "-not-existing", TagKeys=["tag_key_1"])
-    assert client_error.value.response["Error"]["Message"] == (
-        "The specified queue does not exist for this wsdl version."
-    )
-
     with pytest.raises(ClientError) as client_error:
         client.untag_queue(QueueUrl=queue_url, TagKeys=[])
     assert client_error.value.response["Error"]["Message"] == (