def test_generate_azure_w_endpoints(azure_config: types.MachConfig, tf_mock): config = azure_config config.sites[0].endpoints = [ types.Endpoint(key="public", url="api.mach-example.com") ] data = tf.generate(parse.parse_config(config)) # 'public' endpoint not used in component yet; no resources created assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps", "azurerm_resource_group.main", ] config.components[0].endpoints = { "main": "public", } data = tf.generate(parse.parse_config(config)) # Frontdoor instance need to be created since a component now uses it expected_resources = [ "azurerm_app_service_plan.functionapps", "azurerm_dns_cname_record.public", "azurerm_frontdoor.app-service", "azurerm_frontdoor_custom_https_configuration.public", "azurerm_resource_group.main", ] assert tf.get_resource_ids(data) == expected_resources config.sites[0].endpoints.append( types.Endpoint(key="private", url="private-api.mach-example.com")) data = tf.generate(parse.parse_config(config)) # We've added an extra endpoint definition, but hasn't been used. # List of resources should be the same as previous check assert tf.get_resource_ids(data) == expected_resources config.components.append( types.ComponentConfig( name="logger", source="some-source//terraform", version="1.0", endpoints={ "main": "private", }, )) config.sites[0].components.append(types.Component(name="logger", )) data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps", "azurerm_dns_cname_record.private", "azurerm_dns_cname_record.public", "azurerm_frontdoor.app-service", "azurerm_frontdoor_custom_https_configuration.private", "azurerm_frontdoor_custom_https_configuration.public", "azurerm_resource_group.main", ]
def test_parse_w_variables(config: types.MachConfig, encrypted): config.sites[0].components[0].variables = { "my-value": r"${var.site1.my-value}" } config.variables_encrypted = encrypted with pytest.raises(Exception): config = parse.parse_config(config) config.variables = {"site1": {"my-value": "foo"}} config = parse.parse_config(config) if encrypted: assert (config.sites[0].components[0].variables["my-value"] == 'data.sops_external.variables.data["site1.my-value"]') else: assert config.sites[0].components[0].variables["my-value"] == "foo"
def test_validate_aws_default_endpoint(config: types.MachConfig): """It must be possible for a component to use the default API Gateway endpoint.""" config.components[0].endpoints = { "main": "public", } config = parse.parse_config(config) with pytest.raises(ValidationError) as e: validate.validate_config(config) assert str(e.value) == "Missing required endpoints public" config.components[0].endpoints = { "main": "default", } config = parse.parse_config(config) validate.validate_config(config)
def test_generate_azure_service_plans(azure_config: types.MachConfig, tf_mock): config = azure_config config.components[0].azure = None config.sites[0].components.append( types.Component( name="payment", ) ) data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "azurerm_resource_group.main", ] config.sites[0].components[0].azure.service_plan = "default" data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps", "azurerm_resource_group.main", ] config.general_config.azure.service_plans["premium"] = types.ServicePlan( kind="Linux", tier="PremiumV2", size="P2v2", ) data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps", "azurerm_resource_group.main", ] config.sites[0].components[0].azure.service_plan = "premium" data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps_premium", "azurerm_resource_group.main", ] config.sites[0].components[1].azure.service_plan = "default" data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps", "azurerm_app_service_plan.functionapps_premium", "azurerm_resource_group.main", ]
def test_generate_aws_w_default_endpoint(config: types.MachConfig, tf_mock): """When endpoint 'default' is used, no custom domain has to be set.""" data = tf.generate(parse.parse_config(config)) # 'public' endpoint not used in component yet; no resources created assert "resource" not in data config.components[0].endpoints = { "main": "default", } data = tf.generate(parse.parse_config(config)) # API gateway items need to be created since a component now uses it expected_resources = [ "aws_apigatewayv2_api.default_gateway", "aws_apigatewayv2_route.default_application", "aws_apigatewayv2_stage.default_default", ] assert tf.get_resource_ids(data) == expected_resources
def test_parse_azure_service_plans(azure_config: types.MachConfig): config = azure_config # Sanity check assert not config.general_config.azure.service_plans config = parse.parse_config(config) assert "default" in config.general_config.azure.service_plans assert config.general_config.azure.service_plans[ "default"] == types.ServicePlan(kind="FunctionApp", tier="Dynamic", size="Y1")
def test_generate_azure_w_default_endpoint(azure_config: types.MachConfig, tf_mock): """When endpoint 'default' is used, no custom domain has to be set.""" config = azure_config data = tf.generate(parse.parse_config(config)) # 'public' endpoint not used in component yet; no resources created assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps", "azurerm_resource_group.main", ] config.components[0].endpoints = { "main": "default", } data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "azurerm_app_service_plan.functionapps", "azurerm_frontdoor.app-service", "azurerm_resource_group.main", ]
def test_validate_component_endpoint(config: types.MachConfig): """An endpoint defined on a component must exist for all sites that use that component.""" config.components[0].endpoints = { "main": "public", } config = parse.parse_config(config) with pytest.raises(ValidationError): validate.validate_config(config) config.sites[0].endpoints = [ types.Endpoint( key="public", url="api.mach-example.com", ), types.Endpoint( key="services", url="services.mach-example.com", ), ] validate.validate_config(config) new_site = types.Site( identifier="unittest-nl", components=[], aws=types.SiteAWSSettings( account_id=1234567890, region="eu-central-1", ), ) config.sites.append(new_site) validate.validate_config(config) new_site.components.append(types.Component(name="api-extensions", )) config = parse.parse_config(config) with pytest.raises(ValidationError): validate.validate_config(config)
def test_parse_endpoints(config: types.MachConfig): config.sites[0].endpoints = [ types.Endpoint( key="public", url="api.mach-example.com", ), types.Endpoint( key="services", url="services.mach-example.com", ), ] config = parse.parse_config(config) for endpoint in config.sites[0].endpoints: assert endpoint.zone == "mach-example.com"
def test_aws_endpoint_with_cdn_generates_one_us_east_provider( config: types.MachConfig, tf_mock): config.sites[0].endpoints = [ types.Endpoint(key="public", url="api.mach-example.com", aws=AWSEndpoint(enable_cdn=True)) ] config.components[0].endpoints = { "main": "public", } data = tf.generate(parse.parse_config(config)) assert data["provider"]["aws"] == { "alias": ["mach-cf-us-east-1"], "region": ["us-east-1"], }
def test_generate_aws_w_endpoints(config: types.MachConfig, tf_mock): config.sites[0].endpoints = [ types.Endpoint(key="public", url="api.mach-example.com") ] data = tf.generate(parse.parse_config(config)) # 'public' endpoint not used in component yet; no resources created assert "resource" not in data config.components[0].endpoints = { "main": "public", } data = tf.generate(parse.parse_config(config)) # API gateway items need to be created since a component now uses it expected_resources = [ "aws_acm_certificate.public", "aws_apigatewayv2_api.public_gateway", "aws_apigatewayv2_api_mapping.public", "aws_apigatewayv2_domain_name.public", "aws_apigatewayv2_route.public_application", "aws_apigatewayv2_stage.public_default", "aws_route53_record.public", "aws_route53_record.public_acm_validation", ] expected_data_sources = [ "aws_route53_zone.mach_examplecom", ] assert tf.get_resource_ids(data) == expected_resources assert tf.get_data_ids(data) == expected_data_sources config.sites[0].endpoints.append( types.Endpoint(key="private", url="private-api.mach-services.io")) data = tf.generate(parse.parse_config(config)) # We've added an extra endpoint definition, but hasn't been used. # List of resources should be the same as previous check assert tf.get_resource_ids(data) == expected_resources assert tf.get_data_ids(data) == expected_data_sources config.components.append( types.ComponentConfig( name="logger", source="some-source//terraform", version="1.0", endpoints={ "main": "private", }, )) config.sites[0].components.append(types.Component(name="logger", )) data = tf.generate(parse.parse_config(config)) assert tf.get_resource_ids(data) == [ "aws_acm_certificate.private", "aws_acm_certificate.public", "aws_apigatewayv2_api.private_gateway", "aws_apigatewayv2_api.public_gateway", "aws_apigatewayv2_api_mapping.private", "aws_apigatewayv2_api_mapping.public", "aws_apigatewayv2_domain_name.private", "aws_apigatewayv2_domain_name.public", "aws_apigatewayv2_route.private_application", "aws_apigatewayv2_route.public_application", "aws_apigatewayv2_stage.private_default", "aws_apigatewayv2_stage.public_default", "aws_route53_record.private", "aws_route53_record.private_acm_validation", "aws_route53_record.public", "aws_route53_record.public_acm_validation", ] assert tf.get_data_ids(data) == [ "aws_route53_zone.mach_examplecom", "aws_route53_zone.mach_servicesio", ]
def parsed_config(config): return parse.parse_config(config)
def parsed_azure_config(azure_config): return parse.parse_config(azure_config)
def test_generate_w_stores(config: types.MachConfig, tf_mock): config.sites[0].commercetools = types.CommercetoolsSettings( project_key="ct-unit-test", client_id="a96e59be-24da-4f41-a6cf-d61d7b6e1766", client_secret="98c32de8-1a6c-45a9-a718-d3cce5201799", scopes="manage_project:ct-unit-test", project_settings=types.CommercetoolsProjectSettings( languages=["nl-NL"], countries=["NL"], currencies=["EUR"], ), stores=[ types.CommercetoolsStore( name={ "en-GB": "Default store", }, key="main-store", ), types.CommercetoolsStore( name={ "en-GB": "Some other store", }, key="other-store", ), types.CommercetoolsStore( name={ "en-GB": "Forgotten store", }, key="forgotten-store", ), ], ) config.components[0].integrations = ["aws", "commercetools"] data = tf.generate(parse.parse_config(config)) assert len(data.resource.commercetools_store) == 3 assert "main-store" in data.resource.commercetools_store assert "other-store" in data.resource.commercetools_store assert "forgotten-store" in data.resource.commercetools_store assert len(data.module["api-extensions"].ct_stores) == 3 for store_key, store in data.module["api-extensions"].ct_stores.items(): assert store["key"] == store_key assert not store["variables"] assert not store["secrets"] config.sites[0].components[0].store_variables = { "main-store": { "FOO": "BAR", "EXTRA": "VALUES", }, "other-store": { "FOO": "SOMETHING ELSE", }, } config.sites[0].components[0].store_secrets = { "main-store": { "PAYMENT_KEY": "TLrlDf6XhKkXFGGHeQGY", }, } data = tf.generate(parse.parse_config(config)) main_store = data.module["api-extensions"].ct_stores["main-store"] other_store = data.module["api-extensions"].ct_stores["other-store"] assert len(main_store.variables) == 2 assert len(other_store.variables) == 1 assert len(main_store.secrets) == 1 assert not other_store.secrets
def test_commercetools_frontend_credentials(config: types.MachConfig, tf_mock): config.sites[0].commercetools = types.CommercetoolsSettings( project_key="ct-unit-test", client_id="a96e59be-24da-4f41-a6cf-d61d7b6e1766", client_secret="98c32de8-1a6c-45a9-a718-d3cce5201799", scopes="manage_project:ct-unit-test", project_settings=types.CommercetoolsProjectSettings( languages=["nl-NL"], countries=["NL"], currencies=["EUR"], ), stores=[ types.CommercetoolsStore( name={ "en-GB": "Default store", }, key="main-store", ), types.CommercetoolsStore( name={ "en-GB": "Some other store", }, key="other-store", ), types.CommercetoolsStore( name={ "en-GB": "Forgotten store", }, key="forgotten-store", ), ], ) data = tf.generate(parse.parse_config(config)) assert list(data.resource.commercetools_api_client.keys()) == [ "frontend_credentials_main-store", "frontend_credentials_other-store", "frontend_credentials_forgotten-store", ] assert data.resource.commercetools_api_client[ "frontend_credentials_main-store"].scope == [ "create_anonymous_token:ct-unit-test", "manage_my_profile:ct-unit-test", "manage_my_profile:ct-unit-test:main-store", "manage_my_orders:ct-unit-test", "manage_my_orders:ct-unit-test:main-store", "manage_my_shopping_lists:ct-unit-test", "manage_my_payments:ct-unit-test", "view_products:ct-unit-test", "view_project_settings:ct-unit-test", ] config.sites[0].commercetools.frontend.create_credentials = False data = tf.generate(parse.parse_config(config)) assert "commercetools_api_client" not in data.resource config.sites[0].commercetools.frontend.create_credentials = True config.sites[0].commercetools.frontend.permission_scopes = [ "manage_my_profile", "manage_my_orders", "view_products", "manage_my_payments", "create_anonymous_token", "view_stores", ] data = tf.generate(parse.parse_config(config)) assert data.resource.commercetools_api_client[ "frontend_credentials_main-store"].scope == [ "manage_my_profile:ct-unit-test", "manage_my_profile:ct-unit-test:main-store", "manage_my_orders:ct-unit-test", "manage_my_orders:ct-unit-test:main-store", "view_products:ct-unit-test", "manage_my_payments:ct-unit-test", "create_anonymous_token:ct-unit-test", "view_stores:ct-unit-test", ]
def test_site(config: types.MachConfig): config.components.append( types.ComponentConfig( name="private-api", source="some-private-source/terraform", version="1.0", )) config.sites[0].components.append(types.Component(name="private-api")) config.sites[0].endpoints = [ types.Endpoint( key="public", url="api.example.com", ), types.Endpoint( key="private", url="private-api.example.com", ), ] config = parse.parse_config(config) site = config.sites[0] assert site.used_endpoints == [] config.components[0].endpoints = { "main": "public", } config = parse.parse_config(config) assert site.used_endpoints == [ types.Endpoint(key="public", url="api.example.com", components=[site.components[0]]) ] config.components[1].endpoints = { "main": "public", } config = parse.parse_config(config) assert site.used_endpoints == [ types.Endpoint( key="public", url="api.example.com", components=[site.components[0], site.components[1]], ) ] config.components[1].endpoints = { "main": "private", } config = parse.parse_config(config) assert site.used_endpoints == [ types.Endpoint( key="public", url="api.example.com", components=[ site.components[0], ], ), types.Endpoint( key="private", url="private-api.example.com", components=[site.components[1]], ), ]