add support for AWS Organizations
endpoints covers so far: - create_organization - describe_organization - create_account - describe_account - list_accounts all tests passing. could use some advise from maintaners.
This commit is contained in:
		
							parent
							
								
									a1d095c14b
								
							
						
					
					
						commit
						edbc57e00d
					
				| @ -27,6 +27,7 @@ from .glacier import mock_glacier, mock_glacier_deprecated  # flake8: noqa | |||||||
| from .iam import mock_iam, mock_iam_deprecated  # flake8: noqa | from .iam import mock_iam, mock_iam_deprecated  # flake8: noqa | ||||||
| from .kinesis import mock_kinesis, mock_kinesis_deprecated  # flake8: noqa | from .kinesis import mock_kinesis, mock_kinesis_deprecated  # flake8: noqa | ||||||
| from .kms import mock_kms, mock_kms_deprecated  # flake8: noqa | from .kms import mock_kms, mock_kms_deprecated  # flake8: noqa | ||||||
|  | from .organizations import mock_organizations  # flake8: noqa | ||||||
| from .opsworks import mock_opsworks, mock_opsworks_deprecated  # flake8: noqa | from .opsworks import mock_opsworks, mock_opsworks_deprecated  # flake8: noqa | ||||||
| from .polly import mock_polly  # flake8: noqa | from .polly import mock_polly  # flake8: noqa | ||||||
| from .rds import mock_rds, mock_rds_deprecated  # flake8: noqa | from .rds import mock_rds, mock_rds_deprecated  # flake8: noqa | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ from moto.kinesis import kinesis_backends | |||||||
| from moto.kms import kms_backends | from moto.kms import kms_backends | ||||||
| from moto.logs import logs_backends | from moto.logs import logs_backends | ||||||
| from moto.opsworks import opsworks_backends | from moto.opsworks import opsworks_backends | ||||||
|  | from moto.organizations import organizations_backends | ||||||
| from moto.polly import polly_backends | from moto.polly import polly_backends | ||||||
| from moto.rds2 import rds2_backends | from moto.rds2 import rds2_backends | ||||||
| from moto.redshift import redshift_backends | from moto.redshift import redshift_backends | ||||||
| @ -72,6 +73,7 @@ BACKENDS = { | |||||||
|     'kinesis': kinesis_backends, |     'kinesis': kinesis_backends, | ||||||
|     'kms': kms_backends, |     'kms': kms_backends, | ||||||
|     'opsworks': opsworks_backends, |     'opsworks': opsworks_backends, | ||||||
|  |     'organizations': organizations_backends, | ||||||
|     'polly': polly_backends, |     'polly': polly_backends, | ||||||
|     'redshift': redshift_backends, |     'redshift': redshift_backends, | ||||||
|     'rds': rds2_backends, |     'rds': rds2_backends, | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								moto/organizations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								moto/organizations/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | from __future__ import unicode_literals | ||||||
|  | from .models import organizations_backend | ||||||
|  | from ..core.models import base_decorator | ||||||
|  | 
 | ||||||
|  | organizations_backends = {"global": organizations_backend} | ||||||
|  | mock_organizations = base_decorator(organizations_backends) | ||||||
							
								
								
									
										131
									
								
								moto/organizations/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								moto/organizations/models.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | |||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | import datetime | ||||||
|  | import time | ||||||
|  | 
 | ||||||
|  | from moto.core import BaseBackend, BaseModel | ||||||
|  | from moto.core.utils import unix_time | ||||||
|  | from moto.organizations import utils | ||||||
|  | 
 | ||||||
|  | MASTER_ACCOUNT_ID = '123456789012' | ||||||
|  | MASTER_ACCOUNT_EMAIL = 'fakeorg@moto-example.com' | ||||||
|  | ORGANIZATION_ARN_FORMAT = 'arn:aws:organizations::{0}:organization/{1}' | ||||||
|  | MASTER_ACCOUNT_ARN_FORMAT = 'arn:aws:organizations::{0}:account/{1}/{0}' | ||||||
|  | ACCOUNT_ARN_FORMAT = 'arn:aws:organizations::{0}:account/{1}/{2}' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class FakeOrganization(BaseModel): | ||||||
|  | 
 | ||||||
|  |     def __init__(self, feature_set): | ||||||
|  |         self.id = utils.make_random_org_id() | ||||||
|  |         self.feature_set = feature_set | ||||||
|  |         self.master_account_id = MASTER_ACCOUNT_ID | ||||||
|  |         self.master_account_email = MASTER_ACCOUNT_EMAIL | ||||||
|  |         self.available_policy_types = [{ | ||||||
|  |             'Type': 'SERVICE_CONTROL_POLICY', | ||||||
|  |             'Status': 'ENABLED' | ||||||
|  |         }] | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def arn(self): | ||||||
|  |         return ORGANIZATION_ARN_FORMAT.format(self.master_account_id, self.id) | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def master_account_arn(self): | ||||||
|  |         return MASTER_ACCOUNT_ARN_FORMAT.format(self.master_account_id, self.id) | ||||||
|  | 
 | ||||||
|  |     def _describe(self): | ||||||
|  |         return { | ||||||
|  |             'Organization': { | ||||||
|  |                 'Id': self.id, | ||||||
|  |                 'Arn': self.arn, | ||||||
|  |                 'FeatureSet': self.feature_set, | ||||||
|  |                 'MasterAccountArn': self.master_account_arn, | ||||||
|  |                 'MasterAccountId': self.master_account_id, | ||||||
|  |                 'MasterAccountEmail': self.master_account_email, | ||||||
|  |                 'AvailablePolicyTypes': self.available_policy_types, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class FakeAccount(BaseModel): | ||||||
|  | 
 | ||||||
|  |     def __init__(self, organization, **kwargs): | ||||||
|  |         self.organization_id = organization.id | ||||||
|  |         self.master_account_id = organization.master_account_id | ||||||
|  |         self.create_account_status_id = utils.make_random_create_account_status_id() | ||||||
|  |         self.account_id = utils.make_random_account_id() | ||||||
|  |         self.account_name = kwargs['AccountName'] | ||||||
|  |         self.email = kwargs['Email'] | ||||||
|  |         self.create_time = datetime.datetime.utcnow() | ||||||
|  |         self.status = 'ACTIVE' | ||||||
|  |         self.joined_method = 'CREATED' | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def arn(self): | ||||||
|  |         return ACCOUNT_ARN_FORMAT.format( | ||||||
|  |             self.master_account_id, | ||||||
|  |             self.organization_id, | ||||||
|  |             self.account_id | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def create_account_status(self): | ||||||
|  |         return { | ||||||
|  |             'CreateAccountStatus': { | ||||||
|  |                 'Id': self.create_account_status_id, | ||||||
|  |                 'AccountName': self.account_name, | ||||||
|  |                 'State': 'SUCCEEDED', | ||||||
|  |                 'RequestedTimestamp': unix_time(self.create_time), | ||||||
|  |                 'CompletedTimestamp': unix_time(self.create_time), | ||||||
|  |                 'AccountId': self.account_id, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     def describe(self): | ||||||
|  |         return { | ||||||
|  |             'Account': { | ||||||
|  |                 'Id': self.account_id, | ||||||
|  |                 'Arn': self.arn, | ||||||
|  |                 'Email': self.email, | ||||||
|  |                 'Name': self.account_name, | ||||||
|  |                 'Status': self.status, | ||||||
|  |                 'JoinedMethod': self.joined_method, | ||||||
|  |                 'JoinedTimestamp': unix_time(self.create_time), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class OrganizationsBackend(BaseBackend): | ||||||
|  | 
 | ||||||
|  |     def __init__(self): | ||||||
|  |         self.org = None | ||||||
|  |         self.accounts = [] | ||||||
|  | 
 | ||||||
|  |     def create_organization(self, **kwargs): | ||||||
|  |         self.org = FakeOrganization(kwargs['FeatureSet']) | ||||||
|  |         return self.org._describe() | ||||||
|  | 
 | ||||||
|  |     def describe_organization(self): | ||||||
|  |         return self.org._describe() | ||||||
|  | 
 | ||||||
|  |     def create_account(self, **kwargs): | ||||||
|  |         new_account = FakeAccount(self.org, **kwargs) | ||||||
|  |         self.accounts.append(new_account) | ||||||
|  |         return new_account.create_account_status | ||||||
|  | 
 | ||||||
|  |     def describe_account(self, **kwargs): | ||||||
|  |         account = [account for account in self.accounts  | ||||||
|  |                    if account.account_id == kwargs['AccountId']][0] | ||||||
|  |         return account.describe() | ||||||
|  | 
 | ||||||
|  |     def list_accounts(self): | ||||||
|  |         return dict( | ||||||
|  |             Accounts=[account.describe()['Account'] for account in self.accounts] | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | organizations_backend = OrganizationsBackend() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										48
									
								
								moto/organizations/responses.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								moto/organizations/responses.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | from __future__ import unicode_literals | ||||||
|  | import json | ||||||
|  | 
 | ||||||
|  | from moto.core.responses import BaseResponse | ||||||
|  | from .models import organizations_backend | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class OrganizationsResponse(BaseResponse): | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def organizations_backend(self): | ||||||
|  |         return organizations_backend | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def request_params(self): | ||||||
|  |         try: | ||||||
|  |             return json.loads(self.body) | ||||||
|  |         except ValueError: | ||||||
|  |             return {} | ||||||
|  | 
 | ||||||
|  |     def _get_param(self, param, default=None): | ||||||
|  |         return self.request_params.get(param, default) | ||||||
|  | 
 | ||||||
|  |     def create_organization(self): | ||||||
|  |         return json.dumps( | ||||||
|  |             self.organizations_backend.create_organization(**self.request_params) | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def describe_organization(self): | ||||||
|  |         return json.dumps( | ||||||
|  |             self.organizations_backend.describe_organization() | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def create_account(self): | ||||||
|  |         return json.dumps( | ||||||
|  |             self.organizations_backend.create_account(**self.request_params) | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def describe_account(self): | ||||||
|  |         return json.dumps( | ||||||
|  |             self.organizations_backend.describe_account(**self.request_params) | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def list_accounts(self): | ||||||
|  |         return json.dumps( | ||||||
|  |             self.organizations_backend.list_accounts() | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
							
								
								
									
										10
									
								
								moto/organizations/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								moto/organizations/urls.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | from __future__ import unicode_literals | ||||||
|  | from .responses import OrganizationsResponse | ||||||
|  | 
 | ||||||
|  | url_bases = [ | ||||||
|  |     "https?://organizations.(.+).amazonaws.com", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | url_paths = { | ||||||
|  |     '{0}/$': OrganizationsResponse.dispatch, | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								moto/organizations/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								moto/organizations/utils.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | import random | ||||||
|  | import string | ||||||
|  | 
 | ||||||
|  | CHARSET=string.ascii_lowercase + string.digits | ||||||
|  | ORG_ID_SIZE = 10 | ||||||
|  | ROOT_ID_SIZE = 4 | ||||||
|  | ACCOUNT_ID_SIZE = 12 | ||||||
|  | CREATE_ACCOUNT_STATUS_ID_SIZE = 8 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def make_random_org_id(): | ||||||
|  |     # The regex pattern for an organization ID string requires "o-"  | ||||||
|  |     # followed by from 10 to 32 lower-case letters or digits. | ||||||
|  |     # e.g. 'o-vipjnq5z86' | ||||||
|  |     return 'o-' + ''.join(random.choice(CHARSET) for x in range(ORG_ID_SIZE)) | ||||||
|  | 
 | ||||||
|  | def make_random_root_id(): | ||||||
|  |     # The regex pattern for a root ID string requires "r-" followed by  | ||||||
|  |     # from 4 to 32 lower-case letters or digits. | ||||||
|  |     # e.g. 'r-3zwx' | ||||||
|  |     return 'r-' + ''.join(random.choice(CHARSET) for x in range(ROOT_ID_SIZE)) | ||||||
|  | 
 | ||||||
|  | def make_random_account_id(): | ||||||
|  |     # The regex pattern for an account ID string requires exactly 12 digits. | ||||||
|  |     # e.g. '488633172133' | ||||||
|  |     return ''.join([random.choice(string.digits) for n in range(ACCOUNT_ID_SIZE)]) | ||||||
|  | 
 | ||||||
|  | def make_random_create_account_status_id(): | ||||||
|  |     # The regex pattern for an create account request ID string requires  | ||||||
|  |     # "car-" followed by from 8 to 32 lower-case letters or digits. | ||||||
|  |     # e.g. 'car-35gxzwrp' | ||||||
|  |     return 'car-' + ''.join(random.choice(CHARSET) for x in range(CREATE_ACCOUNT_STATUS_ID_SIZE)) | ||||||
							
								
								
									
										0
									
								
								tests/test_organizations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/test_organizations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										24
									
								
								tests/test_organizations/object_syntax.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tests/test_organizations/object_syntax.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | """ | ||||||
|  | Temporary functions for checking object structures while specing out | ||||||
|  | models.  This module will go away. | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | import yaml | ||||||
|  | import moto | ||||||
|  | from moto import organizations as orgs | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # utils | ||||||
|  | print(orgs.utils.make_random_org_id()) | ||||||
|  | print(orgs.utils.make_random_root_id()) | ||||||
|  | print(orgs.utils.make_random_account_id()) | ||||||
|  | print(orgs.utils.make_random_create_account_id()) | ||||||
|  | 
 | ||||||
|  | # models | ||||||
|  | my_org = orgs.models.FakeOrganization(feature_set = 'ALL') | ||||||
|  | print(yaml.dump(my_org._describe())) | ||||||
|  | #assert False | ||||||
|  | 
 | ||||||
|  | my_account = orgs.models.FakeAccount(my_org, AccountName='blee01', Email='blee01@moto-example.org') | ||||||
|  | print(yaml.dump(my_account)) | ||||||
|  | #assert False | ||||||
							
								
								
									
										193
									
								
								tests/test_organizations/test_organizations_boto3.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								tests/test_organizations/test_organizations_boto3.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,193 @@ | |||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | import boto3 | ||||||
|  | import botocore.exceptions | ||||||
|  | import sure   # noqa | ||||||
|  | import yaml | ||||||
|  | import re | ||||||
|  | import datetime | ||||||
|  | 
 | ||||||
|  | import moto | ||||||
|  | from moto import mock_organizations | ||||||
|  | from moto.organizations.models import ( | ||||||
|  |     MASTER_ACCOUNT_ID, | ||||||
|  |     MASTER_ACCOUNT_EMAIL, | ||||||
|  |     ORGANIZATION_ARN_FORMAT, | ||||||
|  |     MASTER_ACCOUNT_ARN_FORMAT, | ||||||
|  |     ACCOUNT_ARN_FORMAT, | ||||||
|  | ) | ||||||
|  | from .test_organizations_utils import ( | ||||||
|  |     ORG_ID_REGEX, | ||||||
|  |     ROOT_ID_REGEX, | ||||||
|  |     ACCOUNT_ID_REGEX, | ||||||
|  |     CREATE_ACCOUNT_STATUS_ID_REGEX, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | EMAIL_REGEX = "^.+@[a-zA-Z0-9-.]+.[a-zA-Z]{2,3}|[0-9]{1,3}$" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def validate_organization(response): | ||||||
|  |     org = response['Organization'] | ||||||
|  |     sorted(org.keys()).should.equal([ | ||||||
|  |         'Arn', | ||||||
|  |         'AvailablePolicyTypes', | ||||||
|  |         'FeatureSet', | ||||||
|  |         'Id', | ||||||
|  |         'MasterAccountArn', | ||||||
|  |         'MasterAccountEmail', | ||||||
|  |         'MasterAccountId', | ||||||
|  |     ]) | ||||||
|  |     org['Id'].should.match(ORG_ID_REGEX) | ||||||
|  |     org['MasterAccountId'].should.equal(MASTER_ACCOUNT_ID) | ||||||
|  |     org['MasterAccountArn'].should.equal(MASTER_ACCOUNT_ARN_FORMAT.format( | ||||||
|  |         org['MasterAccountId'], | ||||||
|  |         org['Id'], | ||||||
|  |     )) | ||||||
|  |     org['Arn'].should.equal(ORGANIZATION_ARN_FORMAT.format( | ||||||
|  |         org['MasterAccountId'], | ||||||
|  |         org['Id'], | ||||||
|  |     )) | ||||||
|  |     org['MasterAccountEmail'].should.equal(MASTER_ACCOUNT_EMAIL) | ||||||
|  |     org['FeatureSet'].should.be.within(['ALL', 'CONSOLIDATED_BILLING']) | ||||||
|  |     org['AvailablePolicyTypes'].should.equal([{ | ||||||
|  |         'Type': 'SERVICE_CONTROL_POLICY', | ||||||
|  |         'Status': 'ENABLED' | ||||||
|  |     }]) | ||||||
|  |     # | ||||||
|  |     #'Organization': { | ||||||
|  |     #    'Id': 'string', | ||||||
|  |     #    'Arn': 'string', | ||||||
|  |     #    'FeatureSet': 'ALL'|'CONSOLIDATED_BILLING', | ||||||
|  |     #    'MasterAccountArn': 'string', | ||||||
|  |     #    'MasterAccountId': 'string', | ||||||
|  |     #    'MasterAccountEmail': 'string', | ||||||
|  |     #    'AvailablePolicyTypes': [ | ||||||
|  |     #        { | ||||||
|  |     #            'Type': 'SERVICE_CONTROL_POLICY', | ||||||
|  |     #            'Status': 'ENABLED'|'PENDING_ENABLE'|'PENDING_DISABLE' | ||||||
|  |     #        }, | ||||||
|  |     #    ] | ||||||
|  |     #} | ||||||
|  | 
 | ||||||
|  | def validate_account(org, account): | ||||||
|  |     sorted(account.keys()).should.equal([ | ||||||
|  |         'Arn', | ||||||
|  |         'Email', | ||||||
|  |         'Id', | ||||||
|  |         'JoinedMethod', | ||||||
|  |         'JoinedTimestamp', | ||||||
|  |         'Name', | ||||||
|  |         'Status', | ||||||
|  |     ]) | ||||||
|  |     account['Id'].should.match(ACCOUNT_ID_REGEX) | ||||||
|  |     account['Arn'].should.equal(ACCOUNT_ARN_FORMAT.format( | ||||||
|  |         org['MasterAccountId'], | ||||||
|  |         org['Id'], | ||||||
|  |         account['Id'], | ||||||
|  |     ))         | ||||||
|  |     account['Email'].should.match(EMAIL_REGEX) | ||||||
|  |     account['JoinedMethod'].should.be.within(['INVITED', 'CREATED']) | ||||||
|  |     account['Status'].should.be.within(['ACTIVE', 'SUSPENDED']) | ||||||
|  |     account['Name'].should.be.a(str) | ||||||
|  |     account['JoinedTimestamp'].should.be.a(datetime.datetime) | ||||||
|  |     #'Account': { | ||||||
|  |     #    'Id': 'string', | ||||||
|  |     #    'Arn': 'string', | ||||||
|  |     #    'Email': 'string', | ||||||
|  |     #    'Name': 'string', | ||||||
|  |     #    'Status': 'ACTIVE'|'SUSPENDED', | ||||||
|  |     #    'JoinedMethod': 'INVITED'|'CREATED', | ||||||
|  |     #    'JoinedTimestamp': datetime(2015, 1, 1) | ||||||
|  |     #} | ||||||
|  | 
 | ||||||
|  | def validate_create_account_status(create_status): | ||||||
|  |     sorted(create_status.keys()).should.equal([ | ||||||
|  |         'AccountId', | ||||||
|  |         'AccountName', | ||||||
|  |         'CompletedTimestamp', | ||||||
|  |         'Id', | ||||||
|  |         'RequestedTimestamp', | ||||||
|  |         'State', | ||||||
|  |     ]) | ||||||
|  |     create_status['Id'].should.match(CREATE_ACCOUNT_STATUS_ID_REGEX) | ||||||
|  |     create_status['AccountId'].should.match(ACCOUNT_ID_REGEX) | ||||||
|  |     create_status['AccountName'].should.be.a(str) | ||||||
|  |     create_status['State'].should.equal('SUCCEEDED') | ||||||
|  |     create_status['RequestedTimestamp'].should.be.a(datetime.datetime) | ||||||
|  |     create_status['CompletedTimestamp'].should.be.a(datetime.datetime) | ||||||
|  |     #'CreateAccountStatus': { | ||||||
|  |     #    'Id': 'string', | ||||||
|  |     #    'AccountName': 'string', | ||||||
|  |     #    'State': 'IN_PROGRESS'|'SUCCEEDED'|'FAILED', | ||||||
|  |     #    'RequestedTimestamp': datetime(2015, 1, 1), | ||||||
|  |     #    'CompletedTimestamp': datetime(2015, 1, 1), | ||||||
|  |     #    'AccountId': 'string', | ||||||
|  |     #    'FailureReason': 'ACCOUNT_LIMIT_EXCEEDED'|'EMAIL_ALREADY_EXISTS'|'INVALID_ADDRESS'|'INVALID_EMAIL'|'CONCURRENT_ACCOUNT_MODIFICATION'|'INTERNAL_FAILURE' | ||||||
|  |     #} | ||||||
|  | 
 | ||||||
|  | @mock_organizations | ||||||
|  | def test_create_organization(): | ||||||
|  |     client = boto3.client('organizations', region_name='us-east-1') | ||||||
|  |     response = client.create_organization(FeatureSet='ALL') | ||||||
|  |     #print(yaml.dump(response)) | ||||||
|  |     validate_organization(response) | ||||||
|  |     response['Organization']['FeatureSet'].should.equal('ALL') | ||||||
|  |     #assert False | ||||||
|  | 
 | ||||||
|  | @mock_organizations | ||||||
|  | def test_describe_organization(): | ||||||
|  |     client = boto3.client('organizations', region_name='us-east-1') | ||||||
|  |     client.create_organization(FeatureSet='ALL') | ||||||
|  |     response = client.describe_organization() | ||||||
|  |     #print(yaml.dump(response)) | ||||||
|  |     validate_organization(response) | ||||||
|  |     #assert False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | mockname = 'mock-account' | ||||||
|  | mockdomain = 'moto-example.org' | ||||||
|  | mockemail = '@'.join([mockname, mockdomain]) | ||||||
|  | 
 | ||||||
|  | @mock_organizations | ||||||
|  | def test_create_account(): | ||||||
|  |     client = boto3.client('organizations', region_name='us-east-1') | ||||||
|  |     client.create_organization(FeatureSet='ALL') | ||||||
|  |     create_status = client.create_account( | ||||||
|  |             AccountName=mockname, Email=mockemail)['CreateAccountStatus'] | ||||||
|  |     #print(yaml.dump(create_status, default_flow_style=False)) | ||||||
|  |     validate_create_account_status(create_status) | ||||||
|  |     create_status['AccountName'].should.equal(mockname) | ||||||
|  |     #assert False | ||||||
|  | 
 | ||||||
|  | @mock_organizations | ||||||
|  | def test_describe_account(): | ||||||
|  |     client = boto3.client('organizations', region_name='us-east-1') | ||||||
|  |     org = client.create_organization(FeatureSet='ALL')['Organization'] | ||||||
|  |     account_id = client.create_account( | ||||||
|  |             AccountName=mockname, Email=mockemail)['CreateAccountStatus']['AccountId'] | ||||||
|  |     response = client.describe_account(AccountId=account_id) | ||||||
|  |     #print(yaml.dump(response, default_flow_style=False)) | ||||||
|  |     validate_account(org, response['Account']) | ||||||
|  |     response['Account']['Name'].should.equal(mockname) | ||||||
|  |     response['Account']['Email'].should.equal(mockemail) | ||||||
|  |     #assert False | ||||||
|  | 
 | ||||||
|  | @mock_organizations | ||||||
|  | def test_list_accounts(): | ||||||
|  |     client = boto3.client('organizations', region_name='us-east-1') | ||||||
|  |     org = client.create_organization(FeatureSet='ALL')['Organization'] | ||||||
|  |     for i in range(5): | ||||||
|  |         name = mockname + str(i) | ||||||
|  |         email = name + '@' + mockdomain | ||||||
|  |         client.create_account(AccountName=name, Email=email) | ||||||
|  |     response = client.list_accounts() | ||||||
|  |     #print(yaml.dump(response, default_flow_style=False)) | ||||||
|  |     response.should.have.key('Accounts') | ||||||
|  |     accounts = response['Accounts'] | ||||||
|  |     len(accounts).should.equal(5) | ||||||
|  |     for account in accounts: | ||||||
|  |         validate_account(org, account) | ||||||
|  |     accounts[3]['Name'].should.equal(mockname + '3') | ||||||
|  |     accounts[2]['Email'].should.equal(mockname + '2' + '@' + mockdomain) | ||||||
|  |     #assert False | ||||||
|  | 
 | ||||||
							
								
								
									
										26
									
								
								tests/test_organizations/test_organizations_utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tests/test_organizations/test_organizations_utils.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | import sure   # noqa | ||||||
|  | import moto | ||||||
|  | from moto.organizations import utils | ||||||
|  | 
 | ||||||
|  | ORG_ID_REGEX = r'o-[a-z0-9]{%s}' % utils.ORG_ID_SIZE | ||||||
|  | ROOT_ID_REGEX = r'r-[a-z0-9]{%s}' % utils.ROOT_ID_SIZE | ||||||
|  | ACCOUNT_ID_REGEX = r'[0-9]{%s}' % utils.ACCOUNT_ID_SIZE | ||||||
|  | CREATE_ACCOUNT_STATUS_ID_REGEX = r'car-[a-z0-9]{%s}' % utils.CREATE_ACCOUNT_STATUS_ID_SIZE | ||||||
|  | 
 | ||||||
|  | def test_make_random_org_id(): | ||||||
|  |     org_id = utils.make_random_org_id() | ||||||
|  |     org_id.should.match(ORG_ID_REGEX) | ||||||
|  | 
 | ||||||
|  | def test_make_random_root_id(): | ||||||
|  |     org_id = utils.make_random_root_id() | ||||||
|  |     org_id.should.match(ROOT_ID_REGEX) | ||||||
|  | 
 | ||||||
|  | def test_make_random_account_id(): | ||||||
|  |     account_id = utils.make_random_account_id() | ||||||
|  |     account_id.should.match(ACCOUNT_ID_REGEX) | ||||||
|  | 
 | ||||||
|  | def test_make_random_create_account_status_id(): | ||||||
|  |     create_account_status_id = utils.make_random_create_account_status_id() | ||||||
|  |     create_account_status_id.should.match(CREATE_ACCOUNT_STATUS_ID_REGEX) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user