Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does altering the backend pass between fixtures and tests #6859

Closed
WesleyHindle opened this issue Sep 27, 2023 · 4 comments
Closed

Does altering the backend pass between fixtures and tests #6859

WesleyHindle opened this issue Sep 27, 2023 · 4 comments
Labels
debugging Working with user to figure out if there is an issue

Comments

@WesleyHindle
Copy link

Relates to #5927 and #6809

moto 4.2.3

I'm wanting to setup a fake role which is used in a fixture, with a fake last used date. I then want to return this value for use in an actual test, so I can separate the setup from the test.

So far I have

import boto3
from datetime import datetime, timedelta
from freezegun import freeze_time
from moto import mock_iam, mock_sts
from moto.backends import get_backend
from moto.core import DEFAULT_ACCOUNT_ID
import os
import pytest
import pytz

@pytest.fixture
@mock_iam
def aws_credentials():
    """Mocked AWS Credentials for moto."""
    os.environ["AWS_ACCESS_KEY_ID"] = "testing"
    os.environ["AWS_SECRET_ACCESS_KEY"] = "testing"
    os.environ["AWS_SECURITY_TOKEN"] = "testing"
    os.environ["AWS_SESSION_TOKEN"] = "testing"
    os.environ["AWS_DEFAULT_REGION"] = "eu-west-2"

@pytest.fixture
def iam_client(aws_credentials):
    with mock_iam():
        yield boto3.client("iam")

@pytest.fixture
def sts(aws_credentials):
    with mock_sts():
        yield boto3.client("sts")

# Create and attach role to created user and return results for use in later tests
@pytest.fixture
@freeze_time(date_181_days_ago)
def test_create_role_with_invalid_date(iam_client, sts): 
    role_name = "role_name_invalid_date"
    user_name = "test.user"

    response = iam_client.create_role(
        RoleName=role_name,
        AssumeRolePolicyDocument="example policy"
    )

    role_arn = response["Role"]["Arn"]

    iam_client.create_user(UserName=user_name)

    iam_client.attach_user_policy(
        UserName=user_name,
        PolicyArn="arn:aws:iam::aws:policy/AmazonS3FullAccess"
    )

    assumed_role = sts.assume_role(
        RoleArn = role_arn,
        RoleSessionName = "temp_session"
        )
    
    assumed_role_creds = assumed_role["Credentials"]

    iam_backend = get_backend("iam")[DEFAULT_ACCOUNT_ID]["global"]
    iam_backend.get_role(role_name).last_used = date_181_days_ago

    iam_backend = boto3.client(
        "iam",
        aws_access_key_id = assumed_role_creds["AccessKeyId"],
        aws_secret_access_key = assumed_role_creds["SecretAccessKey"],
        aws_session_token = assumed_role_creds["SessionToken"]
        )
    
    print("-----------------Output from fixture -----------------------")
    print(iam_backend.get_role(RoleName=role_name))
    
    return iam_backend, role_name


# Actual test

def test_get_all_roles(test_create_role_with_invalid_date):
    iam_backend, role_name = test_create_role_with_invalid_date

    r = iam_backend.get_role(RoleName=role_name) 
    print("----------------Output from actual test-----------------")   
    print(r)

So the print from the fixture outputs the correct faked date, when the print from the test outputs the wrong (current) date.

Is this a quirk of moto, or I've used the backend stuff incorrectly between functuions?

@bblommers
Copy link
Collaborator

Hi @WesleyHindle, I would argue that this the expected behaviour, actually.

Two important notes:

  • Because you're calling a function (any function) using the assumed_role_creds, the role behind those credentials is now used - and Moto set the last_used value to now().
  • The fixture uses a freeze_time, so that now() actually becomes date_181_days_ago

So the timeline is:

  1. role.last_used is None
  2. role.last_used = date_181_days_ago (set programmatically)
  3. role.last_used = Moto tries to set it to now(), but freeze_time turns that into date_181_days_ago)
  4. The freeze_time decorator ends
  5. role.last_used = Moto sets it to now() when calling boto3.client(.. assumed creds..).get_role()

@bblommers bblommers added the debugging Working with user to figure out if there is an issue label Sep 27, 2023
@WesleyHindle
Copy link
Author

Thank you the reply.

Interesting to know that freeze_time doesn't pass between functions when assuming roles.

Am I wrong to assume by Because you're calling a function (any function) using the assumed_role_creds, the role behind those credentials is now used - and Moto set the last_used value to now(). you're saying that when you assume a role and call one method you have to assume the role again to call another method?


So if I want to keep some separation between fixtures and tests (and have a LastUsedDate set in the past) I'd have to do something like...

@pytest.fixture
@freeze_time(date_181_days_ago)
def test_create_role_with_invalid_date(iam_client, sts): 
    role_name = "role_name_invalid_date"
    user_name = "test.user"

    response = iam_client.create_role(
        RoleName=role_name,
        AssumeRolePolicyDocument="example policy"
    )

    role_arn = response["Role"]["Arn"]

    iam_client.create_user(UserName=user_name)

    iam_client.attach_user_policy(
        UserName=user_name,
        PolicyArn="arn:aws:iam::aws:policy/AmazonS3FullAccess"
    )

    assumed_role = sts.assume_role(
        RoleArn = role_arn,
        RoleSessionName = "temp_session"
        )
    
    assumed_role_creds = assumed_role["Credentials"]

    return assumed_role_creds, role_name


def test_get_all_roles(test_create_role_with_invalid_date):
    iam_backend, role_name = test_create_role_with_invalid_date

    iam_backend = get_backend("iam")[DEFAULT_ACCOUNT_ID]["global"]
    iam_backend.get_role(role_name).last_used = date_181_days_ago

    iam_backend = boto3.client(
        "iam",
        aws_access_key_id = assumed_role_creds["AccessKeyId"],
        aws_secret_access_key = assumed_role_creds["SecretAccessKey"],
        aws_session_token = assumed_role_creds["SessionToken"]
        )

    r = iam_backend.get_role(RoleName=role_name) 
    print("----------------Output from actual test-----------------")   
    print(r)

   assert r["LastUsedDate"] == whatever the date was 181 days ago?

@bblommers
Copy link
Collaborator

No, you can re-use the same role to call any number of methods.
Let me rephrase it my quote to make it more obvious what I meant:

Because you're calling a function (any function) using the assumed_role_creds, we now know when the role behind those credentials was used last, so Moto will set that value to now().

@bblommers
Copy link
Collaborator

This question has been answered, as far as I can tell, so I'll close this. Let us know if you have any other questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
debugging Working with user to figure out if there is an issue
Projects
None yet
Development

No branches or pull requests

2 participants