Repository: getmoto/moto

Issue:
Moto returns wrong code for DryRun requests
Moto returns 400 fro dryRun request when it is actually should be 412.

Moto response example:
```
HTTP/1.0 400 BAD REQUEST
status: 400
server: amazon.com
Content-Type: text/html; charset=utf-8
Content-Length: 388
Date: Fri, 07 Dec 2018 18:38:32 GMT

<?xml version="1.0" encoding="UTF-8"?>
  <Response>
    <Errors>
      <Error>
        <Code>DryRunOperation</Code>
        <Message>An error occurred (DryRunOperation) when calling the DescribeInstances operation: Request would have succeeded, but DryRun flag is set</Message>
        
      </Error>
    </Errors>
  <RequestID>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestID>
</Response>
```

AWS respons example:
```
HTTP/1.1 412 Precondition Failed
Transfer-Encoding: chunked
Date: Fri, 07 Dec 2018 18:16:40 GMT
Server: AmazonEC2

fb
<?xml version="1.0" encoding="UTF-8"?>
<Response><Errors><Error><Code>DryRunOperation</Code><Message>Request would have succeeded, but DryRun flag is set.</Message></Error></Errors><RequestID>7dde7961-fbfd-4731-8600-7a1f62a32e3c</RequestID></Response>
0
```
Thank you!



Discussion:
Thanks; setting as a feature request.
Thank you @spulec! Please not that this issue depends on problem described here: https://github.com/pallets/werkzeug/issues/1231. It will be fixed with next version of werkzeug.

Resolving patch:
diff --git a/moto/core/exceptions.py b/moto/core/exceptions.py
--- a/moto/core/exceptions.py
+++ b/moto/core/exceptions.py
@@ -83,7 +83,7 @@ def get_body(self, *args, **kwargs):
 
 
 class DryRunClientError(RESTError):
-    code = 400
+    code = 412
 
 
 class JsonRESTError(RESTError):


