Stepfunctions improvements (#3427)

* Implement filtering for stepfunctions:ListExecutions

* Add pagination to Step Functions endpoints

Implements a generalized approach to pagination via a decorator method for the
Step Functions endpoints.  Modeled on the real AWS backend behavior, `nextToken`
is a dictionary of pagination information encoded in an opaque string.

With just a bit of metadata hard-coded (`utils.PAGINATION_MODEL`), backend `list`
methods need only be decorated with `@paginate` and ensure that their returned
entities are sorted to get full pagination support without any duplicated code
polluting the model.

Closes #3137
This commit is contained in:
Brian Pandola 2020-11-01 02:16:41 -08:00 committed by GitHub
commit 68e3d394ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 284 additions and 26 deletions

View file

@ -168,15 +168,15 @@ def test_state_machine_list_returns_empty_list_by_default():
def test_state_machine_list_returns_created_state_machines():
client = boto3.client("stepfunctions", region_name=region)
#
machine2 = client.create_state_machine(
name="name2", definition=str(simple_definition), roleArn=_get_default_role()
)
machine1 = client.create_state_machine(
name="name1",
definition=str(simple_definition),
roleArn=_get_default_role(),
tags=[{"key": "tag_key", "value": "tag_value"}],
)
machine2 = client.create_state_machine(
name="name2", definition=str(simple_definition), roleArn=_get_default_role()
)
list = client.list_state_machines()
#
list["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
@ -195,6 +195,28 @@ def test_state_machine_list_returns_created_state_machines():
)
@mock_stepfunctions
def test_state_machine_list_pagination():
client = boto3.client("stepfunctions", region_name=region)
for i in range(25):
machine_name = "StateMachine-{}".format(i)
client.create_state_machine(
name=machine_name,
definition=str(simple_definition),
roleArn=_get_default_role(),
)
resp = client.list_state_machines()
resp.should_not.have.key("nextToken")
resp["stateMachines"].should.have.length_of(25)
paginator = client.get_paginator("list_state_machines")
page_iterator = paginator.paginate(maxResults=5)
for page in page_iterator:
page["stateMachines"].should.have.length_of(5)
page["stateMachines"][-1]["name"].should.contain("24")
@mock_stepfunctions
@mock_sts
def test_state_machine_creation_is_idempotent_by_name():
@ -489,6 +511,69 @@ def test_state_machine_list_executions():
executions["executions"][0].shouldnt.have("stopDate")
@mock_stepfunctions
def test_state_machine_list_executions_with_filter():
client = boto3.client("stepfunctions", region_name=region)
sm = client.create_state_machine(
name="name", definition=str(simple_definition), roleArn=_get_default_role()
)
for i in range(20):
execution = client.start_execution(stateMachineArn=sm["stateMachineArn"])
if not i % 4:
client.stop_execution(executionArn=execution["executionArn"])
resp = client.list_executions(stateMachineArn=sm["stateMachineArn"])
resp["executions"].should.have.length_of(20)
resp = client.list_executions(
stateMachineArn=sm["stateMachineArn"], statusFilter="ABORTED"
)
resp["executions"].should.have.length_of(5)
all([e["status"] == "ABORTED" for e in resp["executions"]]).should.be.true
@mock_stepfunctions
def test_state_machine_list_executions_with_pagination():
client = boto3.client("stepfunctions", region_name=region)
sm = client.create_state_machine(
name="name", definition=str(simple_definition), roleArn=_get_default_role()
)
for _ in range(100):
client.start_execution(stateMachineArn=sm["stateMachineArn"])
resp = client.list_executions(stateMachineArn=sm["stateMachineArn"])
resp.should_not.have.key("nextToken")
resp["executions"].should.have.length_of(100)
paginator = client.get_paginator("list_executions")
page_iterator = paginator.paginate(
stateMachineArn=sm["stateMachineArn"], maxResults=25
)
for page in page_iterator:
page["executions"].should.have.length_of(25)
with assert_raises(ClientError) as ex:
resp = client.list_executions(
stateMachineArn=sm["stateMachineArn"], maxResults=10
)
client.list_executions(
stateMachineArn=sm["stateMachineArn"],
maxResults=10,
statusFilter="ABORTED",
nextToken=resp["nextToken"],
)
ex.exception.response["Error"]["Code"].should.equal("InvalidToken")
ex.exception.response["Error"]["Message"].should.contain(
"Input inconsistent with page token"
)
with assert_raises(ClientError) as ex:
client.list_executions(
stateMachineArn=sm["stateMachineArn"], nextToken="invalid"
)
ex.exception.response["Error"]["Code"].should.equal("InvalidToken")
@mock_stepfunctions
@mock_sts
def test_state_machine_list_executions_when_none_exist():