Merge pull request #1687 from sthuber90/master

Fix ECR and bug fixes
This commit is contained in:
Steve Pulec 2018-09-22 16:40:33 -04:00 committed by GitHub
commit 693c677b87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 379 additions and 51 deletions

View File

@ -4,12 +4,12 @@ import hashlib
from copy import copy from copy import copy
from random import random from random import random
from botocore.exceptions import ParamValidationError
from moto.core import BaseBackend, BaseModel from moto.core import BaseBackend, BaseModel
from moto.ec2 import ec2_backends from moto.ec2 import ec2_backends
from moto.ecr.exceptions import ImageNotFoundException, RepositoryNotFoundException from moto.ecr.exceptions import ImageNotFoundException, RepositoryNotFoundException
from botocore.exceptions import ParamValidationError
DEFAULT_REGISTRY_ID = '012345678910' DEFAULT_REGISTRY_ID = '012345678910'
@ -97,13 +97,14 @@ class Repository(BaseObject):
class Image(BaseObject): class Image(BaseObject):
def __init__(self, tag, manifest, repository, registry_id=DEFAULT_REGISTRY_ID): def __init__(self, tag, manifest, repository, digest=None, registry_id=DEFAULT_REGISTRY_ID):
self.image_tag = tag self.image_tag = tag
self.image_tags = [tag] if tag is not None else []
self.image_manifest = manifest self.image_manifest = manifest
self.image_size_in_bytes = 50 * 1024 * 1024 self.image_size_in_bytes = 50 * 1024 * 1024
self.repository = repository self.repository = repository
self.registry_id = registry_id self.registry_id = registry_id
self.image_digest = None self.image_digest = digest
self.image_pushed_at = None self.image_pushed_at = None
def _create_digest(self): def _create_digest(self):
@ -115,6 +116,14 @@ class Image(BaseObject):
self._create_digest() self._create_digest()
return self.image_digest return self.image_digest
def get_image_manifest(self):
return self.image_manifest
def update_tag(self, tag):
self.image_tag = tag
if tag not in self.image_tags and tag is not None:
self.image_tags.append(tag)
@property @property
def response_object(self): def response_object(self):
response_object = self.gen_response_object() response_object = self.gen_response_object()
@ -124,26 +133,26 @@ class Image(BaseObject):
response_object['imageManifest'] = self.image_manifest response_object['imageManifest'] = self.image_manifest
response_object['repositoryName'] = self.repository response_object['repositoryName'] = self.repository
response_object['registryId'] = self.registry_id response_object['registryId'] = self.registry_id
return response_object return {k: v for k, v in response_object.items() if v is not None and v != [None]}
@property @property
def response_list_object(self): def response_list_object(self):
response_object = self.gen_response_object() response_object = self.gen_response_object()
response_object['imageTag'] = self.image_tag response_object['imageTag'] = self.image_tag
response_object['imageDigest'] = "i don't know" response_object['imageDigest'] = "i don't know"
return response_object return {k: v for k, v in response_object.items() if v is not None and v != [None]}
@property @property
def response_describe_object(self): def response_describe_object(self):
response_object = self.gen_response_object() response_object = self.gen_response_object()
response_object['imageTags'] = [self.image_tag] response_object['imageTags'] = self.image_tags
response_object['imageDigest'] = self.get_image_digest() response_object['imageDigest'] = self.get_image_digest()
response_object['imageManifest'] = self.image_manifest response_object['imageManifest'] = self.image_manifest
response_object['repositoryName'] = self.repository response_object['repositoryName'] = self.repository
response_object['registryId'] = self.registry_id response_object['registryId'] = self.registry_id
response_object['imageSizeInBytes'] = self.image_size_in_bytes response_object['imageSizeInBytes'] = self.image_size_in_bytes
response_object['imagePushedAt'] = '2017-05-09' response_object['imagePushedAt'] = '2017-05-09'
return response_object return {k: v for k, v in response_object.items() if v is not None and v != []}
@property @property
def response_batch_get_image(self): def response_batch_get_image(self):
@ -154,7 +163,7 @@ class Image(BaseObject):
response_object['imageManifest'] = self.image_manifest response_object['imageManifest'] = self.image_manifest
response_object['repositoryName'] = self.repository response_object['repositoryName'] = self.repository
response_object['registryId'] = self.registry_id response_object['registryId'] = self.registry_id
return response_object return {k: v for k, v in response_object.items() if v is not None and v != [None]}
class ECRBackend(BaseBackend): class ECRBackend(BaseBackend):
@ -231,7 +240,7 @@ class ECRBackend(BaseBackend):
found = False found = False
for image in repository.images: for image in repository.images:
if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or
('imageTag' in image_id and image.image_tag == image_id['imageTag'])): ('imageTag' in image_id and image_id['imageTag'] in image.image_tags)):
found = True found = True
response.add(image) response.add(image)
if not found: if not found:
@ -257,9 +266,16 @@ class ECRBackend(BaseBackend):
else: else:
raise Exception("{0} is not a repository".format(repository_name)) raise Exception("{0} is not a repository".format(repository_name))
image = Image(image_tag, image_manifest, repository_name) existing_images = list(filter(lambda x: x.response_object['imageManifest'] == image_manifest, repository.images))
repository.images.append(image) if not existing_images:
return image # this image is not in ECR yet
image = Image(image_tag, image_manifest, repository_name)
repository.images.append(image)
return image
else:
# update existing image
existing_images[0].update_tag(image_tag)
return existing_images[0]
def batch_get_image(self, repository_name, registry_id=None, image_ids=None, accepted_media_types=None): def batch_get_image(self, repository_name, registry_id=None, image_ids=None, accepted_media_types=None):
if repository_name in self.repositories: if repository_name in self.repositories:

