diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index b5a280640..411f55a8b 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -58,6 +58,7 @@ - [ ] get_room - [ ] get_room_skill_parameter - [ ] get_skill_group +- [ ] list_device_events - [ ] list_skills - [ ] list_tags - [ ] put_room_skill_parameter @@ -351,6 +352,7 @@ - [ ] delete_scaling_plan - [ ] describe_scaling_plan_resources - [ ] describe_scaling_plans +- [ ] update_scaling_plan ## batch - 93% implemented - [ ] cancel_job @@ -434,6 +436,7 @@ - [ ] get_applied_schema_version - [ ] get_directory - [ ] get_facet +- [ ] get_object_attributes - [ ] get_object_information - [ ] get_schema_as_json - [ ] get_typed_link_facet_information @@ -764,6 +767,8 @@ - [ ] create_pipeline - [ ] delete_custom_action_type - [ ] delete_pipeline +- [ ] delete_webhook +- [ ] deregister_webhook_with_third_party - [ ] disable_stage_transition - [ ] enable_stage_transition - [ ] get_job_details @@ -774,6 +779,7 @@ - [ ] list_action_types - [ ] list_pipeline_executions - [ ] list_pipelines +- [ ] list_webhooks - [ ] poll_for_jobs - [ ] poll_for_third_party_jobs - [ ] put_action_revision @@ -782,6 +788,8 @@ - [ ] put_job_success_result - [ ] put_third_party_job_failure_result - [ ] put_third_party_job_success_result +- [ ] put_webhook +- [ ] register_webhook_with_third_party - [ ] retry_stage_execution - [ ] start_pipeline_execution - [ ] update_pipeline @@ -1057,6 +1065,7 @@ - [ ] create_project - [ ] create_remote_access_session - [ ] create_upload +- [ ] create_vpce_configuration - [ ] delete_device_pool - [ ] delete_instance_profile - [ ] delete_network_profile @@ -1064,6 +1073,7 @@ - [ ] delete_remote_access_session - [ ] delete_run - [ ] delete_upload +- [ ] delete_vpce_configuration - [ ] get_account_settings - [ ] get_device - [ ] get_device_instance @@ -1079,6 +1089,7 @@ - [ ] get_suite - [ ] get_test - [ ] get_upload +- [ ] get_vpce_configuration - [ ] install_to_remote_access_session - [ ] list_artifacts - [ ] list_device_instances @@ -1098,6 +1109,7 @@ - [ ] list_tests - [ ] list_unique_problems - [ ] list_uploads +- [ ] list_vpce_configurations - [ ] purchase_offering - [ ] renew_offering - [ ] schedule_run @@ -1108,6 +1120,7 @@ - [ ] update_instance_profile - [ ] update_network_profile - [ ] update_project +- [ ] update_vpce_configuration ## directconnect - 0% implemented - [ ] allocate_connection_on_interconnect @@ -1264,7 +1277,7 @@ - [ ] update_radius - [ ] verify_trust -## dynamodb - 22% implemented +## dynamodb - 21% implemented - [ ] batch_get_item - [ ] batch_write_item - [ ] create_backup @@ -1276,6 +1289,7 @@ - [ ] describe_backup - [ ] describe_continuous_backups - [ ] describe_global_table +- [ ] describe_global_table_settings - [ ] describe_limits - [ ] describe_table - [ ] describe_time_to_live @@ -1293,6 +1307,7 @@ - [ ] untag_resource - [ ] update_continuous_backups - [ ] update_global_table +- [ ] update_global_table_settings - [ ] update_item - [ ] update_table - [ ] update_time_to_live @@ -1341,6 +1356,7 @@ - [ ] create_default_vpc - [X] create_dhcp_options - [ ] create_egress_only_internet_gateway +- [ ] create_fleet - [ ] create_flow_logs - [ ] create_fpga_image - [X] create_image @@ -1375,6 +1391,7 @@ - [X] delete_customer_gateway - [ ] delete_dhcp_options - [ ] delete_egress_only_internet_gateway +- [ ] delete_fleets - [ ] delete_flow_logs - [ ] delete_fpga_image - [X] delete_internet_gateway @@ -1416,6 +1433,9 @@ - [ ] describe_egress_only_internet_gateways - [ ] describe_elastic_gpus - [ ] describe_export_tasks +- [ ] describe_fleet_history +- [ ] describe_fleet_instances +- [ ] describe_fleets - [ ] describe_flow_logs - [ ] describe_fpga_image_attribute - [ ] describe_fpga_images @@ -1512,6 +1532,7 @@ - [X] import_key_pair - [ ] import_snapshot - [ ] import_volume +- [ ] modify_fleet - [ ] modify_fpga_image_attribute - [ ] modify_hosts - [ ] modify_id_format @@ -1884,8 +1905,11 @@ - [ ] delete_delivery_stream - [ ] describe_delivery_stream - [ ] list_delivery_streams +- [ ] list_tags_for_delivery_stream - [ ] put_record - [ ] put_record_batch +- [ ] tag_delivery_stream +- [ ] untag_delivery_stream - [ ] update_destination ## fms - 0% implemented @@ -2375,7 +2399,7 @@ - [ ] unsubscribe_from_event - [ ] update_assessment_target -## iot - 29% implemented +## iot - 30% implemented - [ ] accept_certificate_transfer - [X] add_thing_to_thing_group - [ ] associate_targets_with_job @@ -2387,7 +2411,7 @@ - [ ] clear_default_authorizer - [ ] create_authorizer - [ ] create_certificate_from_csr -- [ ] create_job +- [X] create_job - [X] create_keys_and_certificate - [ ] create_ota_update - [X] create_policy @@ -2420,7 +2444,7 @@ - [ ] describe_endpoint - [ ] describe_event_configurations - [ ] describe_index -- [ ] describe_job +- [X] describe_job - [ ] describe_job_execution - [ ] describe_role_alias - [ ] describe_stream @@ -2512,6 +2536,38 @@ - [ ] start_next_pending_job_execution - [ ] update_job_execution +## iotanalytics - 0% implemented +- [ ] batch_put_message +- [ ] cancel_pipeline_reprocessing +- [ ] create_channel +- [ ] create_dataset +- [ ] create_dataset_content +- [ ] create_datastore +- [ ] create_pipeline +- [ ] delete_channel +- [ ] delete_dataset +- [ ] delete_dataset_content +- [ ] delete_datastore +- [ ] delete_pipeline +- [ ] describe_channel +- [ ] describe_dataset +- [ ] describe_datastore +- [ ] describe_logging_options +- [ ] describe_pipeline +- [ ] get_dataset_content +- [ ] list_channels +- [ ] list_datasets +- [ ] list_datastores +- [ ] list_pipelines +- [ ] put_logging_options +- [ ] run_pipeline_activity +- [ ] sample_channel_data +- [ ] start_pipeline_reprocessing +- [ ] update_channel +- [ ] update_dataset +- [ ] update_datastore +- [ ] update_pipeline + ## kinesis - 56% implemented - [X] add_tags_to_stream - [X] create_stream @@ -3513,6 +3569,9 @@ - [ ] update_tags_for_domain - [ ] view_billing +## runtime.sagemaker - 0% implemented +- [ ] invoke_endpoint + ## s3 - 15% implemented - [ ] abort_multipart_upload - [ ] complete_multipart_upload @@ -3938,6 +3997,7 @@ - [ ] delete_activation - [ ] delete_association - [ ] delete_document +- [ ] delete_inventory - [ ] delete_maintenance_window - [X] delete_parameter - [X] delete_parameters @@ -3961,6 +4021,7 @@ - [ ] describe_instance_patch_states - [ ] describe_instance_patch_states_for_patch_group - [ ] describe_instance_patches +- [ ] describe_inventory_deletions - [ ] describe_maintenance_window_execution_task_invocations - [ ] describe_maintenance_window_execution_tasks - [ ] describe_maintenance_window_executions @@ -4378,6 +4439,7 @@ - [ ] create_user - [ ] delete_alias - [ ] delete_group +- [ ] delete_mailbox_permissions - [ ] delete_resource - [ ] delete_user - [ ] deregister_from_work_mail @@ -4390,35 +4452,48 @@ - [ ] list_aliases - [ ] list_group_members - [ ] list_groups +- [ ] list_mailbox_permissions - [ ] list_organizations - [ ] list_resource_delegates - [ ] list_resources - [ ] list_users +- [ ] put_mailbox_permissions - [ ] register_to_work_mail - [ ] reset_password - [ ] update_primary_email_address - [ ] update_resource ## workspaces - 0% implemented +- [ ] associate_ip_groups +- [ ] authorize_ip_rules +- [ ] create_ip_group - [ ] create_tags - [ ] create_workspaces +- [ ] delete_ip_group - [ ] delete_tags +- [ ] describe_ip_groups - [ ] describe_tags - [ ] describe_workspace_bundles - [ ] describe_workspace_directories - [ ] describe_workspaces - [ ] describe_workspaces_connection_status +- [ ] disassociate_ip_groups - [ ] modify_workspace_properties +- [ ] modify_workspace_state - [ ] reboot_workspaces - [ ] rebuild_workspaces +- [ ] revoke_ip_rules - [ ] start_workspaces - [ ] stop_workspaces - [ ] terminate_workspaces +- [ ] update_rules_of_ip_group ## xray - 0% implemented - [ ] batch_get_traces +- [ ] get_encryption_config - [ ] get_service_graph - [ ] get_trace_graph - [ ] get_trace_summaries +- [ ] put_encryption_config - [ ] put_telemetry_records - [ ] put_trace_segments diff --git a/Makefile b/Makefile index 98840ba9b..f224d7091 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ publish: upload_pypi_artifact \ push_dockerhub_image implementation_coverage: - ./scripts/implementation_coverage.py > IMPLEMENTATION_COVERAGE.md + ./scripts/implementation_coverage.py git commit IMPLEMENTATION_COVERAGE.md -m "Updating implementation coverage" || true scaffold: diff --git a/moto/ecr/responses.py b/moto/ecr/responses.py index ca45c63c9..af237769f 100644 --- a/moto/ecr/responses.py +++ b/moto/ecr/responses.py @@ -5,7 +5,7 @@ from datetime import datetime import time from moto.core.responses import BaseResponse -from .models import ecr_backends +from .models import ecr_backends, DEFAULT_REGISTRY_ID class ECRResponse(BaseResponse): @@ -120,7 +120,7 @@ class ECRResponse(BaseResponse): def get_authorization_token(self): registry_ids = self._get_param('registryIds') if not registry_ids: - registry_ids = [self.region] + registry_ids = [DEFAULT_REGISTRY_ID] auth_data = [] for registry_id in registry_ids: password = '{}-auth-token'.format(registry_id) @@ -128,7 +128,7 @@ class ECRResponse(BaseResponse): auth_data.append({ 'authorizationToken': auth_token, 'expiresAt': time.mktime(datetime(2015, 1, 1).timetuple()), - 'proxyEndpoint': 'https://012345678910.dkr.ecr.{}.amazonaws.com'.format(registry_id) + 'proxyEndpoint': 'https://{}.dkr.ecr.{}.amazonaws.com'.format(registry_id, self.region) }) return json.dumps({'authorizationData': auth_data}) diff --git a/moto/iot/models.py b/moto/iot/models.py index 77b0dde08..1b10c09fc 100644 --- a/moto/iot/models.py +++ b/moto/iot/models.py @@ -5,6 +5,8 @@ import string import random import hashlib import uuid +import re +from datetime import datetime from moto.core import BaseBackend, BaseModel from collections import OrderedDict from .exceptions import ( @@ -159,11 +161,76 @@ class FakePolicy(BaseModel): } +class FakeJob(BaseModel): + JOB_ID_REGEX_PATTERN = "[a-zA-Z0-9_-]" + JOB_ID_REGEX = re.compile(JOB_ID_REGEX_PATTERN) + + def __init__(self, job_id, targets, document_source, document, description, presigned_url_config, target_selection, + job_executions_rollout_config, document_parameters, region_name): + if not self._job_id_matcher(self.JOB_ID_REGEX, job_id): + raise InvalidRequestException() + + self.region_name = region_name + self.job_id = job_id + self.job_arn = 'arn:aws:iot:%s:1:job/%s' % (self.region_name, job_id) + self.targets = targets + self.document_source = document_source + self.document = document + self.description = description + self.presigned_url_config = presigned_url_config + self.target_selection = target_selection + self.job_executions_rollout_config = job_executions_rollout_config + self.status = None # IN_PROGRESS | CANCELED | COMPLETED + self.comment = None + self.created_at = time.mktime(datetime(2015, 1, 1).timetuple()) + self.last_updated_at = time.mktime(datetime(2015, 1, 1).timetuple()) + self.completed_at = None + self.job_process_details = { + 'processingTargets': targets, + 'numberOfQueuedThings': 1, + 'numberOfCanceledThings': 0, + 'numberOfSucceededThings': 0, + 'numberOfFailedThings': 0, + 'numberOfRejectedThings': 0, + 'numberOfInProgressThings': 0, + 'numberOfRemovedThings': 0 + } + self.document_parameters = document_parameters + + def to_dict(self): + obj = { + 'jobArn': self.job_arn, + 'jobId': self.job_id, + 'targets': self.targets, + 'description': self.description, + 'presignedUrlConfig': self.presigned_url_config, + 'targetSelection': self.target_selection, + 'jobExecutionsRolloutConfig': self.job_executions_rollout_config, + 'status': self.status, + 'comment': self.comment, + 'createdAt': self.created_at, + 'lastUpdatedAt': self.last_updated_at, + 'completedAt': self.completedAt, + 'jobProcessDetails': self.job_process_details, + 'documentParameters': self.document_parameters, + 'document': self.document, + 'documentSource': self.document_source + } + + return obj + + def _job_id_matcher(self, regex, argument): + regex_match = regex.match(argument) + length_match = len(argument) <= 64 + return regex_match and length_match + + class IoTBackend(BaseBackend): def __init__(self, region_name=None): super(IoTBackend, self).__init__() self.region_name = region_name self.things = OrderedDict() + self.jobs = OrderedDict() self.thing_types = OrderedDict() self.thing_groups = OrderedDict() self.certificates = OrderedDict() @@ -507,6 +574,16 @@ class IoTBackend(BaseBackend): thing.thing_name, None ) + def create_job(self, job_id, targets, document_source, document, description, presigned_url_config, + target_selection, job_executions_rollout_config, document_parameters): + job = FakeJob(job_id, targets, document_source, document, description, presigned_url_config, target_selection, + job_executions_rollout_config, document_parameters, self.region_name) + self.jobs[job_id] = job + return job.job_arn, job_id, description + + def describe_job(self, job_id): + return self.jobs[job_id] + available_regions = boto3.session.Session().get_available_regions("iot") iot_backends = {region: IoTBackend(region) for region in available_regions} diff --git a/moto/iot/responses.py b/moto/iot/responses.py index 4bd35bce4..fcdf12f78 100644 --- a/moto/iot/responses.py +++ b/moto/iot/responses.py @@ -102,6 +102,42 @@ class IoTResponse(BaseResponse): ) return json.dumps(dict()) + def create_job(self): + job_arn, job_id, description = self.iot_backend.create_job( + job_id=self._get_param("jobId"), + targets=self._get_param("targets"), + description=self._get_param("description"), + document_source=self._get_param("documentSource"), + document=self._get_param("document"), + presigned_url_config=self._get_param("presignedUrlConfig"), + target_selection=self._get_param("targetSelection"), + job_executions_rollout_config=self._get_param("jobExecutionsRolloutConfig"), + document_parameters=self._get_param("documentParameters") + ) + + return json.dumps(dict(jobArn=job_arn, jobId=job_id, description=description)) + + def describe_job(self): + job = self.iot_backend.describe_job(job_id=self._get_param("jobId")) + return json.dumps(dict( + documentSource=job.document_source, + job=dict( + comment=job.comment, + completedAt=job.completed_at, + createdAt=job.created_at, + description=job.description, + documentParameters=job.document_parameters, + jobArn=job.job_arn, + jobExecutionsRolloutConfig=job.job_executions_rollout_config, + jobId=job.job_id, + jobProcessDetails=job.job_process_details, + lastUpdatedAt=job.last_updated_at, + presignedUrlConfig=job.presigned_url_config, + status=job.status, + targets=job.targets, + targetSelection=job.target_selection + ))) + def create_keys_and_certificate(self): set_as_active = self._get_bool_param("setAsActive") cert, key_pair = self.iot_backend.create_keys_and_certificate( diff --git a/scripts/implementation_coverage.py b/scripts/implementation_coverage.py index 13175e9d1..74ce9590d 100755 --- a/scripts/implementation_coverage.py +++ b/scripts/implementation_coverage.py @@ -1,5 +1,6 @@ #!/usr/bin/env python import moto +import os from botocore import xform_name from botocore.session import Session import boto3 @@ -42,8 +43,7 @@ def calculate_implementation_coverage(): return coverage -def print_implementation_coverage(): - coverage = calculate_implementation_coverage() +def print_implementation_coverage(coverage): for service_name in sorted(coverage): implemented = coverage.get(service_name)['implemented'] not_implemented = coverage.get(service_name)['not_implemented'] @@ -65,5 +65,37 @@ def print_implementation_coverage(): print("- [ ] {}".format(op)) +def write_implementation_coverage_to_file(coverage): + # try deleting the implementation coverage file + try: + os.remove("../IMPLEMENTATION_COVERAGE.md") + except OSError: + pass + + for service_name in sorted(coverage): + implemented = coverage.get(service_name)['implemented'] + not_implemented = coverage.get(service_name)['not_implemented'] + operations = sorted(implemented + not_implemented) + + if implemented and not_implemented: + percentage_implemented = int(100.0 * len(implemented) / (len(implemented) + len(not_implemented))) + elif implemented: + percentage_implemented = 100 + else: + percentage_implemented = 0 + + # rewrite the implementation coverage file with updated values + with open("../IMPLEMENTATION_COVERAGE.md", "a+") as file: + file.write("\n") + file.write("## {} - {}% implemented\n".format(service_name, percentage_implemented)) + for op in operations: + if op in implemented: + file.write("- [X] {}\n".format(op)) + else: + file.write("- [ ] {}\n".format(op)) + + if __name__ == '__main__': - print_implementation_coverage() + cov = calculate_implementation_coverage() + write_implementation_coverage_to_file(cov) + print_implementation_coverage(cov) diff --git a/tests/test_ecr/test_ecr_boto3.py b/tests/test_ecr/test_ecr_boto3.py index b4497ef60..7651dc832 100644 --- a/tests/test_ecr/test_ecr_boto3.py +++ b/tests/test_ecr/test_ecr_boto3.py @@ -418,7 +418,7 @@ def test_get_authorization_token_assume_region(): auth_token_response.should.contain('ResponseMetadata') auth_token_response['authorizationData'].should.equal([ { - 'authorizationToken': 'QVdTOnVzLWVhc3QtMS1hdXRoLXRva2Vu', + 'authorizationToken': 'QVdTOjAxMjM0NTY3ODkxMC1hdXRoLXRva2Vu', 'proxyEndpoint': 'https://012345678910.dkr.ecr.us-east-1.amazonaws.com', 'expiresAt': datetime(2015, 1, 1, tzinfo=tzlocal()) }, @@ -428,19 +428,19 @@ def test_get_authorization_token_assume_region(): @mock_ecr def test_get_authorization_token_explicit_regions(): client = boto3.client('ecr', region_name='us-east-1') - auth_token_response = client.get_authorization_token(registryIds=['us-east-1', 'us-west-1']) + auth_token_response = client.get_authorization_token(registryIds=['10987654321', '878787878787']) auth_token_response.should.contain('authorizationData') auth_token_response.should.contain('ResponseMetadata') auth_token_response['authorizationData'].should.equal([ { - 'authorizationToken': 'QVdTOnVzLWVhc3QtMS1hdXRoLXRva2Vu', - 'proxyEndpoint': 'https://012345678910.dkr.ecr.us-east-1.amazonaws.com', + 'authorizationToken': 'QVdTOjEwOTg3NjU0MzIxLWF1dGgtdG9rZW4=', + 'proxyEndpoint': 'https://10987654321.dkr.ecr.us-east-1.amazonaws.com', 'expiresAt': datetime(2015, 1, 1, tzinfo=tzlocal()), }, { - 'authorizationToken': 'QVdTOnVzLXdlc3QtMS1hdXRoLXRva2Vu', - 'proxyEndpoint': 'https://012345678910.dkr.ecr.us-west-1.amazonaws.com', + 'authorizationToken': 'QVdTOjg3ODc4Nzg3ODc4Ny1hdXRoLXRva2Vu', + 'proxyEndpoint': 'https://878787878787.dkr.ecr.us-east-1.amazonaws.com', 'expiresAt': datetime(2015, 1, 1, tzinfo=tzlocal()) } diff --git a/tests/test_iot/test_iot.py b/tests/test_iot/test_iot.py index e69e55fc0..19e11476b 100644 --- a/tests/test_iot/test_iot.py +++ b/tests/test_iot/test_iot.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import boto3 import sure # noqa +import json from moto import mock_iot @@ -96,6 +97,7 @@ def test_certs(): res = client.list_certificates() res.should.have.key('certificates').which.should.have.length_of(0) + @mock_iot def test_certs_create_inactive(): client = boto3.client('iot', region_name='ap-northeast-1') @@ -113,6 +115,7 @@ def test_certs_create_inactive(): cert_desc = cert['certificateDescription'] cert_desc.should.have.key('status').which.should.equal('ACTIVE') + @mock_iot def test_policy(): client = boto3.client('iot', region_name='ap-northeast-1') @@ -239,9 +242,9 @@ def test_thing_groups(): thing_group.should.have.key('thingGroupArn') thing_group = client.describe_thing_group(thingGroupName=group_name) - thing_group.should.have.key('thingGroupProperties')\ - .which.should.have.key('attributePayload')\ - .which.should.have.key('attributes') + thing_group.should.have.key('thingGroupProperties') \ + .which.should.have.key('attributePayload') \ + .which.should.have.key('attributes') res_props = thing_group['thingGroupProperties']['attributePayload']['attributes'] res_props.should.have.key('key1').which.should.equal('val01') res_props.should.have.key('Key02').which.should.equal('VAL2') @@ -260,9 +263,9 @@ def test_thing_groups(): thingGroupProperties=new_props ) thing_group = client.describe_thing_group(thingGroupName=group_name) - thing_group.should.have.key('thingGroupProperties')\ - .which.should.have.key('attributePayload')\ - .which.should.have.key('attributes') + thing_group.should.have.key('thingGroupProperties') \ + .which.should.have.key('attributePayload') \ + .which.should.have.key('attributes') res_props = thing_group['thingGroupProperties']['attributePayload']['attributes'] res_props.should.have.key('key1').which.should.equal('val01') res_props.should.have.key('Key02').which.should.equal('VAL2') @@ -282,9 +285,9 @@ def test_thing_groups(): thingGroupProperties=new_props ) thing_group = client.describe_thing_group(thingGroupName=group_name) - thing_group.should.have.key('thingGroupProperties')\ - .which.should.have.key('attributePayload')\ - .which.should.have.key('attributes') + thing_group.should.have.key('thingGroupProperties') \ + .which.should.have.key('attributePayload') \ + .which.should.have.key('attributes') res_props = thing_group['thingGroupProperties']['attributePayload']['attributes'] res_props.should.have.key('k4').which.should.equal('v4') res_props.should_not.have.key('key1') @@ -383,3 +386,135 @@ def test_thing_group_relations(): ) things.should.have.key('things') things['things'].should.have.length_of(0) + + +@mock_iot +def test_create_job(): + client = boto3.client('iot', region_name='eu-west-1') + name = "my-thing" + job_id = "TestJob" + # thing + thing = client.create_thing(thingName=name) + thing.should.have.key('thingName').which.should.equal(name) + thing.should.have.key('thingArn') + + # job document + job_document = { + "field": "value" + } + + job = client.create_job( + jobId=job_id, + targets=[thing["thingArn"]], + document=json.dumps(job_document), + description="Description", + presignedUrlConfig={ + 'roleArn': 'arn:aws:iam::1:role/service-role/iot_job_role', + 'expiresInSec': 123 + }, + targetSelection="CONTINUOUS", + jobExecutionsRolloutConfig={ + 'maximumPerMinute': 10 + } + ) + + job.should.have.key('jobId').which.should.equal(job_id) + job.should.have.key('jobArn') + job.should.have.key('description') + +@mock_iot +def test_describe_job(): + client = boto3.client('iot', region_name='eu-west-1') + name = "my-thing" + job_id = "TestJob" + # thing + thing = client.create_thing(thingName=name) + thing.should.have.key('thingName').which.should.equal(name) + thing.should.have.key('thingArn') + + job = client.create_job( + jobId=job_id, + targets=[thing["thingArn"]], + documentSource="https://s3-eu-west-1.amazonaws.com/bucket-name/job_document.json", + presignedUrlConfig={ + 'roleArn': 'arn:aws:iam::1:role/service-role/iot_job_role', + 'expiresInSec': 123 + }, + targetSelection="CONTINUOUS", + jobExecutionsRolloutConfig={ + 'maximumPerMinute': 10 + } + ) + + job.should.have.key('jobId').which.should.equal(job_id) + job.should.have.key('jobArn') + + job = client.describe_job(jobId=job_id) + job.should.have.key('documentSource') + job.should.have.key('job') + job.should.have.key('job').which.should.have.key("jobArn") + job.should.have.key('job').which.should.have.key("jobId").which.should.equal(job_id) + job.should.have.key('job').which.should.have.key("targets") + job.should.have.key('job').which.should.have.key("jobProcessDetails") + job.should.have.key('job').which.should.have.key("lastUpdatedAt") + job.should.have.key('job').which.should.have.key("createdAt") + job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig") + job.should.have.key('job').which.should.have.key("targetSelection").which.should.equal("CONTINUOUS") + job.should.have.key('job').which.should.have.key("presignedUrlConfig") + job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key( + "roleArn").which.should.equal('arn:aws:iam::1:role/service-role/iot_job_role') + job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key( + "expiresInSec").which.should.equal(123) + job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig").which.should.have.key( + "maximumPerMinute").which.should.equal(10) + + +@mock_iot +def test_describe_job_1(): + client = boto3.client('iot', region_name='eu-west-1') + name = "my-thing" + job_id = "TestJob" + # thing + thing = client.create_thing(thingName=name) + thing.should.have.key('thingName').which.should.equal(name) + thing.should.have.key('thingArn') + + # job document + job_document = { + "field": "value" + } + + job = client.create_job( + jobId=job_id, + targets=[thing["thingArn"]], + document=json.dumps(job_document), + presignedUrlConfig={ + 'roleArn': 'arn:aws:iam::1:role/service-role/iot_job_role', + 'expiresInSec': 123 + }, + targetSelection="CONTINUOUS", + jobExecutionsRolloutConfig={ + 'maximumPerMinute': 10 + } + ) + + job.should.have.key('jobId').which.should.equal(job_id) + job.should.have.key('jobArn') + + job = client.describe_job(jobId=job_id) + job.should.have.key('job') + job.should.have.key('job').which.should.have.key("jobArn") + job.should.have.key('job').which.should.have.key("jobId").which.should.equal(job_id) + job.should.have.key('job').which.should.have.key("targets") + job.should.have.key('job').which.should.have.key("jobProcessDetails") + job.should.have.key('job').which.should.have.key("lastUpdatedAt") + job.should.have.key('job').which.should.have.key("createdAt") + job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig") + job.should.have.key('job').which.should.have.key("targetSelection").which.should.equal("CONTINUOUS") + job.should.have.key('job').which.should.have.key("presignedUrlConfig") + job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key( + "roleArn").which.should.equal('arn:aws:iam::1:role/service-role/iot_job_role') + job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key( + "expiresInSec").which.should.equal(123) + job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig").which.should.have.key( + "maximumPerMinute").which.should.equal(10)