Test patch:
diff --git a/tests/test_ec2/test_amis.py b/tests/test_ec2/test_amis.py
--- a/tests/test_ec2/test_amis.py
+++ b/tests/test_ec2/test_amis.py
@@ -32,7 +32,7 @@ def test_ami_create_and_delete():
             instance.id, "test-ami", "this is a test ami", dry_run=True
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateImage operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -79,7 +79,7 @@ def test_ami_create_and_delete():
     with pytest.raises(EC2ResponseError) as ex:
         success = conn.deregister_image(image_id, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DeregisterImage operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -121,7 +121,7 @@ def test_ami_copy():
             dry_run=True,
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CopyImage operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -211,7 +211,7 @@ def test_ami_tagging():
     with pytest.raises(EC2ResponseError) as ex:
         image.add_tag("a key", "some value", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateTags operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -402,7 +402,7 @@ def test_ami_attribute_group_permissions():
     with pytest.raises(EC2ResponseError) as ex:
         conn.modify_image_attribute(**dict(ADD_GROUP_ARGS, **{"dry_run": True}))
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifyImageAttribute operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_elastic_block_store.py b/tests/test_ec2/test_elastic_block_store.py
--- a/tests/test_ec2/test_elastic_block_store.py
+++ b/tests/test_ec2/test_elastic_block_store.py
@@ -32,7 +32,7 @@ def test_create_and_delete_volume():
     with pytest.raises(EC2ResponseError) as ex:
         volume.delete(dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DeleteVolume operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -96,7 +96,7 @@ def test_create_encrypted_volume_dryrun():
     with pytest.raises(EC2ResponseError) as ex:
         conn.create_volume(80, "us-east-1a", encrypted=True, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateVolume operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -110,7 +110,7 @@ def test_create_encrypted_volume():
     with pytest.raises(EC2ResponseError) as ex:
         conn.create_volume(80, "us-east-1a", encrypted=True, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateVolume operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -260,7 +260,7 @@ def test_volume_attach_and_detach():
     with pytest.raises(EC2ResponseError) as ex:
         volume.attach(instance.id, "/dev/sdh", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the AttachVolume operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -276,7 +276,7 @@ def test_volume_attach_and_detach():
     with pytest.raises(EC2ResponseError) as ex:
         volume.detach(dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DetachVolume operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -313,7 +313,7 @@ def test_create_snapshot():
     with pytest.raises(EC2ResponseError) as ex:
         snapshot = volume.create_snapshot("a dryrun snapshot", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateSnapshot operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -485,7 +485,7 @@ def test_snapshot_attribute():
     with pytest.raises(EC2ResponseError) as ex:
         conn.modify_snapshot_attribute(**dict(ADD_GROUP_ARGS, **{"dry_run": True}))
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifySnapshotAttribute operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -507,7 +507,7 @@ def test_snapshot_attribute():
     with pytest.raises(EC2ResponseError) as ex:
         conn.modify_snapshot_attribute(**dict(REMOVE_GROUP_ARGS, **{"dry_run": True}))
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifySnapshotAttribute operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -598,7 +598,7 @@ def test_modify_snapshot_attribute():
 
     cm.value.response["Error"]["Code"].should.equal("DryRunOperation")
     cm.value.response["ResponseMetadata"]["RequestId"].should_not.be.none
-    cm.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
+    cm.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(412)
 
     ec2_client.modify_snapshot_attribute(**ADD_GROUP_ARGS)
 
@@ -624,7 +624,7 @@ def test_modify_snapshot_attribute():
         )
     cm.value.response["Error"]["Code"].should.equal("DryRunOperation")
     cm.value.response["ResponseMetadata"]["RequestId"].should_not.be.none
-    cm.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
+    cm.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(412)
 
     ec2_client.modify_snapshot_attribute(**REMOVE_GROUP_ARGS)
 
@@ -741,7 +741,7 @@ def test_create_volume_from_snapshot():
     with pytest.raises(EC2ResponseError) as ex:
         snapshot = volume.create_snapshot("a test snapshot", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateSnapshot operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -789,7 +789,7 @@ def test_modify_attribute_blockDeviceMapping():
             "blockDeviceMapping", {"/dev/sda1": True}, dry_run=True
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifyInstanceAttribute operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -810,7 +810,7 @@ def test_volume_tag_escaping():
     with pytest.raises(EC2ResponseError) as ex:
         snapshot.add_tags({"key": "</closed>"}, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateTags operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_elastic_ip_addresses.py b/tests/test_ec2/test_elastic_ip_addresses.py
--- a/tests/test_ec2/test_elastic_ip_addresses.py
+++ b/tests/test_ec2/test_elastic_ip_addresses.py
@@ -22,7 +22,7 @@ def test_eip_allocate_classic():
     with pytest.raises(EC2ResponseError) as ex:
         standard = conn.allocate_address(dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the AllocateAddress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -36,7 +36,7 @@ def test_eip_allocate_classic():
     with pytest.raises(EC2ResponseError) as ex:
         standard.release(dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ReleaseAddress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -53,7 +53,7 @@ def test_eip_allocate_vpc():
     with pytest.raises(EC2ResponseError) as ex:
         vpc = conn.allocate_address(domain="vpc", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the AllocateAddress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -111,7 +111,7 @@ def test_eip_associate_classic():
             instance_id=instance.id, public_ip=eip.public_ip, dry_run=True
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the AssociateAddress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -124,7 +124,7 @@ def test_eip_associate_classic():
     with pytest.raises(EC2ResponseError) as ex:
         conn.disassociate_address(public_ip=eip.public_ip, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DisAssociateAddress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -170,7 +170,7 @@ def test_eip_associate_vpc():
     with pytest.raises(EC2ResponseError) as ex:
         eip.release(dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ReleaseAddress operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_elastic_network_interfaces.py b/tests/test_ec2/test_elastic_network_interfaces.py
--- a/tests/test_ec2/test_elastic_network_interfaces.py
+++ b/tests/test_ec2/test_elastic_network_interfaces.py
@@ -22,7 +22,7 @@ def test_elastic_network_interfaces():
     with pytest.raises(EC2ResponseError) as ex:
         eni = conn.create_network_interface(subnet.id, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateNetworkInterface operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -39,7 +39,7 @@ def test_elastic_network_interfaces():
     with pytest.raises(EC2ResponseError) as ex:
         conn.delete_network_interface(eni.id, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DeleteNetworkInterface operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -136,7 +136,7 @@ def test_elastic_network_interfaces_modify_attribute():
             eni.id, "groupset", [security_group1.id, security_group2.id], dry_run=True
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifyNetworkInterface operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -232,7 +232,7 @@ def test_elastic_network_interfaces_get_by_tag_name():
     with pytest.raises(ClientError) as ex:
         eni1.create_tags(Tags=[{"Key": "Name", "Value": "eni1"}], DryRun=True)
     ex.value.response["Error"]["Code"].should.equal("DryRunOperation")
-    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
+    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(412)
     ex.value.response["Error"]["Message"].should.equal(
         "An error occurred (DryRunOperation) when calling the CreateTags operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_flow_logs.py b/tests/test_ec2/test_flow_logs.py
--- a/tests/test_ec2/test_flow_logs.py
+++ b/tests/test_ec2/test_flow_logs.py
@@ -41,7 +41,7 @@ def test_create_flow_logs_s3():
             DryRun=True,
         )
     ex.value.response["Error"]["Code"].should.equal("DryRunOperation")
-    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
+    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(412)
     ex.value.response["Error"]["Message"].should.equal(
         "An error occurred (DryRunOperation) when calling the CreateFlowLogs operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -93,7 +93,7 @@ def test_create_flow_logs_cloud_watch():
             DryRun=True,
         )
     ex.value.response["Error"]["Code"].should.equal("DryRunOperation")
-    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
+    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(412)
     ex.value.response["Error"]["Message"].should.equal(
         "An error occurred (DryRunOperation) when calling the CreateFlowLogs operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_instances.py b/tests/test_ec2/test_instances.py
--- a/tests/test_ec2/test_instances.py
+++ b/tests/test_ec2/test_instances.py
@@ -51,7 +51,7 @@ def test_instance_launch_and_terminate():
     with pytest.raises(EC2ResponseError) as ex:
         reservation = conn.run_instances(EXAMPLE_AMI_ID, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the RunInstance operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -86,7 +86,7 @@ def test_instance_launch_and_terminate():
     with pytest.raises(EC2ResponseError) as ex:
         conn.terminate_instances([instance.id], dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the TerminateInstance operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -787,7 +787,7 @@ def test_instance_start_and_stop():
     with pytest.raises(EC2ResponseError) as ex:
         stopped_instances = conn.stop_instances(instance_ids, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the StopInstance operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -800,7 +800,7 @@ def test_instance_start_and_stop():
     with pytest.raises(EC2ResponseError) as ex:
         started_instances = conn.start_instances([instances[0].id], dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the StartInstance operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -818,7 +818,7 @@ def test_instance_reboot():
     with pytest.raises(EC2ResponseError) as ex:
         instance.reboot(dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the RebootInstance operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -836,7 +836,7 @@ def test_instance_attribute_instance_type():
     with pytest.raises(EC2ResponseError) as ex:
         instance.modify_attribute("instanceType", "m1.small", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifyInstanceType operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -864,7 +864,7 @@ def test_modify_instance_attribute_security_groups():
     with pytest.raises(EC2ResponseError) as ex:
         instance.modify_attribute("groupSet", [sg_id, sg_id2], dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifyInstanceSecurityGroups operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -887,7 +887,7 @@ def test_instance_attribute_user_data():
     with pytest.raises(EC2ResponseError) as ex:
         instance.modify_attribute("userData", "this is my user data", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifyUserData operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -917,7 +917,7 @@ def test_instance_attribute_source_dest_check():
     with pytest.raises(EC2ResponseError) as ex:
         instance.modify_attribute("sourceDestCheck", False, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifySourceDestCheck operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -963,7 +963,7 @@ def test_run_instance_with_security_group_name():
     with pytest.raises(EC2ResponseError) as ex:
         group = conn.create_security_group("group1", "some description", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateSecurityGroup operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -1240,7 +1240,7 @@ def test_instance_with_nic_attach_detach():
     with pytest.raises(EC2ResponseError) as ex:
         conn.attach_network_interface(eni.id, instance.id, device_index=1, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the AttachNetworkInterface operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -1267,7 +1267,7 @@ def test_instance_with_nic_attach_detach():
     with pytest.raises(EC2ResponseError) as ex:
         conn.detach_network_interface(instance_eni.attachment.id, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DetachNetworkInterface operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -1583,7 +1583,7 @@ def test_get_instance_by_security_group():
             instance.id, "groupSet", [security_group.id], dry_run=True
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ModifyInstanceSecurityGroups operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_internet_gateways.py b/tests/test_ec2/test_internet_gateways.py
--- a/tests/test_ec2/test_internet_gateways.py
+++ b/tests/test_ec2/test_internet_gateways.py
@@ -29,7 +29,7 @@ def test_igw_create():
     with pytest.raises(EC2ResponseError) as ex:
         igw = conn.create_internet_gateway(dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateInternetGateway operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -52,7 +52,7 @@ def test_igw_attach():
     with pytest.raises(EC2ResponseError) as ex:
         conn.attach_internet_gateway(igw.id, vpc.id, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the AttachInternetGateway operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -103,7 +103,7 @@ def test_igw_detach():
     with pytest.raises(EC2ResponseError) as ex:
         conn.detach_internet_gateway(igw.id, vpc.id, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DetachInternetGateway operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -170,7 +170,7 @@ def test_igw_delete():
     with pytest.raises(EC2ResponseError) as ex:
         conn.delete_internet_gateway(igw.id, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DeleteInternetGateway operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py
--- a/tests/test_ec2/test_key_pairs.py
+++ b/tests/test_ec2/test_key_pairs.py
@@ -68,7 +68,7 @@ def test_key_pairs_create():
     with pytest.raises(EC2ResponseError) as ex:
         conn.create_key_pair("foo", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateKeyPair operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -131,7 +131,7 @@ def test_key_pairs_delete_exist():
     with pytest.raises(EC2ResponseError) as ex:
         r = conn.delete_key_pair("foo", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DeleteKeyPair operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -148,7 +148,7 @@ def test_key_pairs_import():
     with pytest.raises(EC2ResponseError) as ex:
         conn.import_key_pair("foo", RSA_PUBLIC_KEY_OPENSSH, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the ImportKeyPair operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_security_groups.py b/tests/test_ec2/test_security_groups.py
--- a/tests/test_ec2/test_security_groups.py
+++ b/tests/test_ec2/test_security_groups.py
@@ -25,7 +25,7 @@ def test_create_and_describe_security_group():
             "test security group", "this is a test security group", dry_run=True
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateSecurityGroup operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -156,7 +156,7 @@ def test_deleting_security_groups():
     with pytest.raises(EC2ResponseError) as ex:
         conn.delete_security_group("test2", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DeleteSecurityGroup operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -193,7 +193,7 @@ def test_authorize_ip_range_and_revoke():
             dry_run=True,
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the GrantSecurityGroupIngress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -229,7 +229,7 @@ def test_authorize_ip_range_and_revoke():
             dry_run=True,
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the RevokeSecurityGroupIngress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -258,7 +258,7 @@ def test_authorize_ip_range_and_revoke():
             dry_run=True,
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the GrantSecurityGroupEgress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -276,9 +276,6 @@ def test_authorize_ip_range_and_revoke():
     # the default outbound rule and the new one
     int(egress_security_group.rules_egress[1].to_port).should.equal(2222)
     actual_cidr = egress_security_group.rules_egress[1].grants[0].cidr_ip
-    # Deal with Python2 dict->unicode, instead of dict->string
-    if type(actual_cidr) == "unicode":
-        actual_cidr = json.loads(actual_cidr.replace("u'", "'").replace("'", '"'))
     actual_cidr.should.equal("123.123.123.123/32")
 
     # Wrong Cidr should throw error
@@ -297,7 +294,7 @@ def test_authorize_ip_range_and_revoke():
             dry_run=True,
         )
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the RevokeSecurityGroupEgress operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -496,7 +493,7 @@ def test_security_group_tagging():
     with pytest.raises(EC2ResponseError) as ex:
         sg.add_tag("Test", "Tag", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateTags operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -785,7 +782,7 @@ def test_security_group_tagging_boto3():
             DryRun=True,
         )
     ex.value.response["Error"]["Code"].should.equal("DryRunOperation")
-    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
+    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(412)
     ex.value.response["Error"]["Message"].should.equal(
         "An error occurred (DryRunOperation) when calling the CreateTags operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_spot_instances.py b/tests/test_ec2/test_spot_instances.py
--- a/tests/test_ec2/test_spot_instances.py
+++ b/tests/test_ec2/test_spot_instances.py
@@ -56,7 +56,7 @@ def test_request_spot_instances():
             DryRun=True,
         )
     ex.value.response["Error"]["Code"].should.equal("DryRunOperation")
-    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
+    ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(412)
     ex.value.response["Error"]["Message"].should.equal(
         "An error occurred (DryRunOperation) when calling the RequestSpotInstance operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -159,7 +159,7 @@ def test_cancel_spot_instance_request():
     with pytest.raises(EC2ResponseError) as ex:
         conn.cancel_spot_instance_requests([requests[0].id], dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CancelSpotInstance operation: Request would have succeeded, but DryRun flag is set"
     )
diff --git a/tests/test_ec2/test_tags.py b/tests/test_ec2/test_tags.py
--- a/tests/test_ec2/test_tags.py
+++ b/tests/test_ec2/test_tags.py
@@ -24,7 +24,7 @@ def test_add_tag():
     with pytest.raises(EC2ResponseError) as ex:
         instance.add_tag("a key", "some value", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateTags operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -55,7 +55,7 @@ def test_remove_tag():
     with pytest.raises(EC2ResponseError) as ex:
         instance.remove_tag("a key", dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the DeleteTags operation: Request would have succeeded, but DryRun flag is set"
     )
@@ -110,7 +110,7 @@ def test_create_tags():
     with pytest.raises(EC2ResponseError) as ex:
         conn.create_tags(instance.id, tag_dict, dry_run=True)
     ex.value.error_code.should.equal("DryRunOperation")
-    ex.value.status.should.equal(400)
+    ex.value.status.should.equal(412)
     ex.value.message.should.equal(
         "An error occurred (DryRunOperation) when calling the CreateTags operation: Request would have succeeded, but DryRun flag is set"
     )