import datetime import time import pytest import boto.kinesis import boto3 from boto.kinesis.exceptions import ResourceNotFoundException, InvalidArgumentException from botocore.exceptions import ClientError from dateutil.tz import tzlocal from moto import mock_kinesis, mock_kinesis_deprecated from moto.core import ACCOUNT_ID import sure # noqa # pylint: disable=unused-import # Has boto3 equivalent @mock_kinesis_deprecated def test_create_cluster(): conn = boto.kinesis.connect_to_region("us-west-2") conn.create_stream("my_stream", 3) stream_response = conn.describe_stream("my_stream") stream = stream_response["StreamDescription"] stream["StreamName"].should.equal("my_stream") stream["HasMoreShards"].should.equal(False) stream["StreamARN"].should.equal( "arn:aws:kinesis:us-west-2:{}:my_stream".format(ACCOUNT_ID) ) stream["StreamStatus"].should.equal("ACTIVE") shards = stream["Shards"] shards.should.have.length_of(3) # Has boto3 equivalent @mock_kinesis_deprecated def test_describe_non_existent_stream(): conn = boto.kinesis.connect_to_region("us-east-1") conn.describe_stream.when.called_with("not-a-stream").should.throw( ResourceNotFoundException ) @mock_kinesis def test_describe_non_existent_stream_boto3(): client = boto3.client("kinesis", region_name="us-west-2") with pytest.raises(ClientError) as exc: client.describe_stream_summary(StreamName="not-a-stream") err = exc.value.response["Error"] err["Code"].should.equal("ResourceNotFoundException") err["Message"].should.equal( "Stream not-a-stream under account 123456789012 not found." ) # Has boto3 equivalent @mock_kinesis_deprecated def test_list_and_delete_stream(): conn = boto.kinesis.connect_to_region("us-west-2") conn.create_stream("stream1", 1) conn.create_stream("stream2", 1) conn.list_streams()["StreamNames"].should.have.length_of(2) conn.delete_stream("stream2") conn.list_streams()["StreamNames"].should.have.length_of(1) # Delete invalid id conn.delete_stream.when.called_with("not-a-stream").should.throw( ResourceNotFoundException ) @mock_kinesis def test_list_and_delete_stream_boto3(): client = boto3.client("kinesis", region_name="us-west-2") client.list_streams()["StreamNames"].should.have.length_of(0) client.create_stream(StreamName="stream1", ShardCount=1) client.create_stream(StreamName="stream2", ShardCount=1) client.list_streams()["StreamNames"].should.have.length_of(2) client.delete_stream(StreamName="stream1") client.list_streams()["StreamNames"].should.have.length_of(1) @mock_kinesis def test_delete_unknown_stream(): client = boto3.client("kinesis", region_name="us-west-2") with pytest.raises(ClientError) as exc: client.delete_stream(StreamName="not-a-stream") err = exc.value.response["Error"] err["Code"].should.equal("ResourceNotFoundException") err["Message"].should.equal( "Stream not-a-stream under account 123456789012 not found." ) @mock_kinesis def test_list_many_streams(): conn = boto3.client("kinesis", region_name="us-west-2") for i in range(11): conn.create_stream(StreamName="stream%d" % i, ShardCount=1) resp = conn.list_streams() stream_names = resp["StreamNames"] has_more_streams = resp["HasMoreStreams"] stream_names.should.have.length_of(10) has_more_streams.should.be(True) resp2 = conn.list_streams(ExclusiveStartStreamName=stream_names[-1]) stream_names = resp2["StreamNames"] has_more_streams = resp2["HasMoreStreams"] stream_names.should.have.length_of(1) has_more_streams.should.equal(False) @mock_kinesis def test_describe_stream_summary(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream_summary" shard_count = 5 conn.create_stream(StreamName=stream_name, ShardCount=shard_count) resp = conn.describe_stream_summary(StreamName=stream_name) stream = resp["StreamDescriptionSummary"] stream["StreamName"].should.equal(stream_name) stream["OpenShardCount"].should.equal(shard_count) stream["StreamARN"].should.equal( "arn:aws:kinesis:us-west-2:{}:{}".format(ACCOUNT_ID, stream_name) ) stream["StreamStatus"].should.equal("ACTIVE") # Has boto3 equivalent @mock_kinesis_deprecated def test_basic_shard_iterator(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) response = conn.describe_stream(stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator(stream_name, shard_id, "TRIM_HORIZON") shard_iterator = response["ShardIterator"] response = conn.get_records(shard_iterator) shard_iterator = response["NextShardIterator"] response["Records"].should.equal([]) response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_basic_shard_iterator_boto3(): client = boto3.client("kinesis", region_name="us-west-1") stream_name = "mystream" client.create_stream(StreamName=stream_name, ShardCount=1) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shard_id = stream["Shards"][0]["ShardId"] resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="TRIM_HORIZON" ) shard_iterator = resp["ShardIterator"] resp = client.get_records(ShardIterator=shard_iterator) resp.should.have.key("Records").length_of(0) resp.should.have.key("MillisBehindLatest").equal(0) # Has boto3 equivalent @mock_kinesis_deprecated def test_get_invalid_shard_iterator(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) conn.get_shard_iterator.when.called_with( stream_name, "123", "TRIM_HORIZON" ).should.throw(ResourceNotFoundException) @mock_kinesis def test_get_invalid_shard_iterator_boto3(): client = boto3.client("kinesis", region_name="us-west-1") stream_name = "mystream" client.create_stream(StreamName=stream_name, ShardCount=1) with pytest.raises(ClientError) as exc: client.get_shard_iterator( StreamName=stream_name, ShardId="123", ShardIteratorType="TRIM_HORIZON" ) err = exc.value.response["Error"] err["Code"].should.equal("ResourceNotFoundException") err["Message"].should.equal("Shard 123 under account 123456789012 not found.") # Has boto3 equivalent @mock_kinesis_deprecated def test_put_records(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) data = "hello world" partition_key = "1234" conn.put_record.when.called_with(stream_name, data, 1234).should.throw( InvalidArgumentException ) conn.put_record(stream_name, data, partition_key) response = conn.describe_stream(stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator(stream_name, shard_id, "TRIM_HORIZON") shard_iterator = response["ShardIterator"] response = conn.get_records(shard_iterator) shard_iterator = response["NextShardIterator"] response["Records"].should.have.length_of(1) record = response["Records"][0] record["Data"].should.equal("hello world") record["PartitionKey"].should.equal("1234") record["SequenceNumber"].should.equal("1") @mock_kinesis def test_put_records_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=1) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shard_id = stream["Shards"][0]["ShardId"] data = b"hello world" partition_key = "1234" client.put_record(StreamName=stream_name, Data=data, PartitionKey=partition_key) resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="TRIM_HORIZON" ) shard_iterator = resp["ShardIterator"] resp = client.get_records(ShardIterator=shard_iterator) resp["Records"].should.have.length_of(1) record = resp["Records"][0] record["Data"].should.equal(b"hello world") record["PartitionKey"].should.equal("1234") record["SequenceNumber"].should.equal("1") # Has boto3 equivalent @mock_kinesis_deprecated def test_get_records_limit(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) # Create some data data = "hello world" for index in range(5): conn.put_record(stream_name, data, str(index)) # Get a shard iterator response = conn.describe_stream(stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator(stream_name, shard_id, "TRIM_HORIZON") shard_iterator = response["ShardIterator"] # Retrieve only 3 records response = conn.get_records(shard_iterator, limit=3) response["Records"].should.have.length_of(3) # Then get the rest of the results next_shard_iterator = response["NextShardIterator"] response = conn.get_records(next_shard_iterator) response["Records"].should.have.length_of(2) @mock_kinesis def test_get_records_limit_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=1) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shard_id = stream["Shards"][0]["ShardId"] data = b"hello world" for index in range(5): client.put_record(StreamName=stream_name, Data=data, PartitionKey=str(index)) resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="TRIM_HORIZON" ) shard_iterator = resp["ShardIterator"] # Retrieve only 3 records resp = client.get_records(ShardIterator=shard_iterator, Limit=3) resp["Records"].should.have.length_of(3) # Then get the rest of the results next_shard_iterator = resp["NextShardIterator"] response = client.get_records(ShardIterator=next_shard_iterator) response["Records"].should.have.length_of(2) # Has boto3 equivalent @mock_kinesis_deprecated def test_get_records_at_sequence_number(): # AT_SEQUENCE_NUMBER - Start reading exactly from the position denoted by # a specific sequence number. conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) # Create some data for index in range(1, 5): conn.put_record(stream_name, str(index), str(index)) # Get a shard iterator response = conn.describe_stream(stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator(stream_name, shard_id, "TRIM_HORIZON") shard_iterator = response["ShardIterator"] # Get the second record response = conn.get_records(shard_iterator, limit=2) second_sequence_id = response["Records"][1]["SequenceNumber"] # Then get a new iterator starting at that id response = conn.get_shard_iterator( stream_name, shard_id, "AT_SEQUENCE_NUMBER", second_sequence_id ) shard_iterator = response["ShardIterator"] response = conn.get_records(shard_iterator) # And the first result returned should be the second item response["Records"][0]["SequenceNumber"].should.equal(second_sequence_id) response["Records"][0]["Data"].should.equal("2") @mock_kinesis def test_get_records_at_sequence_number_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=1) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shard_id = stream["Shards"][0]["ShardId"] for index in range(1, 5): client.put_record( StreamName=stream_name, Data=f"data_{index}".encode("utf-8"), PartitionKey=str(index), ) resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="TRIM_HORIZON" ) shard_iterator = resp["ShardIterator"] # Retrieve only 2 records resp = client.get_records(ShardIterator=shard_iterator, Limit=2) sequence_nr = resp["Records"][1]["SequenceNumber"] # Then get a new iterator starting at that id resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="AT_SEQUENCE_NUMBER", StartingSequenceNumber=sequence_nr, ) shard_iterator = resp["ShardIterator"] resp = client.get_records(ShardIterator=shard_iterator) # And the first result returned should be the second item resp["Records"][0]["SequenceNumber"].should.equal(sequence_nr) resp["Records"][0]["Data"].should.equal(b"data_2") # Has boto3 equivalent @mock_kinesis_deprecated def test_get_records_after_sequence_number(): # AFTER_SEQUENCE_NUMBER - Start reading right after the position denoted # by a specific sequence number. conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) # Create some data for index in range(1, 5): conn.put_record(stream_name, str(index), str(index)) # Get a shard iterator response = conn.describe_stream(stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator(stream_name, shard_id, "TRIM_HORIZON") shard_iterator = response["ShardIterator"] # Get the second record response = conn.get_records(shard_iterator, limit=2) second_sequence_id = response["Records"][1]["SequenceNumber"] # Then get a new iterator starting after that id response = conn.get_shard_iterator( stream_name, shard_id, "AFTER_SEQUENCE_NUMBER", second_sequence_id ) shard_iterator = response["ShardIterator"] response = conn.get_records(shard_iterator) # And the first result returned should be the third item response["Records"][0]["Data"].should.equal("3") response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_get_records_after_sequence_number_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=1) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shard_id = stream["Shards"][0]["ShardId"] for index in range(1, 5): client.put_record( StreamName=stream_name, Data=f"data_{index}".encode("utf-8"), PartitionKey=str(index), ) resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="TRIM_HORIZON" ) shard_iterator = resp["ShardIterator"] # Retrieve only 2 records resp = client.get_records(ShardIterator=shard_iterator, Limit=2) sequence_nr = resp["Records"][1]["SequenceNumber"] # Then get a new iterator starting at that id resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="AFTER_SEQUENCE_NUMBER", StartingSequenceNumber=sequence_nr, ) shard_iterator = resp["ShardIterator"] resp = client.get_records(ShardIterator=shard_iterator) # And the first result returned should be the second item resp["Records"][0]["SequenceNumber"].should.equal("3") resp["Records"][0]["Data"].should.equal(b"data_3") resp["MillisBehindLatest"].should.equal(0) # Has boto3 equivalent @mock_kinesis_deprecated def test_get_records_latest(): # LATEST - Start reading just after the most recent record in the shard, # so that you always read the most recent data in the shard. conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) # Create some data for index in range(1, 5): conn.put_record(stream_name, str(index), str(index)) # Get a shard iterator response = conn.describe_stream(stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator(stream_name, shard_id, "TRIM_HORIZON") shard_iterator = response["ShardIterator"] # Get the second record response = conn.get_records(shard_iterator, limit=2) second_sequence_id = response["Records"][1]["SequenceNumber"] # Then get a new iterator starting after that id response = conn.get_shard_iterator( stream_name, shard_id, "LATEST", second_sequence_id ) shard_iterator = response["ShardIterator"] # Write some more data conn.put_record(stream_name, "last_record", "last_record") response = conn.get_records(shard_iterator) # And the only result returned should be the new item response["Records"].should.have.length_of(1) response["Records"][0]["PartitionKey"].should.equal("last_record") response["Records"][0]["Data"].should.equal("last_record") response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_get_records_latest_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=1) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shard_id = stream["Shards"][0]["ShardId"] for index in range(1, 5): client.put_record( StreamName=stream_name, Data=f"data_{index}".encode("utf-8"), PartitionKey=str(index), ) resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="TRIM_HORIZON" ) shard_iterator = resp["ShardIterator"] # Retrieve only 2 records resp = client.get_records(ShardIterator=shard_iterator, Limit=2) sequence_nr = resp["Records"][1]["SequenceNumber"] # Then get a new iterator starting at that id resp = client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="LATEST", StartingSequenceNumber=sequence_nr, ) shard_iterator = resp["ShardIterator"] client.put_record( StreamName=stream_name, Data=b"last_record", PartitionKey="last_record" ) resp = client.get_records(ShardIterator=shard_iterator) # And the first result returned should be the second item resp["Records"].should.have.length_of(1) resp["Records"][0]["SequenceNumber"].should.equal("5") resp["Records"][0]["PartitionKey"].should.equal("last_record") resp["Records"][0]["Data"].should.equal(b"last_record") resp["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_get_records_at_timestamp(): # AT_TIMESTAMP - Read the first record at or after the specified timestamp conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) # Create some data for index in range(1, 5): conn.put_record( StreamName=stream_name, Data=str(index), PartitionKey=str(index) ) # When boto3 floors the timestamp that we pass to get_shard_iterator to # second precision even though AWS supports ms precision: # http://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html # To test around this limitation we wait until we well into the next second # before capturing the time and storing the records we expect to retrieve. time.sleep(1.0) timestamp = datetime.datetime.utcnow() keys = [str(i) for i in range(5, 10)] for k in keys: conn.put_record(StreamName=stream_name, Data=k, PartitionKey=k) # Get a shard iterator response = conn.describe_stream(StreamName=stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="AT_TIMESTAMP", Timestamp=timestamp, ) shard_iterator = response["ShardIterator"] response = conn.get_records(ShardIterator=shard_iterator) response["Records"].should.have.length_of(len(keys)) partition_keys = [r["PartitionKey"] for r in response["Records"]] partition_keys.should.equal(keys) response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_get_records_at_very_old_timestamp(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) # Create some data keys = [str(i) for i in range(1, 5)] for k in keys: conn.put_record(StreamName=stream_name, Data=k, PartitionKey=k) # Get a shard iterator response = conn.describe_stream(StreamName=stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="AT_TIMESTAMP", Timestamp=1, ) shard_iterator = response["ShardIterator"] response = conn.get_records(ShardIterator=shard_iterator) response["Records"].should.have.length_of(len(keys)) partition_keys = [r["PartitionKey"] for r in response["Records"]] partition_keys.should.equal(keys) response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_get_records_timestamp_filtering(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) conn.put_record(StreamName=stream_name, Data="0", PartitionKey="0") time.sleep(1.0) timestamp = datetime.datetime.now(tz=tzlocal()) conn.put_record(StreamName=stream_name, Data="1", PartitionKey="1") response = conn.describe_stream(StreamName=stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="AT_TIMESTAMP", Timestamp=timestamp, ) shard_iterator = response["ShardIterator"] response = conn.get_records(ShardIterator=shard_iterator) response["Records"].should.have.length_of(1) response["Records"][0]["PartitionKey"].should.equal("1") response["Records"][0]["ApproximateArrivalTimestamp"].should.be.greater_than( timestamp ) response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_get_records_millis_behind_latest(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) conn.put_record(StreamName=stream_name, Data="0", PartitionKey="0") time.sleep(1.0) conn.put_record(StreamName=stream_name, Data="1", PartitionKey="1") response = conn.describe_stream(StreamName=stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="TRIM_HORIZON" ) shard_iterator = response["ShardIterator"] response = conn.get_records(ShardIterator=shard_iterator, Limit=1) response["Records"].should.have.length_of(1) response["MillisBehindLatest"].should.be.greater_than(0) @mock_kinesis def test_get_records_at_very_new_timestamp(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) # Create some data keys = [str(i) for i in range(1, 5)] for k in keys: conn.put_record(StreamName=stream_name, Data=k, PartitionKey=k) timestamp = datetime.datetime.utcnow() + datetime.timedelta(seconds=1) # Get a shard iterator response = conn.describe_stream(StreamName=stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="AT_TIMESTAMP", Timestamp=timestamp, ) shard_iterator = response["ShardIterator"] response = conn.get_records(ShardIterator=shard_iterator) response["Records"].should.have.length_of(0) response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_get_records_from_empty_stream_at_timestamp(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) timestamp = datetime.datetime.utcnow() # Get a shard iterator response = conn.describe_stream(StreamName=stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="AT_TIMESTAMP", Timestamp=timestamp, ) shard_iterator = response["ShardIterator"] response = conn.get_records(ShardIterator=shard_iterator) response["Records"].should.have.length_of(0) response["MillisBehindLatest"].should.equal(0) @mock_kinesis def test_valid_increase_stream_retention_period(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) conn.increase_stream_retention_period( StreamName=stream_name, RetentionPeriodHours=40 ) response = conn.describe_stream(StreamName=stream_name) response["StreamDescription"]["RetentionPeriodHours"].should.equal(40) @mock_kinesis def test_invalid_increase_stream_retention_period(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "my_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) conn.increase_stream_retention_period( StreamName=stream_name, RetentionPeriodHours=30 ) with pytest.raises(ClientError) as ex: conn.increase_stream_retention_period( StreamName=stream_name, RetentionPeriodHours=20 ) ex.value.response["Error"]["Code"].should.equal("InvalidArgumentException") ex.value.response["Error"]["Message"].should.equal(20) @mock_kinesis def test_valid_decrease_stream_retention_period(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "decrease_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) conn.increase_stream_retention_period( StreamName=stream_name, RetentionPeriodHours=30 ) conn.decrease_stream_retention_period( StreamName=stream_name, RetentionPeriodHours=25 ) response = conn.describe_stream(StreamName=stream_name) response["StreamDescription"]["RetentionPeriodHours"].should.equal(25) @mock_kinesis def test_invalid_decrease_stream_retention_period(): conn = boto3.client("kinesis", region_name="us-west-2") stream_name = "decrease_stream" conn.create_stream(StreamName=stream_name, ShardCount=1) conn.increase_stream_retention_period( StreamName=stream_name, RetentionPeriodHours=30 ) with pytest.raises(ClientError) as ex: conn.decrease_stream_retention_period( StreamName=stream_name, RetentionPeriodHours=20 ) ex.value.response["Error"]["Code"].should.equal("InvalidArgumentException") ex.value.response["Error"]["Message"].should.equal(20) # Has boto3 equivalent @mock_kinesis_deprecated def test_invalid_shard_iterator_type(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) response = conn.describe_stream(stream_name) shard_id = response["StreamDescription"]["Shards"][0]["ShardId"] response = conn.get_shard_iterator.when.called_with( stream_name, shard_id, "invalid-type" ).should.throw(InvalidArgumentException) @mock_kinesis def test_invalid_shard_iterator_type_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=1) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shard_id = stream["Shards"][0]["ShardId"] with pytest.raises(ClientError) as exc: client.get_shard_iterator( StreamName=stream_name, ShardId=shard_id, ShardIteratorType="invalid-type" ) err = exc.value.response["Error"] err["Code"].should.equal("InvalidArgumentException") err["Message"].should.equal("Invalid ShardIteratorType: invalid-type") # Has boto3 equivalent @mock_kinesis_deprecated def test_add_tags(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) conn.describe_stream(stream_name) conn.add_tags_to_stream(stream_name, {"tag1": "val1"}) conn.add_tags_to_stream(stream_name, {"tag2": "val2"}) conn.add_tags_to_stream(stream_name, {"tag1": "val3"}) conn.add_tags_to_stream(stream_name, {"tag2": "val4"}) @mock_kinesis def test_add_list_remove_tags_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=1) client.add_tags_to_stream( StreamName=stream_name, Tags={"tag1": "val1", "tag2": "val2", "tag3": "val3", "tag4": "val4",}, ) tags = client.list_tags_for_stream(StreamName=stream_name)["Tags"] tags.should.have.length_of(4) tags.should.contain({"Key": "tag1", "Value": "val1"}) tags.should.contain({"Key": "tag2", "Value": "val2"}) tags.should.contain({"Key": "tag3", "Value": "val3"}) tags.should.contain({"Key": "tag4", "Value": "val4"}) client.add_tags_to_stream(StreamName=stream_name, Tags={"tag5": "val5"}) tags = client.list_tags_for_stream(StreamName=stream_name)["Tags"] tags.should.have.length_of(5) tags.should.contain({"Key": "tag5", "Value": "val5"}) client.remove_tags_from_stream(StreamName=stream_name, TagKeys=["tag2", "tag3"]) tags = client.list_tags_for_stream(StreamName=stream_name)["Tags"] tags.should.have.length_of(3) tags.should.contain({"Key": "tag1", "Value": "val1"}) tags.should.contain({"Key": "tag4", "Value": "val4"}) tags.should.contain({"Key": "tag5", "Value": "val5"}) # Has boto3 equivalent @mock_kinesis_deprecated def test_list_tags(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) conn.describe_stream(stream_name) conn.add_tags_to_stream(stream_name, {"tag1": "val1"}) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag1").should.equal("val1") conn.add_tags_to_stream(stream_name, {"tag2": "val2"}) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag2").should.equal("val2") conn.add_tags_to_stream(stream_name, {"tag1": "val3"}) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag1").should.equal("val3") conn.add_tags_to_stream(stream_name, {"tag2": "val4"}) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag2").should.equal("val4") # Has boto3 equivalent @mock_kinesis_deprecated def test_remove_tags(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 1) conn.describe_stream(stream_name) conn.add_tags_to_stream(stream_name, {"tag1": "val1"}) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag1").should.equal("val1") conn.remove_tags_from_stream(stream_name, ["tag1"]) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag1").should.equal(None) conn.add_tags_to_stream(stream_name, {"tag2": "val2"}) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag2").should.equal("val2") conn.remove_tags_from_stream(stream_name, ["tag2"]) tags = dict( [ (tag["Key"], tag["Value"]) for tag in conn.list_tags_for_stream(stream_name)["Tags"] ] ) tags.get("tag2").should.equal(None) # Has boto3 equivalent @mock_kinesis_deprecated def test_split_shard(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 2) # Create some data for index in range(1, 100): conn.put_record(stream_name, str(index), str(index)) stream_response = conn.describe_stream(stream_name) stream = stream_response["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(2) shard_range = shards[0]["HashKeyRange"] new_starting_hash = ( int(shard_range["EndingHashKey"]) + int(shard_range["StartingHashKey"]) ) // 2 conn.split_shard("my_stream", shards[0]["ShardId"], str(new_starting_hash)) stream_response = conn.describe_stream(stream_name) stream = stream_response["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(3) shard_range = shards[2]["HashKeyRange"] new_starting_hash = ( int(shard_range["EndingHashKey"]) + int(shard_range["StartingHashKey"]) ) // 2 conn.split_shard("my_stream", shards[2]["ShardId"], str(new_starting_hash)) stream_response = conn.describe_stream(stream_name) stream = stream_response["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(4) @mock_kinesis def test_split_shard_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=2) for index in range(1, 100): client.put_record( StreamName=stream_name, Data=f"data_{index}".encode("utf-8"), PartitionKey=str(index), ) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(2) shard_range = shards[0]["HashKeyRange"] new_starting_hash = ( int(shard_range["EndingHashKey"]) + int(shard_range["StartingHashKey"]) ) // 2 client.split_shard( StreamName=stream_name, ShardToSplit=shards[0]["ShardId"], NewStartingHashKey=str(new_starting_hash), ) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(3) shard_range = shards[2]["HashKeyRange"] new_starting_hash = ( int(shard_range["EndingHashKey"]) + int(shard_range["StartingHashKey"]) ) // 2 client.split_shard( StreamName=stream_name, ShardToSplit=shards[2]["ShardId"], NewStartingHashKey=str(new_starting_hash), ) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(4) # Has boto3 equivalent @mock_kinesis_deprecated def test_merge_shards(): conn = boto.kinesis.connect_to_region("us-west-2") stream_name = "my_stream" conn.create_stream(stream_name, 4) # Create some data for index in range(1, 100): conn.put_record(stream_name, str(index), str(index)) stream_response = conn.describe_stream(stream_name) stream = stream_response["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(4) conn.merge_shards.when.called_with( stream_name, "shardId-000000000000", "shardId-000000000002" ).should.throw(InvalidArgumentException) stream_response = conn.describe_stream(stream_name) stream = stream_response["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(4) conn.merge_shards(stream_name, "shardId-000000000000", "shardId-000000000001") stream_response = conn.describe_stream(stream_name) stream = stream_response["StreamDescription"] shards = stream["Shards"] active_shards = [ shard for shard in shards if "EndingSequenceNumber" not in shard["SequenceNumberRange"] ] active_shards.should.have.length_of(3) conn.merge_shards(stream_name, "shardId-000000000002", "shardId-000000000000") stream_response = conn.describe_stream(stream_name) stream = stream_response["StreamDescription"] shards = stream["Shards"] active_shards = [ shard for shard in shards if "EndingSequenceNumber" not in shard["SequenceNumberRange"] ] active_shards.should.have.length_of(2) @mock_kinesis def test_merge_shards_boto3(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=4) for index in range(1, 100): client.put_record( StreamName=stream_name, Data=f"data_{index}".encode("utf-8"), PartitionKey=str(index), ) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shards = stream["Shards"] shards.should.have.length_of(4) client.merge_shards( StreamName=stream_name, ShardToMerge="shardId-000000000000", AdjacentShardToMerge="shardId-000000000001", ) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shards = stream["Shards"] active_shards = [ shard for shard in shards if "EndingSequenceNumber" not in shard["SequenceNumberRange"] ] active_shards.should.have.length_of(3) client.merge_shards( StreamName=stream_name, ShardToMerge="shardId-000000000002", AdjacentShardToMerge="shardId-000000000000", ) stream = client.describe_stream(StreamName=stream_name)["StreamDescription"] shards = stream["Shards"] active_shards = [ shard for shard in shards if "EndingSequenceNumber" not in shard["SequenceNumberRange"] ] active_shards.should.have.length_of(2) @mock_kinesis def test_merge_shards_invalid_arg(): client = boto3.client("kinesis", region_name="eu-west-2") stream_name = "my_stream_summary" client.create_stream(StreamName=stream_name, ShardCount=4) with pytest.raises(ClientError) as exc: client.merge_shards( StreamName=stream_name, ShardToMerge="shardId-000000000000", AdjacentShardToMerge="shardId-000000000002", ) err = exc.value.response["Error"] err["Code"].should.equal("InvalidArgumentException") err["Message"].should.equal("shardId-000000000002")