Repository: getmoto/moto

Issue:
Add support for retention hours in Kinesis
Hello,

Thanks for this great library! I would like to contribute to moto, and I noticed that the methods to interact with the retention_hours present in Kinesis are not yet implement(specifically `increase_stream_retention_period` and `decrease_stream_retention_period`. I would like to work on implementing these functions.

Thanks!


Discussion:

Resolving patch:
diff --git a/moto/kinesis/models.py b/moto/kinesis/models.py
--- a/moto/kinesis/models.py
+++ b/moto/kinesis/models.py
@@ -145,7 +145,9 @@ def __init__(self, stream_name, shard_count, retention_period_hours, region_name
         self.status = "ACTIVE"
         self.shard_count = None
         self.update_shard_count(shard_count)
-        self.retention_period_hours = retention_period_hours
+        self.retention_period_hours = (
+            retention_period_hours if retention_period_hours else 24
+        )
 
     def update_shard_count(self, shard_count):
         # ToDo: This was extracted from init.  It's only accurate for new streams.
@@ -574,6 +576,26 @@ def merge_shards(self, stream_name, shard_to_merge, adjacent_shard_to_merge):
                 record.partition_key, record.data, record.explicit_hash_key
             )
 
+    def increase_stream_retention_period(self, stream_name, retention_period_hours):
+        stream = self.describe_stream(stream_name)
+        if (
+            retention_period_hours <= stream.retention_period_hours
+            or retention_period_hours < 24
+            or retention_period_hours > 8760
+        ):
+            raise InvalidArgumentError(retention_period_hours)
+        stream.retention_period_hours = retention_period_hours
+
+    def decrease_stream_retention_period(self, stream_name, retention_period_hours):
+        stream = self.describe_stream(stream_name)
+        if (
+            retention_period_hours >= stream.retention_period_hours
+            or retention_period_hours < 24
+            or retention_period_hours > 8760
+        ):
+            raise InvalidArgumentError(retention_period_hours)
+        stream.retention_period_hours = retention_period_hours
+
     """ Firehose """
 
     def create_delivery_stream(self, stream_name, **stream_kwargs):
diff --git a/moto/kinesis/responses.py b/moto/kinesis/responses.py
--- a/moto/kinesis/responses.py
+++ b/moto/kinesis/responses.py
@@ -149,6 +149,22 @@ def merge_shards(self):
         )
         return ""
 
+    def increase_stream_retention_period(self):
+        stream_name = self.parameters.get("StreamName")
+        retention_period_hours = self.parameters.get("RetentionPeriodHours")
+        self.kinesis_backend.increase_stream_retention_period(
+            stream_name, retention_period_hours
+        )
+        return ""
+
+    def decrease_stream_retention_period(self):
+        stream_name = self.parameters.get("StreamName")
+        retention_period_hours = self.parameters.get("RetentionPeriodHours")
+        self.kinesis_backend.decrease_stream_retention_period(
+            stream_name, retention_period_hours
+        )
+        return ""
+
     """ Firehose """
 
     def create_delivery_stream(self):


Test patch:
diff --git a/tests/test_kinesis/test_kinesis.py b/tests/test_kinesis/test_kinesis.py
--- a/tests/test_kinesis/test_kinesis.py
+++ b/tests/test_kinesis/test_kinesis.py
@@ -2,10 +2,13 @@
 
 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
@@ -479,6 +482,71 @@ def test_get_records_from_empty_stream_at_timestamp():
     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)
+
+
 @mock_kinesis_deprecated
 def test_invalid_shard_iterator_type():
     conn = boto.kinesis.connect_to_region("us-west-2")