diff --git a/docs/docs/configuration/recorder/index.rst b/docs/docs/configuration/recorder/index.rst index 07974d284..11976fd8f 100644 --- a/docs/docs/configuration/recorder/index.rst +++ b/docs/docs/configuration/recorder/index.rst @@ -68,3 +68,46 @@ The requests are stored in a file called `moto_recording`, in the directory that The recorder is disabled by default. If you want to enable it, use the following environment variable: `MOTO_ENABLE_RECORDING=True` + + +Deterministic Identifiers +############################## + +Moto creates random identifiers for most resources, just like AWS. The Recorder will recreate the same resources every time, but with different identifiers. + +It is possible to seed Moto and ensure that the 'random' identifiers are always the same for subsequent requests. + +Example invocation: + +.. sourcecode:: python + + # Ensure the provided parameter `a` is an integer + requests.post("http://motoapi.amazonaws.com/moto-api/seed?a=42") + + # To try this out, generate a EC2 instance + client = boto3.client("ec2", region_name="us-east-1") + resp = client.run_instances(ImageId="ami-12c6146b", MinCount=1, MaxCount=1) + + # The resulting InstanceId will always be the same + instance_id = resp["Instances"][0]["InstanceId"] + assert instance_id == "i-d1026706d7e805da8" + +To seed Moto in ServerMode: + +.. sourcecode:: python + + requests.post(f"http://localhost:5000/moto-api/seed?a=42") + + +Because the seeding API is only exposed as a request, it will be recorded just like any other request. :raw-html:`
` +Seed Moto at the beginning of a recording to ensure the resulting state will always be the same: + +.. sourcecode:: python + + requests.post("http://localhost:5000/moto-api/recorder/start-recording") + requests.post("http://localhost:5000/moto-api/seed?a=42") + + client = boto3.client("ec2", region_name="us-east-1") + resp = client.run_instances(ImageId="ami-12c6146b", MinCount=1, MaxCount=1) + + requests.post("http://localhost:5000/moto-api/recorder/stop-recording") diff --git a/moto/acm/utils.py b/moto/acm/utils.py index 6d695d95c..c25e17213 100644 --- a/moto/acm/utils.py +++ b/moto/acm/utils.py @@ -1,9 +1,9 @@ -import uuid +from moto.moto_api._internal import mock_random def make_arn_for_certificate(account_id, region_name): # Example # arn:aws:acm:eu-west-2:764371465172:certificate/c4b738b8-56fe-4b3a-b841-1c047654780b return "arn:aws:acm:{0}:{1}:certificate/{2}".format( - region_name, account_id, uuid.uuid4() + region_name, account_id, mock_random.uuid4() ) diff --git a/moto/amp/models.py b/moto/amp/models.py index 1159d62fb..02160b1a4 100644 --- a/moto/amp/models.py +++ b/moto/amp/models.py @@ -2,10 +2,10 @@ from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, unix_time +from moto.moto_api._internal import mock_random from moto.utilities.paginator import paginate from moto.utilities.tagging_service import TaggingService from typing import Dict -from uuid import uuid4 from .exceptions import RuleGroupNamespaceNotFound, WorkspaceNotFound from .utils import PAGINATION_MODEL @@ -38,7 +38,7 @@ class RuleGroupNamespace(BaseModel): class Workspace(BaseModel): def __init__(self, account_id, region, alias, tag_fn): self.alias = alias - self.workspace_id = f"ws-{uuid4()}" + self.workspace_id = f"ws-{mock_random.uuid4()}" self.arn = f"arn:aws:aps:{region}:{account_id}:workspace/{self.workspace_id}" self.endpoint = f"https://aps-workspaces.{region}.amazonaws.com/workspaces/{self.workspace_id}/" self.status = {"statusCode": "ACTIVE"} diff --git a/moto/apigateway/models.py b/moto/apigateway/models.py index 1390db1a3..544174e7e 100644 --- a/moto/apigateway/models.py +++ b/moto/apigateway/models.py @@ -1,6 +1,5 @@ from __future__ import absolute_import -import random import string import re from collections import defaultdict @@ -66,6 +65,7 @@ from .exceptions import ( ) from ..core.models import responses_mock from moto.apigateway.exceptions import MethodNotFoundException +from moto.moto_api._internal import mock_random as random STAGE_URL = "https://{api_id}.execute-api.{region_name}.amazonaws.com/{stage_name}" diff --git a/moto/apigateway/utils.py b/moto/apigateway/utils.py index 416e10631..facecca82 100644 --- a/moto/apigateway/utils.py +++ b/moto/apigateway/utils.py @@ -1,7 +1,7 @@ -import random import string import json import yaml +from moto.moto_api._internal import mock_random as random def create_id(): diff --git a/moto/apigatewayv2/models.py b/moto/apigatewayv2/models.py index 9ce721ea9..52b338cad 100644 --- a/moto/apigatewayv2/models.py +++ b/moto/apigatewayv2/models.py @@ -1,10 +1,10 @@ """ApiGatewayV2Backend class with methods for supported APIs.""" -import random import string import yaml from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, unix_time +from moto.moto_api._internal import mock_random as random from moto.utilities.tagging_service import TaggingService from .exceptions import ( diff --git a/moto/applicationautoscaling/models.py b/moto/applicationautoscaling/models.py index b0f369de8..027e5ce48 100644 --- a/moto/applicationautoscaling/models.py +++ b/moto/applicationautoscaling/models.py @@ -1,11 +1,11 @@ from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict from moto.ecs import ecs_backends +from moto.moto_api._internal import mock_random from .exceptions import AWSValidationException from collections import OrderedDict from enum import Enum, unique import time -import uuid @unique @@ -418,7 +418,7 @@ class FakeApplicationAutoscalingPolicy(BaseModel): self.scalable_dimension = scalable_dimension self.policy_name = policy_name self.policy_type = policy_type - self._guid = uuid.uuid4() + self._guid = mock_random.uuid4() self.policy_arn = "arn:aws:autoscaling:{}:scalingPolicy:{}:resource/{}/{}:policyName/{}".format( region_name, self._guid, diff --git a/moto/appsync/models.py b/moto/appsync/models.py index 1b7b65654..ecce39a6b 100644 --- a/moto/appsync/models.py +++ b/moto/appsync/models.py @@ -2,10 +2,9 @@ import base64 from datetime import timedelta, datetime, timezone from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, unix_time +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService -from uuid import uuid4 - from .exceptions import GraphqlAPINotFound @@ -66,7 +65,7 @@ class GraphqlAPI(BaseModel): ): self.region = region self.name = name - self.api_id = str(uuid4()) + self.api_id = str(mock_random.uuid4()) self.authentication_type = authentication_type self.additional_authentication_providers = additional_authentication_providers self.lambda_authorizer_config = lambda_authorizer_config @@ -157,7 +156,7 @@ class GraphqlAPI(BaseModel): class GraphqlAPIKey(BaseModel): def __init__(self, description, expires): - self.key_id = str(uuid4())[0:6] + self.key_id = str(mock_random.uuid4())[0:6] self.description = description self.expires = expires if not self.expires: diff --git a/moto/athena/models.py b/moto/athena/models.py index 7bf7e3f79..beb7923e6 100644 --- a/moto/athena/models.py +++ b/moto/athena/models.py @@ -2,8 +2,7 @@ import time from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict - -from uuid import uuid4 +from moto.moto_api._internal import mock_random class TaggableResourceMixin(object): @@ -66,7 +65,7 @@ class DataCatalog(TaggableResourceMixin, BaseModel): class Execution(BaseModel): def __init__(self, query, context, config, workgroup): - self.id = str(uuid4()) + self.id = str(mock_random.uuid4()) self.query = query self.context = context self.config = config @@ -77,7 +76,7 @@ class Execution(BaseModel): class NamedQuery(BaseModel): def __init__(self, name, description, database, query_string, workgroup): - self.id = str(uuid4()) + self.id = str(mock_random.uuid4()) self.name = name self.description = description self.database = database diff --git a/moto/autoscaling/models.py b/moto/autoscaling/models.py index e06575724..1a2d4af41 100644 --- a/moto/autoscaling/models.py +++ b/moto/autoscaling/models.py @@ -1,6 +1,4 @@ import itertools -import random -from uuid import uuid4 from moto.packages.boto.ec2.blockdevicemapping import ( BlockDeviceType, @@ -15,6 +13,7 @@ from moto.ec2 import ec2_backends from moto.elb import elb_backends from moto.elbv2 import elbv2_backends from moto.elb.exceptions import LoadBalancerNotFoundError +from moto.moto_api._internal import mock_random as random from .exceptions import ( AutoscalingClientError, ResourceContentionError, @@ -375,7 +374,7 @@ class FakeAutoScalingGroup(CloudFormationModel): self.autoscaling_backend = autoscaling_backend self.ec2_backend = ec2_backend self.name = name - self._id = str(uuid4()) + self._id = str(random.uuid4()) self.region = self.autoscaling_backend.region_name self.account_id = self.autoscaling_backend.account_id self.service_linked_role = f"arn:aws:iam::{self.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" diff --git a/moto/autoscaling/responses.py b/moto/autoscaling/responses.py index e6e355111..924970565 100644 --- a/moto/autoscaling/responses.py +++ b/moto/autoscaling/responses.py @@ -1,11 +1,8 @@ import datetime from moto.core.responses import BaseResponse -from moto.core.utils import ( - amz_crc32, - amzn_request_id, - iso_8601_datetime_with_milliseconds, -) +from moto.core.utils import iso_8601_datetime_with_milliseconds +from moto.utilities.aws_headers import amz_crc32, amzn_request_id from .models import autoscaling_backends diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 11740ae54..dd2318c97 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -16,7 +16,6 @@ import os import json import re import zipfile -import uuid import tarfile import calendar import threading @@ -26,11 +25,12 @@ import requests.exceptions from moto.awslambda.policy import Policy from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core.exceptions import RESTError +from moto.core.utils import unix_time_millis, BackendDict from moto.iam.models import iam_backends from moto.iam.exceptions import IAMNotFoundException -from moto.core.utils import unix_time_millis, BackendDict -from moto.s3.models import s3_backends from moto.logs.models import logs_backends +from moto.moto_api._internal import mock_random as random +from moto.s3.models import s3_backends from moto.s3.exceptions import MissingBucket, MissingKey from moto import settings from .exceptions import ( @@ -54,7 +54,6 @@ from moto.dynamodb import dynamodb_backends from moto.dynamodbstreams import dynamodbstreams_backends from moto.utilities.docker_utilities import DockerModel, parse_image_ref from tempfile import TemporaryDirectory -from uuid import uuid4 logger = logging.getLogger(__name__) @@ -335,7 +334,7 @@ class LambdaAlias(BaseModel): self.function_version = function_version self.description = description self.routing_config = routing_config - self.revision_id = str(uuid4()) + self.revision_id = str(random.uuid4()) def update(self, description, function_version, routing_config): if description is not None: @@ -439,7 +438,7 @@ class LambdaFunction(CloudFormationModel, DockerModel): ) = _zipfile_content(self.code["ZipFile"]) # TODO: we should be putting this in a lambda bucket - self.code["UUID"] = str(uuid.uuid4()) + self.code["UUID"] = str(random.uuid4()) self.code["S3Key"] = "{}-{}".format(self.function_name, self.code["UUID"]) elif "S3Bucket" in self.code: key = _validate_s3_bucket_and_key(self.account_id, data=self.code) @@ -610,7 +609,7 @@ class LambdaFunction(CloudFormationModel, DockerModel): ) = _zipfile_content(updated_spec["ZipFile"]) # TODO: we should be putting this in a lambda bucket - self.code["UUID"] = str(uuid.uuid4()) + self.code["UUID"] = str(random.uuid4()) self.code["S3Key"] = "{}-{}".format(self.function_name, self.code["UUID"]) elif "S3Bucket" in updated_spec and "S3Key" in updated_spec: key = None @@ -757,7 +756,7 @@ class LambdaFunction(CloudFormationModel, DockerModel): def save_logs(self, output): # Send output to "logs" backend - invoke_id = uuid.uuid4().hex + invoke_id = random.uuid4().hex log_stream_name = ( "{date.year}/{date.month:02d}/{date.day:02d}/[{version}]{invoke_id}".format( date=datetime.datetime.utcnow(), @@ -935,7 +934,7 @@ class FunctionUrlConfig: def __init__(self, function: LambdaFunction, config): self.function = function self.config = config - self.url = f"https://{uuid.uuid4().hex}.lambda-url.{function.region}.on.aws" + self.url = f"https://{random.uuid4().hex}.lambda-url.{function.region}.on.aws" self.created = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S") self.last_modified = self.created @@ -970,7 +969,7 @@ class EventSourceMapping(CloudFormationModel): self.starting_position_timestamp = spec.get("StartingPositionTimestamp", None) self.function_arn = spec["FunctionArn"] - self.uuid = str(uuid.uuid4()) + self.uuid = str(random.uuid4()) self.last_modified = time.mktime(datetime.datetime.utcnow().timetuple()) def _get_service_source_from_arn(self, event_source_arn): diff --git a/moto/awslambda/policy.py b/moto/awslambda/policy.py index c17aa8c9f..17eabb4b6 100644 --- a/moto/awslambda/policy.py +++ b/moto/awslambda/policy.py @@ -1,15 +1,15 @@ import json -import uuid from moto.awslambda.exceptions import ( PreconditionFailedException, UnknownPolicyException, ) +from moto.moto_api._internal import mock_random class Policy: def __init__(self, parent): - self.revision = str(uuid.uuid4()) + self.revision = str(mock_random.uuid4()) self.statements = [] self.parent = parent @@ -45,7 +45,7 @@ class Policy: policy.statements[0]["Resource"] + ":" + qualifier ) self.statements.append(policy.statements[0]) - self.revision = str(uuid.uuid4()) + self.revision = str(mock_random.uuid4()) # removes the statement that matches 'sid' from the policy def del_statement(self, sid, revision=""): @@ -73,7 +73,7 @@ class Policy: # set some default values if these keys are not set self.ensure_set(obj, "Effect", "Allow") self.ensure_set(obj, "Resource", self.parent.function_arn + ":$LATEST") - self.ensure_set(obj, "StatementId", str(uuid.uuid4())) + self.ensure_set(obj, "StatementId", str(mock_random.uuid4())) # transform field names and values self.transform_property(obj, "StatementId", "Sid", self.nop_formatter) diff --git a/moto/awslambda/responses.py b/moto/awslambda/responses.py index e64c1c9dd..94588b615 100644 --- a/moto/awslambda/responses.py +++ b/moto/awslambda/responses.py @@ -3,7 +3,8 @@ import sys from urllib.parse import unquote -from moto.core.utils import amz_crc32, amzn_request_id, path_url +from moto.core.utils import path_url +from moto.utilities.aws_headers import amz_crc32, amzn_request_id from moto.core.responses import BaseResponse from .models import lambda_backends diff --git a/moto/batch/models.py b/moto/batch/models.py index 0af0677b1..6e58161d8 100644 --- a/moto/batch/models.py +++ b/moto/batch/models.py @@ -3,7 +3,6 @@ from itertools import cycle from time import sleep import datetime import time -import uuid import logging import threading import dateutil.parser @@ -29,6 +28,7 @@ from moto.ec2.models.instance_types import INSTANCE_FAMILIES as EC2_INSTANCE_FAM from moto.iam.exceptions import IAMNotFoundException from moto.core.utils import unix_time_millis, BackendDict from moto.moto_api import state_manager +from moto.moto_api._internal import mock_random from moto.moto_api._internal.managed_state_model import ManagedState from moto.utilities.docker_utilities import DockerModel from moto import settings @@ -444,7 +444,7 @@ class Job(threading.Thread, BaseModel, DockerModel, ManagedState): ) self.job_name = name - self.job_id = str(uuid.uuid4()) + self.job_id = str(mock_random.uuid4()) self.job_definition = job_def self.container_overrides = container_overrides or {} self.job_queue = job_queue @@ -1110,7 +1110,7 @@ class BatchBackend(BaseBackend): # Create ECS cluster # Should be of format P2OnDemand_Batch_UUID - cluster_name = "OnDemand_Batch_" + str(uuid.uuid4()) + cluster_name = "OnDemand_Batch_" + str(mock_random.uuid4()) ecs_cluster = self.ecs_backend.create_cluster(cluster_name) new_comp_env.set_ecs(ecs_cluster.arn, cluster_name) diff --git a/moto/ce/models.py b/moto/ce/models.py index beee9c424..77666d464 100644 --- a/moto/ce/models.py +++ b/moto/ce/models.py @@ -3,7 +3,7 @@ from .exceptions import CostCategoryNotFound from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict -from uuid import uuid4 +from moto.moto_api._internal import mock_random class CostCategoryDefinition(BaseModel): @@ -15,7 +15,7 @@ class CostCategoryDefinition(BaseModel): self.rules = rules self.default_value = default_value self.split_charge_rules = split_charge_rules - self.arn = f"arn:aws:ce::{account_id}:costcategory/{str(uuid4())}" + self.arn = f"arn:aws:ce::{account_id}:costcategory/{str(mock_random.uuid4())}" def update(self, rule_version, rules, default_value, split_charge_rules): self.rule_version = rule_version diff --git a/moto/cloudformation/custom_model.py b/moto/cloudformation/custom_model.py index 2b888b088..b101bb7d2 100644 --- a/moto/cloudformation/custom_model.py +++ b/moto/cloudformation/custom_model.py @@ -4,7 +4,7 @@ import threading from moto import settings from moto.core import CloudFormationModel from moto.awslambda import lambda_backends -from uuid import uuid4 +from moto.moto_api._internal import mock_random class CustomModel(CloudFormationModel): @@ -44,7 +44,7 @@ class CustomModel(CloudFormationModel): backend = lambda_backends[account_id][region_name] fn = backend.get_function(service_token) - request_id = str(uuid4()) + request_id = str(mock_random.uuid4()) custom_resource = CustomModel( region_name, request_id, logical_id, resource_name diff --git a/moto/cloudformation/models.py b/moto/cloudformation/models.py index 53f769891..9a65d789d 100644 --- a/moto/cloudformation/models.py +++ b/moto/cloudformation/models.py @@ -1,7 +1,6 @@ from datetime import datetime, timedelta import json import yaml -import uuid from collections import OrderedDict from yaml.parser import ParserError # pylint:disable=c-extension-no-member @@ -13,6 +12,7 @@ from moto.core.utils import ( iso_8601_datetime_without_milliseconds, BackendDict, ) +from moto.moto_api._internal import mock_random from moto.sns.models import sns_backends from .parsing import ResourceMap, OutputMap @@ -103,7 +103,7 @@ class FakeStackSet(BaseModel): operation_id=None, ): if not operation_id: - operation_id = uuid.uuid4() + operation_id = mock_random.uuid4() self.template = template if template else self.template self.description = description if description is not None else self.description @@ -126,7 +126,7 @@ class FakeStackSet(BaseModel): def create_stack_instances(self, accounts, regions, parameters, operation_id=None): if not operation_id: - operation_id = uuid.uuid4() + operation_id = mock_random.uuid4() if not parameters: parameters = self.parameters @@ -141,7 +141,7 @@ class FakeStackSet(BaseModel): def delete_stack_instances(self, accounts, regions, operation_id=None): if not operation_id: - operation_id = uuid.uuid4() + operation_id = mock_random.uuid4() self.instances.delete(accounts, regions) @@ -156,7 +156,7 @@ class FakeStackSet(BaseModel): def update_instances(self, accounts, regions, parameters, operation_id=None): if not operation_id: - operation_id = uuid.uuid4() + operation_id = mock_random.uuid4() self.instances.update(accounts, regions, parameters) operation = self._create_operation( @@ -488,7 +488,7 @@ class FakeEvent(BaseModel): self.resource_status_reason = resource_status_reason self.resource_properties = resource_properties self.timestamp = datetime.utcnow() - self.event_id = uuid.uuid4() + self.event_id = mock_random.uuid4() self.client_request_token = client_request_token def sendToSns(self, account_id, region, sns_topic_arns): diff --git a/moto/cloudformation/responses.py b/moto/cloudformation/responses.py index 1bb19baf8..9edc88e04 100644 --- a/moto/cloudformation/responses.py +++ b/moto/cloudformation/responses.py @@ -5,9 +5,9 @@ from yaml.parser import ParserError # pylint:disable=c-extension-no-member from yaml.scanner import ScannerError # pylint:disable=c-extension-no-member from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id from moto.s3.models import s3_backends from moto.s3.exceptions import S3ClientError +from moto.utilities.aws_headers import amzn_request_id from .models import cloudformation_backends from .exceptions import ValidationError, MissingParameterError from .utils import yaml_tag_constructor diff --git a/moto/cloudformation/utils.py b/moto/cloudformation/utils.py index e31273063..5ddfb073e 100644 --- a/moto/cloudformation/utils.py +++ b/moto/cloudformation/utils.py @@ -1,22 +1,21 @@ -import uuid -import random import yaml import os import string +from moto.moto_api._internal import mock_random as random def generate_stack_id(stack_name, region, account): - random_id = uuid.uuid4() + random_id = random.uuid4() return f"arn:aws:cloudformation:{region}:{account}:stack/{stack_name}/{random_id}" def generate_changeset_id(changeset_name, region_name, account_id): - random_id = uuid.uuid4() + random_id = random.uuid4() return f"arn:aws:cloudformation:{region_name}:{account_id}:changeSet/{changeset_name}/{random_id}" def generate_stackset_id(stackset_name): - random_id = uuid.uuid4() + random_id = random.uuid4() return "{}:{}".format(stackset_name, random_id) diff --git a/moto/cloudfront/models.py b/moto/cloudfront/models.py index d4cc7f682..58b738b3d 100644 --- a/moto/cloudfront/models.py +++ b/moto/cloudfront/models.py @@ -1,4 +1,3 @@ -import random import string from datetime import datetime @@ -6,8 +5,8 @@ from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, iso_8601_datetime_with_milliseconds from moto.moto_api import state_manager from moto.moto_api._internal.managed_state_model import ManagedState +from moto.moto_api._internal import mock_random as random from moto.utilities.tagging_service import TaggingService -from uuid import uuid4 from .exceptions import ( OriginDoesNotExist, @@ -153,7 +152,7 @@ class DistributionConfig: self.enabled = config.get("Enabled") or False self.viewer_certificate = ViewerCertificate() self.geo_restriction = GeoRestrictions(config.get("Restrictions") or {}) - self.caller_reference = config.get("CallerReference", str(uuid4())) + self.caller_reference = config.get("CallerReference", str(random.uuid4())) self.origins = config["Origins"]["Items"]["Origin"] if not isinstance(self.origins, list): self.origins = [self.origins] diff --git a/moto/cloudwatch/models.py b/moto/cloudwatch/models.py index 0751b747c..189b55212 100644 --- a/moto/cloudwatch/models.py +++ b/moto/cloudwatch/models.py @@ -6,9 +6,9 @@ from moto.core.utils import ( iso_8601_datetime_with_nanoseconds, BackendDict, ) +from moto.moto_api._internal import mock_random from datetime import datetime, timedelta from dateutil.tz import tzutc -from uuid import uuid4 from .exceptions import ( InvalidFormat, @@ -678,7 +678,7 @@ class CloudWatchBackend(BaseBackend): def _get_paginated(self, metrics): if len(metrics) > 500: - next_token = str(uuid4()) + next_token = str(mock_random.uuid4()) self.paged_metric_data[next_token] = metrics[500:] return next_token, metrics[0:500] else: diff --git a/moto/cloudwatch/responses.py b/moto/cloudwatch/responses.py index 3f4061a82..e340a66e3 100644 --- a/moto/cloudwatch/responses.py +++ b/moto/cloudwatch/responses.py @@ -3,7 +3,7 @@ import json from dateutil.parser import parse as dtparse from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id +from moto.utilities.aws_headers import amzn_request_id from .models import cloudwatch_backends, MetricDataQuery, MetricStat, Metric, Dimension from .exceptions import InvalidParameterCombination diff --git a/moto/codebuild/models.py b/moto/codebuild/models.py index 306483a98..2f4635267 100644 --- a/moto/codebuild/models.py +++ b/moto/codebuild/models.py @@ -1,10 +1,9 @@ from moto.core import BaseBackend, BaseModel from moto.core.utils import iso_8601_datetime_with_milliseconds, BackendDict +from moto.moto_api._internal import mock_random from collections import defaultdict -from random import randint from dateutil import parser import datetime -import uuid class CodeBuildProjectMetadata(BaseModel): @@ -26,7 +25,7 @@ class CodeBuildProjectMetadata(BaseModel): "arn" ] = f"arn:aws:codebuild:{region_name}:{account_id}:build/{build_id}" - self.build_metadata["buildNumber"] = randint(1, 100) + self.build_metadata["buildNumber"] = mock_random.randint(1, 100) self.build_metadata["startTime"] = current_date self.build_metadata["currentPhase"] = "QUEUED" self.build_metadata["buildStatus"] = "IN_PROGRESS" @@ -168,7 +167,7 @@ class CodeBuildBackend(BaseBackend): def start_build(self, project_name, source_version=None, artifact_override=None): - build_id = "{0}:{1}".format(project_name, uuid.uuid4()) + build_id = "{0}:{1}".format(project_name, mock_random.uuid4()) # construct a new build self.build_metadata[project_name] = CodeBuildProjectMetadata( @@ -215,7 +214,7 @@ class CodeBuildBackend(BaseBackend): phase["phaseStatus"] = "SUCCEEDED" phase["startTime"] = current_date phase["endTime"] = current_date - phase["durationInSeconds"] = randint(10, 100) + phase["durationInSeconds"] = mock_random.randint(10, 100) phases.append(phase) return phases @@ -229,7 +228,7 @@ class CodeBuildBackend(BaseBackend): build["phases"] = self._set_phases(build["phases"]) build["endTime"] = iso_8601_datetime_with_milliseconds( parser.parse(build["startTime"]) - + datetime.timedelta(minutes=randint(1, 5)) + + datetime.timedelta(minutes=mock_random.randint(1, 5)) ) build["currentPhase"] = "COMPLETED" build["buildStatus"] = "SUCCEEDED" @@ -264,7 +263,7 @@ class CodeBuildBackend(BaseBackend): build["phases"] = self._set_phases(build["phases"]) build["endTime"] = iso_8601_datetime_with_milliseconds( parser.parse(build["startTime"]) - + datetime.timedelta(minutes=randint(1, 5)) + + datetime.timedelta(minutes=mock_random.randint(1, 5)) ) build["currentPhase"] = "COMPLETED" build["buildStatus"] = "STOPPED" diff --git a/moto/codecommit/models.py b/moto/codecommit/models.py index 4a662666d..6da08bcd6 100644 --- a/moto/codecommit/models.py +++ b/moto/codecommit/models.py @@ -1,8 +1,8 @@ from moto.core import BaseBackend, BaseModel from moto.core.utils import iso_8601_datetime_with_milliseconds, BackendDict +from moto.moto_api._internal import mock_random from datetime import datetime from .exceptions import RepositoryDoesNotExistException, RepositoryNameExistsException -import uuid class CodeCommit(BaseModel): @@ -23,7 +23,7 @@ class CodeCommit(BaseModel): self.repository_metadata["creationDate"] = current_date self.repository_metadata["lastModifiedDate"] = current_date self.repository_metadata["repositoryDescription"] = repository_description - self.repository_metadata["repositoryId"] = str(uuid.uuid4()) + self.repository_metadata["repositoryId"] = str(mock_random.uuid4()) self.repository_metadata[ "Arn" ] = f"arn:aws:codecommit:{region}:{account_id}:{repository_name}" diff --git a/moto/cognitoidentity/utils.py b/moto/cognitoidentity/utils.py index 54016ad17..34a1798d1 100644 --- a/moto/cognitoidentity/utils.py +++ b/moto/cognitoidentity/utils.py @@ -1,5 +1,5 @@ -from uuid import uuid4 +from moto.moto_api._internal import mock_random def get_random_identity_id(region): - return "{0}:{1}".format(region, uuid4()) + return "{0}:{1}".format(region, mock_random.uuid4()) diff --git a/moto/cognitoidp/models.py b/moto/cognitoidp/models.py index 577c347b2..d49965e98 100644 --- a/moto/cognitoidp/models.py +++ b/moto/cognitoidp/models.py @@ -3,13 +3,12 @@ import json import os import time import typing -import uuid import enum -import random from jose import jws from collections import OrderedDict from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random as random from .exceptions import ( GroupExistsException, NotAuthorizedError, @@ -562,7 +561,7 @@ class CognitoIdpUserPool(BaseModel): return id_token, expires_in def create_refresh_token(self, client_id, username): - refresh_token = str(uuid.uuid4()) + refresh_token = str(random.uuid4()) self.refresh_tokens[refresh_token] = (client_id, username) return refresh_token @@ -633,7 +632,7 @@ class CognitoIdpUserPoolDomain(BaseModel): if extended: return { "UserPoolId": self.user_pool_id, - "AWSAccountId": str(uuid.uuid4()), + "AWSAccountId": str(random.uuid4()), "CloudFrontDistribution": distribution, "Domain": self.domain, "S3Bucket": None, @@ -649,7 +648,7 @@ class CognitoIdpUserPoolClient(BaseModel): def __init__(self, user_pool_id, generate_secret, extended_config): self.user_pool_id = user_pool_id self.id = create_id() - self.secret = str(uuid.uuid4()) + self.secret = str(random.uuid4()) self.generate_secret = generate_secret or False self.extended_config = extended_config or {} @@ -736,7 +735,7 @@ class CognitoIdpGroup(BaseModel): class CognitoIdpUser(BaseModel): def __init__(self, user_pool_id, username, password, status, attributes): - self.id = str(uuid.uuid4()) + self.id = str(random.uuid4()) self.user_pool_id = user_pool_id # Username is None when users sign up with an email or phone_number, # and should be given the value of the internal id generate (sub) @@ -1289,7 +1288,7 @@ class CognitoIdpBackend(BaseBackend): UserStatus.FORCE_CHANGE_PASSWORD, UserStatus.RESET_REQUIRED, ]: - session = str(uuid.uuid4()) + session = str(random.uuid4()) self.sessions[session] = user_pool return { @@ -1635,15 +1634,15 @@ class CognitoIdpBackend(BaseBackend): if user.status is UserStatus.UNCONFIRMED: raise UserNotConfirmedException("User is not confirmed.") - session = str(uuid.uuid4()) + session = str(random.uuid4()) self.sessions[session] = user_pool return { "ChallengeName": "PASSWORD_VERIFIER", "Session": session, "ChallengeParameters": { - "SALT": uuid.uuid4().hex, - "SRP_B": uuid.uuid4().hex, + "SALT": random.uuid4().hex, + "SRP_B": random.uuid4().hex, "USERNAME": user.username, "USER_ID_FOR_SRP": user.id, "SECRET_BLOCK": session, @@ -1664,7 +1663,7 @@ class CognitoIdpBackend(BaseBackend): if user.status is UserStatus.UNCONFIRMED: raise UserNotConfirmedException("User is not confirmed.") - session = str(uuid.uuid4()) + session = str(random.uuid4()) self.sessions[session] = user_pool if user.status is UserStatus.FORCE_CHANGE_PASSWORD: @@ -1732,7 +1731,7 @@ class CognitoIdpBackend(BaseBackend): _, username = user_pool.access_tokens[access_token] self.admin_get_user(user_pool.id, username) - return {"SecretCode": str(uuid.uuid4())} + return {"SecretCode": str(random.uuid4())} raise NotAuthorizedError(access_token) diff --git a/moto/cognitoidp/utils.py b/moto/cognitoidp/utils.py index b4e7b0bb8..f1a594d27 100644 --- a/moto/cognitoidp/utils.py +++ b/moto/cognitoidp/utils.py @@ -1,10 +1,9 @@ -import random import string import hashlib import hmac import base64 import re -import uuid +from moto.moto_api._internal import mock_random as random FORMATS = { "email": r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", @@ -92,7 +91,7 @@ def generate_id(strategy, *args): def _generate_id_uuid(): - return uuid.uuid4().hex + return random.uuid4().hex def _generate_id_hash(args): diff --git a/moto/config/models.py b/moto/config/models.py index b5732db89..c516410c7 100644 --- a/moto/config/models.py +++ b/moto/config/models.py @@ -2,8 +2,6 @@ import json import re import time -import random -import string from datetime import datetime @@ -53,6 +51,7 @@ from moto.core import BaseBackend, BaseModel from moto.core.responses import AWSServiceSpec from moto.core.utils import BackendDict from moto.iam.config import role_config_query, policy_config_query +from moto.moto_api._internal import mock_random as random from moto.s3.config import s3_config_query from moto.s3control.config import s3_account_public_access_block_query from moto.utilities.utils import load_resource @@ -107,11 +106,7 @@ def snake_to_camels(original, cap_start, cap_arn): def random_string(): """Returns a random set of 8 lowercase letters for the Config Aggregator ARN""" - chars = [] - for _ in range(0, 8): - chars.append(random.choice(string.ascii_lowercase)) - - return "".join(chars) + return random.get_random_string(length=8, include_digits=False, lower_case=True) def validate_tag_key(tag_key, exception_param="tags.X.member.key"): diff --git a/moto/core/base_backend.py b/moto/core/base_backend.py index a6d3d97cb..6068dfd80 100644 --- a/moto/core/base_backend.py +++ b/moto/core/base_backend.py @@ -1,4 +1,3 @@ -import random import re import string from collections import defaultdict @@ -113,6 +112,8 @@ class BaseBackend: @staticmethod def vpce_random_number(): + from moto.moto_api._internal import mock_random as random + """Return random number for a VPC endpoint service ID.""" return "".join([random.choice(string.hexdigits.lower()) for i in range(17)]) diff --git a/moto/core/models.py b/moto/core/models.py index 041ef717a..5179f2e90 100644 --- a/moto/core/models.py +++ b/moto/core/models.py @@ -21,7 +21,6 @@ from .custom_responses_mock import ( not_implemented_callback, reset_responses_mock, ) -from .utils import convert_flask_to_responses_response DEFAULT_ACCOUNT_ID = "123456789012" @@ -272,6 +271,9 @@ class BotocoreEventMockAWS(BaseMockAWS): reset_responses_mock(responses_mock) def enable_patching(self, reset=True): # pylint: disable=unused-argument + # Circumvent circular imports + from .utils import convert_flask_to_responses_response + botocore_stubber.enabled = True for method in BOTOCORE_HTTP_METHODS: for backend in self.backends_for_urls: diff --git a/moto/core/utils.py b/moto/core/utils.py index 0595fbf8a..cff0ad78d 100644 --- a/moto/core/utils.py +++ b/moto/core/utils.py @@ -1,11 +1,8 @@ -from functools import lru_cache, wraps +from functools import lru_cache -import binascii import datetime import inspect -import random import re -import string from botocore.exceptions import ClientError from boto3 import Session from moto.settings import allow_unknown_region @@ -14,10 +11,6 @@ from urllib.parse import urlparse from uuid import uuid4 -REQUEST_ID_LONG = string.digits + string.ascii_uppercase -HEX_CHARS = list(range(10)) + ["a", "b", "c", "d", "e", "f"] - - def camelcase_to_underscores(argument): """Converts a camelcase param like theNewAttribute to the equivalent python underscore variable like the_new_attribute""" @@ -75,20 +68,6 @@ def method_names_from_class(clazz): return [x[0] for x in inspect.getmembers(clazz, predicate=predicate)] -def get_random_hex(length=8): - return "".join(str(random.choice(HEX_CHARS)) for _ in range(length)) - - -def get_random_message_id(): - return "{0}-{1}-{2}-{3}-{4}".format( - get_random_hex(8), - get_random_hex(4), - get_random_hex(4), - get_random_hex(4), - get_random_hex(12), - ) - - def convert_regex_to_flask_path(url_path): """ Converts a regex matching url to one that can be used with flask @@ -206,86 +185,6 @@ def unix_time_millis(dt=None): return unix_time(dt) * 1000.0 -def gen_amz_crc32(response, headerdict=None): - if not isinstance(response, bytes): - response = response.encode("utf-8") - - crc = binascii.crc32(response) - - if headerdict is not None and isinstance(headerdict, dict): - headerdict.update({"x-amz-crc32": str(crc)}) - - return crc - - -def gen_amzn_requestid_long(headerdict=None): - req_id = "".join([random.choice(REQUEST_ID_LONG) for _ in range(0, 52)]) - - if headerdict is not None and isinstance(headerdict, dict): - headerdict.update({"x-amzn-requestid": req_id}) - - return req_id - - -def amz_crc32(f): - @wraps(f) - def _wrapper(*args, **kwargs): - response = f(*args, **kwargs) - - headers = {} - status = 200 - - if isinstance(response, str): - body = response - else: - if len(response) == 2: - body, new_headers = response - status = new_headers.get("status", 200) - else: - status, new_headers, body = response - headers.update(new_headers) - # Cast status to string - if "status" in headers: - headers["status"] = str(headers["status"]) - - gen_amz_crc32(body, headers) - - return status, headers, body - - return _wrapper - - -def amzn_request_id(f): - @wraps(f) - def _wrapper(*args, **kwargs): - response = f(*args, **kwargs) - - headers = {} - status = 200 - - if isinstance(response, str): - body = response - else: - if len(response) == 2: - body, new_headers = response - status = new_headers.get("status", 200) - else: - status, new_headers, body = response - headers.update(new_headers) - - request_id = gen_amzn_requestid_long(headers) - - # Update request ID in XML - try: - body = re.sub(r"(?<=).*(?=<\/RequestId>)", request_id, body) - except Exception: # Will just ignore if it cant work - pass - - return status, headers, body - - return _wrapper - - def path_url(url): parsed_url = urlparse(url) path = parsed_url.path diff --git a/moto/databrew/responses.py b/moto/databrew/responses.py index 400ff3716..056380c0e 100644 --- a/moto/databrew/responses.py +++ b/moto/databrew/responses.py @@ -2,7 +2,7 @@ import json from urllib.parse import urlparse from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id +from moto.utilities.aws_headers import amzn_request_id from .models import databrew_backends diff --git a/moto/datapipeline/utils.py b/moto/datapipeline/utils.py index cb9c5e46c..0372c7b3e 100644 --- a/moto/datapipeline/utils.py +++ b/moto/datapipeline/utils.py @@ -1,9 +1,9 @@ import collections.abc as collections_abc -from moto.core.utils import get_random_hex +from moto.moto_api._internal import mock_random def get_random_pipeline_id(): - return "df-{0}".format(get_random_hex(length=19)) + return "df-{0}".format(mock_random.get_random_hex(length=19)) def remove_capitalization_of_dict_keys(obj): diff --git a/moto/dax/models.py b/moto/dax/models.py index e293a1993..2fbd9e21a 100644 --- a/moto/dax/models.py +++ b/moto/dax/models.py @@ -1,7 +1,8 @@ """DAXBackend class with methods for supported APIs.""" from moto.core import BaseBackend, BaseModel -from moto.core.utils import BackendDict, get_random_hex, unix_time +from moto.core.utils import BackendDict, unix_time from moto.moto_api import state_manager +from moto.moto_api._internal import mock_random as random from moto.moto_api._internal.managed_state_model import ManagedState from moto.utilities.tagging_service import TaggingService from moto.utilities.paginator import paginate @@ -89,7 +90,7 @@ class DaxCluster(BaseModel, ManagedState): self.arn = f"arn:aws:dax:{region}:{account_id}:cache/{self.name}" self.node_type = node_type self.replication_factor = replication_factor - self.cluster_hex = get_random_hex(6) + self.cluster_hex = random.get_random_hex(6) self.endpoint = DaxEndpoint( name=name, cluster_hex=self.cluster_hex, region=region ) @@ -99,7 +100,10 @@ class DaxCluster(BaseModel, ManagedState): self.iam_role_arn = iam_role_arn self.parameter_group = DaxParameterGroup() self.security_groups = [ - {"SecurityGroupIdentifier": f"sg-{get_random_hex(10)}", "Status": "active"} + { + "SecurityGroupIdentifier": f"sg-{random.get_random_hex(10)}", + "Status": "active", + } ] self.sse_specification = sse_specification self.encryption_type = encryption_type diff --git a/moto/ds/models.py b/moto/ds/models.py index c4eb1a274..c555e4123 100644 --- a/moto/ds/models.py +++ b/moto/ds/models.py @@ -2,7 +2,7 @@ from datetime import datetime, timezone from moto.core import BaseBackend, BaseModel -from moto.core.utils import get_random_hex, BackendDict +from moto.core.utils import BackendDict from moto.ds.exceptions import ( ClientException, DirectoryLimitExceededException, @@ -16,6 +16,7 @@ from moto.ds.utils import PAGINATION_MODEL from moto.ds.validations import validate_args from moto.ec2.exceptions import InvalidSubnetIdError from moto.ec2 import ec2_backends +from moto.moto_api._internal import mock_random from moto.utilities.paginator import paginate from moto.utilities.tagging_service import TaggingService @@ -71,7 +72,7 @@ class Directory(BaseModel): # pylint: disable=too-many-instance-attributes self.edition = edition # Calculated or default values for the directory attributes. - self.directory_id = f"d-{get_random_hex(10)}" + self.directory_id = f"d-{mock_random.get_random_hex(10)}" self.access_url = f"{self.directory_id}.awsapps.com" self.alias = self.directory_id self.desired_number_of_domain_controllers = 0 diff --git a/moto/dynamodb/models/__init__.py b/moto/dynamodb/models/__init__.py index 8b23a1aeb..c0f5f4354 100644 --- a/moto/dynamodb/models/__init__.py +++ b/moto/dynamodb/models/__init__.py @@ -4,7 +4,6 @@ import datetime import decimal import json import re -import uuid from collections import OrderedDict from moto.core import BaseBackend, BaseModel, CloudFormationModel @@ -40,6 +39,7 @@ from moto.dynamodb.parsing.executors import UpdateExpressionExecutor from moto.dynamodb.parsing.expressions import UpdateExpressionParser from moto.dynamodb.parsing.validators import UpdateExpressionValidator from moto.dynamodb.limits import HASH_KEY_MAX_LENGTH, RANGE_KEY_MAX_LENGTH +from moto.moto_api._internal import mock_random class DynamoJsonEncoder(json.JSONEncoder): @@ -222,7 +222,7 @@ class StreamRecord(BaseModel): keys[table.range_key_attr] = rec.range_key.to_json() self.record = { - "eventID": uuid.uuid4().hex, + "eventID": mock_random.uuid4().hex, "eventName": event_name, "eventSource": "aws:dynamodb", "eventVersion": "1.0", @@ -1125,7 +1125,7 @@ class Backup(object): def _make_identifier(self): timestamp = int(unix_time_millis(self.creation_date_time)) timestamp_padded = str("0" + str(timestamp))[-16:16] - guid = str(uuid.uuid4()) + guid = str(mock_random.uuid4()) guid_shortened = guid[:8] return "{}-{}".format(timestamp_padded, guid_shortened) diff --git a/moto/dynamodb/responses.py b/moto/dynamodb/responses.py index 3d6007b9a..38c506aa6 100644 --- a/moto/dynamodb/responses.py +++ b/moto/dynamodb/responses.py @@ -5,7 +5,7 @@ import itertools from functools import wraps from moto.core.responses import BaseResponse -from moto.core.utils import camelcase_to_underscores, amz_crc32, amzn_request_id +from moto.core.utils import camelcase_to_underscores from moto.dynamodb.parsing.key_condition_expression import parse_expression from moto.dynamodb.parsing.reserved_keywords import ReservedKeywords from .exceptions import ( @@ -14,6 +14,7 @@ from .exceptions import ( ConditionalCheckFailed, ) from moto.dynamodb.models import dynamodb_backends, dynamo_json_dump +from moto.utilities.aws_headers import amz_crc32, amzn_request_id TRANSACTION_MAX_ITEMS = 25 diff --git a/moto/ebs/models.py b/moto/ebs/models.py index df342ef5f..aa0883294 100644 --- a/moto/ebs/models.py +++ b/moto/ebs/models.py @@ -4,7 +4,7 @@ from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, unix_time from moto.ec2 import ec2_backends from moto.ec2.models.elastic_block_store import Snapshot -from uuid import uuid4 +from moto.moto_api._internal import mock_random class Block(BaseModel): @@ -13,7 +13,7 @@ class Block(BaseModel): self.checksum = checksum self.checksum_algorithm = checksum_algorithm self.data_length = data_length - self.block_token = str(uuid4()) + self.block_token = str(mock_random.uuid4()) class EBSSnapshot(BaseModel): diff --git a/moto/ec2/models/vpc_service_configuration.py b/moto/ec2/models/vpc_service_configuration.py index e679d7760..a7c760e70 100644 --- a/moto/ec2/models/vpc_service_configuration.py +++ b/moto/ec2/models/vpc_service_configuration.py @@ -1,5 +1,5 @@ from moto.core import CloudFormationModel -from moto.core.utils import get_random_hex +from moto.moto_api._internal import mock_random from .core import TaggedEC2Resource from ..exceptions import UnknownVpcEndpointService @@ -8,7 +8,7 @@ class VPCServiceConfiguration(TaggedEC2Resource, CloudFormationModel): def __init__( self, load_balancers, region, acceptance_required, private_dns_name, ec2_backend ): - self.id = f"vpce-svc-{get_random_hex(length=8)}" + self.id = f"vpce-svc-{mock_random.get_random_hex(length=8)}" self.service_name = f"com.amazonaws.vpce.{region}.{self.id}" self.service_state = "Available" diff --git a/moto/ec2/responses/launch_templates.py b/moto/ec2/responses/launch_templates.py index 92cfe7cf4..7a35affd1 100644 --- a/moto/ec2/responses/launch_templates.py +++ b/moto/ec2/responses/launch_templates.py @@ -1,5 +1,5 @@ -import uuid from moto.ec2.exceptions import FilterNotImplementedError +from moto.moto_api._internal import mock_random from ._base_response import EC2BaseResponse from xml.etree import ElementTree @@ -10,7 +10,7 @@ def xml_root(name): root = ElementTree.Element( name, {"xmlns": "http://ec2.amazonaws.com/doc/2016-11-15/"} ) - request_id = str(uuid.uuid4()) + "example" + request_id = str(mock_random.uuid4()) + "example" ElementTree.SubElement(root, "requestId").text = request_id return root diff --git a/moto/ec2/responses/subnets.py b/moto/ec2/responses/subnets.py index a82149768..34f318f9a 100644 --- a/moto/ec2/responses/subnets.py +++ b/moto/ec2/responses/subnets.py @@ -1,5 +1,5 @@ -import random from moto.core.utils import camelcase_to_underscores +from moto.moto_api._internal import mock_random as random from ._base_response import EC2BaseResponse diff --git a/moto/ec2/utils.py b/moto/ec2/utils.py index 1c080b34f..74e180b50 100644 --- a/moto/ec2/utils.py +++ b/moto/ec2/utils.py @@ -1,6 +1,5 @@ import base64 import fnmatch -import random import re import ipaddress @@ -10,6 +9,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa from moto.iam import iam_backends +from moto.moto_api._internal import mock_random as random from moto.utilities.utils import md5_hash EC2_RESOURCE_TO_PREFIX = { diff --git a/moto/ecr/models.py b/moto/ecr/models.py index ec7678074..51056842d 100644 --- a/moto/ecr/models.py +++ b/moto/ecr/models.py @@ -1,10 +1,8 @@ import hashlib import json import re -import uuid from collections import namedtuple from datetime import datetime, timezone -from random import random from typing import Dict, List from botocore.exceptions import ParamValidationError @@ -27,6 +25,7 @@ from moto.ecr.exceptions import ( from moto.ecr.policy_validation import EcrLifecyclePolicyValidator from moto.iam.exceptions import MalformedPolicyDocument from moto.iam.policy_validation import IAMPolicyDocumentValidator +from moto.moto_api._internal import mock_random as random from moto.utilities.tagging_service import TaggingService ECR_REPOSITORY_ARN_PATTERN = "^arn:(?P[^:]+):ecr:(?P[^:]+):(?P[^:]+):repository/(?P.*)$" @@ -97,7 +96,7 @@ class Repository(BaseObject, CloudFormationModel): if encryption_config == {"encryptionType": "KMS"}: encryption_config[ "kmsKey" - ] = f"arn:aws:kms:{self.region_name}:{self.account_id}:key/{uuid.uuid4()}" + ] = f"arn:aws:kms:{self.region_name}:{self.account_id}:key/{random.uuid4()}" return encryption_config def _get_image(self, image_tag, image_digest): @@ -250,7 +249,7 @@ class Image(BaseObject): self.last_scan = None def _create_digest(self): - image_contents = "docker_image{0}".format(int(random() * 10**6)) + image_contents = "docker_image{0}".format(int(random.random() * 10**6)) self.image_digest = ( "sha256:%s" % hashlib.sha256(image_contents.encode("utf-8")).hexdigest() ) diff --git a/moto/ecs/models.py b/moto/ecs/models.py index 1b53cd14b..cb4f4140f 100644 --- a/moto/ecs/models.py +++ b/moto/ecs/models.py @@ -1,8 +1,6 @@ import re -import uuid from copy import copy from datetime import datetime -from random import random, randint import pytz @@ -16,6 +14,7 @@ from moto.core.utils import ( BackendDict, ) from moto.ec2 import ec2_backends +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService from .exceptions import ( EcsClientException, @@ -243,7 +242,7 @@ class TaskDefinition(BaseObject, CloudFormationModel): properties = cloudformation_json["Properties"] family = properties.get( - "Family", "task-definition-{0}".format(int(random() * 10**6)) + "Family", "task-definition-{0}".format(int(mock_random.random() * 10**6)) ) container_definitions = remap_nested_keys( properties.get("ContainerDefinitions", []), pascal_to_camelcase @@ -266,7 +265,7 @@ class TaskDefinition(BaseObject, CloudFormationModel): ): properties = cloudformation_json["Properties"] family = properties.get( - "Family", "task-definition-{0}".format(int(random() * 10**6)) + "Family", "task-definition-{0}".format(int(mock_random.random() * 10**6)) ) container_definitions = properties["ContainerDefinitions"] volumes = properties.get("Volumes") @@ -302,7 +301,7 @@ class Task(BaseObject): started_by="", tags=None, ): - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.cluster_name = cluster.name self.cluster_arn = cluster.arn self.container_instance_arn = container_instance_arn @@ -335,7 +334,7 @@ class Task(BaseObject): class CapacityProvider(BaseObject): def __init__(self, account_id, region_name, name, asg_details, tags): - self._id = str(uuid.uuid4()) + self._id = str(mock_random.uuid4()) self.capacity_provider_arn = f"arn:aws:ecs:{region_name}:{account_id}:capacity_provider/{name}/{self._id}" self.name = name self.status = "ACTIVE" @@ -391,7 +390,7 @@ class Service(BaseObject, CloudFormationModel): { "createdAt": datetime.now(pytz.utc), "desiredCount": self.desired_count, - "id": "ecs-svc/{}".format(randint(0, 32**12)), + "id": "ecs-svc/{}".format(mock_random.randint(0, 32**12)), "launchType": self.launch_type, "pendingCount": self.desired_count, "runningCount": 0, @@ -620,7 +619,7 @@ class ContainerInstance(BaseObject): } self.registered_at = datetime.now(pytz.utc) self.region_name = region_name - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.cluster_name = cluster_name self._account_id = backend.account_id self._backend = backend @@ -718,7 +717,7 @@ class TaskSet(BaseObject): self.createdAt = datetime.now(pytz.utc) self.updatedAt = datetime.now(pytz.utc) self.stabilityStatusAt = datetime.now(pytz.utc) - self.id = "ecs-svc/{}".format(randint(0, 32**12)) + self.id = "ecs-svc/{}".format(mock_random.randint(0, 32**12)) self.service_arn = "" self.cluster_arn = "" diff --git a/moto/efs/models.py b/moto/efs/models.py index 3fc04ff51..f1d170ce5 100644 --- a/moto/efs/models.py +++ b/moto/efs/models.py @@ -11,7 +11,6 @@ from copy import deepcopy from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core.utils import ( camelcase_to_underscores, - get_random_hex, underscores_to_camelcase, BackendDict, ) @@ -30,6 +29,7 @@ from moto.efs.exceptions import ( SecurityGroupNotFound, SecurityGroupLimitExceeded, ) +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService from moto.utilities.utils import md5_hash @@ -54,7 +54,7 @@ class AccessPoint(BaseModel): root_directory, context, ): - self.access_point_id = get_random_hex(8) + self.access_point_id = mock_random.get_random_hex(8) self.access_point_arn = f"arn:aws:elasticfilesystem:{region_name}:{account_id}:access-point/fsap-{self.access_point_id}" self.client_token = client_token self.file_system_id = file_system_id @@ -297,7 +297,7 @@ class MountTarget(CloudFormationModel): # Init non-user-assigned values. self.owner_id = account_id - self.mount_target_id = "fsmt-{}".format(get_random_hex()) + self.mount_target_id = "fsmt-{}".format(mock_random.get_random_hex()) self.life_cycle_state = "available" self.network_interface_id = None self.availability_zone_id = subnet.availability_zone_id @@ -418,7 +418,7 @@ class EFSBackend(BaseBackend): # Create a new file system ID: def make_id(): - return "fs-{}".format(get_random_hex()) + return "fs-{}".format(mock_random.get_random_hex()) fsid = make_id() while fsid in self.file_systems_by_id: diff --git a/moto/eks/models.py b/moto/eks/models.py index 9b58aab70..d9e842f58 100644 --- a/moto/eks/models.py +++ b/moto/eks/models.py @@ -1,10 +1,9 @@ from datetime import datetime -from uuid import uuid4 from moto.core import BaseBackend from moto.core.utils import iso_8601_datetime_without_milliseconds, BackendDict +from moto.moto_api._internal import mock_random as random -from ..utilities.utils import random_string from .exceptions import ( InvalidParameterException, InvalidRequestException, @@ -17,12 +16,14 @@ from .utils import get_partition, validate_role_arn CLUSTER_ARN_TEMPLATE = "arn:{partition}:eks:{region}:{account_id}:cluster/{name}" FARGATE_PROFILE_ARN_TEMPLATE = "arn:{partition}:eks:{region}:{account_id}:fargateprofile/{cluster_name}/{fargate_profile_name}/{uuid}" NODEGROUP_ARN_TEMPLATE = "arn:{partition}:eks:{region}:{account_id}:nodegroup/{cluster_name}/{nodegroup_name}/{uuid}" -ISSUER_TEMPLATE = "https://oidc.eks.{region}.amazonaws.com/id/" + random_string(10) +ISSUER_TEMPLATE = ( + "https://oidc.eks.{region}.amazonaws.com/id/" + random.get_random_string(length=10) +) ENDPOINT_TEMPLATE = ( "https://" - + random_string() + + random.get_random_string() + "." - + random_string(3) + + random.get_random_string(3) + ".{region}.eks.amazonaws.com/" ) @@ -120,7 +121,7 @@ class Cluster: region=region_name, name=name, ) - self.certificateAuthority = {"data": random_string(1400)} + self.certificateAuthority = {"data": random.get_random_string(1400)} self.creation_date = iso_8601_datetime_without_milliseconds(datetime.now()) self.identity = {"oidc": {"issuer": ISSUER_TEMPLATE.format(region=region_name)}} self.endpoint = ENDPOINT_TEMPLATE.format(region=region_name) @@ -182,7 +183,7 @@ class FargateProfile: tags = dict() self.created_at = iso_8601_datetime_without_milliseconds(datetime.now()) - self.uuid = str(uuid4()) + self.uuid = str(random.uuid4()) self.fargate_profile_arn = FARGATE_PROFILE_ARN_TEMPLATE.format( partition=aws_partition, account_id=account_id, @@ -244,7 +245,7 @@ class ManagedNodegroup: if taints is None: taints = dict() - self.uuid = str(uuid4()) + self.uuid = str(random.uuid4()) self.arn = NODEGROUP_ARN_TEMPLATE.format( partition=aws_partition, account_id=account_id, @@ -258,7 +259,7 @@ class ManagedNodegroup: self.health = DEFAULT_NODEGROUP_HEALTH self.resources = { "autoScalingGroups": [{"name": "eks-" + self.uuid}], - "remoteAccessSecurityGroup": "sg-" + random_string(17).lower(), + "remoteAccessSecurityGroup": "sg-" + random.get_random_string(17).lower(), } self.ami_type = ami_type or DEFAULT_AMI_TYPE diff --git a/moto/elastictranscoder/models.py b/moto/elastictranscoder/models.py index 01ab2d740..f0aadd1f1 100644 --- a/moto/elastictranscoder/models.py +++ b/moto/elastictranscoder/models.py @@ -1,6 +1,6 @@ from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict -import random +from moto.moto_api._internal import mock_random as random import string diff --git a/moto/elb/models.py b/moto/elb/models.py index f5487860d..1b9810c29 100644 --- a/moto/elb/models.py +++ b/moto/elb/models.py @@ -7,7 +7,7 @@ from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core.utils import BackendDict from moto.ec2.models import ec2_backends from moto.ec2.exceptions import InvalidInstanceIdError -from uuid import uuid4 +from moto.moto_api._internal import mock_random from .exceptions import ( BadHealthCheckDefinition, DuplicateLoadBalancerName, @@ -306,7 +306,7 @@ class ELBBackend(BaseBackend): raise EmptyListenersError() if not security_groups: sg = ec2_backend.create_security_group( - name=f"default_elb_{uuid4()}", + name=f"default_elb_{mock_random.uuid4()}", description="ELB created security group used when no security group is specified during ELB creation - modifications could impact traffic to future ELBs", vpc_id=vpc_id, ) diff --git a/moto/elbv2/models.py b/moto/elbv2/models.py index 2b30c3fa8..ad0a92157 100644 --- a/moto/elbv2/models.py +++ b/moto/elbv2/models.py @@ -7,10 +7,10 @@ from moto.core.exceptions import RESTError from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core.utils import ( iso_8601_datetime_with_milliseconds, - get_random_hex, BackendDict, ) from moto.ec2.models import ec2_backends +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService from .utils import make_arn_for_target_group from .utils import make_arn_for_load_balancer @@ -757,7 +757,7 @@ class ELBv2Backend(BaseBackend): self._validate_actions(actions) arn = listener_arn.replace(":listener/", ":listener-rule/") - arn += "/%s" % (get_random_hex(16)) + arn += f"/{mock_random.get_random_hex(16)}" # TODO: check for error 'TooManyRegistrationsForTargetId' # TODO: check for error 'TooManyRules' diff --git a/moto/elbv2/responses.py b/moto/elbv2/responses.py index c03b23395..1ade5f956 100644 --- a/moto/elbv2/responses.py +++ b/moto/elbv2/responses.py @@ -1,6 +1,6 @@ from moto.core.exceptions import RESTError -from moto.core.utils import amzn_request_id from moto.core.responses import BaseResponse +from moto.utilities.aws_headers import amzn_request_id from .models import elbv2_backends from .exceptions import TargetGroupNotFoundError from .exceptions import ListenerOrBalancerMissingError diff --git a/moto/emr/utils.py b/moto/emr/utils.py index b0746ece5..b9af693d0 100644 --- a/moto/emr/utils.py +++ b/moto/emr/utils.py @@ -1,12 +1,12 @@ import copy import datetime -import random import re import string from moto.core.utils import ( camelcase_to_underscores, iso_8601_datetime_with_milliseconds, ) +from moto.moto_api._internal import mock_random as random def random_id(size=13): diff --git a/moto/emrcontainers/utils.py b/moto/emrcontainers/utils.py index 07276318a..09c3cc600 100644 --- a/moto/emrcontainers/utils.py +++ b/moto/emrcontainers/utils.py @@ -1,6 +1,6 @@ # import json import string -import random +from moto.moto_api._internal import mock_random as random def get_partition(region): diff --git a/moto/emrserverless/utils.py b/moto/emrserverless/utils.py index 51f3839b5..afa8153aa 100644 --- a/moto/emrserverless/utils.py +++ b/moto/emrserverless/utils.py @@ -1,5 +1,4 @@ -# import json -import random +from moto.moto_api._internal import mock_random as random import string diff --git a/moto/es/models.py b/moto/es/models.py index a790638a2..c7dbd5236 100644 --- a/moto/es/models.py +++ b/moto/es/models.py @@ -1,5 +1,6 @@ from moto.core import BaseBackend, BaseModel -from moto.core.utils import get_random_hex, BackendDict +from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random from .exceptions import DomainNotFound @@ -23,7 +24,7 @@ class Domain(BaseModel): advanced_security_options, auto_tune_options, ): - self.domain_id = get_random_hex(8) + self.domain_id = mock_random.get_random_hex(8) self.region_name = region_name self.domain_name = domain_name self.es_version = es_version diff --git a/moto/events/models.py b/moto/events/models.py index 8fade1e07..77ec21f9a 100644 --- a/moto/events/models.py +++ b/moto/events/models.py @@ -26,11 +26,10 @@ from moto.events.exceptions import ( InvalidEventPatternException, IllegalStatusException, ) +from moto.moto_api._internal import mock_random as random from moto.utilities.paginator import paginate from moto.utilities.tagging_service import TaggingService -from uuid import uuid4 - from .utils import PAGINATION_MODEL # Sentinel to signal the absence of a field for `Exists` pattern matching @@ -183,12 +182,9 @@ class Rule(CloudFormationModel): datetime.utcfromtimestamp(event_copy["time"]) ) - log_stream_name = str(uuid4()) + log_stream_name = str(random.uuid4()) log_events = [ - { - "timestamp": unix_time_millis(datetime.utcnow()), - "message": json.dumps(event_copy), - } + {"timestamp": unix_time_millis(), "message": json.dumps(event_copy)} ] log_backend = logs_backends[self.account_id][self.region_name] @@ -521,7 +517,7 @@ class Archive(CloudFormationModel): self.arn = f"arn:aws:events:{region_name}:{account_id}:archive/{name}" self.creation_time = unix_time(datetime.utcnow()) self.state = "ENABLED" - self.uuid = str(uuid4()) + self.uuid = str(random.uuid4()) self.events = [] self.event_bus_name = source_arn.split("/")[-1] @@ -691,7 +687,9 @@ class Replay(BaseModel): for rule in event_backend.rules.values(): rule.send_to_targets( event_bus_name, - dict(event, **{"id": str(uuid4()), "replay-name": self.name}), + dict( + event, **{"id": str(random.uuid4()), "replay-name": self.name} + ), ) self.state = ReplayState.COMPLETED @@ -708,7 +706,7 @@ class Connection(BaseModel): authorization_type, auth_parameters, ): - self.uuid = uuid4() + self.uuid = random.uuid4() self.name = name self.region = region_name self.description = description @@ -784,7 +782,7 @@ class Destination(BaseModel): invocation_rate_limit_per_second, http_method, ): - self.uuid = uuid4() + self.uuid = random.uuid4() self.name = name self.region = region_name self.description = description @@ -1234,7 +1232,7 @@ class EventsBackend(BaseBackend): ) continue - event_id = str(uuid4()) + event_id = str(random.uuid4()) entries.append({"EventId": event_id}) # if 'EventBusName' is not especially set, it will be sent to the default one diff --git a/moto/firehose/models.py b/moto/firehose/models.py index 75e28961e..37bd35448 100644 --- a/moto/firehose/models.py +++ b/moto/firehose/models.py @@ -21,7 +21,6 @@ from gzip import GzipFile import io import json from time import time -from uuid import uuid4 import warnings import requests @@ -36,6 +35,7 @@ from moto.firehose.exceptions import ( ResourceNotFoundException, ValidationException, ) +from moto.moto_api._internal import mock_random from moto.s3.models import s3_backends from moto.utilities.tagging_service import TaggingService @@ -407,7 +407,7 @@ class FirehoseBackend(BaseBackend): url = http_destination["EndpointConfiguration"]["Url"] headers = {"Content-Type": "application/json"} record_to_send = { - "requestId": str(uuid4()), + "requestId": str(mock_random.uuid4()), "timestamp": int(time()), "records": [{"data": record["Data"]} for record in records], } @@ -418,7 +418,7 @@ class FirehoseBackend(BaseBackend): raise RuntimeError( "Firehose PutRecord(Batch) to HTTP destination failed" ) from exc - return [{"RecordId": str(uuid4())} for _ in range(len(records))] + return [{"RecordId": str(mock_random.uuid4())} for _ in range(len(records))] @staticmethod def _format_s3_object_path(delivery_stream_name, version_id, prefix): @@ -433,7 +433,7 @@ class FirehoseBackend(BaseBackend): return ( f"{prefix}{now.strftime('%Y/%m/%d/%H')}/" f"{delivery_stream_name}-{version_id}-" - f"{now.strftime('%Y-%m-%d-%H-%M-%S')}-{str(uuid4())}" + f"{now.strftime('%Y-%m-%d-%H-%M-%S')}-{str(mock_random.uuid4())}" ) def put_s3_records(self, delivery_stream_name, version_id, s3_destination, records): @@ -455,7 +455,7 @@ class FirehoseBackend(BaseBackend): raise RuntimeError( "Firehose PutRecord(Batch to S3 destination failed" ) from exc - return [{"RecordId": str(uuid4())} for _ in range(len(records))] + return [{"RecordId": str(mock_random.uuid4())} for _ in range(len(records))] def put_record_batch(self, delivery_stream_name, records): """Write multiple data records into a Kinesis Data firehose stream.""" @@ -494,7 +494,7 @@ class FirehoseBackend(BaseBackend): # This isn't implmented as these services aren't implemented, # so ignore the data, but return a "proper" response. request_responses = [ - {"RecordId": str(uuid4())} for _ in range(len(records)) + {"RecordId": str(mock_random.uuid4())} for _ in range(len(records)) ] return { diff --git a/moto/forecast/responses.py b/moto/forecast/responses.py index bee513d9a..55a830265 100644 --- a/moto/forecast/responses.py +++ b/moto/forecast/responses.py @@ -1,7 +1,7 @@ import json from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id +from moto.utilities.aws_headers import amzn_request_id from .models import forecast_backends diff --git a/moto/glacier/utils.py b/moto/glacier/utils.py index 8c1ec9db3..813945b5f 100644 --- a/moto/glacier/utils.py +++ b/moto/glacier/utils.py @@ -1,4 +1,4 @@ -import random +from moto.moto_api._internal import mock_random as random import string diff --git a/moto/glue/models.py b/moto/glue/models.py index fdb0d9dc1..a2afeac2d 100644 --- a/moto/glue/models.py +++ b/moto/glue/models.py @@ -2,11 +2,11 @@ import time from collections import OrderedDict from datetime import datetime from typing import List -from uuid import uuid4 from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict from moto.moto_api import state_manager +from moto.moto_api._internal import mock_random from moto.moto_api._internal.managed_state_model import ManagedState from .exceptions import ( JsonRESTError, @@ -1072,7 +1072,7 @@ class FakeSchemaVersion(BaseModel): self.schema_definition = schema_definition self.schema_version_status = AVAILABLE_STATUS self.version_number = version_number - self.schema_version_id = str(uuid4()) + self.schema_version_id = str(mock_random.uuid4()) self.created_time = datetime.utcnow() self.updated_time = datetime.utcnow() self.metadata = OrderedDict() diff --git a/moto/greengrass/models.py b/moto/greengrass/models.py index f54892aa0..b653ec037 100644 --- a/moto/greengrass/models.py +++ b/moto/greengrass/models.py @@ -1,11 +1,11 @@ import json -import uuid from collections import OrderedDict from datetime import datetime import re from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, iso_8601_datetime_with_milliseconds +from moto.moto_api._internal import mock_random from .exceptions import ( GreengrassClientError, IdNotFoundException, @@ -21,7 +21,7 @@ class FakeCoreDefinition(BaseModel): def __init__(self, account_id, region_name, name): self.region_name = region_name self.name = name - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{region_name}:{account_id}:greengrass/definition/cores/{self.id}" self.created_at_datetime = datetime.utcnow() self.latest_version = "" @@ -48,7 +48,7 @@ class FakeCoreDefinitionVersion(BaseModel): self.region_name = region_name self.core_definition_id = core_definition_id self.definition = definition - self.version = str(uuid.uuid4()) + self.version = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{region_name}:{account_id}:greengrass/definition/cores/{self.core_definition_id}/versions/{self.version}" self.created_at_datetime = datetime.utcnow() @@ -71,7 +71,7 @@ class FakeCoreDefinitionVersion(BaseModel): class FakeDeviceDefinition(BaseModel): def __init__(self, account_id, region_name, name, initial_version): self.region_name = region_name - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{region_name}:{account_id}:greengrass/definition/devices/{self.id}" self.created_at_datetime = datetime.utcnow() self.update_at_datetime = datetime.utcnow() @@ -103,7 +103,7 @@ class FakeDeviceDefinitionVersion(BaseModel): self.region_name = region_name self.device_definition_id = device_definition_id self.devices = devices - self.version = str(uuid.uuid4()) + self.version = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{region_name}:{account_id}:greengrass/definition/devices/{self.device_definition_id}/versions/{self.version}" self.created_at_datetime = datetime.utcnow() @@ -126,7 +126,7 @@ class FakeDeviceDefinitionVersion(BaseModel): class FakeResourceDefinition(BaseModel): def __init__(self, account_id, region_name, name, initial_version): self.region_name = region_name - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{region_name}:{account_id}:greengrass/definition/resources/{self.id}" self.created_at_datetime = datetime.utcnow() self.update_at_datetime = datetime.utcnow() @@ -156,7 +156,7 @@ class FakeResourceDefinitionVersion(BaseModel): self.region_name = region_name self.resource_definition_id = resource_definition_id self.resources = resources - self.version = str(uuid.uuid4()) + self.version = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{region_name}:{account_id}:greengrass/definition/resources/{self.resource_definition_id}/versions/{self.version}" self.created_at_datetime = datetime.utcnow() @@ -175,7 +175,7 @@ class FakeResourceDefinitionVersion(BaseModel): class FakeFunctionDefinition(BaseModel): def __init__(self, account_id, region_name, name, initial_version): self.region_name = region_name - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{self.region_name}:{account_id}:greengrass/definition/functions/{self.id}" self.created_at_datetime = datetime.utcnow() self.update_at_datetime = datetime.utcnow() @@ -210,7 +210,7 @@ class FakeFunctionDefinitionVersion(BaseModel): self.function_definition_id = function_definition_id self.functions = functions self.default_config = default_config - self.version = str(uuid.uuid4()) + self.version = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{self.region_name}:{account_id}:greengrass/definition/functions/{self.function_definition_id}/versions/{self.version}" self.created_at_datetime = datetime.utcnow() @@ -229,7 +229,7 @@ class FakeFunctionDefinitionVersion(BaseModel): class FakeSubscriptionDefinition(BaseModel): def __init__(self, account_id, region_name, name, initial_version): self.region_name = region_name - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{self.region_name}:{account_id}:greengrass/definition/subscriptions/{self.id}" self.created_at_datetime = datetime.utcnow() self.update_at_datetime = datetime.utcnow() @@ -261,7 +261,7 @@ class FakeSubscriptionDefinitionVersion(BaseModel): self.region_name = region_name self.subscription_definition_id = subscription_definition_id self.subscriptions = subscriptions - self.version = str(uuid.uuid4()) + self.version = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{self.region_name}:{account_id}:greengrass/definition/subscriptions/{self.subscription_definition_id}/versions/{self.version}" self.created_at_datetime = datetime.utcnow() @@ -280,7 +280,7 @@ class FakeSubscriptionDefinitionVersion(BaseModel): class FakeGroup(BaseModel): def __init__(self, account_id, region_name, name): self.region_name = region_name - self.group_id = str(uuid.uuid4()) + self.group_id = str(mock_random.uuid4()) self.name = name self.arn = f"arn:aws:greengrass:{self.region_name}:{account_id}:greengrass/groups/{self.group_id}" self.created_at_datetime = datetime.utcnow() @@ -319,7 +319,7 @@ class FakeGroupVersion(BaseModel): ): self.region_name = region_name self.group_id = group_id - self.version = str(uuid.uuid4()) + self.version = str(mock_random.uuid4()) self.arn = f"arn:aws:greengrass:{self.region_name}:{account_id}:greengrass/groups/{self.group_id}/versions/{self.version}" self.created_at_datetime = datetime.utcnow() self.core_definition_version_arn = core_definition_version_arn @@ -372,7 +372,7 @@ class FakeGroupVersion(BaseModel): class FakeDeployment(BaseModel): def __init__(self, account_id, region_name, group_id, group_arn, deployment_type): self.region_name = region_name - self.id = str(uuid.uuid4()) + self.id = str(mock_random.uuid4()) self.group_id = group_id self.group_arn = group_arn self.created_at_datetime = datetime.utcnow() diff --git a/moto/guardduty/models.py b/moto/guardduty/models.py index fcdf53dd3..afddd0403 100644 --- a/moto/guardduty/models.py +++ b/moto/guardduty/models.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals from moto.core import BaseBackend, BaseModel -from moto.core.utils import BackendDict, get_random_hex +from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random from datetime import datetime from .exceptions import DetectorNotFoundException, FilterNotFoundException @@ -129,7 +130,7 @@ class Detector(BaseModel): datasources, tags, ): - self.id = get_random_hex(length=32) + self.id = mock_random.get_random_hex(length=32) self.created_at = created_at self.finding_publish_freq = finding_publish_freq self.service_role = f"arn:aws:iam::{account_id}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty" diff --git a/moto/iam/models.py b/moto/iam/models.py index 4bf5323b5..bef9c3961 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -1,9 +1,7 @@ import base64 import os -import random import string import sys -import uuid from datetime import datetime import json import re @@ -26,6 +24,7 @@ from moto.iam.policy_validation import ( IAMPolicyDocumentValidator, IAMTrustPolicyDocumentValidator, ) +from moto.moto_api._internal import mock_random as random from moto.utilities.utils import md5_hash from .aws_managed_policies import aws_managed_policies_data @@ -3029,7 +3028,7 @@ class IAMBackend(BaseBackend): def delete_service_linked_role(self, role_name): self.delete_role(role_name) - deletion_task_id = str(uuid.uuid4()) + deletion_task_id = str(random.uuid4()) return deletion_task_id def get_service_linked_role_deletion_status(self): diff --git a/moto/iam/utils.py b/moto/iam/utils.py index 42ca109bf..76743751d 100644 --- a/moto/iam/utils.py +++ b/moto/iam/utils.py @@ -1,4 +1,4 @@ -import random +from moto.moto_api._internal import mock_random as random import string diff --git a/moto/iot/models.py b/moto/iot/models.py index fd01b31bb..a291aec34 100644 --- a/moto/iot/models.py +++ b/moto/iot/models.py @@ -1,9 +1,6 @@ import hashlib -import random import re -import string import time -import uuid from collections import OrderedDict from cryptography import x509 from cryptography.hazmat.backends import default_backend @@ -16,7 +13,7 @@ from .utils import PAGINATION_MODEL from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict -from moto.utilities.utils import random_string +from moto.moto_api._internal import mock_random as random from moto.utilities.paginator import paginate from .exceptions import ( CertificateStateException, @@ -74,7 +71,7 @@ class FakeThingType(BaseModel): self.region_name = region_name self.thing_type_name = thing_type_name self.thing_type_properties = thing_type_properties - self.thing_type_id = str(uuid.uuid4()) # I don't know the rule of id + self.thing_type_id = str(random.uuid4()) # I don't know the rule of id t = time.time() self.metadata = {"deprecated": False, "creationDate": int(t * 1000) / 1000.0} self.arn = "arn:aws:iot:%s:1:thingtype/%s" % (self.region_name, thing_type_name) @@ -100,7 +97,7 @@ class FakeThingGroup(BaseModel): ): self.region_name = region_name self.thing_group_name = thing_group_name - self.thing_group_id = str(uuid.uuid4()) # I don't know the rule of id + self.thing_group_id = str(random.uuid4()) # I don't know the rule of id self.version = 1 # TODO: tmp self.parent_group_name = parent_group_name self.thing_group_properties = thing_group_properties or {} @@ -434,7 +431,7 @@ class FakeEndpoint(BaseModel): "operation: Endpoint type %s not recognized." % endpoint_type ) self.region_name = region_name - identifier = random_string(14).lower() + identifier = random.get_random_string(length=14, lower_case=True) if endpoint_type == "iot:Data": self.endpoint = "{i}.iot.{r}.amazonaws.com".format( i=identifier, r=self.region_name @@ -540,7 +537,7 @@ class FakeDomainConfiguration(BaseModel): self.domain_configuration_arn = "arn:aws:iot:%s:1:domainconfiguration/%s/%s" % ( region_name, domain_configuration_name, - random_string(5), + random.get_random_string(length=5), ) self.domain_name = domain_name self.server_certificates = [] @@ -836,21 +833,14 @@ class IoTBackend(BaseBackend): else: thing.attributes.update(attributes) - def _random_string(self): - n = 20 - random_str = "".join( - [random.choice(string.ascii_letters + string.digits) for i in range(n)] - ) - return random_str - def create_keys_and_certificate(self, set_as_active): # implement here # caCertificate can be blank key_pair = { - "PublicKey": self._random_string(), - "PrivateKey": self._random_string(), + "PublicKey": random.get_random_string(), + "PrivateKey": random.get_random_string(), } - certificate_pem = self._random_string() + certificate_pem = random.get_random_string() status = "ACTIVE" if set_as_active else "INACTIVE" certificate = FakeCertificate( certificate_pem, status, self.account_id, self.region_name @@ -910,7 +900,7 @@ class IoTBackend(BaseBackend): return certs[0] def get_registration_code(self): - return str(uuid.uuid4()) + return str(random.uuid4()) def list_certificates(self): """ diff --git a/moto/kinesisvideo/models.py b/moto/kinesisvideo/models.py index ba2fc3779..221d7d1aa 100644 --- a/moto/kinesisvideo/models.py +++ b/moto/kinesisvideo/models.py @@ -1,9 +1,8 @@ from moto.core import BaseBackend, BaseModel from datetime import datetime from .exceptions import ResourceNotFoundException, ResourceInUseException -import random -import string -from moto.core.utils import get_random_hex, BackendDict +from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random as random class Stream(BaseModel): @@ -26,17 +25,12 @@ class Stream(BaseModel): self.data_retention_in_hours = data_retention_in_hours self.tags = tags self.status = "ACTIVE" - self.version = self._get_random_string() + self.version = random.get_random_string(include_digits=False, lower_case=True) self.creation_time = datetime.utcnow() stream_arn = f"arn:aws:kinesisvideo:{region_name}:{account_id}:stream/{stream_name}/1598784211076" - self.data_endpoint_number = get_random_hex() + self.data_endpoint_number = random.get_random_hex() self.arn = stream_arn - def _get_random_string(self, length=20): - letters = string.ascii_lowercase - result_str = "".join([random.choice(letters) for _ in range(length)]) - return result_str - def get_data_endpoint(self, api_name): data_endpoint_prefix = "s-" if api_name in ("PUT_MEDIA", "GET_MEDIA") else "b-" return "https://{}{}.kinesisvideo.{}.amazonaws.com".format( diff --git a/moto/kms/models.py b/moto/kms/models.py index 0a4120654..5953d4ae0 100644 --- a/moto/kms/models.py +++ b/moto/kms/models.py @@ -9,7 +9,8 @@ from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding from moto.core import BaseBackend, BaseModel, CloudFormationModel -from moto.core.utils import get_random_hex, unix_time, BackendDict +from moto.core.utils import unix_time, BackendDict +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService from moto.core.exceptions import JsonRESTError @@ -40,8 +41,8 @@ class Grant(BaseModel): self.retiring_principal = retiring_principal self.operations = operations self.constraints = constraints - self.id = get_random_hex() - self.token = get_random_hex() + self.id = mock_random.get_random_hex() + self.token = mock_random.get_random_hex() def to_json(self): return { diff --git a/moto/kms/utils.py b/moto/kms/utils.py index 1173a1592..c7fc27409 100644 --- a/moto/kms/utils.py +++ b/moto/kms/utils.py @@ -2,7 +2,7 @@ from collections import namedtuple import io import os import struct -import uuid +from moto.moto_api._internal import mock_random from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes @@ -46,7 +46,7 @@ RESERVED_ALIASES = [ def generate_key_id(multi_region=False): - key = str(uuid.uuid4()) + key = str(mock_random.uuid4()) # https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html # "Notice that multi-Region keys have a distinctive key ID that begins with mrk-. You can use the mrk- prefix to # identify MRKs programmatically." diff --git a/moto/logs/models.py b/moto/logs/models.py index c979f960c..e5ce29d60 100644 --- a/moto/logs/models.py +++ b/moto/logs/models.py @@ -1,11 +1,8 @@ -import uuid - from datetime import datetime, timedelta from moto.core import BaseBackend, BaseModel from moto.core import CloudFormationModel from moto.core.utils import unix_time_millis, BackendDict -from moto.utilities.paginator import paginate from moto.logs.metric_filters import MetricFilters from moto.logs.exceptions import ( ResourceNotFoundException, @@ -13,7 +10,9 @@ from moto.logs.exceptions import ( InvalidParameterException, LimitExceededException, ) +from moto.moto_api._internal import mock_random from moto.s3.models import s3_backends +from moto.utilities.paginator import paginate from .utils import PAGINATION_MODEL, EventMessageFilter MAX_RESOURCE_POLICIES_PER_REGION = 10 @@ -943,7 +942,7 @@ class LogsBackend(BaseBackend): if log_group_name not in self.groups: raise ResourceNotFoundException() - query_id = uuid.uuid1() + query_id = mock_random.uuid1() self.queries[query_id] = LogQuery(query_id, start_time, end_time, query_string) return query_id @@ -951,7 +950,7 @@ class LogsBackend(BaseBackend): s3_backends[self.account_id]["global"].get_bucket(destination) if log_group_name not in self.groups: raise ResourceNotFoundException() - task_id = uuid.uuid4() + task_id = mock_random.uuid4() return task_id diff --git a/moto/managedblockchain/utils.py b/moto/managedblockchain/utils.py index 280f108fc..710939c31 100644 --- a/moto/managedblockchain/utils.py +++ b/moto/managedblockchain/utils.py @@ -1,8 +1,7 @@ import json -import random import re import string - +from moto.moto_api._internal import mock_random as random from urllib.parse import parse_qs, urlparse diff --git a/moto/mediaconnect/models.py b/moto/mediaconnect/models.py index 574fdfd3b..d8e269a43 100644 --- a/moto/mediaconnect/models.py +++ b/moto/mediaconnect/models.py @@ -1,9 +1,9 @@ from collections import OrderedDict -from uuid import uuid4 from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict from moto.mediaconnect.exceptions import NotFoundException +from moto.moto_api._internal import mock_random as random class Flow(BaseModel): @@ -87,7 +87,7 @@ class MediaConnectBackend(BaseBackend): source["ingestIp"] = ingest_ip def _create_flow_add_details(self, flow): - flow_id = uuid4().hex + flow_id = random.uuid4().hex flow.description = "A Moto test flow" flow.egress_ip = "127.0.0.1" @@ -248,7 +248,7 @@ class MediaConnectBackend(BaseBackend): ) flow = self._flows[flow_arn] for source in sources: - source_id = uuid4().hex + source_id = random.uuid4().hex name = source["name"] arn = f"arn:aws:mediaconnect:{self.region_name}:{self.account_id}:source:{source_id}:{name}" source["sourceArn"] = arn diff --git a/moto/medialive/models.py b/moto/medialive/models.py index 7a83e6785..e75383b7e 100644 --- a/moto/medialive/models.py +++ b/moto/medialive/models.py @@ -1,8 +1,8 @@ from collections import OrderedDict -from uuid import uuid4 from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random class Input(BaseModel): @@ -134,7 +134,7 @@ class MediaLiveBackend(BaseBackend): """ The RequestID and Reserved parameters are not yet implemented """ - channel_id = uuid4().hex + channel_id = mock_random.uuid4().hex arn = "arn:aws:medialive:channel:{}".format(channel_id) channel = Channel( arn=arn, @@ -228,7 +228,7 @@ class MediaLiveBackend(BaseBackend): """ The VPC and RequestId parameters are not yet implemented """ - input_id = uuid4().hex + input_id = mock_random.uuid4().hex arn = "arn:aws:medialive:input:{}".format(input_id) a_input = Input( arn=arn, diff --git a/moto/moto_api/_internal/__init__.py b/moto/moto_api/_internal/__init__.py index d12ac2556..5deee67be 100644 --- a/moto/moto_api/_internal/__init__.py +++ b/moto/moto_api/_internal/__init__.py @@ -1,6 +1,12 @@ from .models import moto_api_backend from .state_manager import StateManager # noqa from .recorder.models import Recorder # noqa +from .moto_random import MotoRandom moto_api_backends = {"global": moto_api_backend} + +""" +Random-object used throughout Moto. Can be seeded to make identifiers deterministic. +""" +mock_random = MotoRandom() diff --git a/moto/moto_api/_internal/moto_random.py b/moto/moto_api/_internal/moto_random.py new file mode 100644 index 000000000..f27580525 --- /dev/null +++ b/moto/moto_api/_internal/moto_random.py @@ -0,0 +1,30 @@ +from random import Random +import string +import uuid + + +HEX_CHARS = list(range(10)) + ["a", "b", "c", "d", "e", "f"] + + +class MotoRandom(Random): + """ + Class used for all sources of random-ness in Moto. + Used as a singleton, which is exposed in `moto/moto_api/_internal`. + This Singleton can be seeded to make identifiers deterministic. + """ + + def uuid1(self): + return uuid.UUID(int=self.getrandbits(128), version=1) + + def uuid4(self): + return uuid.UUID(int=self.getrandbits(128), version=4) + + def get_random_hex(self, length=8): + return "".join(str(self.choice(HEX_CHARS)) for _ in range(length)) + + def get_random_string(self, length=20, include_digits=True, lower_case=False): + pool = string.ascii_letters + if include_digits: + pool += string.digits + random_str = "".join([self.choice(pool) for i in range(length)]) + return random_str.lower() if lower_case else random_str diff --git a/moto/moto_api/_internal/recorder/models.py b/moto/moto_api/_internal/recorder/models.py index 5d351d4ed..2c053a56d 100644 --- a/moto/moto_api/_internal/recorder/models.py +++ b/moto/moto_api/_internal/recorder/models.py @@ -44,9 +44,9 @@ class Recorder: body_encoded = False finally: if request_body is not None: - if isinstance(request_body, bytes): - request_body = request_body.decode("utf-8") - request.environ["wsgi.input"] = io.StringIO(request_body) + if isinstance(request_body, str): + request_body = request_body.encode("utf-8") + request.environ["wsgi.input"] = io.BytesIO(request_body) else: body, body_encoded = self._encode_body(body) entry.update({"body": body, "body_encoded": body_encoded}) @@ -87,9 +87,11 @@ class Recorder: def upload_recording(self, data): """ - Replace the current log. Remember to replay the recording afterwards. + Replaces the current log. Remember to replay the recording afterwards. """ filepath = self._location + if isinstance(data, str): + data = data.encode("utf-8") with open(filepath, "bw") as file: file.write(data) diff --git a/moto/moto_api/_internal/responses.py b/moto/moto_api/_internal/responses.py index b452d990b..eba77ae47 100644 --- a/moto/moto_api/_internal/responses.py +++ b/moto/moto_api/_internal/responses.py @@ -106,3 +106,11 @@ class MotoAPIResponse(BaseResponse): moto_api_backend.unset_transition(model_name) return 201, {}, "" + + def seed(self, req, full_url, headers): + self.setup_class(req, full_url, headers) + from . import mock_random + + a = self._get_param("a") + mock_random.seed(int(a)) + return 200, {}, "" diff --git a/moto/moto_api/_internal/urls.py b/moto/moto_api/_internal/urls.py index 1f433d470..da5ea6cef 100644 --- a/moto/moto_api/_internal/urls.py +++ b/moto/moto_api/_internal/urls.py @@ -11,6 +11,7 @@ url_paths = { "{0}/moto-api/data.json": response_instance.model_data, "{0}/moto-api/reset": response_instance.reset_response, "{0}/moto-api/reset-auth": response_instance.reset_auth_response, + "{0}/moto-api/seed": response_instance.seed, "{0}/moto-api/state-manager/get-transition": response_instance.get_transition, "{0}/moto-api/state-manager/set-transition": response_instance.set_transition, "{0}/moto-api/state-manager/unset-transition": response_instance.unset_transition, diff --git a/moto/mq/models.py b/moto/mq/models.py index 82626f12a..f80c9f76b 100644 --- a/moto/mq/models.py +++ b/moto/mq/models.py @@ -2,7 +2,8 @@ import base64 import xmltodict from moto.core import BaseBackend, BaseModel -from moto.core.utils import BackendDict, get_random_hex, unix_time +from moto.core.utils import BackendDict, unix_time +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService from .configuration import DEFAULT_CONFIGURATION_DATA @@ -58,7 +59,7 @@ class ConfigurationRevision(BaseModel): class Configuration(BaseModel): def __init__(self, account_id, region, name, engine_type, engine_version): - self.id = f"c-{get_random_hex(6)}" + self.id = f"c-{mock_random.get_random_hex(6)}" self.arn = f"arn:aws:mq:{region}:{account_id}:configuration:{self.id}" self.created = unix_time() @@ -160,7 +161,7 @@ class Broker(BaseModel): users, ): self.name = name - self.id = get_random_hex(6) + self.id = mock_random.get_random_hex(6) self.arn = f"arn:aws:mq:{region}:{account_id}:broker:{self.id}" self.state = "RUNNING" self.created = unix_time() @@ -217,7 +218,7 @@ class Broker(BaseModel): self.configurations = None else: current_config = configuration or { - "id": f"c-{get_random_hex(6)}", + "id": f"c-{mock_random.get_random_hex(6)}", "revision": 1, } self.configurations = { diff --git a/moto/opsworks/models.py b/moto/opsworks/models.py index 8a22f2b72..ea6500a93 100644 --- a/moto/opsworks/models.py +++ b/moto/opsworks/models.py @@ -1,9 +1,8 @@ from moto.core import BaseBackend, BaseModel from moto.ec2 import ec2_backends from moto.core.utils import BackendDict -import uuid +from moto.moto_api._internal import mock_random as random import datetime -from random import choice from .exceptions import ResourceNotFoundException, ValidationException @@ -83,7 +82,7 @@ class OpsworkInstance(BaseModel): self.infrastructure_class = "ec2 (fixed)" self.platform = "linux (fixed)" - self.id = "{0}".format(uuid.uuid4()) + self.id = "{0}".format(random.uuid4()) self.created_at = datetime.datetime.utcnow() def start(self): @@ -273,7 +272,7 @@ class Layer(BaseModel): self.install_updates_on_boot = install_updates_on_boot self.use_ebs_optimized_instances = use_ebs_optimized_instances - self.id = "{0}".format(uuid.uuid4()) + self.id = "{0}".format(random.uuid4()) self.created_at = datetime.datetime.utcnow() def __eq__(self, other): @@ -369,7 +368,7 @@ class Stack(BaseModel): self.default_root_device_type = default_root_device_type self.agent_version = agent_version - self.id = "{0}".format(uuid.uuid4()) + self.id = "{0}".format(random.uuid4()) self.layers = [] self.apps = [] self.account_number = account_id @@ -381,7 +380,8 @@ class Stack(BaseModel): def generate_hostname(self): # this doesn't match amazon's implementation return "{theme}-{rand}-(moto)".format( - theme=self.hostname_theme, rand=[choice("abcdefghijhk") for _ in range(4)] + theme=self.hostname_theme, + rand=[random.choice("abcdefghijhk") for _ in range(4)], ) @property @@ -469,7 +469,7 @@ class App(BaseModel): if environment is None: self.environment = {} - self.id = "{0}".format(uuid.uuid4()) + self.id = "{0}".format(random.uuid4()) self.created_at = datetime.datetime.utcnow() def __eq__(self, other): diff --git a/moto/organizations/utils.py b/moto/organizations/utils.py index f328889cb..1f56242e1 100644 --- a/moto/organizations/utils.py +++ b/moto/organizations/utils.py @@ -1,6 +1,6 @@ -import random import re import string +from moto.moto_api._internal import mock_random as random MASTER_ACCOUNT_EMAIL = "master@example.com" diff --git a/moto/pinpoint/models.py b/moto/pinpoint/models.py index a2e82d004..1ba47efa3 100644 --- a/moto/pinpoint/models.py +++ b/moto/pinpoint/models.py @@ -1,15 +1,15 @@ from datetime import datetime from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, unix_time +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService -from uuid import uuid4 from .exceptions import ApplicationNotFound, EventStreamNotFound class App(BaseModel): def __init__(self, account_id, name): - self.application_id = str(uuid4()).replace("-", "") + self.application_id = str(mock_random.uuid4()).replace("-", "") self.arn = ( f"arn:aws:mobiletargeting:us-east-1:{account_id}:apps/{self.application_id}" ) diff --git a/moto/ram/models.py b/moto/ram/models.py index eefc7f6ec..4b90304cf 100644 --- a/moto/ram/models.py +++ b/moto/ram/models.py @@ -1,11 +1,10 @@ import re import string from datetime import datetime -import random -from uuid import uuid4 from moto.core import BaseBackend, BaseModel from moto.core.utils import unix_time, BackendDict +from moto.moto_api._internal import mock_random as random from moto.organizations import organizations_backends from moto.ram.exceptions import ( MalformedArnException, @@ -43,7 +42,9 @@ class ResourceShare(BaseModel): self.region = region self.allow_external_principals = kwargs.get("allowExternalPrincipals", True) - self.arn = f"arn:aws:ram:{self.region}:{account_id}:resource-share/{uuid4()}" + self.arn = ( + f"arn:aws:ram:{self.region}:{account_id}:resource-share/{random.uuid4()}" + ) self.creation_time = datetime.utcnow() self.feature_set = "STANDARD" self.last_updated_time = datetime.utcnow() diff --git a/moto/rds/models.py b/moto/rds/models.py index a30d36a4e..744b35a11 100644 --- a/moto/rds/models.py +++ b/moto/rds/models.py @@ -1,7 +1,6 @@ import copy import datetime import os -import random import string from collections import defaultdict @@ -9,9 +8,9 @@ from jinja2 import Template from re import compile as re_compile from collections import OrderedDict from moto.core import BaseBackend, BaseModel, CloudFormationModel - from moto.core.utils import iso_8601_datetime_with_milliseconds, BackendDict from moto.ec2.models import ec2_backends +from moto.moto_api._internal import mock_random as random from .exceptions import ( RDSClientError, DBClusterNotFoundError, diff --git a/moto/redshift/models.py b/moto/redshift/models.py index 98f48389e..a30c5fbf2 100644 --- a/moto/redshift/models.py +++ b/moto/redshift/models.py @@ -4,8 +4,8 @@ import datetime from collections import OrderedDict from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core.utils import iso_8601_datetime_with_milliseconds, BackendDict -from moto.utilities.utils import random_string from moto.ec2 import ec2_backends +from moto.moto_api._internal import mock_random from .exceptions import ( ClusterAlreadyExistsFaultError, ClusterNotFoundError, @@ -1050,7 +1050,7 @@ class RedshiftBackend(BaseBackend): db_user = user_prefix + db_user return { "DbUser": db_user, - "DbPassword": random_string(32), + "DbPassword": mock_random.get_random_string(32), "Expiration": expiration, } else: diff --git a/moto/redshiftdata/models.py b/moto/redshiftdata/models.py index 30a9ea170..abda501b7 100644 --- a/moto/redshiftdata/models.py +++ b/moto/redshiftdata/models.py @@ -1,10 +1,9 @@ import re -import uuid from datetime import datetime -import random from moto.core import BaseBackend from moto.core.utils import BackendDict, iso_8601_datetime_without_milliseconds +from moto.moto_api._internal import mock_random as random from moto.redshiftdata.exceptions import ValidationException, ResourceNotFoundException @@ -20,7 +19,7 @@ class Statement: ): now = iso_8601_datetime_without_milliseconds(datetime.now()) - self.id = str(uuid.uuid4()) + self.id = str(random.uuid4()) self.cluster_identifier = cluster_identifier self.created_at = now self.database = database diff --git a/moto/rekognition/models.py b/moto/rekognition/models.py index 59e8fe5d5..d49155889 100644 --- a/moto/rekognition/models.py +++ b/moto/rekognition/models.py @@ -1,10 +1,10 @@ """RekognitionBackend class with methods for supported APIs.""" -import random import string from moto.core import BaseBackend from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random as random class RekognitionBackend(BaseBackend): diff --git a/moto/resourcegroupstaggingapi/models.py b/moto/resourcegroupstaggingapi/models.py index 369858033..92d4a0cff 100644 --- a/moto/resourcegroupstaggingapi/models.py +++ b/moto/resourcegroupstaggingapi/models.py @@ -1,8 +1,7 @@ -import uuid - from moto.core import BaseBackend from moto.core.exceptions import RESTError from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random from moto.s3 import s3_backends from moto.ec2 import ec2_backends @@ -612,7 +611,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): return None, result # Didn't hit StopIteration so there's stuff left in generator - new_token = str(uuid.uuid4()) + new_token = str(mock_random.uuid4()) self._pages[new_token] = {"gen": generator, "misc": next_item} # Token used up, might as well bin now, if you call it again your an idiot @@ -658,7 +657,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): return None, result # Didn't hit StopIteration so there's stuff left in generator - new_token = str(uuid.uuid4()) + new_token = str(mock_random.uuid4()) self._pages[new_token] = {"gen": generator, "misc": next_item} # Token used up, might as well bin now, if you call it again your an idiot @@ -704,7 +703,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): return None, result # Didn't hit StopIteration so there's stuff left in generator - new_token = str(uuid.uuid4()) + new_token = str(mock_random.uuid4()) self._pages[new_token] = {"gen": generator, "misc": next_item} # Token used up, might as well bin now, if you call it again your an idiot diff --git a/moto/route53/models.py b/moto/route53/models.py index e568d8ff6..c854c166a 100644 --- a/moto/route53/models.py +++ b/moto/route53/models.py @@ -1,11 +1,8 @@ """Route53Backend class with methods for supported APIs.""" import itertools -from collections import defaultdict import re - import string -import random -import uuid +from collections import defaultdict from jinja2 import Template from moto.route53.exceptions import ( @@ -23,6 +20,7 @@ from moto.route53.exceptions import ( ) from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random as random from moto.utilities.paginator import paginate from .utils import PAGINATION_MODEL @@ -645,7 +643,7 @@ class Route53Backend(BaseBackend): return zone def create_health_check(self, caller_reference, health_check_args): - health_check_id = str(uuid.uuid4()) + health_check_id = str(random.uuid4()) health_check = HealthCheck(health_check_id, caller_reference, health_check_args) health_check.set_children(health_check_args.get("children")) health_check.set_regions(health_check_args.get("regions")) @@ -749,7 +747,7 @@ class Route53Backend(BaseBackend): raise QueryLoggingConfigAlreadyExists() # Create an instance of the query logging config. - query_logging_config_id = str(uuid.uuid4()) + query_logging_config_id = str(random.uuid4()) query_logging_config = QueryLoggingConfig( query_logging_config_id, hosted_zone_id, log_group_arn ) diff --git a/moto/route53resolver/models.py b/moto/route53resolver/models.py index 7ae1158a5..4017efc50 100644 --- a/moto/route53resolver/models.py +++ b/moto/route53resolver/models.py @@ -5,10 +5,11 @@ from ipaddress import ip_address, ip_network, IPv4Address import re from moto.core import BaseBackend, BaseModel -from moto.core.utils import get_random_hex, BackendDict +from moto.core.utils import BackendDict from moto.ec2 import ec2_backends from moto.ec2.exceptions import InvalidSubnetIdError from moto.ec2.exceptions import InvalidSecurityGroupNotFoundError +from moto.moto_api._internal import mock_random from moto.route53resolver.exceptions import ( InvalidParameterException, InvalidRequestException, @@ -114,7 +115,7 @@ class ResolverRule(BaseModel): # pylint: disable=too-many-instance-attributes # of X-Amzn-Trace-Id. We don't have that info, so a random number # of similar format and length will be used. self.status_message = ( - f"[Trace id: 1-{get_random_hex(8)}-{get_random_hex(24)}] " + f"[Trace id: 1-{mock_random.get_random_hex(8)}-{mock_random.get_random_hex(24)}] " f"Successfully created Resolver Rule" ) self.share_status = "SHARED_WITH_ME" @@ -199,7 +200,7 @@ class ResolverEndpoint(BaseModel): # pylint: disable=too-many-instance-attribut # of X-Amzn-Trace-Id. We don't have that info, so a random number # of similar format and length will be used. self.status_message = ( - f"[Trace id: 1-{get_random_hex(8)}-{get_random_hex(24)}] " + f"[Trace id: 1-{mock_random.get_random_hex(8)}-{mock_random.get_random_hex(24)}] " f"Successfully created Resolver Endpoint" ) self.creation_time = datetime.now(timezone.utc).isoformat() @@ -228,7 +229,9 @@ class ResolverEndpoint(BaseModel): # pylint: disable=too-many-instance-attribut """ subnets = defaultdict(dict) for entry in self.ip_addresses: - subnets[entry["SubnetId"]][entry["Ip"]] = f"rni-{get_random_hex(17)}" + subnets[entry["SubnetId"]][ + entry["Ip"] + ] = f"rni-{mock_random.get_random_hex(17)}" return subnets def create_eni(self): @@ -298,7 +301,7 @@ class ResolverEndpoint(BaseModel): # pylint: disable=too-many-instance-attribut self.ip_addresses.append(ip_address) self.ip_address_count = len(self.ip_addresses) - eni_id = f"rni-{get_random_hex(17)}" + eni_id = f"rni-{mock_random.get_random_hex(17)}" self.subnets[ip_address["SubnetId"]][ip_address["Ip"]] = eni_id eni_info = self.ec2_backend.create_network_interface( @@ -390,7 +393,7 @@ class Route53ResolverBackend(BaseBackend): f"VPC. Conflict with resolver rule '{resolver_rule_id}'" ) - rule_association_id = f"rslvr-rrassoc-{get_random_hex(17)}" + rule_association_id = f"rslvr-rrassoc-{mock_random.get_random_hex(17)}" rule_association = ResolverRuleAssociation( self.region_name, rule_association_id, resolver_rule_id, vpc_id, name ) @@ -509,9 +512,7 @@ class Route53ResolverBackend(BaseBackend): f"'{creator_request_id}' already exists" ) - endpoint_id = ( - f"rslvr-{'in' if direction == 'INBOUND' else 'out'}-{get_random_hex(17)}" - ) + endpoint_id = f"rslvr-{'in' if direction == 'INBOUND' else 'out'}-{mock_random.get_random_hex(17)}" resolver_endpoint = ResolverEndpoint( self.account_id, region, @@ -605,7 +606,7 @@ class Route53ResolverBackend(BaseBackend): f"'{creator_request_id}' already exists" ) - rule_id = f"rslvr-rr-{get_random_hex(17)}" + rule_id = f"rslvr-rr-{mock_random.get_random_hex(17)}" resolver_rule = ResolverRule( self.account_id, region, diff --git a/moto/s3/models.py b/moto/s3/models.py index 77bfa0953..33b5c503b 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -5,20 +5,17 @@ import datetime import copy import itertools import codecs -import random import string import tempfile import threading import pytz import sys -import uuid import urllib.parse from bisect import insort from importlib import reload from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core import CloudWatchMetricProvider - from moto.core.utils import ( iso_8601_datetime_without_milliseconds_s3, rfc_1123_datetime, @@ -28,6 +25,7 @@ from moto.core.utils import ( ) from moto.cloudwatch.models import MetricDatum from moto.moto_api import state_manager +from moto.moto_api._internal import mock_random as random from moto.moto_api._internal.managed_state_model import ManagedState from moto.utilities.tagging_service import TaggingService from moto.utilities.utils import LowercaseDict, md5_hash @@ -80,7 +78,7 @@ class FakeDeleteMarker(BaseModel): self.key = key self.name = key.name self.last_modified = datetime.datetime.utcnow() - self._version_id = str(uuid.uuid4()) + self._version_id = str(random.uuid4()) @property def last_modified_ISO8601(self): @@ -1728,7 +1726,7 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider): storage=storage, etag=etag, is_versioned=bucket.is_versioned, - version_id=str(uuid.uuid4()) if bucket.is_versioned else "null", + version_id=str(random.uuid4()) if bucket.is_versioned else "null", multipart=multipart, encryption=encryption, kms_key_id=kms_key_id, diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 49221db9c..56f380872 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -7,7 +7,6 @@ import urllib.parse from moto import settings from moto.core.utils import ( - amzn_request_id, extract_region_from_aws_authorization, str_to_rfc_1123_datetime, ) @@ -23,6 +22,7 @@ from moto.s3bucket_path.utils import ( parse_key_name as bucketpath_parse_key_name, is_delete_keys as bucketpath_is_delete_keys, ) +from moto.utilities.aws_headers import amzn_request_id from .exceptions import ( BucketAlreadyExists, diff --git a/moto/s3control/models.py b/moto/s3control/models.py index f8b0951d8..ba573f4f4 100644 --- a/moto/s3control/models.py +++ b/moto/s3control/models.py @@ -1,7 +1,8 @@ from collections import defaultdict from datetime import datetime from moto.core import BaseBackend, BaseModel -from moto.core.utils import get_random_hex, BackendDict +from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random from moto.s3.exceptions import ( WrongPublicAccessBlockAccountIdError, NoSuchPublicAccessBlockConfiguration, @@ -22,7 +23,7 @@ class AccessPoint(BaseModel): public_access_block_configuration, ): self.name = name - self.alias = f"{name}-{get_random_hex(34)}-s3alias" + self.alias = f"{name}-{mock_random.get_random_hex(34)}-s3alias" self.bucket = bucket self.created = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f") self.arn = f"arn:aws:s3:us-east-1:{account_id}:accesspoint/{name}" diff --git a/moto/s3control/responses.py b/moto/s3control/responses.py index 1c166d478..18c7231d0 100644 --- a/moto/s3control/responses.py +++ b/moto/s3control/responses.py @@ -2,9 +2,9 @@ import json import xmltodict from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id from moto.s3.exceptions import S3ClientError from moto.s3.responses import S3_PUBLIC_ACCESS_BLOCK_CONFIGURATION +from moto.utilities.aws_headers import amzn_request_id from .models import s3control_backends diff --git a/moto/sagemaker/responses.py b/moto/sagemaker/responses.py index 195678502..a2bcbdff5 100644 --- a/moto/sagemaker/responses.py +++ b/moto/sagemaker/responses.py @@ -3,7 +3,7 @@ import json from moto.sagemaker.exceptions import AWSValidationException from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id +from moto.utilities.aws_headers import amzn_request_id from .models import sagemaker_backends diff --git a/moto/secretsmanager/models.py b/moto/secretsmanager/models.py index 91ff04760..dd1e7d66c 100644 --- a/moto/secretsmanager/models.py +++ b/moto/secretsmanager/models.py @@ -1,12 +1,12 @@ import time import json -import uuid import datetime from typing import List, Tuple from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random from .exceptions import ( SecretNotFoundException, SecretHasNoValueException, @@ -221,7 +221,7 @@ class SecretsManagerBackend(BaseBackend): if version_id: self._client_request_token_validator(version_id) else: - version_id = str(uuid.uuid4()) + version_id = str(mock_random.uuid4()) return version_id def get_secret_value(self, secret_id, version_id, version_stage): @@ -512,7 +512,7 @@ class SecretsManagerBackend(BaseBackend): self._client_request_token_validator(client_request_token) new_version_id = client_request_token else: - new_version_id = str(uuid.uuid4()) + new_version_id = str(mock_random.uuid4()) # We add the new secret version as "pending". The previous version remains # as "current" for now. Once we've passed the new secret through the lambda diff --git a/moto/secretsmanager/utils.py b/moto/secretsmanager/utils.py index e46b36717..684e0c337 100644 --- a/moto/secretsmanager/utils.py +++ b/moto/secretsmanager/utils.py @@ -1,6 +1,6 @@ -import random import string import re +from moto.moto_api._internal import mock_random as random def random_password( diff --git a/moto/servicediscovery/models.py b/moto/servicediscovery/models.py index 2753d79e0..1c8a5ce7f 100644 --- a/moto/servicediscovery/models.py +++ b/moto/servicediscovery/models.py @@ -1,8 +1,8 @@ -import random import string from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, unix_time +from moto.moto_api._internal import mock_random as random from moto.utilities.tagging_service import TaggingService from .exceptions import ( diff --git a/moto/ses/utils.py b/moto/ses/utils.py index 96445ad5f..5f40f8f4b 100644 --- a/moto/ses/utils.py +++ b/moto/ses/utils.py @@ -1,6 +1,6 @@ -import random import string from email.utils import parseaddr +from moto.moto_api._internal import mock_random as random def random_hex(length): diff --git a/moto/signer/models.py b/moto/signer/models.py index 85d974cb2..323c0320c 100644 --- a/moto/signer/models.py +++ b/moto/signer/models.py @@ -1,5 +1,6 @@ from moto.core import BaseBackend, BaseModel -from moto.core.utils import BackendDict, get_random_hex +from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random class SigningProfile(BaseModel): @@ -16,7 +17,7 @@ class SigningProfile(BaseModel): self.status = "Active" self.arn = f"arn:aws:signer:{region}:{account_id}:/signing-profiles/{name}" - self.profile_version = get_random_hex(10) + self.profile_version = mock_random.get_random_hex(10) self.profile_version_arn = f"{self.arn}/{self.profile_version}" def cancel(self): diff --git a/moto/sns/models.py b/moto/sns/models.py index 3af72f86c..2279f33d6 100644 --- a/moto/sns/models.py +++ b/moto/sns/models.py @@ -1,5 +1,4 @@ import datetime -import uuid import json import requests @@ -12,6 +11,7 @@ from moto.core.utils import ( camelcase_to_underscores, BackendDict, ) +from moto.moto_api._internal import mock_random from moto.sqs import sqs_backends from moto.sqs.exceptions import MissingParameter @@ -60,7 +60,7 @@ class Topic(CloudFormationModel): self.content_based_deduplication = "false" def publish(self, message, subject=None, message_attributes=None, group_id=None): - message_id = str(uuid.uuid4()) + message_id = str(mock_random.uuid4()) subscriptions, _ = self.sns_backend.list_subscriptions(self.arn) for subscription in subscriptions: subscription.publish( @@ -424,7 +424,7 @@ class PlatformEndpoint(BaseModel): self.custom_user_data = custom_user_data self.token = token self.attributes = attributes - self.id = uuid.uuid4() + self.id = mock_random.uuid4() self.arn = f"arn:aws:sns:{region}:{account_id}:endpoint/{self.application.platform}/{self.application.name}/{self.id}" self.messages = OrderedDict() self.__fixup_attributes() @@ -449,7 +449,7 @@ class PlatformEndpoint(BaseModel): raise SnsEndpointDisabled("Endpoint %s disabled" % self.id) # This is where we would actually send a message - message_id = str(uuid.uuid4()) + message_id = str(mock_random.uuid4()) self.messages[message_id] = message return message_id @@ -651,7 +651,7 @@ class SNSBackend(BaseBackend): if len(message) > MAXIMUM_SMS_MESSAGE_BYTES: raise ValueError("SMS message must be less than 1600 bytes") - message_id = str(uuid.uuid4()) + message_id = str(mock_random.uuid4()) self.sms_messages[message_id] = (phone_number, message) return message_id diff --git a/moto/sns/utils.py b/moto/sns/utils.py index 41839c372..d2bee67b7 100644 --- a/moto/sns/utils.py +++ b/moto/sns/utils.py @@ -1,5 +1,5 @@ import re -import uuid +from moto.moto_api._internal import mock_random E164_REGEX = re.compile(r"^\+?[1-9]\d{1,14}$") @@ -9,7 +9,7 @@ def make_arn_for_topic(account_id, name, region_name): def make_arn_for_subscription(topic_arn): - subscription_id = uuid.uuid4() + subscription_id = mock_random.uuid4() return "{0}:{1}".format(topic_arn, subscription_id) diff --git a/moto/sqs/models.py b/moto/sqs/models.py index 32abbb1df..c3666befb 100644 --- a/moto/sqs/models.py +++ b/moto/sqs/models.py @@ -1,7 +1,6 @@ import base64 import hashlib import json -import random import re import string @@ -14,12 +13,12 @@ from moto.core.exceptions import RESTError from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core.utils import ( camelcase_to_underscores, - get_random_message_id, unix_time, unix_time_millis, tags_from_cloudformation_tags_list, BackendDict, ) +from moto.moto_api._internal import mock_random as random from moto.utilities.utils import md5_hash from .utils import generate_receipt_handle from .exceptions import ( @@ -763,7 +762,7 @@ class SQSBackend(BaseBackend): else: delay_seconds = queue.delay_seconds - message_id = get_random_message_id() + message_id = str(random.uuid4()) message = Message(message_id, message_body, system_attributes) # if content based deduplication is set then set sha256 hash of the message diff --git a/moto/sqs/responses.py b/moto/sqs/responses.py index 28fd57e85..0877c43ee 100644 --- a/moto/sqs/responses.py +++ b/moto/sqs/responses.py @@ -2,12 +2,8 @@ import re from moto.core.exceptions import RESTError from moto.core.responses import BaseResponse -from moto.core.utils import ( - amz_crc32, - amzn_request_id, - underscores_to_camelcase, - camelcase_to_pascal, -) +from moto.core.utils import underscores_to_camelcase, camelcase_to_pascal +from moto.utilities.aws_headers import amz_crc32, amzn_request_id from urllib.parse import urlparse from .exceptions import ( diff --git a/moto/sqs/utils.py b/moto/sqs/utils.py index 24d374248..fde3dab39 100644 --- a/moto/sqs/utils.py +++ b/moto/sqs/utils.py @@ -1,6 +1,5 @@ -import random import string - +from moto.moto_api._internal import mock_random as random from .exceptions import MessageAttributesInvalid diff --git a/moto/ssm/models.py b/moto/ssm/models.py index d29aad2ac..6f8f43601 100644 --- a/moto/ssm/models.py +++ b/moto/ssm/models.py @@ -14,12 +14,10 @@ from moto.utilities.utils import load_resource import datetime import time -import uuid import json import yaml import hashlib -import random - +from moto.moto_api._internal import mock_random as random from .utils import parameter_arn, convert_to_params from .exceptions import ( ValidationException, @@ -576,7 +574,7 @@ class Command(BaseModel): if targets is None: targets = [] - self.command_id = str(uuid.uuid4()) + self.command_id = str(random.uuid4()) self.status = "Success" self.status_details = "Details placeholder" self.account_id = account_id diff --git a/moto/ssoadmin/models.py b/moto/ssoadmin/models.py index 26a743c34..abe79d11b 100644 --- a/moto/ssoadmin/models.py +++ b/moto/ssoadmin/models.py @@ -2,8 +2,7 @@ from .exceptions import ResourceNotFound from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict, unix_time -from uuid import uuid4 -import random +from moto.moto_api._internal import mock_random as random from moto.utilities.paginator import paginate from .utils import PAGINATION_MODEL @@ -18,7 +17,7 @@ class AccountAssignment(BaseModel): principal_type, principal_id, ): - self.request_id = str(uuid4()) + self.request_id = str(random.uuid4()) self.instance_arn = instance_arn self.target_id = target_id self.target_type = target_type diff --git a/moto/ssoadmin/responses.py b/moto/ssoadmin/responses.py index e5a70a9be..83ad84388 100644 --- a/moto/ssoadmin/responses.py +++ b/moto/ssoadmin/responses.py @@ -1,7 +1,7 @@ import json from moto.core.responses import BaseResponse -from uuid import uuid4 +from moto.moto_api._internal import mock_random from .models import ssoadmin_backends @@ -34,7 +34,7 @@ class SSOAdminResponse(BaseResponse): principal_id=principal_id, ) summary["Status"] = "SUCCEEDED" - summary["RequestId"] = str(uuid4()) + summary["RequestId"] = str(mock_random.uuid4()) return json.dumps({"AccountAssignmentCreationStatus": summary}) def delete_account_assignment(self): @@ -54,7 +54,7 @@ class SSOAdminResponse(BaseResponse): principal_id=principal_id, ) summary["Status"] = "SUCCEEDED" - summary["RequestId"] = str(uuid4()) + summary["RequestId"] = str(mock_random.uuid4()) return json.dumps({"AccountAssignmentDeletionStatus": summary}) def list_account_assignments(self): diff --git a/moto/stepfunctions/models.py b/moto/stepfunctions/models.py index aebf5c18a..54da2cbf6 100644 --- a/moto/stepfunctions/models.py +++ b/moto/stepfunctions/models.py @@ -5,7 +5,7 @@ from dateutil.tz import tzlocal from moto.core import BaseBackend, CloudFormationModel from moto.core.utils import iso_8601_datetime_with_milliseconds, BackendDict -from uuid import uuid4 +from moto.moto_api._internal import mock_random from .exceptions import ( ExecutionAlreadyExists, ExecutionDoesNotExist, @@ -498,7 +498,7 @@ class StepFunctionBackend(BaseBackend): execution = state_machine.start_execution( region_name=self.region_name, account_id=self.account_id, - execution_name=name or str(uuid4()), + execution_name=name or str(mock_random.uuid4()), execution_input=execution_input, ) return execution diff --git a/moto/stepfunctions/responses.py b/moto/stepfunctions/responses.py index 540a38d06..d13b14ee5 100644 --- a/moto/stepfunctions/responses.py +++ b/moto/stepfunctions/responses.py @@ -1,7 +1,7 @@ import json from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id +from moto.utilities.aws_headers import amzn_request_id from .models import stepfunction_backends diff --git a/moto/sts/utils.py b/moto/sts/utils.py index fd3f2ac87..eda8ed851 100644 --- a/moto/sts/utils.py +++ b/moto/sts/utils.py @@ -1,7 +1,7 @@ import base64 import os -import random import string +from moto.moto_api._internal import mock_random as random ACCOUNT_SPECIFIC_ACCESS_KEY_PREFIX = "8NWMTLYQ" ACCOUNT_SPECIFIC_ASSUMED_ROLE_ID_PREFIX = "3X42LBCD" diff --git a/moto/support/models.py b/moto/support/models.py index b65ef0069..6533e9add 100644 --- a/moto/support/models.py +++ b/moto/support/models.py @@ -2,9 +2,9 @@ from moto.core import BaseBackend from moto.core.utils import BackendDict from moto.moto_api import state_manager from moto.moto_api._internal.managed_state_model import ManagedState +from moto.moto_api._internal import mock_random as random from moto.utilities.utils import load_resource import datetime -import random checks_json = "resources/describe_trusted_advisor_checks.json" diff --git a/moto/swf/models/activity_task.py b/moto/swf/models/activity_task.py index 8d3ce0c4b..2119188fa 100644 --- a/moto/swf/models/activity_task.py +++ b/moto/swf/models/activity_task.py @@ -1,8 +1,8 @@ from datetime import datetime -import uuid from moto.core import BaseModel from moto.core.utils import unix_time +from moto.moto_api._internal import mock_random from ..exceptions import SWFWorkflowExecutionClosedError from .timeout import Timeout @@ -26,7 +26,7 @@ class ActivityTask(BaseModel): self.scheduled_event_id = scheduled_event_id self.started_event_id = None self.state = "SCHEDULED" - self.task_token = str(uuid.uuid4()) + self.task_token = str(mock_random.uuid4()) self.timeouts = timeouts self.timeout_type = None self.workflow_execution = workflow_execution diff --git a/moto/swf/models/decision_task.py b/moto/swf/models/decision_task.py index 980d5c12f..ead089c5f 100644 --- a/moto/swf/models/decision_task.py +++ b/moto/swf/models/decision_task.py @@ -1,8 +1,8 @@ from datetime import datetime -import uuid from moto.core import BaseModel from moto.core.utils import unix_time +from moto.moto_api._internal import mock_random from ..exceptions import SWFWorkflowExecutionClosedError from .timeout import Timeout @@ -12,7 +12,7 @@ class DecisionTask(BaseModel): def __init__(self, workflow_execution, scheduled_event_id): self.workflow_execution = workflow_execution self.workflow_type = workflow_execution.workflow_type - self.task_token = str(uuid.uuid4()) + self.task_token = str(mock_random.uuid4()) self.scheduled_event_id = scheduled_event_id self.previous_started_event_id = None self.started_event_id = None diff --git a/moto/swf/models/workflow_execution.py b/moto/swf/models/workflow_execution.py index 4cbeee7e6..b02a8cd15 100644 --- a/moto/swf/models/workflow_execution.py +++ b/moto/swf/models/workflow_execution.py @@ -1,8 +1,8 @@ -import uuid from threading import Timer as ThreadingTimer, Lock from moto.core import BaseModel from moto.core.utils import camelcase_to_underscores, unix_time +from moto.moto_api._internal import mock_random from ..constants import DECISIONS_FIELDS from ..exceptions import ( @@ -43,7 +43,7 @@ class WorkflowExecution(BaseModel): def __init__(self, domain, workflow_type, workflow_id, **kwargs): self.domain = domain self.workflow_id = workflow_id - self.run_id = uuid.uuid4().hex + self.run_id = mock_random.uuid4().hex # WorkflowExecutionInfo self.cancel_requested = False # TODO: check valid values among: diff --git a/moto/textract/models.py b/moto/textract/models.py index de5055738..93e25a095 100644 --- a/moto/textract/models.py +++ b/moto/textract/models.py @@ -1,11 +1,10 @@ """TextractBackend class with methods for supported APIs.""" -import uuid -from random import randint from collections import defaultdict from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict +from moto.moto_api._internal import mock_random from .exceptions import InvalidParameterException, InvalidJobIdException @@ -29,7 +28,7 @@ class TextractBackend(BaseBackend): """Implementation of Textract APIs.""" JOB_STATUS = TextractJobStatus.succeeded - PAGES = {"Pages": randint(5, 500)} + PAGES = {"Pages": mock_random.randint(5, 500)} BLOCKS = [] def __init__(self, region_name, account_id): @@ -51,7 +50,7 @@ class TextractBackend(BaseBackend): """ if not document_location: raise InvalidParameterException() - job_id = str(uuid.uuid4()) + job_id = str(mock_random.uuid4()) self.async_text_detection_jobs[job_id] = TextractJob( { "Blocks": TextractBackend.BLOCKS, diff --git a/moto/transcribe/models.py b/moto/transcribe/models.py index 79fd4b1d9..7e44f6c81 100644 --- a/moto/transcribe/models.py +++ b/moto/transcribe/models.py @@ -1,8 +1,8 @@ -import uuid from datetime import datetime, timedelta from moto.core import BaseBackend, BaseModel from moto.core.utils import BackendDict from moto.moto_api import state_manager +from moto.moto_api._internal import mock_random from moto.moto_api._internal.managed_state_model import ManagedState from .exceptions import ConflictException, BadRequestException @@ -204,7 +204,7 @@ class FakeTranscriptionJob(BaseObject, ManagedState): self._region_name, self._account_id, self.transcription_job_name, - uuid.uuid4(), + mock_random.uuid4(), ) self.output_location_type = "SERVICE_BUCKET" self.transcript = {"TranscriptFileUri": transcript_file_uri} @@ -234,7 +234,7 @@ class FakeVocabulary(BaseObject, ManagedState): self.last_modified_time = None self.failure_reason = None self.download_uri = "https://s3.{0}.amazonaws.com/aws-transcribe-dictionary-model-{0}-prod/{1}/{2}/{3}/input.txt".format( # noqa: E501 - region_name, account_id, vocabulary_name, uuid + region_name, account_id, vocabulary_name, mock_random.uuid4() ) def response_object(self, response_type): @@ -437,7 +437,7 @@ class FakeMedicalVocabulary(FakeVocabulary): self.last_modified_time = None self.failure_reason = None self.download_uri = "https://s3.us-east-1.amazonaws.com/aws-transcribe-dictionary-model-{}-prod/{}/medical/{}/{}/input.txt".format( # noqa: E501 - region_name, account_id, self.vocabulary_name, uuid.uuid4() + region_name, account_id, self.vocabulary_name, mock_random.uuid4() ) diff --git a/moto/transcribe/responses.py b/moto/transcribe/responses.py index 05e06bab7..ba9f52a01 100644 --- a/moto/transcribe/responses.py +++ b/moto/transcribe/responses.py @@ -1,7 +1,7 @@ import json from moto.core.responses import BaseResponse -from moto.core.utils import amzn_request_id +from moto.utilities.aws_headers import amzn_request_id from .models import transcribe_backends diff --git a/moto/utilities/aws_headers.py b/moto/utilities/aws_headers.py new file mode 100644 index 000000000..29b817fac --- /dev/null +++ b/moto/utilities/aws_headers.py @@ -0,0 +1,85 @@ +from functools import wraps + +import binascii +import re +from moto.moto_api._internal import mock_random as random + + +def gen_amz_crc32(response, headerdict=None): + if not isinstance(response, bytes): + response = response.encode("utf-8") + + crc = binascii.crc32(response) + + if headerdict is not None and isinstance(headerdict, dict): + headerdict.update({"x-amz-crc32": str(crc)}) + + return crc + + +def gen_amzn_requestid_long(headerdict=None): + req_id = random.get_random_string(length=52) + + if headerdict is not None and isinstance(headerdict, dict): + headerdict.update({"x-amzn-requestid": req_id}) + + return req_id + + +def amz_crc32(f): + @wraps(f) + def _wrapper(*args, **kwargs): + response = f(*args, **kwargs) + + headers = {} + status = 200 + + if isinstance(response, str): + body = response + else: + if len(response) == 2: + body, new_headers = response + status = new_headers.get("status", 200) + else: + status, new_headers, body = response + headers.update(new_headers) + # Cast status to string + if "status" in headers: + headers["status"] = str(headers["status"]) + + gen_amz_crc32(body, headers) + + return status, headers, body + + return _wrapper + + +def amzn_request_id(f): + @wraps(f) + def _wrapper(*args, **kwargs): + response = f(*args, **kwargs) + + headers = {} + status = 200 + + if isinstance(response, str): + body = response + else: + if len(response) == 2: + body, new_headers = response + status = new_headers.get("status", 200) + else: + status, new_headers, body = response + headers.update(new_headers) + + request_id = gen_amzn_requestid_long(headers) + + # Update request ID in XML + try: + body = re.sub(r"(?<=).*(?=<\/RequestId>)", request_id, body) + except Exception: # Will just ignore if it cant work + pass + + return status, headers, body + + return _wrapper diff --git a/moto/utilities/utils.py b/moto/utilities/utils.py index 636e71e1e..878642711 100644 --- a/moto/utilities/utils.py +++ b/moto/utilities/utils.py @@ -1,7 +1,5 @@ import json import hashlib -import random -import string import pkgutil @@ -15,14 +13,6 @@ def str2bool(v): return False -def random_string(length=None): - n = length or 20 - random_str = "".join( - [random.choice(string.ascii_letters + string.digits) for i in range(n)] - ) - return random_str - - def load_resource(package, resource, as_json=True): """ Open a file, and return the contents as JSON. diff --git a/moto/wafv2/models.py b/moto/wafv2/models.py index 18086999b..2432ac731 100644 --- a/moto/wafv2/models.py +++ b/moto/wafv2/models.py @@ -1,12 +1,12 @@ import datetime import re from typing import Dict -from uuid import uuid4 from moto.core import BaseBackend, BaseModel from .utils import make_arn_for_wacl from .exceptions import WAFV2DuplicateItemException, WAFNonexistentItemException from moto.core.utils import iso_8601_datetime_with_milliseconds, BackendDict +from moto.moto_api._internal import mock_random from moto.utilities.tagging_service import TaggingService from collections import OrderedDict @@ -36,7 +36,7 @@ class FakeWebACL(BaseModel): self.rules = rules self.visibility_config = visibility_config self.default_action = default_action - self.lock_token = str(uuid4())[0:6] + self.lock_token = str(mock_random.uuid4())[0:6] def update(self, default_action, rules, description, visibility_config): if default_action is not None: @@ -47,7 +47,7 @@ class FakeWebACL(BaseModel): self.description = description if visibility_config is not None: self.visibility_config = visibility_config - self.lock_token = str(uuid4())[0:6] + self.lock_token = str(mock_random.uuid4())[0:6] def to_dict(self): # Format for summary https://docs.aws.amazon.com/waf/latest/APIReference/API_CreateWebACL.html (response syntax section) @@ -115,7 +115,7 @@ class WAFV2Backend(BaseBackend): """ The following parameters are not yet implemented: CustomResponseBodies, CaptchaConfig """ - wacl_id = str(uuid4()) + wacl_id = str(mock_random.uuid4()) arn = make_arn_for_wacl( name=name, account_id=self.account_id, diff --git a/moto/wafv2/responses.py b/moto/wafv2/responses.py index 68bcce7ac..be327ea94 100644 --- a/moto/wafv2/responses.py +++ b/moto/wafv2/responses.py @@ -1,7 +1,6 @@ import json -from moto.core.utils import amzn_request_id - from moto.core.responses import BaseResponse +from moto.utilities.aws_headers import amzn_request_id from .models import GLOBAL_REGION, wafv2_backends diff --git a/tests/test_cognitoidp/test_cognitoidp_replay.py b/tests/test_cognitoidp/test_cognitoidp_replay.py new file mode 100644 index 000000000..0dbc71739 --- /dev/null +++ b/tests/test_cognitoidp/test_cognitoidp_replay.py @@ -0,0 +1,114 @@ +import os + +import boto3 +import uuid +import sure # noqa # pylint: disable=unused-import +import pytest +import requests + +from botocore.exceptions import ClientError +from moto import mock_cognitoidp, settings +from moto.moto_api import recorder +from unittest import TestCase + + +@mock_cognitoidp +class TestCreateUserPoolWithPredeterminedID(TestCase): + def _reset_recording(self): + if settings.TEST_SERVER_MODE: + requests.post("http://localhost:5000/moto-api/recorder/reset-recording") + else: + recorder.reset_recording() + + def _start_recording(self): + if settings.TEST_SERVER_MODE: + requests.post("http://localhost:5000/moto-api/recorder/start-recording") + else: + recorder.start_recording() + + def _stop_recording(self): + if settings.TEST_SERVER_MODE: + requests.post("http://localhost:5000/moto-api/recorder/stop-recording") + else: + recorder.stop_recording() + + def _download_recording(self): + if settings.TEST_SERVER_MODE: + resp = requests.get( + "http://localhost:5000/moto-api/recorder/download-recording" + ) + resp.status_code.should.equal(200) + return resp.content.decode("utf-8") + else: + return recorder.download_recording() + + def _upload_recording(self, logs): + if settings.TEST_SERVER_MODE: + requests.post( + "http://localhost:5000/moto-api/recorder/upload-recording", data=logs + ) + else: + recorder.upload_recording(logs) + + def _replay_recording(self): + if settings.TEST_SERVER_MODE: + requests.post("http://localhost:5000/moto-api/recorder/replay-recording") + else: + recorder.replay_recording() + + def _set_seed(self, a): + if settings.TEST_SERVER_MODE: + requests.post(f"http://localhost:5000/moto-api/seed?a={a}") + else: + requests.post(f"http://motoapi.amazonaws.com/moto-api/seed?a={a}") + + def setUp(self) -> None: + self.client = boto3.client("cognito-idp", "us-west-2") + self.random_seed = 42 + + # start recording + self._reset_recording() + self._start_recording() + # Create UserPool + name = str(uuid.uuid4()) + value = str(uuid.uuid4()) + self._set_seed(self.random_seed) + resp = self.client.create_user_pool( + PoolName=name, LambdaConfig={"PreSignUp": value} + ) + self.pool_id = resp["UserPool"]["Id"] + + # stop recording + self._stop_recording() + # delete user pool + self.client.delete_user_pool(UserPoolId=self.pool_id) + + def tearDown(self) -> None: + self._stop_recording() + try: + os.remove("moto_recording") + except: # noqa: E722 Do not use bare except + pass + + def test_same_seed(self): + # replay recording + self._replay_recording() + # assert userpool is is the same - it will throw an error if it doesn't exist + self.client.describe_user_pool(UserPoolId=self.pool_id) + + def test_different_seed(self): + # set seed to different number + logs = self._download_recording() + logs = logs.replace("/seed?a=42", "/seed?a=43") + self._upload_recording(logs) + # replay recording, and recreate a userpool + self._replay_recording() + # assert the ID of this userpool is now different + with pytest.raises(ClientError) as exc: + self.client.describe_user_pool(UserPoolId=self.pool_id) + err = exc.value.response["Error"] + err["Code"].should.equal("ResourceNotFoundException") + + # It is created - just with a different ID + all_pools = self.client.list_user_pools(MaxResults=5)["UserPools"] + all_pools.should.have.length_of(1) diff --git a/tests/test_config/test_config_rules.py b/tests/test_config/test_config_rules.py index 12e752b6a..35dba4b11 100644 --- a/tests/test_config/test_config_rules.py +++ b/tests/test_config/test_config_rules.py @@ -13,9 +13,9 @@ from botocore.exceptions import ClientError import pytest from moto.config import mock_config -from moto.config.models import random_string from moto.config.models import ConfigRule, CONFIG_RULE_PAGE_SIZE from moto import settings +from moto.moto_api._internal import mock_random TEST_REGION = "us-east-1" if settings.TEST_SERVER_MODE else "us-west-2" @@ -23,7 +23,7 @@ TEST_REGION = "us-east-1" if settings.TEST_SERVER_MODE else "us-west-2" def managed_config_rule(): """Return a valid managed AWS Config Rule.""" return { - "ConfigRuleName": f"managed_rule_{random_string()}", + "ConfigRuleName": f"managed_rule_{mock_random.get_random_string()}", "Description": "Managed S3 Public Read Prohibited Bucket Rule", "Scope": {"ComplianceResourceTypes": ["AWS::S3::Bucket", "AWS::IAM::Group"]}, "Source": { @@ -220,7 +220,7 @@ def test_aws_managed_rule_errors(): ) # If no MaxExecutionFrequency specified, set it to the default. - # rule_name = f"managed_rule_{random_string()}" + # rule_name = f"managed_rule_{mock_random.get_random_string()}" # managed_rule = { # "ConfigRuleName": rule_name, # "Description": "Managed S3 Public Read Prohibited Bucket Rule", @@ -348,7 +348,7 @@ def test_valid_put_config_managed_rule(): # Valid InputParameters. managed_rule = { - "ConfigRuleName": f"input_param_test_{random_string()}", + "ConfigRuleName": f"input_param_test_{mock_random.get_random_string()}", "Description": "Provide subset of allowed input parameters", "InputParameters": '{"blockedPort1":"22","blockedPort2":"3389"}', "Scope": {"ComplianceResourceTypes": ["AWS::IAM::SecurityGroup"]}, diff --git a/tests/test_config/test_config_tags.py b/tests/test_config/test_config_tags.py index b7257ec0e..67297fb90 100644 --- a/tests/test_config/test_config_tags.py +++ b/tests/test_config/test_config_tags.py @@ -13,8 +13,8 @@ import pytest from moto.config import mock_config from moto.config.models import MAX_TAGS_IN_ARG -from moto.config.models import random_string from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID +from moto.moto_api._internal import mock_random TEST_REGION = "us-east-1" @@ -31,7 +31,7 @@ def config_aggregators_info(client): {"Key": f"{x}", "Value": f"{x}"} for x in range(idx * 10, idx * 10 + 10) ] response = client.put_configuration_aggregator( - ConfigurationAggregatorName=f"testing_{idx}_{random_string()}", + ConfigurationAggregatorName=f"testing_{idx}_{mock_random.get_random_string()}", AccountAggregationSources=[ {"AccountIds": [ACCOUNT_ID], "AllAwsRegions": True} ], @@ -126,7 +126,7 @@ def test_tag_resource(): assert tags == updated_rsp["Tags"] # Verify keys added to ConfigRule. - config_rule_name = f"config-rule-test-{random_string()}" + config_rule_name = f"config-rule-test-{mock_random.get_random_string()}" client.put_config_rule( ConfigRule={ "ConfigRuleName": config_rule_name, @@ -248,7 +248,7 @@ def test_untag_resource(): # Verify keys removed from ConfigRule. Add a new tag to the current set # of tags, then delete the new tag. The original set of tags should remain. - rule_name = f"config-rule-delete-tags-test-{random_string()}" + rule_name = f"config-rule-delete-tags-test-{mock_random.get_random_string()}" client.put_config_rule( ConfigRule={ "ConfigRuleName": rule_name, diff --git a/tests/test_ds/test_ds.py b/tests/test_ds/test_ds.py index cb50136c9..a8c772862 100644 --- a/tests/test_ds/test_ds.py +++ b/tests/test_ds/test_ds.py @@ -10,8 +10,8 @@ from botocore.exceptions import ClientError import pytest from moto import mock_ds -from moto.core.utils import get_random_hex from moto.ec2 import mock_ec2 +from moto.moto_api._internal import mock_random from .test_ds_simple_ad_directory import create_test_directory, TEST_REGION @@ -23,7 +23,7 @@ def test_ds_delete_directory(): client = boto3.client("ds", region_name=TEST_REGION) # Delete a directory when there are none. - random_directory_id = f"d-{get_random_hex(10)}" + random_directory_id = f"d-{mock_random.get_random_hex(10)}" with pytest.raises(ClientError) as exc: client.delete_directory(DirectoryId=random_directory_id) err = exc.value.response["Error"] @@ -47,7 +47,7 @@ def test_ds_delete_directory(): assert "directory controllers" not in group["Description"] # Attempt to delete a non-existent directory. - nonexistent_id = f"d-{get_random_hex(10)}" + nonexistent_id = f"d-{mock_random.get_random_hex(10)}" with pytest.raises(ClientError) as exc: client.delete_directory(DirectoryId=nonexistent_id) err = exc.value.response["Error"] @@ -55,7 +55,7 @@ def test_ds_delete_directory(): assert f"Directory {nonexistent_id} does not exist" in err["Message"] # Attempt to use an invalid directory ID. - bad_id = get_random_hex(3) + bad_id = mock_random.get_random_hex(3) with pytest.raises(ClientError) as exc: client.delete_directory(DirectoryId=bad_id) err = exc.value.response["Error"] @@ -136,7 +136,7 @@ def test_ds_describe_directories(): assert result["DirectoryDescriptions"][0]["DirectoryId"] == directory_ids[5] # Test with a bad directory ID. - bad_id = get_random_hex(3) + bad_id = mock_random.get_random_hex(3) with pytest.raises(ClientError) as exc: client.describe_directories(DirectoryIds=[bad_id]) err = exc.value.response["Error"] @@ -177,7 +177,7 @@ def test_ds_create_alias(): directory_id = create_test_directory(client, ec2_client) # Bad format. - bad_alias = f"d-{get_random_hex(10)}" + bad_alias = f"d-{mock_random.get_random_hex(10)}" with pytest.raises(ClientError) as exc: client.create_alias(DirectoryId=directory_id, Alias=bad_alias) err = exc.value.response["Error"] @@ -189,7 +189,7 @@ def test_ds_create_alias(): ) in err["Message"] # Too long. - bad_alias = f"d-{get_random_hex(62)}" + bad_alias = f"d-{mock_random.get_random_hex(62)}" with pytest.raises(ClientError) as exc: client.create_alias(DirectoryId=directory_id, Alias=bad_alias) err = exc.value.response["Error"] @@ -200,7 +200,7 @@ def test_ds_create_alias(): ) in err["Message"] # Just right. - good_alias = f"{get_random_hex(10)}" + good_alias = f"{mock_random.get_random_hex(10)}" result = client.create_alias(DirectoryId=directory_id, Alias=good_alias) assert result["DirectoryId"] == directory_id assert result["Alias"] == good_alias @@ -210,7 +210,7 @@ def test_ds_create_alias(): assert directory["AccessUrl"] == f"{good_alias}.awsapps.com" # Attempt to create another alias for the same directory. - another_good_alias = f"{get_random_hex(10)}" + another_good_alias = f"{mock_random.get_random_hex(10)}" with pytest.raises(ClientError) as exc: client.create_alias(DirectoryId=directory_id, Alias=another_good_alias) err = exc.value.response["Error"] @@ -253,7 +253,7 @@ def test_ds_enable_sso(): # Password must be less than 128 chars in length. good_username = "test" - bad_password = f"bad_password{get_random_hex(128)}" + bad_password = f"bad_password{mock_random.get_random_hex(128)}" with pytest.raises(ClientError) as exc: client.enable_sso( DirectoryId=directory_id, UserName=good_username, Password=bad_password @@ -298,7 +298,7 @@ def test_ds_disable_sso(): # Password must be less than 128 chars in length. good_username = "test" - bad_password = f"bad_password{get_random_hex(128)}" + bad_password = f"bad_password{mock_random.get_random_hex(128)}" with pytest.raises(ClientError) as exc: client.disable_sso( DirectoryId=directory_id, UserName=good_username, Password=bad_password diff --git a/tests/test_ds/test_ds_ad_connect.py b/tests/test_ds/test_ds_ad_connect.py index 5ce3e3a32..c2fd33c2e 100644 --- a/tests/test_ds/test_ds_ad_connect.py +++ b/tests/test_ds/test_ds_ad_connect.py @@ -10,8 +10,8 @@ from botocore.exceptions import ClientError import pytest from moto import mock_ds -from moto.core.utils import get_random_hex from moto.ec2 import mock_ec2 +from moto.moto_api._internal import mock_random from .test_ds_simple_ad_directory import TEST_REGION, create_vpc, create_subnets @@ -37,7 +37,7 @@ def create_test_ad_connector( tags = [] result = ds_client.connect_directory( - Name=f"test-{get_random_hex(6)}.test", + Name=f"test-{mock_random.get_random_hex(6)}.test", Password="4ADConnectPassword", Size="Small", ConnectSettings={ @@ -59,7 +59,7 @@ def test_ds_connect_directory_validations(): this verifies that it is invoked from connect_directory(). """ client = boto3.client("ds", region_name=TEST_REGION) - random_num = get_random_hex(6) + random_num = mock_random.get_random_hex(6) # Verify ValidationException error messages are accumulated properly. bad_name = f"bad_name_{random_num}" diff --git a/tests/test_ds/test_ds_microsoft_ad.py b/tests/test_ds/test_ds_microsoft_ad.py index 2de06b6d6..ff28362fe 100644 --- a/tests/test_ds/test_ds_microsoft_ad.py +++ b/tests/test_ds/test_ds_microsoft_ad.py @@ -10,8 +10,8 @@ from botocore.exceptions import ClientError import pytest from moto import mock_ds -from moto.core.utils import get_random_hex from moto.ec2 import mock_ec2 +from moto.moto_api._internal import mock_random from .test_ds_simple_ad_directory import TEST_REGION, create_vpc, create_subnets @@ -27,7 +27,7 @@ def create_test_microsoft_ad(ds_client, ec2_client, vpc_settings=None, tags=None tags = [] result = ds_client.create_microsoft_ad( - Name=f"test-{get_random_hex(6)}.test", + Name=f"test-{mock_random.get_random_hex(6)}.test", Password="4MicrosoftADPassword", VpcSettings=vpc_settings, Tags=tags, @@ -44,7 +44,7 @@ def test_ds_create_microsoft_ad_validations(): this verifies that it is invoked from create_microsoft_ad(). """ client = boto3.client("ds", region_name=TEST_REGION) - random_num = get_random_hex(6) + random_num = mock_random.get_random_hex(6) # Verify ValidationException error messages are accumulated properly. bad_name = f"bad_name_{random_num}" diff --git a/tests/test_ds/test_ds_simple_ad_directory.py b/tests/test_ds/test_ds_simple_ad_directory.py index e87d06c6d..8ac856bce 100644 --- a/tests/test_ds/test_ds_simple_ad_directory.py +++ b/tests/test_ds/test_ds_simple_ad_directory.py @@ -5,8 +5,8 @@ import pytest from moto import mock_ds from moto import settings -from moto.core.utils import get_random_hex from moto.ec2 import mock_ec2 +from moto.moto_api._internal import mock_random TEST_REGION = "us-east-1" if settings.TEST_SERVER_MODE else "us-west-2" @@ -41,7 +41,7 @@ def create_test_directory(ds_client, ec2_client, vpc_settings=None, tags=None): tags = [] result = ds_client.create_directory( - Name=f"test-{get_random_hex(6)}.test", + Name=f"test-{mock_random.get_random_hex(6)}.test", Password="Password4TheAges", Size="Large", VpcSettings=vpc_settings, @@ -54,7 +54,7 @@ def create_test_directory(ds_client, ec2_client, vpc_settings=None, tags=None): def test_ds_create_directory_validations(): """Test validation errs that aren't caught by botocore.""" client = boto3.client("ds", region_name=TEST_REGION) - random_num = get_random_hex(6) + random_num = mock_random.get_random_hex(6) # Verify ValidationException error messages are accumulated properly. bad_name = f"bad_name_{random_num}" @@ -148,7 +148,9 @@ def test_ds_create_directory_bad_vpc_settings(): # Error if no VpcSettings argument. with pytest.raises(ClientError) as exc: client.create_directory( - Name=f"test-{get_random_hex(6)}.test", Password="TESTfoobar1", Size="Small" + Name=f"test-{mock_random.get_random_hex(6)}.test", + Password="TESTfoobar1", + Size="Small", ) err = exc.value.response["Error"] assert err["Code"] == "InvalidParameterException" diff --git a/tests/test_ec2/test_vpc_service_configuration.py b/tests/test_ec2/test_vpc_service_configuration.py index 5192d7a25..77dfcfe35 100644 --- a/tests/test_ec2/test_vpc_service_configuration.py +++ b/tests/test_ec2/test_vpc_service_configuration.py @@ -4,7 +4,7 @@ import sure # noqa # pylint: disable=unused-import from botocore.exceptions import ClientError from moto import mock_ec2, mock_elbv2 -from moto.core.utils import get_random_hex +from moto.moto_api._internal import mock_random # See our Development Tips on writing tests for hints on how to write good tests: # http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html @@ -390,7 +390,7 @@ def create_load_balancer(region_name, zone, lb_type): subnet = ec2.create_subnet( VpcId=vpc.id, CidrBlock="172.28.7.192/26", AvailabilityZone=zone ) - lb_name = f"lb_vpce-{get_random_hex(length=10)}" + lb_name = f"lb_vpce-{mock_random.get_random_hex(length=10)}" response = elbv2.create_load_balancer( Name=lb_name, Subnets=[subnet.id], Scheme="internal", Type=lb_type ) diff --git a/tests/test_eks/test_eks.py b/tests/test_eks/test_eks.py index 1cedb9e3a..1f6d96275 100644 --- a/tests/test_eks/test_eks.py +++ b/tests/test_eks/test_eks.py @@ -33,7 +33,7 @@ from moto.eks.models import ( NODEGROUP_NOT_FOUND_MSG, ) from moto.eks.responses import DEFAULT_MAX_RESULTS -from moto.utilities.utils import random_string +from moto.moto_api._internal import mock_random from .test_eks_constants import ( BatchCountSize, @@ -516,14 +516,14 @@ def test_list_nodegroups_returns_custom_second_page_results(NodegroupBuilder): @mock_eks def test_create_nodegroup_throws_exception_when_cluster_not_found(): client = boto3.client(SERVICE, region_name=REGION) - non_existent_cluster_name = random_string() + non_existent_cluster_name = mock_random.get_random_string() expected_exception = ResourceNotFoundException expected_msg = CLUSTER_NOT_FOUND_MSG.format(clusterName=non_existent_cluster_name) with pytest.raises(ClientError) as raised_exception: client.create_nodegroup( clusterName=non_existent_cluster_name, - nodegroupName=random_string(), + nodegroupName=mock_random.get_random_string(), **dict(NodegroupInputs.REQUIRED) ) @@ -571,7 +571,7 @@ def test_create_nodegroup_throws_exception_when_cluster_not_active(NodegroupBuil with pytest.raises(ClientError) as raised_exception: client.create_nodegroup( clusterName=generated_test_data.cluster_name, - nodegroupName=random_string(), + nodegroupName=mock_random.get_random_string(), **dict(NodegroupInputs.REQUIRED) ) count_nodegroups_after_test = len( @@ -827,7 +827,7 @@ def test_create_nodegroup_handles_launch_template_combinations( expected_result, ): client, generated_test_data = ClusterBuilder() - nodegroup_name = random_string() + nodegroup_name = mock_random.get_random_string() expected_exception = InvalidParameterException expected_msg = None @@ -966,14 +966,14 @@ def test_list_fargate_profile_returns_custom_second_page_results(FargateProfileB @mock_eks def test_create_fargate_profile_throws_exception_when_cluster_not_found(): client = boto3.client(SERVICE, region_name=REGION) - non_existent_cluster_name = random_string() + non_existent_cluster_name = mock_random.get_random_string() expected_exception = ResourceNotFoundException expected_msg = CLUSTER_NOT_FOUND_MSG.format(clusterName=non_existent_cluster_name) with pytest.raises(ClientError) as raised_exception: client.create_fargate_profile( clusterName=non_existent_cluster_name, - fargateProfileName=random_string(), + fargateProfileName=mock_random.get_random_string(), **dict(FargateProfileInputs.REQUIRED) ) @@ -1020,7 +1020,7 @@ def test_create_fargate_profile_throws_exception_when_cluster_not_active( with pytest.raises(ClientError) as raised_exception: client.create_fargate_profile( clusterName=generated_test_data.cluster_name, - fargateProfileName=random_string(), + fargateProfileName=mock_random.get_random_string(), **dict(FargateProfileInputs.REQUIRED) ) count_fargate_profiles_after_test = len( @@ -1188,7 +1188,7 @@ def test_delete_fargate_profile_throws_exception_when_fargate_profile_not_found( def test_create_fargate_throws_exception_when_no_selectors_provided(ClusterBuilder): client, generated_test_data = ClusterBuilder() cluster_name = generated_test_data.existing_cluster_name - fargate_profile_name = random_string() + fargate_profile_name = mock_random.get_random_string() expected_exception = InvalidParameterException expected_msg = FARGATE_PROFILE_NEEDS_SELECTOR_MSG @@ -1327,7 +1327,7 @@ def test_create_fargate_selectors( ): client, generated_test_data = ClusterBuilder() cluster_name = generated_test_data.existing_cluster_name - fargate_profile_name = random_string() + fargate_profile_name = mock_random.get_random_string() expected_exception = InvalidParameterException test_inputs = dict( @@ -1392,7 +1392,7 @@ def assert_result_matches_expected_list(result, expected_result, expected_len): def assert_valid_selectors(ClusterBuilder, expected_msg, expected_result, selectors): client, generated_test_data = ClusterBuilder() cluster_name = generated_test_data.existing_cluster_name - fargate_profile_name = random_string() + fargate_profile_name = mock_random.get_random_string() expected_exception = InvalidParameterException test_inputs = dict( diff --git a/tests/test_eks/test_eks_utils.py b/tests/test_eks/test_eks_utils.py index 9ba361c05..6354c9ddb 100644 --- a/tests/test_eks/test_eks_utils.py +++ b/tests/test_eks/test_eks_utils.py @@ -6,7 +6,7 @@ try: except ImportError: from urlparse import urlparse -from moto.utilities.utils import random_string as generate_random_name +from moto.moto_api._internal import mock_random from tests.test_eks.test_eks_constants import ( ClusterAttributes, ClusterInputs, @@ -19,6 +19,9 @@ from tests.test_eks.test_eks_constants import ( ) +generate_random_name = mock_random.get_random_string + + def attributes_to_test(inputs, name): """ Assembles the list of tuples which will be used to validate test results. diff --git a/tests/test_firehose/test_firehose.py b/tests/test_firehose/test_firehose.py index ffcfd15d2..223d9baeb 100644 --- a/tests/test_firehose/test_firehose.py +++ b/tests/test_firehose/test_firehose.py @@ -9,8 +9,8 @@ import pytest from moto import mock_firehose from moto import settings from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -from moto.core.utils import get_random_hex from moto.firehose.models import DeliveryStream +from moto.moto_api._internal import mock_random TEST_REGION = "us-east-1" if settings.TEST_SERVER_MODE else "us-west-2" @@ -33,7 +33,7 @@ def test_warnings(): s3_dest_config = sample_s3_dest_config() # DeliveryStreamEncryption is not supported. - stream_name = f"test_warning_{get_random_hex(6)}" + stream_name = f"test_warning_{mock_random.get_random_hex(6)}" with warnings.catch_warnings(record=True) as warn_msg: client.create_delivery_stream( DeliveryStreamName=stream_name, @@ -45,7 +45,7 @@ def test_warnings(): ) # Can't create a delivery stream for Splunk as it's unimplemented. - stream_name = f"test_splunk_destination_{get_random_hex(6)}" + stream_name = f"test_splunk_destination_{mock_random.get_random_hex(6)}" with warnings.catch_warnings(record=True) as warn_msg: client.create_delivery_stream( DeliveryStreamName=stream_name, @@ -61,7 +61,7 @@ def test_warnings(): ) # Can't update a delivery stream to Splunk as it's unimplemented. - stream_name = f"test_update_splunk_destination_{get_random_hex(6)}" + stream_name = f"test_update_splunk_destination_{mock_random.get_random_hex(6)}" client.create_delivery_stream( DeliveryStreamName=stream_name, S3DestinationConfiguration=s3_dest_config ) @@ -87,7 +87,7 @@ def test_create_delivery_stream_failures(): """Test errors invoking create_delivery_stream().""" client = boto3.client("firehose", region_name=TEST_REGION) s3_dest_config = sample_s3_dest_config() - failure_name = f"test_failure_{get_random_hex(6)}" + failure_name = f"test_failure_{mock_random.get_random_hex(6)}" # Create too many streams. for idx in range(DeliveryStream.MAX_STREAMS_PER_REGION): @@ -177,7 +177,7 @@ def test_delete_delivery_stream(): """Test successful and failed invocations of delete_delivery_stream().""" client = boto3.client("firehose", region_name=TEST_REGION) s3_dest_config = sample_s3_dest_config() - stream_name = f"test_delete_{get_random_hex(6)}" + stream_name = f"test_delete_{mock_random.get_random_hex(6)}" # Create a couple of streams to test with. for idx in range(5): @@ -213,7 +213,7 @@ def test_describe_delivery_stream(): """Test successful, failed invocations of describe_delivery_stream().""" client = boto3.client("firehose", region_name=TEST_REGION) s3_dest_config = sample_s3_dest_config() - stream_name = f"test_describe_{get_random_hex(6)}" + stream_name = f"test_describe_{mock_random.get_random_hex(6)}" role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/testrole" # Create delivery stream with S3 destination, kinesis type and source @@ -371,7 +371,7 @@ def test_list_delivery_streams(): """Test successful and failed invocations of list_delivery_streams().""" client = boto3.client("firehose", region_name=TEST_REGION) s3_dest_config = sample_s3_dest_config() - stream_name = f"test_list_{get_random_hex(6)}" + stream_name = f"test_list_{mock_random.get_random_hex(6)}" # Create a couple of streams of both types to test with. for idx in range(5): @@ -463,7 +463,7 @@ def test_update_destination(): assert f"Firehose foo under accountId {ACCOUNT_ID} not found" in err["Message"] # Create a delivery stream for testing purposes. - stream_name = f"test_update_{get_random_hex(6)}" + stream_name = f"test_update_{mock_random.get_random_hex(6)}" client.create_delivery_stream( DeliveryStreamName=stream_name, DeliveryStreamType="DirectPut", diff --git a/tests/test_firehose/test_firehose_destination_types.py b/tests/test_firehose/test_firehose_destination_types.py index 05f83a748..2f8b7599e 100644 --- a/tests/test_firehose/test_firehose_destination_types.py +++ b/tests/test_firehose/test_firehose_destination_types.py @@ -5,7 +5,7 @@ import sure # noqa # pylint: disable=unused-import from moto import mock_firehose from moto import settings from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -from moto.core.utils import get_random_hex +from moto.moto_api._internal import mock_random TEST_REGION = "us-east-1" if settings.TEST_SERVER_MODE else "us-west-2" @@ -118,7 +118,7 @@ def test_create_redshift_delivery_stream(): """Verify fields of a Redshift delivery stream.""" client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"stream_{get_random_hex(6)}" + stream_name = f"stream_{mock_random.get_random_hex(6)}" response = create_redshift_delivery_stream(client, stream_name) stream_arn = response["DeliveryStreamARN"] @@ -174,7 +174,7 @@ def test_create_extended_s3_delivery_stream(): """Verify fields of a S3 delivery stream.""" client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"stream_{get_random_hex(6)}" + stream_name = f"stream_{mock_random.get_random_hex(6)}" response = create_extended_s3_delivery_stream(client, stream_name) stream_arn = response["DeliveryStreamARN"] @@ -241,7 +241,7 @@ def test_create_elasticsearch_delivery_stream(): """Verify fields of an Elasticsearch delivery stream.""" client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"stream_{get_random_hex(6)}" + stream_name = f"stream_{mock_random.get_random_hex(6)}" response = create_elasticsearch_delivery_stream(client, stream_name) stream_arn = response["DeliveryStreamARN"] @@ -297,7 +297,7 @@ def test_create_s3_delivery_stream(): """Verify fields of an S3 delivery stream.""" client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"stream_{get_random_hex(6)}" + stream_name = f"stream_{mock_random.get_random_hex(6)}" response = client.create_delivery_stream( DeliveryStreamName=stream_name, S3DestinationConfiguration={ @@ -348,7 +348,7 @@ def test_create_http_stream(): """Verify fields of a HTTP delivery stream.""" client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"stream_{get_random_hex(6)}" + stream_name = f"stream_{mock_random.get_random_hex(6)}" response = create_http_delivery_stream(client, stream_name) stream_arn = response["DeliveryStreamARN"] diff --git a/tests/test_firehose/test_firehose_put.py b/tests/test_firehose/test_firehose_put.py index 5704f0a06..f3473e3ca 100644 --- a/tests/test_firehose/test_firehose_put.py +++ b/tests/test_firehose/test_firehose_put.py @@ -5,7 +5,7 @@ import sure # noqa pylint: disable=unused-import from moto import mock_firehose from moto import mock_s3 from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -from moto.core.utils import get_random_hex +from moto.moto_api._internal import mock_random from tests.test_firehose.test_firehose import TEST_REGION from tests.test_firehose.test_firehose import sample_s3_dest_config from tests.test_firehose.test_firehose_destination_types import ( @@ -24,7 +24,7 @@ def test_put_record_redshift_destination(): """ client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"test_put_record_{get_random_hex(6)}" + stream_name = f"test_put_record_{mock_random.get_random_hex(6)}" create_redshift_delivery_stream(client, stream_name) result = client.put_record( DeliveryStreamName=stream_name, Record={"Data": "some test data"} @@ -41,7 +41,7 @@ def test_put_record_batch_redshift_destination(): """ client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"test_put_record_{get_random_hex(6)}" + stream_name = f"test_put_record_{mock_random.get_random_hex(6)}" create_redshift_delivery_stream(client, stream_name) records = [{"Data": "one"}, {"Data": "two"}, {"Data": "three"}] result = client.put_record_batch(DeliveryStreamName=stream_name, Records=records) @@ -63,7 +63,7 @@ def test_put_record_http_destination(): client = boto3.client("firehose", region_name=TEST_REGION) s3_dest_config = sample_s3_dest_config() - stream_name = f"test_put_record_{get_random_hex(6)}" + stream_name = f"test_put_record_{mock_random.get_random_hex(6)}" client.create_delivery_stream( DeliveryStreamName=stream_name, HttpEndpointDestinationConfiguration={ @@ -83,7 +83,7 @@ def test_put_record_batch_http_destination(): client = boto3.client("firehose", region_name=TEST_REGION) s3_dest_config = sample_s3_dest_config() - stream_name = f"test_put_record_{get_random_hex(6)}" + stream_name = f"test_put_record_{mock_random.get_random_hex(6)}" client.create_delivery_stream( DeliveryStreamName=stream_name, HttpEndpointDestinationConfiguration={ @@ -119,7 +119,7 @@ def test_put_record_batch_extended_s3_destination(): CreateBucketConfiguration={"LocationConstraint": S3_LOCATION_CONSTRAINT}, ) - stream_name = f"test_put_record_{get_random_hex(6)}" + stream_name = f"test_put_record_{mock_random.get_random_hex(6)}" client.create_delivery_stream( DeliveryStreamName=stream_name, ExtendedS3DestinationConfiguration={ diff --git a/tests/test_firehose/test_firehose_tags.py b/tests/test_firehose/test_firehose_tags.py index 010ae3f71..3c30dc6af 100644 --- a/tests/test_firehose/test_firehose_tags.py +++ b/tests/test_firehose/test_firehose_tags.py @@ -5,8 +5,8 @@ import pytest from moto import mock_firehose from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -from moto.core.utils import get_random_hex from moto.firehose.models import MAX_TAGS_PER_DELIVERY_STREAM +from moto.moto_api._internal import mock_random from tests.test_firehose.test_firehose import TEST_REGION from tests.test_firehose.test_firehose import sample_s3_dest_config @@ -15,7 +15,7 @@ from tests.test_firehose.test_firehose import sample_s3_dest_config def test_list_tags_for_delivery_stream(): """Test invocations of list_tags_for_delivery_stream().""" client = boto3.client("firehose", region_name=TEST_REGION) - stream_name = f"test_list_tags_{get_random_hex(6)}" + stream_name = f"test_list_tags_{mock_random.get_random_hex(6)}" number_of_tags = 50 tags = [{"Key": f"{x}_k", "Value": f"{x}_v"} for x in range(1, number_of_tags + 1)] @@ -79,7 +79,7 @@ def test_tag_delivery_stream(): client = boto3.client("firehose", region_name=TEST_REGION) # Create a delivery stream for testing purposes. - stream_name = f"test_tags_{get_random_hex(6)}" + stream_name = f"test_tags_{mock_random.get_random_hex(6)}" client.create_delivery_stream( DeliveryStreamName=stream_name, ExtendedS3DestinationConfiguration=sample_s3_dest_config(), @@ -140,7 +140,7 @@ def test_untag_delivery_stream(): client = boto3.client("firehose", region_name=TEST_REGION) # Create a delivery stream for testing purposes. - stream_name = f"test_untag_{get_random_hex(6)}" + stream_name = f"test_untag_{mock_random.get_random_hex(6)}" tag_list = [ {"Key": "one", "Value": "1"}, {"Key": "two", "Value": "2"}, diff --git a/tests/test_moto_api/mock_random/test_mock_random.py b/tests/test_moto_api/mock_random/test_mock_random.py new file mode 100644 index 000000000..814abcd84 --- /dev/null +++ b/tests/test_moto_api/mock_random/test_mock_random.py @@ -0,0 +1,38 @@ +import sure # noqa # pylint: disable=unused-import +from moto.moto_api._internal import mock_random + + +def test_semi_random_uuids(): + # Create random UUID first + random_uuid = str(mock_random.uuid4()) + + # Seed our generator - the next generation should be predetermined + mock_random.seed(42) + fixed_uuid = str(mock_random.uuid4()) + fixed_uuid.should.equal("bdd640fb-0667-4ad1-9c80-317fa3b1799d") + + # Ensure they are different + fixed_uuid.shouldnt.equal(random_uuid) + + # Retrieving another 'fixed' UUID should not return a known UUID + second_fixed = str(mock_random.uuid4()) + second_fixed.shouldnt.equal(random_uuid) + second_fixed.shouldnt.equal(fixed_uuid) + + +def test_semi_random_hex_strings(): + # Create random HEX first + random_hex = mock_random.get_random_hex() + + # Seed our generator - the next generation should be predetermined + mock_random.seed(42) + fixed_hex = mock_random.get_random_hex() + fixed_hex.should.equal("30877432") + + # Ensure they are different + fixed_hex.shouldnt.equal(random_hex) + + # Retrieving another 'fixed' UUID should not return a known UUID + second_hex = mock_random.uuid4() + second_hex.shouldnt.equal(random_hex) + second_hex.shouldnt.equal(fixed_hex) diff --git a/tests/test_route53/test_route53_query_logging_config.py b/tests/test_route53/test_route53_query_logging_config.py index 641bda0f6..25afd5e1d 100644 --- a/tests/test_route53/test_route53_query_logging_config.py +++ b/tests/test_route53/test_route53_query_logging_config.py @@ -7,7 +7,7 @@ from botocore.exceptions import ClientError from moto import mock_logs from moto import mock_route53 from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -from moto.core.utils import get_random_hex +from moto.moto_api._internal import mock_random # The log group must be in the us-east-1 region. TEST_REGION = "us-east-1" @@ -17,7 +17,7 @@ def create_hosted_zone_id(route53_client, hosted_zone_test_name): """Return ID of a newly created Route53 public hosted zone""" response = route53_client.create_hosted_zone( Name=hosted_zone_test_name, - CallerReference=f"test_caller_ref_{get_random_hex(6)}", + CallerReference=f"test_caller_ref_{mock_random.get_random_hex(6)}", ) assert response["ResponseMetadata"]["HTTPStatusCode"] == 201 assert "HostedZone" in response and response["HostedZone"]["Id"] @@ -46,7 +46,7 @@ def test_create_query_logging_config_bad_args(): client = boto3.client("route53", region_name=TEST_REGION) logs_client = boto3.client("logs", region_name=TEST_REGION) - hosted_zone_test_name = f"route53_query_log_{get_random_hex(6)}.test" + hosted_zone_test_name = f"route53_query_log_{mock_random.get_random_hex(6)}.test" hosted_zone_id = create_hosted_zone_id(client, hosted_zone_test_name) log_group_arn = create_log_group_arn(logs_client, hosted_zone_test_name) @@ -114,7 +114,7 @@ def test_create_query_logging_config_good_args(): client = boto3.client("route53", region_name=TEST_REGION) logs_client = boto3.client("logs", region_name=TEST_REGION) - hosted_zone_test_name = f"route53_query_log_{get_random_hex(6)}.test" + hosted_zone_test_name = f"route53_query_log_{mock_random.get_random_hex(6)}.test" hosted_zone_id = create_hosted_zone_id(client, hosted_zone_test_name) log_group_arn = create_log_group_arn(logs_client, hosted_zone_test_name) @@ -141,7 +141,7 @@ def test_delete_query_logging_config(): logs_client = boto3.client("logs", region_name=TEST_REGION) # Create a query logging config that can then be deleted. - hosted_zone_test_name = f"route53_query_log_{get_random_hex(6)}.test" + hosted_zone_test_name = f"route53_query_log_{mock_random.get_random_hex(6)}.test" hosted_zone_id = create_hosted_zone_id(client, hosted_zone_test_name) log_group_arn = create_log_group_arn(logs_client, hosted_zone_test_name) @@ -172,7 +172,7 @@ def test_get_query_logging_config(): logs_client = boto3.client("logs", region_name=TEST_REGION) # Create a query logging config that can then be retrieved. - hosted_zone_test_name = f"route53_query_log_{get_random_hex(6)}.test" + hosted_zone_test_name = f"route53_query_log_{mock_random.get_random_hex(6)}.test" hosted_zone_id = create_hosted_zone_id(client, hosted_zone_test_name) log_group_arn = create_log_group_arn(logs_client, hosted_zone_test_name) @@ -212,7 +212,9 @@ def test_list_query_logging_configs_bad_args(): # Create a couple of query logging configs to work with. for _ in range(3): - hosted_zone_test_name = f"route53_query_log_{get_random_hex(6)}.test" + hosted_zone_test_name = ( + f"route53_query_log_{mock_random.get_random_hex(6)}.test" + ) hosted_zone_id = create_hosted_zone_id(client, hosted_zone_test_name) log_group_arn = create_log_group_arn(logs_client, hosted_zone_test_name) client.create_query_logging_config( @@ -246,7 +248,9 @@ def test_list_query_logging_configs_good_args(): # Create a couple of query logging configs to work with. zone_ids = [] for _ in range(10): - hosted_zone_test_name = f"route53_query_log_{get_random_hex(6)}.test" + hosted_zone_test_name = ( + f"route53_query_log_{mock_random.get_random_hex(6)}.test" + ) hosted_zone_id = create_hosted_zone_id(client, hosted_zone_test_name) zone_ids.append(hosted_zone_id) diff --git a/tests/test_route53resolver/test_route53resolver_endpoint.py b/tests/test_route53resolver/test_route53resolver_endpoint.py index 172c293d3..4a5d72382 100644 --- a/tests/test_route53resolver/test_route53resolver_endpoint.py +++ b/tests/test_route53resolver/test_route53resolver_endpoint.py @@ -9,8 +9,8 @@ import pytest from moto import mock_route53resolver from moto import settings from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -from moto.core.utils import get_random_hex from moto.ec2 import mock_ec2 +from moto.moto_api._internal import mock_random TEST_REGION = "us-east-1" if settings.TEST_SERVER_MODE else "us-west-2" @@ -58,7 +58,7 @@ def create_test_endpoint(client, ec2_client, name=None, tags=None): """ if not tags: tags = [] - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) subnet_ids = create_subnets(ec2_client, create_vpc(ec2_client)) resolver_endpoint = client.create_resolver_endpoint( CreatorRequestId=random_num, @@ -78,7 +78,7 @@ def create_test_endpoint(client, ec2_client, name=None, tags=None): def test_route53resolver_invalid_create_endpoint_args(): """Test invalid arguments to the create_resolver_endpoint API.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Verify ValidationException error messages are accumulated properly: # - creator requestor ID that exceeds the allowed length of 255. @@ -88,7 +88,7 @@ def test_route53resolver_invalid_create_endpoint_args(): # - too many security group IDs. long_id = random_num * 25 + "123456" long_name = random_num * 6 + "abcde" - too_many_security_groups = ["sg-" + get_random_hex(63)] + too_many_security_groups = ["sg-" + mock_random.get_random_hex(63)] bad_direction = "foo" too_many_ip_addresses = [{"SubnetId": f"{x}", "Ip": f"{x}" * 7} for x in range(11)] with pytest.raises(ClientError) as exc: @@ -168,7 +168,7 @@ def test_route53resolver_bad_create_endpoint_subnets(): """Test bad subnet scenarios for create_resolver_endpoint API.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Need 2 IP addresses at the minimum. subnet_ids = create_subnets(ec2_client, create_vpc(ec2_client)) @@ -246,7 +246,7 @@ def test_route53resolver_bad_create_endpoint_security_groups(): """Test bad security group scenarios for create_resolver_endpoint API.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) subnet_ids = create_subnets(ec2_client, create_vpc(ec2_client)) ip_addrs = [ @@ -302,7 +302,7 @@ def test_route53resolver_create_resolver_endpoint(): # pylint: disable=too-many """Test good create_resolver_endpoint API calls.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) vpc_id = create_vpc(ec2_client) subnet_ids = create_subnets(ec2_client, vpc_id) @@ -365,7 +365,7 @@ def test_route53resolver_other_create_resolver_endpoint_errors(): with pytest.raises(ClientError) as exc: client.create_resolver_endpoint( CreatorRequestId=created_endpoint["CreatorRequestId"], - Name="X" + get_random_hex(10), + Name="X" + mock_random.get_random_hex(10), SecurityGroupIds=created_endpoint["SecurityGroupIds"], Direction="INBOUND", IpAddresses=[ @@ -380,7 +380,7 @@ def test_route53resolver_other_create_resolver_endpoint_errors(): ) in err["Message"] # Too many endpoints. - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) for idx in range(4): create_test_endpoint(client, ec2_client, name=f"A{idx}-{random_num}") with pytest.raises(ClientError) as exc: @@ -428,7 +428,7 @@ def test_route53resolver_bad_delete_resolver_endpoint(): """Test delete_resolver_endpoint API calls with a bad ID.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Use a resolver endpoint id that is too long. long_id = "0123456789" * 6 + "xxxxx" @@ -498,7 +498,7 @@ def test_route53resolver_get_resolver_endpoint(): def test_route53resolver_bad_get_resolver_endpoint(): """Test get_resolver_endpoint API calls with a bad ID.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Use a resolver endpoint id that is too long. long_id = "0123456789" * 6 + "xxxxx" @@ -529,7 +529,7 @@ def test_route53resolver_update_resolver_endpoint(): created_endpoint = create_test_endpoint(client, ec2_client) # Now update the resolver endpoint name and verify the response. - new_name = "NewName" + get_random_hex(6) + new_name = "NewName" + mock_random.get_random_hex(6) response = client.update_resolver_endpoint( ResolverEndpointId=created_endpoint["Id"], Name=new_name ) @@ -552,8 +552,8 @@ def test_route53resolver_update_resolver_endpoint(): def test_route53resolver_bad_update_resolver_endpoint(): """Test update_resolver_endpoint API calls with a bad ID.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) - random_name = "Z" + get_random_hex(10) + random_num = mock_random.get_random_hex(10) + random_name = "Z" + mock_random.get_random_hex(10) # Use a resolver endpoint id that is too long. long_id = "0123456789" * 6 + "xxxxx" @@ -581,7 +581,7 @@ def test_route53resolver_list_resolver_endpoint_ip_addresses(): """Test good list_resolver_endpoint_ip_addresses API calls.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) subnet_ids = create_subnets(ec2_client, create_vpc(ec2_client)) response = client.create_resolver_endpoint( @@ -641,7 +641,7 @@ def test_route53resolver_bad_list_resolver_endpoint_ip_addresses(): assert "Resolver endpoint with ID 'foo' does not exist" in err["Message"] # Good endpoint id, but bad max_results. - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) response = create_test_endpoint(client, ec2_client, name=f"A-{random_num}") with pytest.raises(ClientError) as exc: client.list_resolver_endpoint_ip_addresses( @@ -662,7 +662,7 @@ def test_route53resolver_list_resolver_endpoints(): """Test good list_resolver_endpoints API calls.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # List endpoints when there are none. response = client.list_resolver_endpoints() @@ -703,7 +703,7 @@ def test_route53resolver_list_resolver_endpoints_filters(): """Test good list_resolver_endpoints API calls that use filters.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Create some endpoints for testing purposes security_group_id = create_security_group(ec2_client) @@ -832,7 +832,7 @@ def test_route53resolver_bad_list_resolver_endpoints(): ec2_client = boto3.client("ec2", region_name=TEST_REGION) # Bad max_results. - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) create_test_endpoint(client, ec2_client, name=f"A-{random_num}") with pytest.raises(ClientError) as exc: client.list_resolver_endpoints(MaxResults=250) @@ -856,7 +856,7 @@ def test_associate_resolver_endpoint_ip_address(): VpcId=vpc_id, CidrBlock="10.0.2.0/24", AvailabilityZone=f"{TEST_REGION}a" )["Subnet"] # create resolver - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) resolver = create_test_endpoint(client, ec2_client, name=f"A-{random_num}") resolver.should.have.key("IpAddressCount").equals(2) # associate @@ -897,7 +897,7 @@ def test_disassociate_resolver_endpoint_ip_address__using_ip(): VpcId=vpc_id, CidrBlock="10.0.2.0/24", AvailabilityZone=f"{TEST_REGION}a" )["Subnet"]["SubnetId"] # create resolver - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) resolver = create_test_endpoint(client, ec2_client, name=f"A-{random_num}") # associate client.associate_resolver_endpoint_ip_address( @@ -926,7 +926,7 @@ def test_disassociate_resolver_endpoint_ip_address__using_ipid_and_subnet(): VpcId=vpc_id, CidrBlock="10.0.2.0/24", AvailabilityZone=f"{TEST_REGION}a" )["Subnet"]["SubnetId"] # create resolver - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) resolver = create_test_endpoint(client, ec2_client, name=f"A-{random_num}") # associate client.associate_resolver_endpoint_ip_address( @@ -957,7 +957,7 @@ def test_disassociate_resolver_endpoint_ip_address__using_subnet_alone(): VpcId=vpc_id, CidrBlock="10.0.2.0/24", AvailabilityZone=f"{TEST_REGION}a" )["Subnet"]["SubnetId"] # create resolver - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) resolver = create_test_endpoint(client, ec2_client, name=f"A-{random_num}") # associate client.associate_resolver_endpoint_ip_address( diff --git a/tests/test_route53resolver/test_route53resolver_rule.py b/tests/test_route53resolver/test_route53resolver_rule.py index acdc100d9..2801f4008 100644 --- a/tests/test_route53resolver/test_route53resolver_rule.py +++ b/tests/test_route53resolver/test_route53resolver_rule.py @@ -8,8 +8,8 @@ import pytest from moto import mock_route53resolver from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -from moto.core.utils import get_random_hex from moto.ec2 import mock_ec2 +from moto.moto_api._internal import mock_random from .test_route53resolver_endpoint import TEST_REGION, create_test_endpoint, create_vpc @@ -21,7 +21,7 @@ def create_test_rule(client, name=None, tags=None): """ if not tags: tags = [] - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) resolver_rule = client.create_resolver_rule( CreatorRequestId=random_num, @@ -42,7 +42,7 @@ def create_test_rule(client, name=None, tags=None): def test_route53resolver_invalid_create_rule_args(): """Test invalid arguments to the create_resolver_rule API.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Verify ValidationException error messages are accumulated properly: # - creator requestor ID that exceeds the allowed length of 255. @@ -128,7 +128,7 @@ def test_route53resolver_create_resolver_rule(): # pylint: disable=too-many-loc """Test good create_resolver_rule API calls.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Create a good endpoint that we can use to test. created_endpoint = create_test_endpoint(client, ec2_client) @@ -183,7 +183,7 @@ def test_route53resolver_bad_create_resolver_rule(): """Test error scenarios for create_resolver_rule API calls.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Create a good endpoint and rule that we can use to test. created_endpoint = create_test_endpoint(client, ec2_client) @@ -210,7 +210,7 @@ def test_route53resolver_bad_create_resolver_rule(): # Attempt to create a rule with a IPv6 address. with pytest.raises(ClientError) as exc: client.create_resolver_rule( - CreatorRequestId=get_random_hex(10), + CreatorRequestId=mock_random.get_random_hex(10), Name="B" + random_num, RuleType="FORWARD", DomainName=f"{random_num}.test", @@ -224,7 +224,7 @@ def test_route53resolver_bad_create_resolver_rule(): # Attempt to create a rule with an invalid IPv4 address. with pytest.raises(ClientError) as exc: client.create_resolver_rule( - CreatorRequestId=get_random_hex(10), + CreatorRequestId=mock_random.get_random_hex(10), Name="B" + random_num, RuleType="FORWARD", DomainName=f"{random_num}.test", @@ -238,7 +238,7 @@ def test_route53resolver_bad_create_resolver_rule(): # Attempt to create a rule with a non-existent resolver endpoint id. with pytest.raises(ClientError) as exc: client.create_resolver_rule( - CreatorRequestId=get_random_hex(10), + CreatorRequestId=mock_random.get_random_hex(10), Name="B" + random_num, RuleType="FORWARD", DomainName=f"{random_num}.test", @@ -252,7 +252,7 @@ def test_route53resolver_bad_create_resolver_rule(): # Create a rule with a resolver endpoint id and a rule type of SYSTEM. with pytest.raises(ClientError) as exc: client.create_resolver_rule( - CreatorRequestId=get_random_hex(10), + CreatorRequestId=mock_random.get_random_hex(10), Name="B" + random_num, RuleType="SYSTEM", DomainName=f"{random_num}.test", @@ -305,7 +305,7 @@ def test_route53resolver_bad_delete_resolver_rule(): """Test delete_resolver_rule API calls with a bad ID.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Use a resolver rule id that is too long. long_id = "0123456789" * 6 + "xxxxx" @@ -367,7 +367,7 @@ def test_route53resolver_get_resolver_rule(): def test_route53resolver_bad_get_resolver_rule(): """Test get_resolver_rule API calls with a bad ID.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Use a resolver rule id that is too long. long_id = "0123456789" * 6 + "xxxxx" @@ -393,7 +393,7 @@ def test_route53resolver_bad_get_resolver_rule(): def test_route53resolver_list_resolver_rules(): """Test good list_resolver_rules API calls.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # List rules when there are none. response = client.list_resolver_rules() @@ -434,7 +434,7 @@ def test_route53resolver_list_resolver_rules_filters(): """Test good list_resolver_rules API calls that use filters.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Create some endpoints and rules for testing purposes. endpoint1 = create_test_endpoint(client, ec2_client)["Id"] @@ -533,7 +533,7 @@ def test_route53resolver_bad_list_resolver_rules(): client = boto3.client("route53resolver", region_name=TEST_REGION) # Bad max_results. - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) create_test_rule(client, name=f"A-{random_num}") with pytest.raises(ClientError) as exc: client.list_resolver_rules(MaxResults=250) diff --git a/tests/test_route53resolver/test_route53resolver_rule_associations.py b/tests/test_route53resolver/test_route53resolver_rule_associations.py index 595978bca..6a580bd9e 100644 --- a/tests/test_route53resolver/test_route53resolver_rule_associations.py +++ b/tests/test_route53resolver/test_route53resolver_rule_associations.py @@ -5,8 +5,8 @@ from botocore.exceptions import ClientError import pytest from moto import mock_route53resolver -from moto.core.utils import get_random_hex from moto.ec2 import mock_ec2 +from moto.moto_api._internal import mock_random from .test_route53resolver_endpoint import TEST_REGION, create_vpc from .test_route53resolver_rule import create_test_rule @@ -18,7 +18,7 @@ def create_test_rule_association( """Create a Resolver Rule Association for testing purposes.""" if not resolver_rule_id: resolver_rule_id = create_test_rule(client)["Id"] - name = name if name else "R" + get_random_hex(10) + name = name if name else "R" + mock_random.get_random_hex(10) if not vpc_id: vpc_id = create_vpc(ec2_client) return client.associate_resolver_rule( @@ -30,7 +30,7 @@ def create_test_rule_association( def test_route53resolver_invalid_associate_resolver_rule_args(): """Test invalid arguments to the associate_resolver_rule API.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Verify ValidationException error messages are accumulated properly: # - resolver rule ID that exceeds the allowed length of 64. @@ -68,7 +68,7 @@ def test_route53resolver_associate_resolver_rule(): ec2_client = boto3.client("ec2", region_name=TEST_REGION) resolver_rule_id = create_test_rule(client)["Id"] - name = "X" + get_random_hex(10) + name = "X" + mock_random.get_random_hex(10) vpc_id = create_vpc(ec2_client) rule_association = client.associate_resolver_rule( ResolverRuleId=resolver_rule_id, Name=name, VPCId=vpc_id @@ -151,7 +151,7 @@ def test_route53resolver_bad_disassociate_resolver_rule(): """Test disassociate_resolver_rule API calls with a bad ID.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Use a resolver rule id and vpc id that is too long. long_id = "0123456789" * 6 + "xxxxx" @@ -234,7 +234,7 @@ def test_route53resolver_get_resolver_rule_association(): def test_route53resolver_bad_get_resolver_rule_association(): """Test get_resolver_rule_association API calls with a bad ID.""" client = boto3.client("route53resolver", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Use a resolver rule association id that is too long. long_id = "0123456789" * 6 + "xxxxx" @@ -262,7 +262,7 @@ def test_route53resolver_list_resolver_rule_associations(): """Test good list_resolver_rule_associations API calls.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # List rule associations when there are none. response = client.list_resolver_rule_associations() @@ -304,7 +304,7 @@ def test_route53resolver_list_resolver_rule_associations_filters(): """Test good list_resolver_rule_associations API calls that use filters.""" client = boto3.client("route53resolver", region_name=TEST_REGION) ec2_client = boto3.client("ec2", region_name=TEST_REGION) - random_num = get_random_hex(10) + random_num = mock_random.get_random_hex(10) # Create some rule associations for testing purposes vpc_id1 = create_vpc(ec2_client)