From 8bb338248551da9e626a532e3f5e92ac070df15b Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Tue, 3 Nov 2020 15:00:34 -0500 Subject: [PATCH 01/22] chore(android-build) Updates for eventual automation of amplify-android backend --- .../amplify/integration/cdk/__init__.py | 4 + .../android/amplify/integration/cdk/app.py | 56 ++++++-- .../integration/cdk/schemas/ScenarioA.graphql | 37 ----- .../api_instrumented_tests/blogApi.graphql | 39 ++++++ .../instrumented_tests/commentsblogs.graphql | 52 +++++++ .../integration/cdk/scripts/amplify_app.py | 132 ++++++++++++++++++ .../amplify/integration/cdk/scripts/api.py | 116 +++++++-------- .../amplify/integration/cdk/scripts/auth.py | 97 ++++++------- .../integration/cdk/scripts/buildspec.yml | 28 ---- .../amplify/integration/cdk/scripts/common.py | 113 ++++----------- .../deploy_api_instrumented_tests_backend.sh | 1 + .../deploy_instrumented_tests_backend.sh | 1 + .../integration/cdk/scripts/setup_amplify | 86 +++++++++--- .../cdk/stacks/amplify_deployer_stack.py | 90 ++++++++++-- 14 files changed, 540 insertions(+), 312 deletions(-) create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/__init__.py delete mode 100644 src/integ_test_resources/android/amplify/integration/cdk/schemas/ScenarioA.graphql create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/schemas/api_instrumented_tests/blogApi.graphql create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/schemas/instrumented_tests/commentsblogs.graphql create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py delete mode 100644 src/integ_test_resources/android/amplify/integration/cdk/scripts/buildspec.yml create mode 100755 src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_instrumented_tests_backend.sh create mode 100755 src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh diff --git a/src/integ_test_resources/android/amplify/integration/cdk/__init__.py b/src/integ_test_resources/android/amplify/integration/cdk/__init__.py new file mode 100644 index 0000000..1253ac6 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/__init__.py @@ -0,0 +1,4 @@ +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".")) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/app.py b/src/integ_test_resources/android/amplify/integration/cdk/app.py index 2624a23..c53dbff 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/app.py @@ -3,7 +3,25 @@ from aws_cdk import core from stacks.amplify_deployer_stack import AmplifyDeployer +def build_amplify_deployer_stack_props(cb_project_name: str, + github_repo: str, + github_owner: str, + branch: str, + shell_script_name: str): + props = {} + props['cb_project_name'] = cb_project_name + props['shell_script_name'] = shell_script_name + props['github_repo'] = github_repo + if github_owner is not None: + props['github_owner'] = github_owner + if branch is not None: + props['branch'] = branch + return props + app = core.App() +github_owner=app.node.try_get_context("github_owner") +branch=app.node.try_get_context("branch") + TARGET_REGION = app.node.try_get_context("region") TARGET_ACCOUNT = app.node.try_get_context("account") if TARGET_ACCOUNT is None or TARGET_REGION is None: @@ -11,25 +29,33 @@ TARGET_ENV = core.Environment( account=TARGET_ACCOUNT, region=TARGET_REGION) GITHUB_REPO = 'amplify-ci-support' - BANNER_TEXT = f"AWS Account={TARGET_ACCOUNT} Region={TARGET_REGION}" SEPARATOR = "-" * len(BANNER_TEXT) -github_owner=app.node.try_get_context("github_owner") -branch=app.node.try_get_context("branch") - print(SEPARATOR) print(BANNER_TEXT) print(SEPARATOR) -props = {} -props['project_name'] = "AmplifyAndroidIntegTestDeployer" -props['github_repo'] = GITHUB_REPO -if github_owner is not None: - props['github_owner'] = github_owner -if branch is not None: - props['branch'] = branch - -AmplifyDeployer(app, "AndroidIntegTestInfraDeployer", props, env=TARGET_ENV) - -app.synth() \ No newline at end of file +at_auth_props = build_amplify_deployer_stack_props(cb_project_name="AmplifyAuthScenariosDeployer", + github_repo=GITHUB_REPO, + github_owner=github_owner, + branch=branch, + shell_script_name="deploy_at_auth_backend.sh") + +# TODO: rename this to datastore_instrumented_tests* +instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="InstrumentedTestBackendDeployer", + github_repo=GITHUB_REPO, + github_owner=github_owner, + branch=branch, + shell_script_name="deploy_instrumented_tests_backend.sh") + +api_instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="ApiInstrumentedTestBackendDeployer", + github_repo=GITHUB_REPO, + github_owner=github_owner, + branch=branch, + shell_script_name="deploy_api_instrumented_tests_backend.sh") + +instrumented_test_backend_stack = AmplifyDeployer(app, "InstrumentedTestsBackend", instrumented_test_props, env=TARGET_ENV) +api_instrumented_test_backend_stack = AmplifyDeployer(app, "ApiInstrumentedTestsBackend", api_instrumented_test_props, env=TARGET_ENV) + +app.synth() diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/ScenarioA.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/ScenarioA.graphql deleted file mode 100644 index 15e80b2..0000000 --- a/src/integ_test_resources/android/amplify/integration/cdk/schemas/ScenarioA.graphql +++ /dev/null @@ -1,37 +0,0 @@ -# Scenario A - Owner-based auth scenarios - -# Test case 1 - Owner field not explicitly provided in the schema. -type ScenarioATest1Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! -} - -# Test case 2 - Owner field (with default field name of owner) explicitly provided in the schema. -type ScenarioATest2Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - owner: String -} - -# Test 3 is pending - -# Test case 4 - Custom owner field specified in the directive, but not the schema. -type ScenarioATest4Post @model @auth(rules: [{ allow: owner, ownerField: "dominus" }]) { - id: ID! - title: String! -} - -# Test case 5 - Custom owner field specified in the directive and also the schema. -type ScenarioATest5Post @model @auth(rules: [{ allow: owner, ownerField: "dominus" }]) { - id: ID! - title: String! - dominus: String -} - -# Test case 6 - Custom identity claim -type ScenarioATest6Post - @model - @auth(rules: [{ allow: owner, identityClaim: "sub" }]) { - id: ID! - title: String! -} diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_instrumented_tests/blogApi.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_instrumented_tests/blogApi.graphql new file mode 100644 index 0000000..97bb664 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_instrumented_tests/blogApi.graphql @@ -0,0 +1,39 @@ +type Blog @model { + id: ID! + name: String! + tags: [String] + posts: [Post] @connection(name: "BlogPosts") +} + +type Rating @model { + id: ID! + stars: Int! + post: Post! @connection(name: "PostRating") +} + +type Post @model { + id: ID! + title: String! + blog: Blog! @connection(name: "BlogPosts") + rating: Rating @connection(name: "PostRating") + editors: [PostEditor] @connection(keyName: "byPost", fields: ["id"]) +} + +# Create a join model and disable queries as you don't need them +# and can query through Post.editors and User.posts +type PostEditor +@model(queries: null) +@key(name: "byPost", fields: ["postID", "editorID"]) +@key(name: "byEditor", fields: ["editorID", "postID"]) { + id: ID! + postID: ID! + editorID: ID! + post: Post! @connection(fields: ["postID"]) + editor: User! @connection(fields: ["editorID"]) +} + +type User @model { + id: ID! + username: String! + posts: [PostEditor] @connection(keyName: "byEditor", fields: ["id"]) +} \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/instrumented_tests/commentsblogs.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/instrumented_tests/commentsblogs.graphql new file mode 100644 index 0000000..2b2426d --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/instrumented_tests/commentsblogs.graphql @@ -0,0 +1,52 @@ +type Blog @model { + id: ID! + name: String! + posts: [Post] @connection(name: "BlogPosts") + owner: BlogOwner! @connection(name: "BlogOwner") +} + +type BlogOwner @model { + name: String! + id: ID! + blog: Blog @connection(name: "BlogOwner") + wea: String +} + +enum PostStatus { + ACTIVE + INACTIVE +} + +type Post @model { + id: ID! + title: String! + blog: Blog @connection(name: "BlogPosts") + comments: [Comment] @connection(name: "PostComments") + authors: [PostAuthorJoin] @connection(keyName: "byPost", fields: ["id"]) + status: PostStatus! + rating: Int! +} + +type Comment @model { + id: ID! + content: String + post: Post @connection(name: "PostComments") +} + +type Author @model { + id: ID! + name: String! + posts: [PostAuthorJoin] @connection(keyName: "byAuthor", fields: ["id"]) +} + +type PostAuthorJoin + @model + @key(name: "byAuthor", fields: ["authorId"]) + @key(name: "byPost", fields: ["postId"]) { + id: ID! + authorId: ID! + postId: ID! + author: Author @connection(fields: ["authorId"]) + post: Post @connection(fields: ["postId"]) +} + diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py new file mode 100644 index 0000000..89cd8b4 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py @@ -0,0 +1,132 @@ +import json +import os +from common import ( + LOGGER, + AMPLIFY_AWSSDK_CLIENT, + BASE_PATH, + run_command, + OperationType +) +from auth import * + +AMPLIFY_COMMAND = "amplify" +AMPLIFY_ACTION_PULL = "pull" +AMPLIFY_ACTION_INIT = "init" +AMPLIFY_ENVIRONMENT = "main" # Static for now + +AMPLIFY_PROVIDER_CONFIG = { + 'awscloudformation': { + 'configLevel': 'general', + 'region': 'us-east-1' + } +} + +AMPLIFY_FRONTEND_CONFIG = { + 'frontend': 'android', + 'config' : { + 'ResDir': f"app/src/main/res" + } +} + +AMPLIFY_CODEGEN_CONFIG_ANDROID = { + 'generateCode': True, + 'codeLanguage': 'java', + 'generateDocs': True +} + +class AmplifyApp: + backend_name = None + app_id = None + project_dir = None + amplify_meta_content = None + + def __init__(self, *, backend_name:str): + self.backend_name = backend_name + self.project_dir = f"{BASE_PATH}/_amplify_{self.backend_name}" + os.system(f"mkdir -p {self.project_dir}") + self.app_id = self._get_existing_app_id() + if self.app_id is None and self._initialize_new_app() != 0: + raise Exception("Unable to initialize Amplify project.") + else: + self._pull_existing_app() + with open(f"{self.project_dir}/amplify/backend/amplify-meta.json") as amplify_meta_file: + self.amplify_meta_content = json.load(amplify_meta_file) + self._load_metadata() + + def is_category_configured(self, category_name:str): + if self.amplify_meta_content is None: + return False + return category_name in self.amplify_meta_content.keys() + + def config_auth(self, auth_config, op_type:OperationType): + cmd = [AMPLIFY_COMMAND, + op_type.value, + "auth", + "--headless"] + result = run_command(cmd, work_dir=self.project_dir, input=json.dumps(auth_config)) + return result.returncode + + def config_api(self, api_config, op_type:OperationType): + cmd = [AMPLIFY_COMMAND, + op_type.value, + "api", + "--headless"] + result = run_command(cmd, work_dir=self.project_dir, input=json.dumps(api_config)) + return result.returncode + + def get_category_config(self, category_name: str): + if self.amplify_meta_content is None: + return None + return category_name in self.amplify_meta_content.keys() + + def push(self): + push_cmd = [AMPLIFY_COMMAND, + "push", + "--codegen", json.dumps(AMPLIFY_CODEGEN_CONFIG_ANDROID), + "--yes"] + result = run_command(push_cmd, self.project_dir) + self._load_metadata() + return result.returncode + + def _get_existing_app_id(self): + try: + response = AMPLIFY_AWSSDK_CLIENT.list_apps() + existing_app_id = next(app['appId'] for app in response['apps'] if app['name'] == self.backend_name) + return existing_app_id + except StopIteration: + LOGGER.error(f"Unable to find existing Amplify app for {self.backend_name}") + return None + + def _initialize_new_app(self): + init_cmd = [AMPLIFY_COMMAND, + AMPLIFY_ACTION_INIT, + "--amplify", json.dumps(self._get_amplify_config()), + "--providers", json.dumps(AMPLIFY_PROVIDER_CONFIG), + "--frontend", json.dumps(AMPLIFY_FRONTEND_CONFIG)] + result = run_command(init_cmd, self.project_dir) + self.app_id = self._get_existing_app_id() + return result.returncode + + + def _pull_existing_app(self): + amplify_params = self._get_amplify_config().copy() + amplify_params.update({'appId': self.app_id}) + pull_cmd = [AMPLIFY_COMMAND, + AMPLIFY_ACTION_PULL, + "--amplify", json.dumps(amplify_params), + "--providers", json.dumps(AMPLIFY_PROVIDER_CONFIG), + "--frontend", json.dumps(AMPLIFY_FRONTEND_CONFIG), + "--yes"] + result = run_command(pull_cmd, self.project_dir) + return result.returncode + + def _get_amplify_config(self): + return { + 'projectName': self.backend_name, + 'envName': AMPLIFY_ENVIRONMENT, + 'defaultEditor': 'code' + } + + def _load_metadata(self): + with open(f"{self.project_dir}/amplify/backend/amplify-meta.json") as amplify_meta_file: + self.amplify_meta_content = json.load(amplify_meta_file) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py index 00ee629..333b694 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py @@ -1,88 +1,72 @@ import json import os -from common import * +from enum import Enum +from common import ( + OperationType +) -class ApiConfigBuilder: - name = None - schema_dir = None - default_auth_mode = None - additional_auth_modes = {} - is_update = False - - def as_update(self): - self.is_update = True +class ApiAuthMode(Enum): + NONE: "NONE" + API_KEY = "API_KEY" + AWS_IAM = "AWS_IAM" + OPENID_CONNECT = "OPENID_CONNECT" + AMAZON_COGNITO_USER_POOLS = "AMAZON_COGNITO_USER_POOLS" - def with_name(self, name: str): - self.name = name - return self - - def with_schemas_dir(self, schema_dir: str): - self.schema_dir = schema_dir - return self - def with_auth_resource(self, auth_resource_id: str, is_default: bool = False): - self.auth_resource_id = auth_resource_id - user_pool_config = { +class ApiAuthModeFactory: + @classmethod + def create_user_pools_config(cls, auth_resource_name:str): + return { 'mode': 'AMAZON_COGNITO_USER_POOLS', - 'cognitoUserPoolId': auth_resource_id + 'cognitoUserPoolId': auth_resource_name } - self._add_auth_mode('AMAZON_COGNITO_USER_POOLS', is_default, user_pool_config) - return self - def with_api_key(self, is_default: bool = False): - self._add_auth_mode('API_KEY', is_default, { 'mode': 'API_KEY' }) - return self + @classmethod + def create_api_key_config(cls): + return { 'mode': 'API_KEY' } - def with_oidc(self, client_id: str, issuer_url: str, provider_name: str, is_default: bool = False): - self._add_auth_mode('OPENID_CONNECT', is_default, { 'openIDClientID': client_id, 'openIDIssuerURL': issuer_url, 'openIDProviderName': provider_name }) - return self + @classmethod + def create_oidc_config(cls, client_id: str, issuer_url: str, provider_name: str, is_default: bool = False): + return { + 'openIDClientID': client_id, + 'openIDIssuerURL': issuer_url, + 'openIDProviderName': provider_name + } + + @classmethod + def create_iam_config(cls): + return { 'mode': 'AWS_IAM' } - def with_iam(self, is_default: bool = False): - self._add_auth_mode('AWS_IAM', is_default, { 'mode': 'AWS_IAM' }) - return self - def _add_auth_mode(self, mode_name: str, is_default: bool, mode_config): - if is_default: - self.default_auth_mode = mode_config - else: - self.additional_auth_modes[mode_name] = mode_config +class ApiConfigFactory: + name = None + schema_dir = None + default_auth_mode = None + additional_auth_modes = {} + is_update = False - def build(self): + @classmethod + def create(cls, *, api_name:str, + op_type:OperationType, + schema_dir:str, + default_auth_mode:ApiAuthMode, + additional_auth_modes: dict = None ): gql_schema = "" - for entry in os.listdir(self.schema_dir): - if os.path.isfile(os.path.join(self.schema_dir, entry)): - with open(os.path.join(self.schema_dir, entry), "r") as text_file: + for entry in os.listdir(schema_dir): + if os.path.isfile(os.path.join(schema_dir, entry)): + with open(os.path.join(schema_dir, entry), "r") as text_file: gql_schema += text_file.read() + "\n" api_config = { 'version': 1 } - api_config_json_element_name = 'serviceModification' if self.is_update else 'serviceConfiguration' + api_config_json_element_name = 'serviceModification' if op_type == OperationType.UPDATE else 'serviceConfiguration' api_config[api_config_json_element_name] = { 'serviceName': 'AppSync', - 'apiName': self.name, + 'apiName': api_name, 'transformSchema': gql_schema, - 'defaultAuthType': self.default_auth_mode, - 'additionalAuthTypes': list(self.additional_auth_modes.values()) + 'defaultAuthType': default_auth_mode } - return api_config - - -def get_api_config(api_name: str, schemas_dir: str, auth_resource_id: str): - is_update = True if get_category_config("api") is not None else False - builder = ApiConfigBuilder().with_name(api_name) \ - .with_schemas_dir(schemas_dir) \ - .with_api_key(True) \ - .with_auth_resource(auth_resource_id) \ - .with_iam() - if(is_update): - builder.as_update() - - return builder.build() + if additional_auth_modes is not None: + api_config[api_config_json_element_name]['additionalAuthTypes'] = list(additional_auth_modes.values()) -def config_api(api_config): - cmd = [AMPLIFY_COMMAND, - "add" if get_category_config("api") is None else "update", - "api", - "--headless"] - result = run_command(cmd, input=json.dumps(api_config)) - return result.returncode + return api_config diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py index 56e133c..e98a754 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py @@ -1,51 +1,54 @@ -from common import * import json import os -def get_auth_config(): - is_update = True if get_category_config("auth") is not None else False - if(is_update): - auth_config_json_element_name = 'serviceModification' - user_pool_config_json_element_name = 'userPoolModification' - id_pool_config_json_element_name = 'identityPoolModification' - else: - auth_config_json_element_name = 'serviceConfiguration' - user_pool_config_json_element_name = 'userPoolConfiguration' - id_pool_config_json_element_name = 'identityPoolConfiguration' +from common import OperationType - auth_config = { - 'version': 1, - 'resourceName':'AndroidIntegTestAuth' - } - user_pool_config = { - 'requiredSignupAttributes':['EMAIL', 'NAME', 'NICKNAME'], - 'signinMethod':'USERNAME', - 'userPoolGroups': [ - { 'groupName': 'Admins' }, - { 'groupName': 'Bloggers' }, - { 'groupName': 'Moderators' } - ], - 'writeAttributes': ['EMAIL', 'NAME', 'NICKNAME'], - 'readAttributes':['EMAIL', 'NAME', 'NICKNAME'], - 'refreshTokenPeriod': 365 - } - id_pool_config = { - 'unauthenticatedLogin': True, - 'identityPoolName': 'androididpool' - } - - auth_config[auth_config_json_element_name] = { - 'serviceName': 'Cognito', - 'includeIdentityPool': True - } - auth_config[auth_config_json_element_name][user_pool_config_json_element_name] = user_pool_config - auth_config[auth_config_json_element_name][id_pool_config_json_element_name] = id_pool_config +class AuthConfigFactory: + @classmethod + def create(cls, *, auth_resource_name:str, + identity_pool_name:str, + op_type:OperationType, + allow_unauth = True, + signin_method = 'USERNAME', + group_names = [], + refresh_token_period_in_days = 365, + required_signup_attributes = ['EMAIL', 'NAME', 'NICKNAME'], + write_attributes = ['EMAIL', 'NAME', 'NICKNAME'], + read_attributes = ['EMAIL', 'NAME', 'NICKNAME']): + if(OperationType.UPDATE == op_type): + auth_config_json_element_name = 'serviceModification' + user_pool_config_json_element_name = 'userPoolModification' + id_pool_config_json_element_name = 'identityPoolModification' + else: + auth_config_json_element_name = 'serviceConfiguration' + user_pool_config_json_element_name = 'userPoolConfiguration' + id_pool_config_json_element_name = 'identityPoolConfiguration' + + groups = list(map(lambda group_name: { 'groupName': group_name }, group_names)) + + auth_config = { + 'version': 1, + 'resourceName': auth_resource_name + } + user_pool_config = { + 'requiredSignupAttributes': required_signup_attributes, + 'signinMethod': signin_method, + 'userPoolGroups': groups, + 'writeAttributes': write_attributes, + 'readAttributes': read_attributes, + 'refreshTokenPeriod': refresh_token_period_in_days + } + + id_pool_config = { + 'unauthenticatedLogin': allow_unauth, + 'identityPoolName': identity_pool_name + } + + auth_config[auth_config_json_element_name] = { + 'serviceName': 'Cognito', + 'includeIdentityPool': True + } + auth_config[auth_config_json_element_name][user_pool_config_json_element_name] = user_pool_config + auth_config[auth_config_json_element_name][id_pool_config_json_element_name] = id_pool_config + + return auth_config - return auth_config - -def config_auth(auth_config): - cmd = [AMPLIFY_COMMAND, - "add" if get_category_config('auth') is None else "update", - "auth", - "--headless"] - result = run_command(cmd, input=json.dumps(auth_config)) - return result.returncode diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/buildspec.yml b/src/integ_test_resources/android/amplify/integration/cdk/scripts/buildspec.yml deleted file mode 100644 index f22bb77..0000000 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/buildspec.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: 0.2 -env: - shell: /bin/sh -phases: - install: - commands: - - echo 'Install phase starting' - - npm install -g @aws-amplify/cli - finally: - - echo 'Install phase completed.' - pre_build: - commands: - - echo 'Pre-build phase starting' - finally: - - echo 'Pre-build phase completed.' - build: - commands: - - echo 'Build phase starting' - - pwd - - ls -al - - src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify - finally: - - echo 'Build phase completed.' - post_build: - commands: - - echo 'Post-build phase starting' - finally: - - echo 'Post-build phase completed.' diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py index d8c258f..fb70e57 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py @@ -1,104 +1,47 @@ import os import json import subprocess +import argparse import boto3 +import logging +from enum import Enum + +class OperationType(Enum): + ADD = "add" + UPDATE = "update" + REMOVE = "remove" + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Utility that runs the Amplify CLI in headless mode to provision backend resources for integration tests.") + parser.add_argument("--backend_name", help="The name of the Amplify app.", required=True) + parser.add_argument("--schema_dir", help="Name of the subdirectory under the schemas folder that contains the GraphQL schemas for the backend API.", required=True) + parser.add_argument("--group_names", help="Comma-separated list of group names to be created.", default="") + parser.add_argument("--log", help="Set the log level.", default='INFO') + return parser.parse_args() + +LOG_FORMATTER = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') +CONSOLE_HANDLER = logging.StreamHandler() +CONSOLE_HANDLER.setFormatter(LOG_FORMATTER) +LOGGER = logging.getLogger("AmplifyDeployerUtil") +LOGGER.addHandler(CONSOLE_HANDLER) AMPLIFY_AWSSDK_CLIENT = boto3.client('amplify') REGION = 'us-east-1' -PROJECT_NAME = f"amplifyandroidinteg" -ENVIRONMENT = 'integtest' SCRIPTS_DIR = os.path.dirname(__file__) -print(f"SCRIPTS_DIR = {SCRIPTS_DIR}") +LOGGER.info(f"SCRIPTS_DIR = {SCRIPTS_DIR}") # If running within CodeBuild, we want to use the value of CODEBUILD_SRC_DIR environment variable as the base path. # If running on a developer's machine, use the value of the HOME environment variable as the base. CODEBUILD_SRC_DIR = os.getenv('CODEBUILD_SRC_DIR') BASE_PATH = os.getenv('HOME') if CODEBUILD_SRC_DIR is None else CODEBUILD_SRC_DIR -print(f"BASE_PATH = {BASE_PATH}") +LOGGER.info(f"BASE_PATH = {BASE_PATH}") -PROJECT_DIR = f"{BASE_PATH}/_amplify_project_tmp" -print(f"Amplify project dir = {PROJECT_DIR}") - -AMPLIFY_COMMAND = "amplify" -AMPLIFY_ACTION_PULL = "pull" -AMPLIFY_ACTION_INIT = "init" - -AMPLIFY_PROVIDER_CONFIG = { - 'awscloudformation': { - 'configLevel': 'general', - 'region': 'us-east-1' - } -} - -AMPLIFY_FRONTEND_CONFIG = { - 'frontend': 'android', - 'config' : { - 'ResDir': f"app/src/main/res" - } -} - -AMPLIFY_CONFIG = { - 'projectName': PROJECT_NAME, - 'envName': ENVIRONMENT, - 'defaultEditor': 'code' -} - -AMPLIFY_CODEGEN_CONFIG = { - 'generateCode': True, - 'codeLanguage': 'java', - 'generateDocs': True -} - -def get_existing_app_id(): - try: - response = AMPLIFY_AWSSDK_CLIENT.list_apps() - existing_app_id = next(app for app in response['apps'] if app['name'] == PROJECT_NAME) - return existing_app_id - except StopIteration: - print(f"Unable to find existing Amplify app for {PROJECT_NAME}") - return None - -def initialize_new_app(): - init_cmd = [AMPLIFY_COMMAND, - AMPLIFY_ACTION_INIT, - "--amplify", json.dumps(AMPLIFY_CONFIG), - "--providers", json.dumps(AMPLIFY_PROVIDER_CONFIG), - "--frontend", json.dumps(AMPLIFY_FRONTEND_CONFIG)] - result = run_command(init_cmd) - return result.returncode - - -def pull_existing_app(existing_app_id): - amplify_params = AMPLIFY_CONFIG.copy() - amplify_params.update({'appId': existing_app_id}) - pull_cmd = [AMPLIFY_COMMAND, - AMPLIFY_ACTION_PULL, - "--amplify", json.dumps(amplify_params), - "--providers", json.dumps(AMPLIFY_PROVIDER_CONFIG), - "--frontend", json.dumps(AMPLIFY_FRONTEND_CONFIG), - "--yes"] - result = run_command(pull_cmd) - return result.returncode - -def get_category_config(category_name: str): - with open(f"{PROJECT_DIR}/amplify/backend/amplify-meta.json") as amplify_meta_file: - amplify_meta_content = json.load(amplify_meta_file) - category_config = amplify_meta_content[category_name] - return category_config - -def push(): - push_cmd = [AMPLIFY_COMMAND, - "push", - "--codegen", json.dumps(AMPLIFY_CODEGEN_CONFIG), - "--yes"] - result = run_command(push_cmd) - return result.returncode - -def run_command(cmd, input: str = None): +def run_command(cmd, work_dir:str, input: str = None): + LOGGER.debug(msg=" ".join(cmd)) result = subprocess.run(cmd, text=True, input = input if input is not None else '', - cwd=PROJECT_DIR) + cwd = work_dir) # stdout=subprocess.PIPE, # stderr=subprocess.PIPE) - return result \ No newline at end of file + return result diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_instrumented_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_instrumented_tests_backend.sh new file mode 100755 index 0000000..c9427b7 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_instrumented_tests_backend.sh @@ -0,0 +1 @@ +src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='ApiInstrumentedTests' --schema_dir 'api_instrumented_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh new file mode 100755 index 0000000..f663205 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh @@ -0,0 +1 @@ +src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='InstrumentedTests' --schema_dir 'instrumented_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index d99535a..c2f866e 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -1,25 +1,69 @@ #!/usr/bin/env python3 +""" +This is the entry point for the process that uses Amplify CLI commands to deploy backend resources + +Typically, this is executed within a CodeBuild container although it can be executed from anywhere with a +valid AWS credentials having all the permissions listed in +src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py. + +""" + import os -from common import * -from auth import * -from api import * - -# ENTRY POINT -os.system(f"mkdir -p {PROJECT_DIR}") -existing_app = get_existing_app_id() -if existing_app is None: - # create the app - print("Need to create a new app") - initialize_new_app() +import argparse +import logging +from common import ( + OperationType, + parse_arguments, + SCRIPTS_DIR, + LOGGER, + +) +from auth import AuthConfigFactory +from api import ( + ApiAuthModeFactory, + ApiConfigFactory, + ApiAuthMode +) +from amplify_app import AmplifyApp + +arguments = parse_arguments() +LOGGER.setLevel(level=arguments.log) + +amplify_backend_name = arguments.backend_name +schema_dir = arguments.schema_dir +group_names = arguments.group_names.split(",") + + +auth_resource_name = f"{amplify_backend_name}Auth" +idp_name = f"{amplify_backend_name}Idp" + + +amplify_app = AmplifyApp(backend_name=amplify_backend_name) +auth_op_type = OperationType.UPDATE if amplify_app.is_category_configured('auth') else OperationType.ADD +api_op_type = OperationType.UPDATE if amplify_app.is_category_configured('api') else OperationType.ADD + +auth_config = AuthConfigFactory.create(auth_resource_name=auth_resource_name, + identity_pool_name=idp_name, + op_type=auth_op_type, + group_names=group_names) + +auth_cmd_result = amplify_app.config_auth(auth_config=auth_config, op_type=auth_op_type) +if auth_cmd_result == 0: + LOGGER.info("Auth category configured.") else: - # pull the app - print(f"Pulling existing app with id {existing_app['appId']}") - pull_existing_app(existing_app['appId']) - -auth_config = get_auth_config() -if (config_auth(auth_config) == 0): - api_config = get_api_config('AmplifyAndroidIntegTestApi', f"{SCRIPTS_DIR}/../schemas", "authAndroidIntegTestAuth") - config_api(api_config) - push() + LOGGER.error("Failed to configure Auth category.") + exit(-1) + +user_pools_config = ApiAuthModeFactory.create_user_pools_config(auth_resource_name=auth_resource_name) +api_config = ApiConfigFactory.create(api_name=f"{amplify_backend_name}Api", + op_type=api_op_type, + schema_dir=f"{SCRIPTS_DIR}/../schemas/{schema_dir}", + default_auth_mode=user_pools_config) + +api_cmd_result = amplify_app.config_api(api_config, api_op_type) +if api_cmd_result == 0: + LOGGER.info("API category configured.") + amplify_app.push() else: - print("Failed to configure auth.") \ No newline at end of file + LOGGER.error("Failed to configure API category.") + exit(-1) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py b/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py index ae96e4e..2e41e02 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py @@ -9,11 +9,13 @@ class AmplifyDeployer(core.Stack): DEFAULT_GITHUB_OWNER = "aws-amplify" - DEFAULT_BRANCH = "refs/heads/main" + DEFAULT_BRANCH = "main" + SCRIPTS_PATH = "src/integ_test_resources/android/amplify/integration/cdk/scripts" + def __init__(self, scope: core.App, id: str, props, **kwargs) -> None: super().__init__(scope, id, **kwargs) - - build_file_path = 'src/integ_test_resources/android/amplify/integration/cdk/scripts/buildspec.yml' + shell_script_name = props['shell_script_name'] + cb_project_name = props['cb_project_name'] github_repo = props['github_repo'] github_owner = self.DEFAULT_GITHUB_OWNER if 'github_owner' not in props else props['github_owner'] branch = self.DEFAULT_BRANCH if 'branch' not in props else props['branch'] @@ -22,33 +24,72 @@ def __init__(self, scope: core.App, id: str, props, **kwargs) -> None: compute_type=aws_codebuild.ComputeType.SMALL) project = aws_codebuild.Project(self, - props['project_name'], + cb_project_name, source=aws_codebuild.Source.git_hub(owner=github_owner, report_build_status=False, repo=github_repo, branch_or_ref=branch, webhook=False), # Will need to setup creds to make this true environment=build_environment, - build_spec=aws_codebuild.BuildSpec.from_source_filename(filename=build_file_path)) + build_spec=self._generate_buildspec(shell_script_name)) individual_actions = [ - "amplify:Get*", - "amplify:List*", + "amplify:*", + "cognito-identity:CreateIdentityPool", + "cognito-identity:DeleteIdentityPool", + "cognito-identity:DescribeIdentityPool", + "cognito-identity:ListIdentityPools", + "cognito-identity:ListTagsForResource", + "cognito-identity:SetIdentityPoolRoles", + "cognito-identity:UpdateIdentityPool", + "cognito-idp:CreateGroup", + "cognito-idp:CreateIdentityProvider", + "cognito-idp:CreateResourceServer", + "cognito-idp:CreateUserPool", + "cognito-idp:CreateUserPoolClient", + "cognito-idp:CreateUserPoolDomain", + "cognito-idp:DeleteGroup", + "cognito-idp:DeleteIdentityProvider", + "cognito-idp:DeleteResourceServer", + "cognito-idp:DeleteUserPool", + "cognito-idp:DeleteUserPoolClient", + "cognito-idp:DeleteUserPoolDomain", + "cognito-idp:DescribeIdentityProvider", + "cognito-idp:DescribeResourceServer", + "cognito-idp:DescribeUserPool", + "cognito-idp:DescribeUserPoolClient", + "cognito-idp:DescribeUserPoolDomain", + "cognito-idp:ListGroups", + "cognito-idp:ListIdentityProviders", + "cognito-idp:ListResourceServers", + "cognito-idp:ListTagsForResource", + "cognito-idp:ListUserImportJobs", + "cognito-idp:ListUserPoolClients", + "cognito-idp:ListUserPools", + "cognito-idp:UpdateGroup", + "cognito-idp:UpdateIdentityProvider", + "cognito-idp:UpdateResourceServer", + "cognito-idp:UpdateUserPool", + "cognito-idp:UpdateUserPoolClient", + "cognito-idp:UpdateUserPoolDomain", + "iam:AttachRolePolicy", + "iam:CreatePolicy", + "iam:CreatePolicyVersion", "iam:CreateRole", + "iam:DeletePolicy", + "iam:DeletePolicyVersion", "iam:DeleteRole", + "iam:DeleteRolePolicy", + "iam:DetachRolePolicy", "iam:PutRolePolicy", - "iam:DeleteRolePolicy" ] policy = aws_iam.ManagedPolicy(self, - "AmplifyDeployerLeastPrivilegePolicy", - managed_policy_name="AmplifyDeployerLeastPrivilegePolicy", + "AmplifyCodeBuildScriptRunnerPolicy", + managed_policy_name=f"AmplifyCodeBuildScriptRunnerPolicy-{cb_project_name}", description="Policy used by the CodeBuild role that manages the creation of backend resources using the Amplify CLI", - # document=aws_iam.PolicyDocument( statements=[ aws_iam.PolicyStatement(actions=individual_actions, effect=aws_iam.Effect.ALLOW, resources=["*"]), ] - # ) - ) policy.attach_to_role(project.role) @@ -58,3 +99,26 @@ def __init__(self, scope: core.App, id: str, props, **kwargs) -> None: project.role.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name('IAMReadOnlyAccess')) project.role.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name('AWSLambdaFullAccess')) project.role.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name('AWSAppSyncAdministrator')) + + def _generate_buildspec(self, shell_script_name: str): + deployer_command = f"{self.SCRIPTS_PATH}/{shell_script_name}" + return aws_codebuild.BuildSpec.from_object({ + "version": "0.2", + "phases": { + "install": { + "commands":[ + "echo 'Install phase starting'", + "npm install -g @aws-amplify/cli" + ] + }, + "build": { + "commands": [ + "echo 'Build phase starting'", + "pwd", + "ls -al", + deployer_command + ] + } + } + }) + From 8c0a00c87f29e02f00d3a6463fb5ceb6b882fc32 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Tue, 3 Nov 2020 17:03:39 -0500 Subject: [PATCH 02/22] Remove reference to at_auth* stack --- .../android/amplify/integration/cdk/app.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/app.py b/src/integ_test_resources/android/amplify/integration/cdk/app.py index c53dbff..1178039 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/app.py @@ -36,12 +36,6 @@ def build_amplify_deployer_stack_props(cb_project_name: str, print(BANNER_TEXT) print(SEPARATOR) -at_auth_props = build_amplify_deployer_stack_props(cb_project_name="AmplifyAuthScenariosDeployer", - github_repo=GITHUB_REPO, - github_owner=github_owner, - branch=branch, - shell_script_name="deploy_at_auth_backend.sh") - # TODO: rename this to datastore_instrumented_tests* instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="InstrumentedTestBackendDeployer", github_repo=GITHUB_REPO, From 237faa8eb0598b6062c90e8fe526281d87ba9caa Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Mon, 14 Dec 2020 13:59:06 -0500 Subject: [PATCH 03/22] Rename datastore tests --- .../android/amplify/integration/cdk/app.py | 9 ++++----- .../commentsblogs.graphql | 0 .../deploy_datastore_instrumented_tests_backend.sh | 1 + .../cdk/scripts/deploy_instrumented_tests_backend.sh | 1 - 4 files changed, 5 insertions(+), 6 deletions(-) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/{instrumented_tests => datastore_instrumented_tests}/commentsblogs.graphql (100%) create mode 100755 src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh delete mode 100755 src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh diff --git a/src/integ_test_resources/android/amplify/integration/cdk/app.py b/src/integ_test_resources/android/amplify/integration/cdk/app.py index 1178039..fc06789 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/app.py @@ -36,20 +36,19 @@ def build_amplify_deployer_stack_props(cb_project_name: str, print(BANNER_TEXT) print(SEPARATOR) -# TODO: rename this to datastore_instrumented_tests* -instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="InstrumentedTestBackendDeployer", +instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="DataStoreInstrumentedTestsBackend", github_repo=GITHUB_REPO, github_owner=github_owner, branch=branch, - shell_script_name="deploy_instrumented_tests_backend.sh") + shell_script_name="deploy_datastore_instrumented_tests_backend.sh") -api_instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="ApiInstrumentedTestBackendDeployer", +api_instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="ApiInstrumentedTestsBackendDeployer", github_repo=GITHUB_REPO, github_owner=github_owner, branch=branch, shell_script_name="deploy_api_instrumented_tests_backend.sh") -instrumented_test_backend_stack = AmplifyDeployer(app, "InstrumentedTestsBackend", instrumented_test_props, env=TARGET_ENV) +instrumented_test_backend_stack = AmplifyDeployer(app, "DataStoreInstrumentedTestsBackend", instrumented_test_props, env=TARGET_ENV) api_instrumented_test_backend_stack = AmplifyDeployer(app, "ApiInstrumentedTestsBackend", api_instrumented_test_props, env=TARGET_ENV) app.synth() diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/instrumented_tests/commentsblogs.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_instrumented_tests/commentsblogs.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/instrumented_tests/commentsblogs.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_instrumented_tests/commentsblogs.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh new file mode 100755 index 0000000..101ac39 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh @@ -0,0 +1 @@ +src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='DataStoreInstrumentedTestsBackend' --schema_dir 'datastore_instrumented_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh deleted file mode 100755 index f663205..0000000 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_instrumented_tests_backend.sh +++ /dev/null @@ -1 +0,0 @@ -src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='InstrumentedTests' --schema_dir 'instrumented_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file From 6765c16cd52f05a7eb7639a6e3b53438735f729e Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Mon, 14 Dec 2020 14:42:40 -0500 Subject: [PATCH 04/22] Make api key default auth mode --- .../android/amplify/integration/cdk/scripts/setup_amplify | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index c2f866e..9a09beb 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -54,11 +54,13 @@ else: LOGGER.error("Failed to configure Auth category.") exit(-1) +api_key_config = ApiAuthModeFactory.create_api_key_config() user_pools_config = ApiAuthModeFactory.create_user_pools_config(auth_resource_name=auth_resource_name) api_config = ApiConfigFactory.create(api_name=f"{amplify_backend_name}Api", op_type=api_op_type, schema_dir=f"{SCRIPTS_DIR}/../schemas/{schema_dir}", - default_auth_mode=user_pools_config) + default_auth_mode=api_key_config, + additional_auth_modes= { user_pools_config: user_pools_config}) api_cmd_result = amplify_app.config_api(api_config, api_op_type) if api_cmd_result == 0: From 18a0651e4fce79fcf9c4ea1e12772b94785ed09c Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Mon, 14 Dec 2020 14:51:33 -0500 Subject: [PATCH 05/22] Fix dictionary --- .../android/amplify/integration/cdk/scripts/setup_amplify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index 9a09beb..9118915 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -60,7 +60,7 @@ api_config = ApiConfigFactory.create(api_name=f"{amplify_backend_name}Api", op_type=api_op_type, schema_dir=f"{SCRIPTS_DIR}/../schemas/{schema_dir}", default_auth_mode=api_key_config, - additional_auth_modes= { user_pools_config: user_pools_config}) + additional_auth_modes= { "user_pools_config": user_pools_config}) api_cmd_result = amplify_app.config_api(api_config, api_op_type) if api_cmd_result == 0: From 513fdbdbe8d72bd73a3207f1463bc79b7147655f Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Mon, 14 Dec 2020 15:22:45 -0500 Subject: [PATCH 06/22] Renamed projects and stacks --- .../android/amplify/integration/cdk/app.py | 12 ++++++------ .../blogApi.graphql | 0 .../commentsblogs.graphql | 0 ..._tests_backend.sh => deploy_api_tests_backend.sh} | 2 +- .../deploy_datastore_instrumented_tests_backend.sh | 1 - .../cdk/scripts/deploy_datastore_tests_backend.sh | 1 + 6 files changed, 8 insertions(+), 8 deletions(-) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/{api_instrumented_tests => api_tests}/blogApi.graphql (100%) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/{datastore_instrumented_tests => datastore_tests}/commentsblogs.graphql (100%) rename src/integ_test_resources/android/amplify/integration/cdk/scripts/{deploy_api_instrumented_tests_backend.sh => deploy_api_tests_backend.sh} (67%) delete mode 100755 src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh create mode 100755 src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh diff --git a/src/integ_test_resources/android/amplify/integration/cdk/app.py b/src/integ_test_resources/android/amplify/integration/cdk/app.py index fc06789..bd55989 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/app.py @@ -36,19 +36,19 @@ def build_amplify_deployer_stack_props(cb_project_name: str, print(BANNER_TEXT) print(SEPARATOR) -instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="DataStoreInstrumentedTestsBackend", +instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="DataStoreTestsBackendDeployer", github_repo=GITHUB_REPO, github_owner=github_owner, branch=branch, - shell_script_name="deploy_datastore_instrumented_tests_backend.sh") + shell_script_name="deploy_datastore_tests_backend.sh") -api_instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="ApiInstrumentedTestsBackendDeployer", +api_instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="ApiTestsBackendDeployer", github_repo=GITHUB_REPO, github_owner=github_owner, branch=branch, - shell_script_name="deploy_api_instrumented_tests_backend.sh") + shell_script_name="deploy_api_tests_backend.sh") -instrumented_test_backend_stack = AmplifyDeployer(app, "DataStoreInstrumentedTestsBackend", instrumented_test_props, env=TARGET_ENV) -api_instrumented_test_backend_stack = AmplifyDeployer(app, "ApiInstrumentedTestsBackend", api_instrumented_test_props, env=TARGET_ENV) +instrumented_test_backend_stack = AmplifyDeployer(app, "DataStoreTestsBackendDeployer", instrumented_test_props, env=TARGET_ENV) +api_instrumented_test_backend_stack = AmplifyDeployer(app, "ApiTestsBackendDeployer", api_instrumented_test_props, env=TARGET_ENV) app.synth() diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_instrumented_tests/blogApi.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/blogApi.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/api_instrumented_tests/blogApi.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/blogApi.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_instrumented_tests/commentsblogs.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/commentsblogs.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_instrumented_tests/commentsblogs.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/commentsblogs.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_instrumented_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_tests_backend.sh similarity index 67% rename from src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_instrumented_tests_backend.sh rename to src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_tests_backend.sh index c9427b7..c8d8c95 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_instrumented_tests_backend.sh +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_api_tests_backend.sh @@ -1 +1 @@ -src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='ApiInstrumentedTests' --schema_dir 'api_instrumented_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file +src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='ApiInstrumentedTests' --schema_dir 'api_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh deleted file mode 100755 index 101ac39..0000000 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_instrumented_tests_backend.sh +++ /dev/null @@ -1 +0,0 @@ -src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='DataStoreInstrumentedTestsBackend' --schema_dir 'datastore_instrumented_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh new file mode 100755 index 0000000..c01d5b3 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh @@ -0,0 +1 @@ +src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='DataStoreIntegTests' --schema_dir 'datastore_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file From af1e33e6791eab43a2d879e255100705504d3e1d Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Mon, 14 Dec 2020 15:29:25 -0500 Subject: [PATCH 07/22] Add forcePush --- .../android/amplify/integration/cdk/scripts/amplify_app.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py index 89cd8b4..c4accef 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py @@ -102,7 +102,9 @@ def _initialize_new_app(self): AMPLIFY_ACTION_INIT, "--amplify", json.dumps(self._get_amplify_config()), "--providers", json.dumps(AMPLIFY_PROVIDER_CONFIG), - "--frontend", json.dumps(AMPLIFY_FRONTEND_CONFIG)] + "--frontend", json.dumps(AMPLIFY_FRONTEND_CONFIG), + "--forcePush", + "--yes"] result = run_command(init_cmd, self.project_dir) self.app_id = self._get_existing_app_id() return result.returncode From 6daf87b341d1c44643026bb7037c99aaad2d61dd Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Mon, 14 Dec 2020 15:51:19 -0500 Subject: [PATCH 08/22] Remove --codegen from push command --- .../android/amplify/integration/cdk/scripts/amplify_app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py index c4accef..c43e28e 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py @@ -82,7 +82,6 @@ def get_category_config(self, category_name: str): def push(self): push_cmd = [AMPLIFY_COMMAND, "push", - "--codegen", json.dumps(AMPLIFY_CODEGEN_CONFIG_ANDROID), "--yes"] result = run_command(push_cmd, self.project_dir) self._load_metadata() From abc782a56ac9a6c8790479797ef0ff2d24fbb111 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Wed, 23 Dec 2020 16:00:41 -0500 Subject: [PATCH 09/22] Add codegen option --- .../android/amplify/integration/cdk/scripts/amplify_app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py index c43e28e..c4accef 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py @@ -82,6 +82,7 @@ def get_category_config(self, category_name: str): def push(self): push_cmd = [AMPLIFY_COMMAND, "push", + "--codegen", json.dumps(AMPLIFY_CODEGEN_CONFIG_ANDROID), "--yes"] result = run_command(push_cmd, self.project_dir) self._load_metadata() From b9ccfe331e250464336f598ea9f9c4488e9bc19f Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Mon, 28 Dec 2020 17:16:10 -0500 Subject: [PATCH 10/22] Add conflict detection option and push between auth and api --- .../android/amplify/integration/cdk/scripts/api.py | 7 ++++++- .../android/amplify/integration/cdk/scripts/setup_amplify | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py index 333b694..5fcd5ae 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py @@ -64,7 +64,12 @@ def create(cls, *, api_name:str, 'serviceName': 'AppSync', 'apiName': api_name, 'transformSchema': gql_schema, - 'defaultAuthType': default_auth_mode + 'defaultAuthType': default_auth_mode, + 'conflictResolution': { + 'defaultResolutionStrategy': { + 'type': 'AUTOMERGE' + } + } } if additional_auth_modes is not None: api_config[api_config_json_element_name]['additionalAuthTypes'] = list(additional_auth_modes.values()) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index 9118915..aceec55 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -54,8 +54,10 @@ else: LOGGER.error("Failed to configure Auth category.") exit(-1) +amplify_app.push() + api_key_config = ApiAuthModeFactory.create_api_key_config() -user_pools_config = ApiAuthModeFactory.create_user_pools_config(auth_resource_name=auth_resource_name) +user_pools_config = ApiAuthModeFactory.create_user_pools_config(auth_resource_name=f"auth{auth_resource_name}") api_config = ApiConfigFactory.create(api_name=f"{amplify_backend_name}Api", op_type=api_op_type, schema_dir=f"{SCRIPTS_DIR}/../schemas/{schema_dir}", From 0837ec4ab8670b00dda630031f2eff871db060b9 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Tue, 29 Dec 2020 14:40:08 -0500 Subject: [PATCH 11/22] Change variable name --- .../android/amplify/integration/cdk/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/app.py b/src/integ_test_resources/android/amplify/integration/cdk/app.py index bd55989..ac06434 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/app.py @@ -36,7 +36,7 @@ def build_amplify_deployer_stack_props(cb_project_name: str, print(BANNER_TEXT) print(SEPARATOR) -instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="DataStoreTestsBackendDeployer", +datastore_instrumented_test_props = build_amplify_deployer_stack_props(cb_project_name="DataStoreTestsBackendDeployer", github_repo=GITHUB_REPO, github_owner=github_owner, branch=branch, @@ -48,7 +48,7 @@ def build_amplify_deployer_stack_props(cb_project_name: str, branch=branch, shell_script_name="deploy_api_tests_backend.sh") -instrumented_test_backend_stack = AmplifyDeployer(app, "DataStoreTestsBackendDeployer", instrumented_test_props, env=TARGET_ENV) +instrumented_test_backend_stack = AmplifyDeployer(app, "DataStoreTestsBackendDeployer", datastore_instrumented_test_props, env=TARGET_ENV) api_instrumented_test_backend_stack = AmplifyDeployer(app, "ApiTestsBackendDeployer", api_instrumented_test_props, env=TARGET_ENV) app.synth() From 5a170348eccf64397dc49a8ec647b4389016e3a2 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Wed, 30 Dec 2020 15:25:16 -0500 Subject: [PATCH 12/22] Adding schemas for API tests --- .../cdk/schemas/api_tests/eventsApi.graphql | 20 +++++++++++++++++++ .../cdk/schemas/api_tests/personCar.graphql | 14 +++++++++++++ .../cdk/schemas/api_tests/teamproject.graphql | 11 ++++++++++ .../amplify/integration/cdk/scripts/api.py | 14 ++++++++----- .../amplify/integration/cdk/scripts/common.py | 1 + .../scripts/deploy_datastore_tests_backend.sh | 2 +- .../integration/cdk/scripts/setup_amplify | 4 +++- 7 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/eventsApi.graphql create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/personCar.graphql create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/teamproject.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/eventsApi.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/eventsApi.graphql new file mode 100644 index 0000000..294b258 --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/eventsApi.graphql @@ -0,0 +1,20 @@ +type Event @model { + id: ID! + name: String! + where: String! + when: String! + description: String + comments: [Comment] @connection(name: "EventComments") +} + +type Comment @model { + id: ID! + eventId: String! + content: String! + createdAt: AWSTimestamp! + event: Event @connection(name: "EventComments") +} + +type Subscription { + subscribeToEventComments(eventId: String!): Comment @aws_subscribe(mutations: ["createComment"]) +} diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/personCar.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/personCar.graphql new file mode 100644 index 0000000..802636b --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/personCar.graphql @@ -0,0 +1,14 @@ +type Person @model { + id: ID! + first_name: String! + last_name: String! + age: Int + dob: AWSDate + relationship: MaritalStatus +} + +enum MaritalStatus { + single + engaged + married +} \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/teamproject.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/teamproject.graphql new file mode 100644 index 0000000..9a1a60f --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/teamproject.graphql @@ -0,0 +1,11 @@ +type Projectfields @model { + id: ID! + name: String + teamID: ID! + team: Team @connection(fields: ["teamID"]) +} + +type Team @model { + id: ID! + name: String! +} \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py index 5fcd5ae..96c8f23 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py @@ -50,7 +50,8 @@ def create(cls, *, api_name:str, op_type:OperationType, schema_dir:str, default_auth_mode:ApiAuthMode, - additional_auth_modes: dict = None ): + additional_auth_modes: dict = None, + conflict_resolution: str = None ): gql_schema = "" for entry in os.listdir(schema_dir): if os.path.isfile(os.path.join(schema_dir, entry)): @@ -64,13 +65,16 @@ def create(cls, *, api_name:str, 'serviceName': 'AppSync', 'apiName': api_name, 'transformSchema': gql_schema, - 'defaultAuthType': default_auth_mode, - 'conflictResolution': { + 'defaultAuthType': default_auth_mode + + } + print(f"conflict resolution = {conflict_resolution}") + if conflict_resolution is not None: + api_config[api_config_json_element_name]['conflictResolution'] = { 'defaultResolutionStrategy': { - 'type': 'AUTOMERGE' + 'type': conflict_resolution } } - } if additional_auth_modes is not None: api_config[api_config_json_element_name]['additionalAuthTypes'] = list(additional_auth_modes.values()) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py index fb70e57..88b6457 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py @@ -16,6 +16,7 @@ def parse_arguments(): parser.add_argument("--backend_name", help="The name of the Amplify app.", required=True) parser.add_argument("--schema_dir", help="Name of the subdirectory under the schemas folder that contains the GraphQL schemas for the backend API.", required=True) parser.add_argument("--group_names", help="Comma-separated list of group names to be created.", default="") + parser.add_argument("--conflict_resolution", help="Conflict resolution mode.") parser.add_argument("--log", help="Set the log level.", default='INFO') return parser.parse_args() diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh index c01d5b3..3a1d084 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/deploy_datastore_tests_backend.sh @@ -1 +1 @@ -src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='DataStoreIntegTests' --schema_dir 'datastore_tests' --group_names 'Admins' --log=DEBUG \ No newline at end of file +src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify --backend_name='DataStoreIntegTests' --schema_dir 'datastore_tests' --group_names 'Admins' --conflict_resolution 'AUTOMERGE' --log=DEBUG \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index aceec55..cd8c317 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -32,6 +32,7 @@ LOGGER.setLevel(level=arguments.log) amplify_backend_name = arguments.backend_name schema_dir = arguments.schema_dir group_names = arguments.group_names.split(",") +conflict_resolution = arguments.conflict_resolution auth_resource_name = f"{amplify_backend_name}Auth" @@ -62,7 +63,8 @@ api_config = ApiConfigFactory.create(api_name=f"{amplify_backend_name}Api", op_type=api_op_type, schema_dir=f"{SCRIPTS_DIR}/../schemas/{schema_dir}", default_auth_mode=api_key_config, - additional_auth_modes= { "user_pools_config": user_pools_config}) + additional_auth_modes= { "user_pools_config": user_pools_config}, + conflict_resolution=conflict_resolution) api_cmd_result = amplify_app.config_api(api_config, api_op_type) if api_cmd_result == 0: From ebaaafb8d402a41f6b69e7024df37be0ac6b9f2f Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Wed, 30 Dec 2020 16:39:22 -0500 Subject: [PATCH 13/22] Renamed schema files --- .../cdk/schemas/api_tests/{blogApi.graphql => blog_api.graphql} | 0 .../schemas/api_tests/{eventsApi.graphql => events_api.graphql} | 0 .../schemas/api_tests/{personCar.graphql => person_car.graphql} | 0 .../api_tests/{teamproject.graphql => team_project.graphql} | 0 .../{commentsblogs.graphql => comments_blogs.graphql} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/{blogApi.graphql => blog_api.graphql} (100%) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/{eventsApi.graphql => events_api.graphql} (100%) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/{personCar.graphql => person_car.graphql} (100%) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/{teamproject.graphql => team_project.graphql} (100%) rename src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/{commentsblogs.graphql => comments_blogs.graphql} (100%) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/blogApi.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/blog_api.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/blogApi.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/blog_api.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/eventsApi.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/events_api.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/eventsApi.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/events_api.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/personCar.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/person_car.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/personCar.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/person_car.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/teamproject.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/team_project.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/teamproject.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/team_project.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/commentsblogs.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/comments_blogs.graphql similarity index 100% rename from src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/commentsblogs.graphql rename to src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/comments_blogs.graphql From c81bb18382088efa32c6259f4dde34088e18600f Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Thu, 31 Dec 2020 11:21:24 -0500 Subject: [PATCH 14/22] Tweak to the events API schema --- .../cdk/schemas/api_tests/events_api.graphql | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/events_api.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/events_api.graphql index 294b258..1d4059e 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/events_api.graphql +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/api_tests/events_api.graphql @@ -8,13 +8,17 @@ type Event @model { } type Comment @model { - id: ID! - eventId: String! - content: String! - createdAt: AWSTimestamp! + eventId: ID! + commentId: String! + content: String! + createdAt: String! event: Event @connection(name: "EventComments") } +type Mutation { + commentOnEvent(eventId: ID!, content: String!, createdAt: String!): Comment +} + type Subscription { subscribeToEventComments(eventId: String!): Comment @aws_subscribe(mutations: ["createComment"]) } From c4ebbd2d9c4ce18d692574616a5682a8904d4588 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Wed, 6 Jan 2021 14:58:23 -0500 Subject: [PATCH 15/22] Set expiration time for test keys --- .../android/amplify/integration/cdk/scripts/api.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py index 96c8f23..d9eedb1 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py @@ -23,7 +23,10 @@ def create_user_pools_config(cls, auth_resource_name:str): @classmethod def create_api_key_config(cls): - return { 'mode': 'API_KEY' } + return { + 'mode': 'API_KEY', + 'expirationTime': 365 + } @classmethod def create_oidc_config(cls, client_id: str, issuer_url: str, provider_name: str, is_default: bool = False): From a457a28059ef9c29045735c8e2c1903519a1c55a Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Wed, 6 Jan 2021 15:31:45 -0500 Subject: [PATCH 16/22] Updating READMEs --- README.md | 3 ++ .../android/amplify/integration/cdk/README.md | 32 +++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ea78395..1ee90e5 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ integration test environments. To deploy resources necessary to run the Android SDK's integration tests, [see here](./src/integ_test_resources/android/sdk/integration/cdk/README.md). +To deploy resources necessary to run the Amplify for Android's integration +tests, [see here](./src/integ_test_resources/android/amplify/integration/cdk/README.md). + To build a configuration file that can be referenced from an iOS/Android device, [see here](./src/integ_test_resources/common/README.md). diff --git a/src/integ_test_resources/android/amplify/integration/cdk/README.md b/src/integ_test_resources/android/amplify/integration/cdk/README.md index 7efa4c6..c000930 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/README.md +++ b/src/integ_test_resources/android/amplify/integration/cdk/README.md @@ -59,10 +59,23 @@ There are two parts to this CDK application: - The scripts that are executed inside the CodeBuild project. That being said, there are a couple of different usage scenarios: -1. You are setting a new AWS account for integration testing purposes and you want changes made to the `scripts` and/or `schemas` folders to be executed from the CodeBuild project when something is committed to a branch. -2. You just want to setup the backend resources against your own AWS account for running the tests, adding/modifying test scenarios, etc. In this case, you would be running the scripts that run inside CodeBuild on your local environment. +1. You just want to setup the backend resources against your own AWS account for running the tests, adding/modifying test scenarios, etc. In this case, you would be running the scripts that run inside CodeBuild on your local environment. +2. You are setting a new AWS account for integration testing purposes and you want changes made to the `scripts` and/or `schemas` folders to be executed from the CodeBuild project when something is committed to a branch. -### Option 1 - Setup a new AWS account to run integration tests +### Option 1 - Run the scripts locally +Ensure your AWS credentials have rights to execute the script. + +1. Start from the CDK app root, where this `README.md` lives: +```console +cd /src/integ_test_resources/android/amplify/integration/cdk +``` + +2. Run one of the deployment scripts located under the `scripts` folder. For example: +```Console +python ./scripts/deploy_api_tests_backend.sh +``` + +### Option 2 - Setup a new AWS account to run integration tests Ensure that you have [credentials in your environment sufficient to run the CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_credentials). @@ -117,16 +130,3 @@ cdk deploy ```console cdk destroy ``` - -### Option 2 - Run the scripts locally -Ensure your AWS credentials have rights to execute the script. - -1. Start from the CDK app root, where this `README.md` lives: -```console -cd /src/integ_test_resources/android/amplify/integration/cdk -``` - -2. Run the deployment script -```Console -python ./scripts/setup_amplify -``` \ No newline at end of file From 0cdd502bcbb5af2cb0692a399232591502b78b11 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Wed, 6 Jan 2021 16:21:20 -0500 Subject: [PATCH 17/22] Cleaned up warnings --- .../android/amplify/integration/cdk/scripts/api.py | 1 - .../android/amplify/integration/cdk/scripts/auth.py | 1 - .../android/amplify/integration/cdk/scripts/common.py | 1 - .../android/amplify/integration/cdk/scripts/setup_amplify | 6 +----- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py index d9eedb1..161041d 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py @@ -1,4 +1,3 @@ -import json import os from enum import Enum from common import ( diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py index e98a754..92ff903 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py @@ -1,4 +1,3 @@ -import json import os from common import OperationType diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py index 88b6457..47af14a 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py @@ -1,5 +1,4 @@ import os -import json import subprocess import argparse import boto3 diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index cd8c317..ecf13d7 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -8,9 +8,6 @@ src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer """ -import os -import argparse -import logging from common import ( OperationType, parse_arguments, @@ -21,8 +18,7 @@ from common import ( from auth import AuthConfigFactory from api import ( ApiAuthModeFactory, - ApiConfigFactory, - ApiAuthMode + ApiConfigFactory ) from amplify_app import AmplifyApp From 7aad6bae918887d0fefeac6a89e0196cd86889d0 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Fri, 29 Jan 2021 11:47:09 -0500 Subject: [PATCH 18/22] Cleanup unused code and setup artifact buckets --- src/build_infrastructure/android/README.md | 3 +- .../pull_request_builder.py | 12 +- .../android/stacks/build_pipeline_stack.py | 130 ++++-------------- 3 files changed, 40 insertions(+), 105 deletions(-) diff --git a/src/build_infrastructure/android/README.md b/src/build_infrastructure/android/README.md index a015bd8..a0b5b79 100644 --- a/src/build_infrastructure/android/README.md +++ b/src/build_infrastructure/android/README.md @@ -71,7 +71,8 @@ cdk deploy AndroidBuildPipeline \ --yes ``` -**NOTE:** be sure to copy the config files in the bucket whose name contains "amplify-ci-assets" created by the AccountBootstrap. +**NOTE 1:** be sure to copy the config files in the bucket whose name contains "amplify-ci-assets" created by the AccountBootstrap. +**NOTE 2:** When deploying in an account for testing purposes, it's a good idea to set the branch to something other than main so the webhook doesn't trigger a build (unless you're modifying/testing the webhook of course). If necessary, during testing/debugging, add: diff --git a/src/build_infrastructure/android/amplify_custom_resources/pull_request_builder.py b/src/build_infrastructure/android/amplify_custom_resources/pull_request_builder.py index f693a93..4c1b79f 100644 --- a/src/build_infrastructure/android/amplify_custom_resources/pull_request_builder.py +++ b/src/build_infrastructure/android/amplify_custom_resources/pull_request_builder.py @@ -1,4 +1,3 @@ - from aws_cdk import core from aws_cdk.aws_codebuild import ( BuildEnvironment, @@ -6,6 +5,7 @@ ComputeType, EventAction, FilterGroup, + IArtifacts, LinuxBuildImage, Project, Source @@ -19,7 +19,9 @@ def __init__(self, scope: core.Construct, id: str, *, github_repo, buildspec_path, environment_variables = {}, - base_branch: str = "main"): + base_branch: str = "main", + primary_artifact = None, + secondary_artifacts = []): build_environment = BuildEnvironment(build_image=self.BUILD_IMAGE, privileged = True, compute_type = ComputeType.LARGE) @@ -30,9 +32,15 @@ def __init__(self, scope: core.Construct, id: str, *, environment_variables = environment_variables, build_spec=BuildSpec.from_source_filename(buildspec_path), badge = True, + artifacts=primary_artifact, + secondary_artifacts=secondary_artifacts, source = Source.git_hub(owner = github_owner, report_build_status = True, repo = github_repo, webhook = True, webhook_filters = [trigger_on_pr]), environment = build_environment) + + def add_secondary_artifact(self): + pass + \ No newline at end of file diff --git a/src/build_infrastructure/android/stacks/build_pipeline_stack.py b/src/build_infrastructure/android/stacks/build_pipeline_stack.py index 384704f..c48fde3 100644 --- a/src/build_infrastructure/android/stacks/build_pipeline_stack.py +++ b/src/build_infrastructure/android/stacks/build_pipeline_stack.py @@ -243,6 +243,9 @@ def __init__(self, scope: core.App, id: str, props, **kwargs) -> None: df_project = DeviceFarmProject(self, id, project_name=device_farm_project_name) df_pool = DeviceFarmDevicePool(self, f"{id}DevicePool", project_arn=core.Token.as_string(df_project.project_arn), device_pool_name="SingleDeviceIntegTestDevicePool") + + # Bucket to store build artifacts, logs, test results, etc. + artifact_bucket = self.__create_artifact_bucket("ArtifactBucket", bucket_name=f"{codebuild_project_name_prefix.lower()}-builds-{self.account}") PullRequestBuilder(self, "UnitTestRunner", project_name=f"{codebuild_project_name_prefix}-UnitTest", github_owner=owner, @@ -255,18 +258,35 @@ def __init__(self, scope: core.App, id: str, props, **kwargs) -> None: github_repo=repo, base_branch=base_branch, buildspec_path="scripts/devicefarm-test-runner-buildspec.yml", + primary_artifact=aws_codebuild.Artifacts.s3( + bucket=artifact_bucket, + encryption=True, + include_build_id=True, + package_zip=False, + path="instrumented/apks" + ), + secondary_artifacts=[ + aws_codebuild.Artifacts.s3( + bucket=artifact_bucket, + identifier="reports", + encryption=True, + include_build_id=True, + package_zip=False, + path="instrumented/reports" + )], environment_variables={ 'DEVICEFARM_PROJECT_ARN': aws_codebuild.BuildEnvironmentVariable(value=df_project.get_arn()), 'DEVICEFARM_POOL_ARN': aws_codebuild.BuildEnvironmentVariable(value=df_pool.device_pool_arn), 'CONFIG_SOURCE_BUCKET': aws_codebuild.BuildEnvironmentVariable(value=config_source_bucket) }) - self._add_codebuild_project_runner_permissions(integtest_project.role) - self._add_devicefarm_test_runner_permissions_to_role(integtest_project.role) + + self.__add_codebuild_project_runner_permissions(integtest_project.role) + self.__add_devicefarm_test_runner_permissions_to_role(integtest_project.role) def get_codebuild_project_name(self): return self.code_build_project.project_name - def _add_devicefarm_test_runner_permissions_to_role(self, role: aws_iam.Role): + def __add_devicefarm_test_runner_permissions_to_role(self, role: aws_iam.Role): df_runner_policy = aws_iam.ManagedPolicy(self, "AmplifyAndroidDeviceFarmTestRunnerPolicy", managed_policy_name=f"AmplifyAndroidDeviceFarmTestRunnerPolicy", @@ -277,23 +297,12 @@ def _add_devicefarm_test_runner_permissions_to_role(self, role: aws_iam.Role): ) df_runner_policy.attach_to_role(role) - def _add_devicefarm_test_stage(self, pipeline, device_farm_project_id, device_farm_pool_arn): - test_actions = [] - for module_name in self.MODULES_WITH_INSTRUMENTED_TESTS: - test_actions.append(self._create_devicefarm_test_action(device_farm_project_id, device_farm_pool_arn, module_name)) - - testing_stage = { - "Name": "Test", - "Actions": test_actions - } - pipeline_node = pipeline.node.default_child - pipeline_node.add_property_override("Stages.2", testing_stage) - - def _create_artifact_bucket(self, bucket_name:str): - artifact_bucket = aws_s3.Bucket(self, "PipelineAssets", + def __create_artifact_bucket(self, id, *, bucket_name:str): + artifact_bucket = aws_s3.Bucket(self, id, bucket_name=bucket_name, encryption=aws_s3.BucketEncryption.KMS_MANAGED, removal_policy=core.RemovalPolicy.DESTROY) + artifact_bucket.add_to_resource_policy(permission=aws_iam.PolicyStatement( principals=[aws_iam.AnyPrincipal()], effect=aws_iam.Effect.DENY, @@ -324,40 +333,7 @@ def _create_artifact_bucket(self, bucket_name:str): )) return artifact_bucket - # Not calling this right now since we can't filter out PRs in CodePipeline. - def _create_pipeline(self, - build_pipeline_name: str, - github_source: aws_codepipeline_actions.GitHubSourceAction, - codebuild_project: aws_codebuild.PipelineProject, - config_file_source_bucket_name:str, - df_project: DeviceFarmProject, - device_farm_pool_arn:str): - artifact_bucket = self._create_artifact_bucket(f"pipeline-assets-{build_pipeline_name.lower()}-{self.account}") - self.code_build_project = self._create_codebuild_project("AmplifyAndroidCodeBuildProject") - amplify_android_build_output = aws_codepipeline.Artifact("AmplifyAndroidBuildOutput") - pipeline = aws_codepipeline.Pipeline(self, - f"{build_pipeline_name}Pipeline", - pipeline_name=build_pipeline_name, - artifact_bucket=artifact_bucket, - stages=[ - aws_codepipeline.StageProps( - stage_name="Source", - actions=[ github_source ] - ), - aws_codepipeline.StageProps( - stage_name="Build", - actions=[self._create_build_and_assemble_action(input_artifact=github_source.action_properties.outputs[0], - output_artifact=amplify_android_build_output, - pipeline_project=codebuild_project, - config_source_bucket=config_file_source_bucket_name) - ] - ) - ]) - self._add_devicefarm_test_runner_permissions_to_role(pipeline.role) - self._add_devicefarm_test_stage(pipeline, df_project.get_project_id(), device_farm_pool_arn) - return pipeline - - def _create_codebuild_project(self, id: str): + def __create_codebuild_project(self, id: str): pipeline_project = aws_codebuild.PipelineProject(self, id, environment=aws_codebuild.BuildEnvironment(build_image=aws_codebuild.LinuxBuildImage.AMAZON_LINUX_2_3, @@ -375,7 +351,7 @@ def _create_codebuild_project(self, id: str): build_exec_policy.attach_to_role(pipeline_project.role) return pipeline_project - def _add_codebuild_project_runner_permissions(self, role: aws_iam.Role): + def __add_codebuild_project_runner_permissions(self, role: aws_iam.Role): build_exec_policy = aws_iam.ManagedPolicy(self, "AmplifyAndroidBuildExecutorPolicy", managed_policy_name=f"AmplifyAndroidBuildExecutorPolicy", @@ -385,53 +361,3 @@ def _add_codebuild_project_runner_permissions(self, role: aws_iam.Role): ] ) build_exec_policy.attach_to_role(role) - - - def _create_build_and_assemble_action(self, - input_artifact:aws_codepipeline.Artifact, - output_artifact:aws_codepipeline.Artifact, - pipeline_project:aws_codebuild.PipelineProject, - config_source_bucket: str = None): - if config_source_bucket is None: - return aws_codepipeline_actions.CodeBuildAction( - action_name='BuildAndAssemble', - input=input_artifact, - project=pipeline_project, - outputs=[output_artifact] - ) - else: - return aws_codepipeline_actions.CodeBuildAction( - action_name='BuildAndAssemble', - input=input_artifact, - project=pipeline_project, - environment_variables={ - 'CONFIG_SOURCE_BUCKET': aws_codebuild.BuildEnvironmentVariable(value=config_source_bucket) - }, - outputs=[output_artifact] - ) - - def _create_devicefarm_test_action(self, project_id: str, device_pool_arn: str, module_name: str): - return { - "Name":f"{module_name}-InstrumentedTests", - "ActionTypeId": { - "Category": "Test", - "Owner": "AWS", - "Provider": "DeviceFarm", - "Version": "1" - }, - "RunOrder": 1, - "Configuration": { - "App": f"{module_name}-debug-androidTest.apk", - "Test": f"{module_name}-debug-androidTest.apk", - "AppType": "Android", - "DevicePoolArn": device_pool_arn, - "ProjectId": project_id, - "TestType": "INSTRUMENTATION" - }, - "OutputArtifacts": [], - "InputArtifacts": [ - { - "Name": "AmplifyAndroidBuildOutput" - } - ] - } From 2e6597bf9d134a0b46d2cafebf999a217fd5dcf5 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Tue, 11 May 2021 21:43:38 -0400 Subject: [PATCH 19/22] Adding schemas and changes for multiauth --- .../datastore_tests/multiauth_schemas.graphql | 244 ++++++++++++++++++ .../amplify/integration/cdk/scripts/api.py | 1 + .../amplify/integration/cdk/scripts/common.py | 1 - .../integration/cdk/scripts/setup_amplify | 4 +- 4 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/multiauth_schemas.graphql diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/multiauth_schemas.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/multiauth_schemas.graphql new file mode 100644 index 0000000..65c802b --- /dev/null +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/multiauth_schemas.graphql @@ -0,0 +1,244 @@ +type OwnerUPPost @model @auth(rules: [{ allow: owner }]) { + id: ID! + name: String! +} + +type OwnerOIDCPost + @model + @auth(rules: [{ allow: owner, provider: oidc, identityClaim: "sub" }]) { + id: ID! + name: String! +} + +type GroupUPPost @model @auth(rules: [{ allow: groups, groups: ["Admins"] }]) { + id: ID! + name: String! +} + +type PrivateUPPost + @model + @auth(rules: [{ allow: private, provider: userPools }]) { + id: ID! + name: String! +} + +type PrivateIAMPost @model @auth(rules: [{ allow: private, provider: iam }]) { + id: ID! + name: String! +} + +type PublicIAMPost @model @auth(rules: [{ allow: public, provider: iam }]) { + id: ID! + name: String! +} + +type PublicAPIPost @model @auth(rules: [{ allow: public, provider: apiKey }]) { + id: ID! + name: String! +} + +type OwnerPrivateUPIAMPost + @model + @auth(rules: [{ allow: owner }, { allow: private, provider: iam }]) { + id: ID! + name: String! +} + +type OwnerPublicUPAPIPost + @model + @auth(rules: [{ allow: owner }, { allow: public, provider: apiKey }]) { + id: ID! + name: String! +} + +type OwnerPublicUPIAMPost + @model + @auth(rules: [{ allow: owner }, { allow: public, provider: iam }]) { + id: ID! + name: String! +} + +type OwnerPublicOIDAPIPost + @model + @auth( + rules: [ + { allow: owner, provider: oidc, identityClaim: "sub" } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type GroupPrivateUPIAMPost + @model + @auth( + rules: [ + { allow: groups, groups: ["Admins"] } + { allow: private, provider: iam } + ] + ) { + id: ID! + name: String! +} + +type GroupPublicUPAPIPost + @model + @auth( + rules: [ + { allow: groups, groups: ["Admins"] } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type GroupPublicUPIAMPost + @model + @auth( + rules: [ + { allow: groups, groups: ["Admins"] } + { allow: public, provider: iam } + ] + ) { + id: ID! + name: String! +} + +type PrivatePrivateUPIAMPost + @model + @auth( + rules: [ + { allow: private, provider: userPools } + { allow: private, provider: iam } + ] + ) { + id: ID! + name: String! +} + +type PrivatePublicUPAPIPost + @model + @auth( + rules: [ + { allow: private, provider: userPools } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type PrivatePublicUPIAMPost + @model + @auth( + rules: [ + { allow: private, provider: userPools } + { allow: public, provider: iam } + ] + ) { + id: ID! + name: String! +} + +type PrivatePublicIAMAPIPost + @model + @auth( + rules: [ + { allow: private, provider: iam } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type PublicPublicIAMAPIPost + @model + @auth( + rules: [ + { allow: public, provider: iam } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type OwnerPrivatePublicUPIAMAPIPost + @model + @auth( + rules: [ + { allow: owner } + { allow: private, provider: iam } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type GroupPrivatePublicUPIAMAPIPost + @model + @auth( + rules: [ + { allow: groups, groups: ["Admins"] } + { allow: private, provider: iam } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type PrivatePrivatePublicUPIAMIAMPost + @model + @auth( + rules: [ + { allow: private, provider: userPools } + { allow: private, provider: iam } + { allow: public, provider: iam } + ] + ) { + id: ID! + name: String! +} + +type PrivatePrivatePublicUPIAMAPIPost + @model + @auth( + rules: [ + { allow: private, provider: userPools } + { allow: private, provider: iam } + { allow: public, provider: apiKey } + ] + ) { + id: ID! + name: String! +} + +type PrivatePublicPublicUPAPIIAMPost + @model + @auth( + rules: [ + { allow: private, provider: userPools } + { allow: public, provider: apiKey } + { allow: public, provider: iam } + ] + ) { + id: ID! + name: String! +} + +type PrivatePublicComboUPPost @model @auth(rules: [{ allow: owner }]) { + id: ID! + name: String! +} + +type PrivatePublicComboAPIPost + @model + @auth(rules: [{ allow: public, provider: apiKey }]) { + id: ID! + name: String! +} \ No newline at end of file diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py index 161041d..e481bcc 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/api.py @@ -30,6 +30,7 @@ def create_api_key_config(cls): @classmethod def create_oidc_config(cls, client_id: str, issuer_url: str, provider_name: str, is_default: bool = False): return { + 'mode': 'OPENID_CONNECT', 'openIDClientID': client_id, 'openIDIssuerURL': issuer_url, 'openIDProviderName': provider_name diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py index 47af14a..5d0734c 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py @@ -37,7 +37,6 @@ def parse_arguments(): LOGGER.info(f"BASE_PATH = {BASE_PATH}") def run_command(cmd, work_dir:str, input: str = None): - LOGGER.debug(msg=" ".join(cmd)) result = subprocess.run(cmd, text=True, input = input if input is not None else '', diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index ecf13d7..59f5872 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -55,11 +55,13 @@ amplify_app.push() api_key_config = ApiAuthModeFactory.create_api_key_config() user_pools_config = ApiAuthModeFactory.create_user_pools_config(auth_resource_name=f"auth{auth_resource_name}") +oidc_config = ApiAuthModeFactory.create_oidc_config(client_id='dummy', issuer_url="https://localhost/", provider_name="Dummy provider") +iam_config = ApiAuthModeFactory.create_iam_config() api_config = ApiConfigFactory.create(api_name=f"{amplify_backend_name}Api", op_type=api_op_type, schema_dir=f"{SCRIPTS_DIR}/../schemas/{schema_dir}", default_auth_mode=api_key_config, - additional_auth_modes= { "user_pools_config": user_pools_config}, + additional_auth_modes= { "user_pools_config": user_pools_config, "oidc": oidc_config, "iam": iam_config }, conflict_resolution=conflict_resolution) api_cmd_result = amplify_app.config_api(api_config, api_op_type) From 22e3c01a9b1739a6eb7aae6c8dd8f13e19a5f7c3 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Thu, 20 May 2021 14:11:10 -0400 Subject: [PATCH 20/22] Adding createdAt field to datastore schema --- .../cdk/schemas/datastore_tests/comments_blogs.graphql | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/comments_blogs.graphql b/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/comments_blogs.graphql index 2b2426d..cdbeff1 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/comments_blogs.graphql +++ b/src/integ_test_resources/android/amplify/integration/cdk/schemas/datastore_tests/comments_blogs.graphql @@ -3,6 +3,7 @@ type Blog @model { name: String! posts: [Post] @connection(name: "BlogPosts") owner: BlogOwner! @connection(name: "BlogOwner") + createdAt: AWSDateTime } type BlogOwner @model { @@ -10,6 +11,7 @@ type BlogOwner @model { id: ID! blog: Blog @connection(name: "BlogOwner") wea: String + createdAt: AWSDateTime } enum PostStatus { @@ -25,18 +27,21 @@ type Post @model { authors: [PostAuthorJoin] @connection(keyName: "byPost", fields: ["id"]) status: PostStatus! rating: Int! + createdAt: AWSDateTime } type Comment @model { id: ID! content: String post: Post @connection(name: "PostComments") + createdAt: AWSDateTime } type Author @model { id: ID! name: String! posts: [PostAuthorJoin] @connection(keyName: "byAuthor", fields: ["id"]) + createdAt: AWSDateTime } type PostAuthorJoin @@ -48,5 +53,6 @@ type PostAuthorJoin postId: ID! author: Author @connection(fields: ["authorId"]) post: Post @connection(fields: ["postId"]) + createdAt: AWSDateTime } From 5421bc44b2d2b3959fd77acdae236d66360083e8 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Thu, 20 May 2021 14:21:19 -0400 Subject: [PATCH 21/22] pin old version of cli for now --- .../amplify/integration/cdk/stacks/amplify_deployer_stack.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py b/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py index 2e41e02..a91a794 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py @@ -108,14 +108,12 @@ def _generate_buildspec(self, shell_script_name: str): "install": { "commands":[ "echo 'Install phase starting'", - "npm install -g @aws-amplify/cli" + "npm install -g @aws-amplify/cli@4.40.1" ] }, "build": { "commands": [ "echo 'Build phase starting'", - "pwd", - "ls -al", deployer_command ] } From 699b8728c12b76a61544ce3bb7218ee368dacd67 Mon Sep 17 00:00:00 2001 From: Rafael Juliano Date: Fri, 18 Jun 2021 16:09:05 -0400 Subject: [PATCH 22/22] chore: add oidc config to api --- .../amplify/integration/cdk/scripts/amplify_app.py | 5 +++++ .../android/amplify/integration/cdk/scripts/auth.py | 4 ++++ .../amplify/integration/cdk/scripts/common.py | 2 ++ .../amplify/integration/cdk/scripts/setup_amplify | 12 ++++++++---- .../integration/cdk/stacks/amplify_deployer_stack.py | 12 ++++++++++++ 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py index c4accef..2534423 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/amplify_app.py @@ -3,6 +3,7 @@ from common import ( LOGGER, AMPLIFY_AWSSDK_CLIENT, + SECRETS_MANAGER_CLIENT, BASE_PATH, run_command, OperationType @@ -88,6 +89,10 @@ def push(self): self._load_metadata() return result.returncode + def retrieve_secret(self, secret_name: str): + get_secret_result = SECRETS_MANAGER_CLIENT.get_secret_value(SecretId=secret_name) + return json.loads(get_secret_result["SecretString"]) + def _get_existing_app_id(self): try: response = AMPLIFY_AWSSDK_CLIENT.list_apps() diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py index 92ff903..a96937d 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/auth.py @@ -9,6 +9,7 @@ def create(cls, *, auth_resource_name:str, allow_unauth = True, signin_method = 'USERNAME', group_names = [], + oauth_config = None, refresh_token_period_in_days = 365, required_signup_attributes = ['EMAIL', 'NAME', 'NICKNAME'], write_attributes = ['EMAIL', 'NAME', 'NICKNAME'], @@ -37,6 +38,9 @@ def create(cls, *, auth_resource_name:str, 'refreshTokenPeriod': refresh_token_period_in_days } + if oauth_config is not None: + user_pool_config['oAuth'] = oauth_config + id_pool_config = { 'unauthenticatedLogin': allow_unauth, 'identityPoolName': identity_pool_name diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py index 5d0734c..43ef31e 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/common.py @@ -13,6 +13,7 @@ class OperationType(Enum): def parse_arguments(): parser = argparse.ArgumentParser(description="Utility that runs the Amplify CLI in headless mode to provision backend resources for integration tests.") parser.add_argument("--backend_name", help="The name of the Amplify app.", required=True) + parser.add_argument("--oidc_provider", help="Name of the oidc provider.") parser.add_argument("--schema_dir", help="Name of the subdirectory under the schemas folder that contains the GraphQL schemas for the backend API.", required=True) parser.add_argument("--group_names", help="Comma-separated list of group names to be created.", default="") parser.add_argument("--conflict_resolution", help="Conflict resolution mode.") @@ -26,6 +27,7 @@ def parse_arguments(): LOGGER.addHandler(CONSOLE_HANDLER) AMPLIFY_AWSSDK_CLIENT = boto3.client('amplify') +SECRETS_MANAGER_CLIENT = boto3.client('secretsmanager') REGION = 'us-east-1' SCRIPTS_DIR = os.path.dirname(__file__) LOGGER.info(f"SCRIPTS_DIR = {SCRIPTS_DIR}") diff --git a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify index 59f5872..98e66f2 100755 --- a/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify +++ b/src/integ_test_resources/android/amplify/integration/cdk/scripts/setup_amplify @@ -46,16 +46,20 @@ auth_config = AuthConfigFactory.create(auth_resource_name=auth_resource_name, auth_cmd_result = amplify_app.config_auth(auth_config=auth_config, op_type=auth_op_type) if auth_cmd_result == 0: - LOGGER.info("Auth category configured.") + LOGGER.info("Auth category configured. Pushing changes.") + push_cmd_result = amplify_app.push() + if push_cmd_result == 0: + LOGGER.info("Auth category changed pushed.") + else: + LOGGER.error("Failed to push Auth category changes.") + exit(-1) else: LOGGER.error("Failed to configure Auth category.") exit(-1) -amplify_app.push() - api_key_config = ApiAuthModeFactory.create_api_key_config() user_pools_config = ApiAuthModeFactory.create_user_pools_config(auth_resource_name=f"auth{auth_resource_name}") -oidc_config = ApiAuthModeFactory.create_oidc_config(client_id='dummy', issuer_url="https://localhost/", provider_name="Dummy provider") +oidc_config = ApiAuthModeFactory.create_oidc_config(client_id='dummy', issuer_url="https://accounts.google.com/", provider_name='GoogleIntegTestOIDC') iam_config = ApiAuthModeFactory.create_iam_config() api_config = ApiConfigFactory.create(api_name=f"{amplify_backend_name}Api", op_type=api_op_type, diff --git a/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py b/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py index a91a794..d92aeb8 100644 --- a/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py +++ b/src/integ_test_resources/android/amplify/integration/cdk/stacks/amplify_deployer_stack.py @@ -91,9 +91,21 @@ def __init__(self, scope: core.App, id: str, props, **kwargs) -> None: aws_iam.PolicyStatement(actions=individual_actions, effect=aws_iam.Effect.ALLOW, resources=["*"]), ] ) + policy.attach_to_role(project.role) + policy = aws_iam.ManagedPolicy(self, + "AmplifyCodeBuildScriptRunnerSecretReaderPolicy", + managed_policy_name=f"AmplifyCodeBuildScriptRunnerSecretReaderPolicy-{cb_project_name}", + description="Policy used by the CodeBuild role that manages the creation of backend resources using the Amplify CLI", + statements=[ + aws_iam.PolicyStatement(actions=["secretsmanager:GetSecretValue"], + effect=aws_iam.Effect.ALLOW, + resources=[f"arn:aws:secretsmanager:us-east-1:{self.account}:secret:awsmobilesdk/android/*"]), + ] + ) policy.attach_to_role(project.role) + project.role.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name("AmazonS3FullAccess")) project.role.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name("AWSCloudFormationFullAccess")) project.role.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name('IAMReadOnlyAccess'))