View File

@ -1,14 +1,17 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import time
import boto3
import string
import random
import hashlib import hashlib
import uuid import random
import re import re
from datetime import datetime import string
from moto.core import BaseBackend, BaseModel import time
import uuid
from collections import OrderedDict from collections import OrderedDict
from datetime import datetime
import boto3
from moto.core import BaseBackend, BaseModel
from .exceptions import ( from .exceptions import (
ResourceNotFoundException, ResourceNotFoundException,
InvalidRequestException, InvalidRequestException,
@ -271,15 +274,37 @@ class IoTBackend(BaseBackend):
def list_thing_types(self, thing_type_name=None): def list_thing_types(self, thing_type_name=None):
if thing_type_name: if thing_type_name:
# It's wierd but thing_type_name is filterd by forward match, not complete match # It's weird but thing_type_name is filtered by forward match, not complete match
return [_ for _ in self.thing_types.values() if _.thing_type_name.startswith(thing_type_name)] return [_ for _ in self.thing_types.values() if _.thing_type_name.startswith(thing_type_name)]
thing_types = self.thing_types.values() return self.thing_types.values()
return thing_types
def list_things(self, attribute_name, attribute_value, thing_type_name): def list_things(self, attribute_name, attribute_value, thing_type_name, max_results, token):
# TODO: filter by attributess or thing_type all_things = [_.to_dict() for _ in self.things.values()]
things = self.things.values() if attribute_name is not None and thing_type_name is not None:
return things filtered_things = list(filter(lambda elem:
attribute_name in elem["attributes"] and
elem["attributes"][attribute_name] == attribute_value and
"thingTypeName" in elem and
elem["thingTypeName"] == thing_type_name, all_things))
elif attribute_name is not None and thing_type_name is None:
filtered_things = list(filter(lambda elem:
attribute_name in elem["attributes"] and
elem["attributes"][attribute_name] == attribute_value, all_things))
elif attribute_name is None and thing_type_name is not None:
filtered_things = list(
filter(lambda elem: "thingTypeName" in elem and elem["thingTypeName"] == thing_type_name, all_things))
else:
filtered_things = all_things
if token is None:
things = filtered_things[0:max_results]
next_token = str(max_results) if len(filtered_things) > max_results else None
else:
token = int(token)
things = filtered_things[token:token + max_results]
next_token = str(token + max_results) if len(filtered_things) > token + max_results else None
return things, next_token
def describe_thing(self, thing_name): def describe_thing(self, thing_name):
things = [_ for _ in self.things.values() if _.thing_name == thing_name] things = [_ for _ in self.things.values() if _.thing_name == thing_name]

View File

@ -1,7 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json
from moto.core.responses import BaseResponse from moto.core.responses import BaseResponse
from .models import iot_backends from .models import iot_backends
import json
class IoTResponse(BaseResponse): class IoTResponse(BaseResponse):
@ -32,30 +34,39 @@ class IoTResponse(BaseResponse):
return json.dumps(dict(thingTypeName=thing_type_name, thingTypeArn=thing_type_arn)) return json.dumps(dict(thingTypeName=thing_type_name, thingTypeArn=thing_type_arn))
def list_thing_types(self): def list_thing_types(self):
# previous_next_token = self._get_param("nextToken") previous_next_token = self._get_param("nextToken")
# max_results = self._get_int_param("maxResults") max_results = self._get_int_param("maxResults", 50) # not the default, but makes testing easier
thing_type_name = self._get_param("thingTypeName") thing_type_name = self._get_param("thingTypeName")
thing_types = self.iot_backend.list_thing_types( thing_types = self.iot_backend.list_thing_types(
thing_type_name=thing_type_name thing_type_name=thing_type_name
) )
# TODO: implement pagination in the future
next_token = None thing_types = [_.to_dict() for _ in thing_types]
return json.dumps(dict(thingTypes=[_.to_dict() for _ in thing_types], nextToken=next_token)) if previous_next_token is None:
result = thing_types[0:max_results]
next_token = str(max_results) if len(thing_types) > max_results else None
else:
token = int(previous_next_token)
result = thing_types[token:token + max_results]
next_token = str(token + max_results) if len(thing_types) > token + max_results else None
return json.dumps(dict(thingTypes=result, nextToken=next_token))
def list_things(self): def list_things(self):
# previous_next_token = self._get_param("nextToken") previous_next_token = self._get_param("nextToken")
# max_results = self._get_int_param("maxResults") max_results = self._get_int_param("maxResults", 50) # not the default, but makes testing easier
attribute_name = self._get_param("attributeName") attribute_name = self._get_param("attributeName")
attribute_value = self._get_param("attributeValue") attribute_value = self._get_param("attributeValue")
thing_type_name = self._get_param("thingTypeName") thing_type_name = self._get_param("thingTypeName")
things = self.iot_backend.list_things( things, next_token = self.iot_backend.list_things(
attribute_name=attribute_name, attribute_name=attribute_name,
attribute_value=attribute_value, attribute_value=attribute_value,
thing_type_name=thing_type_name, thing_type_name=thing_type_name,
max_results=max_results,
token=previous_next_token
) )
# TODO: implement pagination in the future
next_token = None return json.dumps(dict(things=things, nextToken=next_token))
return json.dumps(dict(things=[_.to_dict() for _ in things], nextToken=next_token))
def describe_thing(self): def describe_thing(self):
thing_name = self._get_param("thingName") thing_name = self._get_param("thingName")

View File

@ -10,12 +10,13 @@ script_dir = os.path.dirname(os.path.abspath(__file__))
def get_moto_implementation(service_name): def get_moto_implementation(service_name):
if not hasattr(moto, service_name): service_name_standardized = service_name.replace("-", "") if "-" in service_name else service_name
if not hasattr(moto, service_name_standardized):
return None return None
module = getattr(moto, service_name) module = getattr(moto, service_name_standardized)
if module is None: if module is None:
return None return None
mock = getattr(module, "mock_{}".format(service_name)) mock = getattr(module, "mock_{}".format(service_name_standardized))
if mock is None: if mock is None:
return None return None
backends = list(mock().backends.values()) backends = list(mock().backends.values())

View File

@ -45,7 +45,8 @@ def _create_image_manifest():
{ {
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 73109, "size": 73109,
"digest": _create_image_digest("layer3") # randomize image digest
"digest": _create_image_digest()
} }
] ]
} }
@ -197,6 +198,47 @@ def test_put_image():
response['image']['repositoryName'].should.equal('test_repository') response['image']['repositoryName'].should.equal('test_repository')
response['image']['registryId'].should.equal('012345678910') response['image']['registryId'].should.equal('012345678910')
@mock_ecr
def test_put_image_with_multiple_tags():
client = boto3.client('ecr', region_name='us-east-1')
_ = client.create_repository(
repositoryName='test_repository'
)
manifest = _create_image_manifest()
response = client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(manifest),
imageTag='v1'
)
response['image']['imageId']['imageTag'].should.equal('v1')
response['image']['imageId']['imageDigest'].should.contain("sha")
response['image']['repositoryName'].should.equal('test_repository')
response['image']['registryId'].should.equal('012345678910')
response1 = client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(manifest),
imageTag='latest'
)
response1['image']['imageId']['imageTag'].should.equal('latest')
response1['image']['imageId']['imageDigest'].should.contain("sha")
response1['image']['repositoryName'].should.equal('test_repository')
response1['image']['registryId'].should.equal('012345678910')
response2 = client.describe_images(repositoryName='test_repository')
type(response2['imageDetails']).should.be(list)
len(response2['imageDetails']).should.be(1)
response2['imageDetails'][0]['imageDigest'].should.contain("sha")
response2['imageDetails'][0]['registryId'].should.equal("012345678910")
response2['imageDetails'][0]['repositoryName'].should.equal("test_repository")
len(response2['imageDetails'][0]['imageTags']).should.be(2)
response2['imageDetails'][0]['imageTags'].should.be.equal(['v1', 'latest'])
@mock_ecr @mock_ecr
def test_list_images(): def test_list_images():
@ -281,6 +323,11 @@ def test_describe_images():
repositoryName='test_repository' repositoryName='test_repository'
) )
_ = client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(_create_image_manifest())
)
_ = client.put_image( _ = client.put_image(
repositoryName='test_repository', repositoryName='test_repository',
imageManifest=json.dumps(_create_image_manifest()), imageManifest=json.dumps(_create_image_manifest()),
@ -301,32 +348,37 @@ def test_describe_images():
response = client.describe_images(repositoryName='test_repository') response = client.describe_images(repositoryName='test_repository')
type(response['imageDetails']).should.be(list) type(response['imageDetails']).should.be(list)
len(response['imageDetails']).should.be(3) len(response['imageDetails']).should.be(4)
response['imageDetails'][0]['imageDigest'].should.contain("sha") response['imageDetails'][0]['imageDigest'].should.contain("sha")
response['imageDetails'][1]['imageDigest'].should.contain("sha") response['imageDetails'][1]['imageDigest'].should.contain("sha")
response['imageDetails'][2]['imageDigest'].should.contain("sha") response['imageDetails'][2]['imageDigest'].should.contain("sha")
response['imageDetails'][3]['imageDigest'].should.contain("sha")
response['imageDetails'][0]['registryId'].should.equal("012345678910") response['imageDetails'][0]['registryId'].should.equal("012345678910")
response['imageDetails'][1]['registryId'].should.equal("012345678910") response['imageDetails'][1]['registryId'].should.equal("012345678910")
response['imageDetails'][2]['registryId'].should.equal("012345678910") response['imageDetails'][2]['registryId'].should.equal("012345678910")
response['imageDetails'][3]['registryId'].should.equal("012345678910")
response['imageDetails'][0]['repositoryName'].should.equal("test_repository") response['imageDetails'][0]['repositoryName'].should.equal("test_repository")
response['imageDetails'][1]['repositoryName'].should.equal("test_repository") response['imageDetails'][1]['repositoryName'].should.equal("test_repository")
response['imageDetails'][2]['repositoryName'].should.equal("test_repository") response['imageDetails'][2]['repositoryName'].should.equal("test_repository")
response['imageDetails'][3]['repositoryName'].should.equal("test_repository")
len(response['imageDetails'][0]['imageTags']).should.be(1) response['imageDetails'][0].should_not.have.key('imageTags')
len(response['imageDetails'][1]['imageTags']).should.be(1) len(response['imageDetails'][1]['imageTags']).should.be(1)
len(response['imageDetails'][2]['imageTags']).should.be(1) len(response['imageDetails'][2]['imageTags']).should.be(1)
len(response['imageDetails'][3]['imageTags']).should.be(1)
image_tags = ['latest', 'v1', 'v2'] image_tags = ['latest', 'v1', 'v2']
set([response['imageDetails'][0]['imageTags'][0], set([response['imageDetails'][1]['imageTags'][0],
response['imageDetails'][1]['imageTags'][0], response['imageDetails'][2]['imageTags'][0],
response['imageDetails'][2]['imageTags'][0]]).should.equal(set(image_tags)) response['imageDetails'][3]['imageTags'][0]]).should.equal(set(image_tags))
response['imageDetails'][0]['imageSizeInBytes'].should.equal(52428800) response['imageDetails'][0]['imageSizeInBytes'].should.equal(52428800)
response['imageDetails'][1]['imageSizeInBytes'].should.equal(52428800) response['imageDetails'][1]['imageSizeInBytes'].should.equal(52428800)
response['imageDetails'][2]['imageSizeInBytes'].should.equal(52428800) response['imageDetails'][2]['imageSizeInBytes'].should.equal(52428800)
response['imageDetails'][3]['imageSizeInBytes'].should.equal(52428800)
@mock_ecr @mock_ecr
@ -355,6 +407,68 @@ def test_describe_images_by_tag():
image_detail['imageDigest'].should.equal(put_response['imageId']['imageDigest']) image_detail['imageDigest'].should.equal(put_response['imageId']['imageDigest'])
@mock_ecr
def test_describe_images_tags_should_not_contain_empty_tag1():
client = boto3.client('ecr', region_name='us-east-1')
_ = client.create_repository(
repositoryName='test_repository'
)
manifest = _create_image_manifest()
client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(manifest)
)
tags = ['v1', 'v2', 'latest']
for tag in tags:
client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(manifest),
imageTag=tag
)
response = client.describe_images(repositoryName='test_repository', imageIds=[{'imageTag': tag}])
len(response['imageDetails']).should.be(1)
image_detail = response['imageDetails'][0]
len(image_detail['imageTags']).should.equal(3)
image_detail['imageTags'].should.be.equal(tags)
@mock_ecr
def test_describe_images_tags_should_not_contain_empty_tag2():
client = boto3.client('ecr', region_name='us-east-1')
_ = client.create_repository(
repositoryName='test_repository'
)
manifest = _create_image_manifest()
tags = ['v1', 'v2']
for tag in tags:
client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(manifest),
imageTag=tag
)
client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(manifest)
)
client.put_image(
repositoryName='test_repository',
imageManifest=json.dumps(manifest),
imageTag='latest'
)
response = client.describe_images(repositoryName='test_repository', imageIds=[{'imageTag': tag}])
len(response['imageDetails']).should.be(1)
image_detail = response['imageDetails'][0]
len(image_detail['imageTags']).should.equal(3)
image_detail['imageTags'].should.be.equal(['v1', 'v2', 'latest'])
@mock_ecr @mock_ecr
def test_describe_repository_that_doesnt_exist(): def test_describe_repository_that_doesnt_exist():
client = boto3.client('ecr', region_name='us-east-1') client = boto3.client('ecr', region_name='us-east-1')

