Repository: getmoto/moto
Pull request #6447 (2023-06-26 11:14:19)

StepFunctions: validation according to api docs
Closes https://github.com/getmoto/moto/issues/6438


Patch:
diff --git a/moto/stepfunctions/exceptions.py b/moto/stepfunctions/exceptions.py
index b7e449a54..8467daf33 100644
--- a/moto/stepfunctions/exceptions.py
+++ b/moto/stepfunctions/exceptions.py
@@ -45,3 +45,18 @@ class ResourceNotFound(AWSError):
 
     def __init__(self, arn: str):
         super().__init__(f"Resource not found: '{arn}'")
+
+
+class ValidationException(AWSError):
+    TYPE = "ValidationException"
+
+    def __init__(self, msg: str):
+        super().__init__(msg)
+
+
+class NameTooLongException(ValidationException):
+    def __init__(self, name: str):
+        super().__init__(
+            f"1 validation error detected: Value '{name}' at 'name' "
+            "failed to satisfy constraint: Member must have length less than or equal to 80"
+        )
diff --git a/moto/stepfunctions/models.py b/moto/stepfunctions/models.py
index 3df09e648..e007d604e 100644
--- a/moto/stepfunctions/models.py
+++ b/moto/stepfunctions/models.py
@@ -15,6 +15,7 @@ from .exceptions import (
     InvalidName,
     ResourceNotFound,
     StateMachineDoesNotExist,
+    NameTooLongException,
 )
 from .utils import api_to_cfn_tags, cfn_to_api_tags, PAGINATION_MODEL
 from moto import settings
@@ -533,6 +534,8 @@ class StepFunctionBackend(BaseBackend):
     def start_execution(
         self, state_machine_arn: str, name: str, execution_input: str
     ) -> Execution:
+        if name:
+            self._validate_name(name)
         state_machine = self.describe_state_machine(state_machine_arn)
         return state_machine.start_execution(
             region_name=self.region_name,
@@ -634,6 +637,9 @@ class StepFunctionBackend(BaseBackend):
         if any(name.find(char) >= 0 for char in self.invalid_unicodes_for_name):
             raise InvalidName("Invalid Name: '" + name + "'")
 
+        if len(name) > 80:
+            raise NameTooLongException(name)
+
     def _validate_role_arn(self, role_arn: str) -> None:
         self._validate_arn(
             arn=role_arn,


Test patch:
diff --git a/tests/test_stepfunctions/test_stepfunctions.py b/tests/test_stepfunctions/test_stepfunctions.py
index 04b129702..70d8faa11 100644
--- a/tests/test_stepfunctions/test_stepfunctions.py
+++ b/tests/test_stepfunctions/test_stepfunctions.py
@@ -959,5 +959,53 @@ def test_state_machine_get_execution_history_contains_expected_failure_events_wh
     assert exc["status"] == "FAILED"
 
 
+@mock_stepfunctions
+def test_state_machine_name_limits():
+    # Setup
+    client = boto3.client("stepfunctions", region_name=region)
+    long_name = "t" * 81
+
+    # Execute
+    with pytest.raises(ClientError) as exc:
+        client.create_state_machine(
+            name=long_name,
+            definition=simple_definition,
+            roleArn=_get_default_role(),
+        )
+
+    # Verify
+    assert exc.value.response["Error"]["Code"] == "ValidationException"
+    assert (
+        exc.value.response["Error"]["Message"]
+        == f"1 validation error detected: Value '{long_name}' at 'name' failed to satisfy constraint: "
+        "Member must have length less than or equal to 80"
+    )
+
+
+@mock_stepfunctions
+def test_state_machine_execution_name_limits():
+    # Setup
+    client = boto3.client("stepfunctions", region_name=region)
+    machine_name = "test_name"
+    long_name = "t" * 81
+    resp = client.create_state_machine(
+        name=machine_name,
+        definition=simple_definition,
+        roleArn=_get_default_role(),
+    )
+
+    # Execute
+    with pytest.raises(ClientError) as exc:
+        client.start_execution(name=long_name, stateMachineArn=resp["stateMachineArn"])
+
+    # Verify
+    assert exc.value.response["Error"]["Code"] == "ValidationException"
+    assert (
+        exc.value.response["Error"]["Message"]
+        == f"1 validation error detected: Value '{long_name}' at 'name' failed to satisfy constraint: "
+        "Member must have length less than or equal to 80"
+    )
+
+
 def _get_default_role():
     return "arn:aws:iam::" + ACCOUNT_ID + ":role/unknown_sf_role"