import pytest import random import string import os import requests import boto3 from fixtures import get_order, get_product, iam_auth # pylint: disable=import-error,no-name-in-module from helpers import get_parameter # pylint: disable=import-error,no-name-in-module @pytest.fixture(scope="module") def products_table_name(): """ Products DynamoDB table name """ return get_parameter("/ecommerce/{Environment}/products/table/name") @pytest.fixture(scope="module") def orders_table_name(): """ Orders DynamoDB table name """ return get_parameter("/ecommerce/{Environment}/orders/table/name") @pytest.fixture(scope="module") def user_pool_id(): """ Cognito User Pool ID """ return get_parameter("/ecommerce/{Environment}/users/user-pool/id") @pytest.fixture(scope="module") def delivery_pricing_api_url(): """ Delivery Pricing API """ return get_parameter("/ecommerce/{Environment}/delivery-pricing/api/url") @pytest.fixture def api_id(): """ Frontend GraphQL API ID """ return get_parameter("/ecommerce/{Environment}/frontend-api/api/id") @pytest.fixture def api_url(): """ Frontend GraphQL API URL """ return get_parameter("/ecommerce/{Environment}/frontend-api/api/url") @pytest.fixture def payment_3p_api_url(): return get_parameter("/ecommerce/{Environment}/payment-3p/api/url") @pytest.fixture def api_key(api_id): """ API Key for AppSync """ appsync = boto3.client("appsync") response = appsync.create_api_key(apiId=api_id) yield response["apiKey"]["id"] appsync.delete_api_key(apiId=api_id, id=response["apiKey"]["id"]) @pytest.fixture(scope="module") def password(): """ Generate a unique password for the user """ return "".join( random.choices(string.ascii_uppercase, k=10) + random.choices(string.ascii_lowercase, k=10) + random.choices(string.digits, k=5) + random.choices(string.punctuation, k=3) ) @pytest.fixture(scope="module") def email(): """ Generate a unique email address for the user """ return "".join(random.choices(string.ascii_lowercase, k=20))+"@example.local" @pytest.fixture(scope="module") def client_id(user_pool_id): """ Return a user pool client """ cognito = boto3.client("cognito-idp") # Create a Cognito User Pool Client response = cognito.create_user_pool_client( UserPoolId=user_pool_id, ClientName="ecommerce-{}-frontend-api-test".format(os.environ["ECOM_ENVIRONMENT"]), GenerateSecret=False, ExplicitAuthFlows=["ADMIN_NO_SRP_AUTH"] ) # Return the client ID client_id = response["UserPoolClient"]["ClientId"] yield client_id # Delete the client cognito.delete_user_pool_client( UserPoolId=user_pool_id, ClientId=client_id ) @pytest.fixture(scope="module") def user_id(user_pool_id, email, password): """ User ID generated by Cognito """ cognito = boto3.client("cognito-idp") # Create a Cognito user response = cognito.admin_create_user( UserPoolId=user_pool_id, Username=email, UserAttributes=[{ "Name": "email", "Value": email }], MessageAction="SUPPRESS" ) user_id = response["User"]["Username"] cognito.admin_set_user_password( UserPoolId=user_pool_id, Username=user_id, Password=password, Permanent=True ) # Return the user ID yield user_id # Delete the user cognito.admin_delete_user( UserPoolId=user_pool_id, Username=user_id ) @pytest.fixture(scope="module") def jwt_token(user_pool_id, user_id, client_id, email, password): """ Returns a JWT token for API Gateway """ cognito = boto3.client("cognito-idp") response = cognito.admin_initiate_auth( UserPoolId=user_pool_id, ClientId=client_id, AuthFlow="ADMIN_NO_SRP_AUTH", AuthParameters={ "USERNAME": email, "PASSWORD": password } ) return response["AuthenticationResult"]["IdToken"] @pytest.fixture(scope="function") def product(get_product, products_table_name): """ Product """ table = boto3.resource("dynamodb").Table(products_table_name) # pylint: disable=no-member product = get_product() table.put_item(Item=product) yield product table.delete_item(Key={"productId": product["productId"]}) @pytest.fixture(scope="function") def order_request(get_order, product, iam_auth, delivery_pricing_api_url, payment_3p_api_url): """ Order Request """ order = get_order() # Grab the correct delivery price from the backend res = requests.post( "{}/backend/pricing".format(delivery_pricing_api_url), auth=iam_auth(delivery_pricing_api_url), json={ "products": [product], "address": order["address"] } ) delivery_price = res.json()["pricing"] # Get a payment token total = delivery_price + sum([p["price"]*p.get("quantity", 1) for p in order["products"]]) res = requests.post( "{}/preauth".format(payment_3p_api_url), json={ "cardNumber": "1234567890123456", "amount": total } ) payment_token = res.json()["paymentToken"] return { "products": [product], "address": order["address"], "deliveryPrice": delivery_price, "paymentToken": payment_token } def test_create_order(jwt_token, api_url, order_request): """ Test createOrder """ headers = {"Authorization": jwt_token} query = """ mutation ($order: CreateOrderRequest!) { createOrder(order: $order) { success message errors order { orderId userId } } } """ variables = { "order": order_request } response = requests.post(api_url, json={"query": query, "variables": variables}, headers=headers) data = response.json() print(data) assert "data" in data assert data["data"] is not None assert "createOrder" in data["data"] result = data["data"]["createOrder"] assert result["success"] == True assert "order" in result def test_get_products(api_url, product, api_key): """ Test getProducts """ headers = {"X-Api-Key": api_key} query = """ query { getProducts { products { productId name } } } """ response = requests.post(api_url, json={"query": query}, headers=headers) data = response.json() assert "data" in data assert data["data"] is not None assert "getProducts" in data["data"] assert "products" in data["data"]["getProducts"] found = False for res_product in data["data"]["getProducts"]["products"]: if res_product["productId"] == product["productId"]: found = True assert found == True def test_get_product(api_url, product, api_key): """ Test getProduct """ headers = {"X-Api-Key": api_key} query = """ query ($productId: ID!) { getProduct(productId: $productId) { productId name } } """ variables = { "productId": product["productId"] } response = requests.post(api_url, json={"query": query, "variables": variables}, headers=headers) data = response.json() assert "data" in data assert data["data"] is not None assert "getProduct" in data["data"] assert data["data"]["getProduct"]["productId"] == product["productId"] assert data["data"]["getProduct"]["name"] == product["name"] def test_get_orders(jwt_token, api_url): """ Test getOrders """ headers = {"Authorization": jwt_token} query = """ query { getOrders { orders { orderId userId } } } """ response = requests.post(api_url, json={"query": query}, headers=headers) data = response.json() print(data) assert "data" in data assert "getOrders" in data["data"] assert "orders" in data["data"]["getOrders"] def test_get_delivery_pricing(get_order, jwt_token, api_url): """ Test getDeliveryPricing """ order = get_order() headers = {"Authorization": jwt_token} query = """ query($input: DeliveryPricingInput!) { getDeliveryPricing(input: $input) { pricing } } """ variables = { "input": { "products": order["products"], "address": order["address"] } } print("VARIABLES", variables) response = requests.post(api_url, json={"query": query, "variables": variables}, headers=headers) data = response.json() print(data) assert "data" in data assert "getDeliveryPricing" in data["data"] assert "pricing" in data["data"]["getDeliveryPricing"]