View File

@ -1,8 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import boto3
import sure # noqa
import json import json
import sure # noqa
import boto3
from moto import mock_iot from moto import mock_iot
@ -63,6 +64,166 @@ def test_things():
res.should.have.key('thingTypes').which.should.have.length_of(0) res.should.have.key('thingTypes').which.should.have.length_of(0)
@mock_iot
def test_list_thing_types():
client = boto3.client('iot', region_name='ap-northeast-1')
for i in range(0, 100):
client.create_thing_type(thingTypeName=str(i + 1))
thing_types = client.list_thing_types()
thing_types.should.have.key('nextToken')
thing_types.should.have.key('thingTypes').which.should.have.length_of(50)
thing_types['thingTypes'][0]['thingTypeName'].should.equal('1')
thing_types['thingTypes'][-1]['thingTypeName'].should.equal('50')
thing_types = client.list_thing_types(nextToken=thing_types['nextToken'])
thing_types.should.have.key('thingTypes').which.should.have.length_of(50)
thing_types.should_not.have.key('nextToken')
thing_types['thingTypes'][0]['thingTypeName'].should.equal('51')
thing_types['thingTypes'][-1]['thingTypeName'].should.equal('100')
@mock_iot
def test_list_thing_types_with_typename_filter():
client = boto3.client('iot', region_name='ap-northeast-1')
client.create_thing_type(thingTypeName='thing')
client.create_thing_type(thingTypeName='thingType')
client.create_thing_type(thingTypeName='thingTypeName')
client.create_thing_type(thingTypeName='thingTypeNameGroup')
client.create_thing_type(thingTypeName='shouldNotFind')
client.create_thing_type(thingTypeName='find me it shall not')
thing_types = client.list_thing_types(thingTypeName='thing')
thing_types.should_not.have.key('nextToken')
thing_types.should.have.key('thingTypes').which.should.have.length_of(4)
thing_types['thingTypes'][0]['thingTypeName'].should.equal('thing')
thing_types['thingTypes'][-1]['thingTypeName'].should.equal('thingTypeNameGroup')
thing_types = client.list_thing_types(thingTypeName='thingTypeName')
thing_types.should_not.have.key('nextToken')
thing_types.should.have.key('thingTypes').which.should.have.length_of(2)
thing_types['thingTypes'][0]['thingTypeName'].should.equal('thingTypeName')
thing_types['thingTypes'][-1]['thingTypeName'].should.equal('thingTypeNameGroup')
@mock_iot
def test_list_things_with_next_token():
client = boto3.client('iot', region_name='ap-northeast-1')
for i in range(0, 200):
client.create_thing(thingName=str(i + 1))
things = client.list_things()
things.should.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(50)
things['things'][0]['thingName'].should.equal('1')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/1')
things['things'][-1]['thingName'].should.equal('50')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/50')
things = client.list_things(nextToken=things['nextToken'])
things.should.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(50)
things['things'][0]['thingName'].should.equal('51')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/51')
things['things'][-1]['thingName'].should.equal('100')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/100')
things = client.list_things(nextToken=things['nextToken'])
things.should.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(50)
things['things'][0]['thingName'].should.equal('101')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/101')
things['things'][-1]['thingName'].should.equal('150')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/150')
things = client.list_things(nextToken=things['nextToken'])
things.should_not.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(50)
things['things'][0]['thingName'].should.equal('151')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/151')
things['things'][-1]['thingName'].should.equal('200')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/200')
@mock_iot
def test_list_things_with_attribute_and_thing_type_filter_and_next_token():
client = boto3.client('iot', region_name='ap-northeast-1')
client.create_thing_type(thingTypeName='my-thing-type')
for i in range(0, 200):
if not (i + 1) % 3:
attribute_payload = {
'attributes': {
'foo': 'bar'
}
}
elif not (i + 1) % 5:
attribute_payload = {
'attributes': {
'bar': 'foo'
}
}
else:
attribute_payload = {}
if not (i + 1) % 2:
thing_type_name = 'my-thing-type'
client.create_thing(thingName=str(i + 1), thingTypeName=thing_type_name, attributePayload=attribute_payload)
else:
client.create_thing(thingName=str(i + 1), attributePayload=attribute_payload)
# Test filter for thingTypeName
things = client.list_things(thingTypeName=thing_type_name)
things.should.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(50)
things['things'][0]['thingName'].should.equal('2')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/2')
things['things'][-1]['thingName'].should.equal('100')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/100')
all(item['thingTypeName'] == thing_type_name for item in things['things'])
things = client.list_things(nextToken=things['nextToken'], thingTypeName=thing_type_name)
things.should_not.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(50)
things['things'][0]['thingName'].should.equal('102')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/102')
things['things'][-1]['thingName'].should.equal('200')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/200')
all(item['thingTypeName'] == thing_type_name for item in things['things'])
# Test filter for attributes
things = client.list_things(attributeName='foo', attributeValue='bar')
things.should.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(50)
things['things'][0]['thingName'].should.equal('3')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/3')
things['things'][-1]['thingName'].should.equal('150')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/150')
all(item['attributes'] == {'foo': 'bar'} for item in things['things'])
things = client.list_things(nextToken=things['nextToken'], attributeName='foo', attributeValue='bar')
things.should_not.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(16)
things['things'][0]['thingName'].should.equal('153')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/153')
things['things'][-1]['thingName'].should.equal('198')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/198')
all(item['attributes'] == {'foo': 'bar'} for item in things['things'])
# Test filter for attributes and thingTypeName
things = client.list_things(thingTypeName=thing_type_name, attributeName='foo', attributeValue='bar')
things.should_not.have.key('nextToken')
things.should.have.key('things').which.should.have.length_of(33)
things['things'][0]['thingName'].should.equal('6')
things['things'][0]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/6')
things['things'][-1]['thingName'].should.equal('198')
things['things'][-1]['thingArn'].should.equal('arn:aws:iot:ap-northeast-1:1:thing/198')
all(item['attributes'] == {'foo': 'bar'} and item['thingTypeName'] == thing_type_name for item in things['things'])
@mock_iot @mock_iot
def test_certs(): def test_certs():
client = boto3.client('iot', region_name='ap-northeast-1') client = boto3.client('iot', region_name='ap-northeast-1')
@ -204,7 +365,6 @@ def test_principal_thing():
@mock_iot @mock_iot
def test_thing_groups(): def test_thing_groups():
client = boto3.client('iot', region_name='ap-northeast-1') client = boto3.client('iot', region_name='ap-northeast-1')
name = 'my-thing'
group_name = 'my-group-name' group_name = 'my-group-name'
# thing group # thing group
@ -424,6 +584,7 @@ def test_create_job():
job.should.have.key('jobArn') job.should.have.key('jobArn')
job.should.have.key('description') job.should.have.key('description')
@mock_iot @mock_iot
def test_describe_job(): def test_describe_job():
client = boto3.client('iot', region_name='eu-west-1') client = boto3.client('iot', region_name='eu-west-1')