diff --git a/testing-unit-cs/Testing.cs b/testing-unit-cs/Testing.cs index 4c04fc9ac..33c50d3cf 100644 --- a/testing-unit-cs/Testing.cs +++ b/testing-unit-cs/Testing.cs @@ -1,14 +1,47 @@ // Copyright 2016-2020, Pulumi Corporation -using System; using System.Collections.Immutable; using System.Threading.Tasks; -using Moq; using Pulumi; using Pulumi.Testing; namespace UnitTesting { + class Mocks : IMocks + { + public Task<(string id, object state)> NewResourceAsync(string type, string name, ImmutableDictionary inputs, string? provider, string? id) + { + var outputs = ImmutableDictionary.CreateBuilder(); + + // Forward all input parameters as resource outputs, so that we could test them. + outputs.AddRange(inputs); + + if (type == "aws:ec2/instance:Instance") + { + outputs.Add("publicIp", "203.0.113.12"); + outputs.Add("publicDns", "ec2-203-0-113-12.compute-1.amazonaws.com"); + } + + // Default the resource ID to `{name}_id`. + // We could also format it as `/subscription/abc/resourceGroups/xyz/...` if that was important for tests. + id ??= $"{name}_id"; + return Task.FromResult((id, (object)outputs)); + } + + public Task CallAsync(string token, ImmutableDictionary inputs, string? provider) + { + var outputs = ImmutableDictionary.CreateBuilder(); + + if (token == "aws:index/getAmi:getAmi") + { + outputs.Add("architecture", "x86_64"); + outputs.Add("id", "ami-0eb1f3cdeeb8eed2a"); + } + + return Task.FromResult((object)outputs); + } + } + /// /// Helper methods to streamlines unit testing experience. /// @@ -19,13 +52,7 @@ public static class Testing /// public static Task> RunAsync() where T : Stack, new() { - var mocks = new Mock(); - mocks.Setup(m => m.NewResourceAsync(It.IsAny(), It.IsAny(), - It.IsAny>(), It.IsAny(), It.IsAny())) - .ReturnsAsync((string type, string name, ImmutableDictionary inputs, string? provider, string? id) => (name + "_id", inputs)); - mocks.Setup(m => m.CallAsync(It.IsAny(), It.IsAny>(), It.IsAny())) - .ReturnsAsync((string token, ImmutableDictionary args, string? provider) => args); - return Deployment.TestAsync(mocks.Object, new TestOptions { IsPreview = false }); + return Deployment.TestAsync(new Mocks(), new TestOptions { IsPreview = false }); } /// diff --git a/testing-unit-cs/UnitTesting.csproj b/testing-unit-cs/UnitTesting.csproj index de8d79caf..ad74ae550 100644 --- a/testing-unit-cs/UnitTesting.csproj +++ b/testing-unit-cs/UnitTesting.csproj @@ -9,7 +9,6 @@ - diff --git a/testing-unit-cs/WebserverStack.cs b/testing-unit-cs/WebserverStack.cs index 1c5bfe94f..4ce807d0d 100644 --- a/testing-unit-cs/WebserverStack.cs +++ b/testing-unit-cs/WebserverStack.cs @@ -1,8 +1,10 @@ // Copyright 2016-2020, Pulumi Corporation using Pulumi; +using Pulumi.Aws; using Pulumi.Aws.Ec2; using Pulumi.Aws.Ec2.Inputs; +using Pulumi.Aws.Inputs; /// /// A simple stack to be tested. @@ -21,13 +23,26 @@ public WebserverStack() } }); + var amiId = Output.Create(GetAmi.InvokeAsync(new GetAmiArgs + { + MostRecent = true, + Owners = {"099720109477"}, + Filters = { + new GetAmiFilterArgs + { + Name = "name", + Values = {"ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"}, + } + } + })).Apply(ami => ami.Id); + // var userData = "#!/bin/bash echo \"Hello, World!\" > index.html nohup python -m SimpleHTTPServer 80 &"; var server = new Instance("web-server-www", new InstanceArgs { InstanceType = "t2.micro", - SecurityGroups = { group.Name }, // reference the group object above - Ami = "ami-c55673a0", // AMI for us-east-2 (Ohio), + VpcSecurityGroupIds = { group.Id }, // reference the group object above + Ami = amiId, // Comment out to fail a test: Tags = { { "Name", "webserver" }}, // Uncomment to fail a test: diff --git a/testing-unit-go/main.go b/testing-unit-go/main.go index 5c6352f66..77585f620 100644 --- a/testing-unit-go/main.go +++ b/testing-unit-go/main.go @@ -1,6 +1,7 @@ package main import ( + "github.com/pulumi/pulumi-aws/sdk/v3/go/aws" "github.com/pulumi/pulumi-aws/sdk/v3/go/aws/ec2" "github.com/pulumi/pulumi/sdk/v2/go/pulumi" ) @@ -32,14 +33,29 @@ func createInfrastructure(ctx *pulumi.Context) (*infrastructure, error) { return nil, err } + mostRecent := true + ami, err := aws.GetAmi(ctx, &aws.GetAmiArgs{ + Filters: []aws.GetAmiFilter{ + { + Name: "name", + Values: []string{"ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"}, + }, + }, + Owners: []string{"137112412989"}, + MostRecent: &mostRecent, + }) + if err != nil { + return nil, err + } + const userData = `#!/bin/bash echo "Hello, World!" > index.html nohup python -m SimpleHTTPServer 80 &` server, err := ec2.NewInstance(ctx, "web-server-www", &ec2.InstanceArgs{ - InstanceType: pulumi.String("t2-micro"), - SecurityGroups: pulumi.StringArray{group.ID()}, // reference the group object above - Ami: pulumi.String("ami-c55673a0"), // AMI for us-east-2 (Ohio) + InstanceType: pulumi.String("t2-micro"), + VpcSecurityGroupIds: pulumi.StringArray{group.ID()}, // reference the group object above + Ami: pulumi.String(ami.Id), // Comment out to fail a test: - Tags: pulumi.Map{"Name": pulumi.String("webserver")}, + Tags: pulumi.StringMap{"Name": pulumi.String("webserver")}, // Uncomment to fail a test: //UserData: pulumi.String(userData), // start a simple web server }) diff --git a/testing-unit-go/main_test.go b/testing-unit-go/main_test.go index bb42ae1a7..cc77ac942 100644 --- a/testing-unit-go/main_test.go +++ b/testing-unit-go/main_test.go @@ -13,12 +13,22 @@ import ( type mocks int // Create the mock. -func (mocks) NewResource(typeToken, name string, inputs resource.PropertyMap, provider, id string) (string, resource.PropertyMap, error) { - return name + "_id", inputs, nil +func (mocks) NewResource(token, name string, inputs resource.PropertyMap, provider, id string) (string, resource.PropertyMap, error) { + outputs := inputs.Mappable() + if token == "aws:ec2/instance:Instance" { + outputs["publicIp"] = "203.0.113.12" + outputs["publicDns"] = "ec2-203-0-113-12.compute-1.amazonaws.com" + } + return name + "_id", resource.NewPropertyMapFromMap(outputs), nil } func (mocks) Call(token string, args resource.PropertyMap, provider string) (resource.PropertyMap, error) { - return args, nil + outputs := map[string]interface{}{} + if token == "aws:index/getAmi:getAmi" { + outputs["architecture"] = "x86_64" + outputs["id"] = "ami-0eb1f3cdeeb8eed2a" + } + return resource.NewPropertyMapFromMap(outputs), nil } // Applying unit tests. @@ -33,7 +43,7 @@ func TestInfrastructure(t *testing.T) { // Test if the service has tags and a name tag. pulumi.All(infra.server.URN(), infra.server.Tags).ApplyT(func(all []interface{}) error { urn := all[0].(pulumi.URN) - tags := all[1].(map[string]interface{}) + tags := all[1].(map[string]string) assert.Containsf(t, tags, "Name", "missing a Name tag on server %v", urn) wg.Done() diff --git a/testing-unit-py/infra.py b/testing-unit-py/infra.py index fac40eda4..a4b2641f5 100644 --- a/testing-unit-py/infra.py +++ b/testing-unit-py/infra.py @@ -1,5 +1,5 @@ import pulumi -from pulumi_aws import ec2 +from pulumi_aws import ec2, get_ami, GetAmiFilterArgs group = ec2.SecurityGroup('web-secgrp', ingress=[ # Uncomment to fail a test: @@ -9,11 +9,21 @@ user_data = '#!/bin/bash echo "Hello, World!" > index.html nohup python -m SimpleHTTPServer 80 &' -server = ec2.Instance('web-server-www;', +ami_id = get_ami( + most_recent=True, + owners=["099720109477"], + filters=[ + GetAmiFilterArgs( + name="name", + values=["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"] + )] +).id + +server = ec2.Instance('web-server-www', instance_type="t2.micro", - security_groups=[ group.name ], # reference the group object above + vpc_security_group_ids=[ group.id ], # reference the group object above # Comment out to fail a test: - tags={'Name': 'webserver'}, # name tag - ami="ami-c55673a0") # AMI for us-east-2 (Ohio) + tags={'Name': 'webserver'}, # name tag # Uncomment to fail a test: - #user_data=user_data) # start a simple web server + #user_data=user_data) # start a simple web server + ami=ami_id) diff --git a/testing-unit-py/test_ec2.py b/testing-unit-py/test_ec2.py index 27d4c7c6a..c3dc682a4 100644 --- a/testing-unit-py/test_ec2.py +++ b/testing-unit-py/test_ec2.py @@ -2,9 +2,21 @@ import pulumi class MyMocks(pulumi.runtime.Mocks): - def new_resource(self, type_, name, inputs, provider, id_): - return [name + '_id', inputs] + def new_resource(self, token, name, inputs, provider, id_): + outputs = inputs + if token == "aws:ec2/instance:Instance": + outputs = { + **inputs, + "publicIp": "203.0.113.12", + "publicDns": "ec2-203-0-113-12.compute-1.amazonaws.com", + } + return [name + '_id', outputs] def call(self, token, args, provider): + if token == "aws:index/getAmi:getAmi": + return { + "architecture": "x86_64", + "id": "ami-0eb1f3cdeeb8eed2a", + } return {} pulumi.runtime.set_mocks(MyMocks()) diff --git a/testing-unit-ts/ec2tests.ts b/testing-unit-ts/ec2tests.ts index 1bd2a74be..38be6df31 100644 --- a/testing-unit-ts/ec2tests.ts +++ b/testing-unit-ts/ec2tests.ts @@ -40,7 +40,15 @@ pulumi.runtime.setMocks({ } }, call: function(token: string, args: any, provider?: string) { - return args; + switch (token) { + case "aws:index/getAmi:getAmi": + return { + "architecture": "x86_64", + "id": "ami-0eb1f3cdeeb8eed2a", + }; + default: + return args; + } }, }); diff --git a/testing-unit-ts/index.ts b/testing-unit-ts/index.ts index 36f73a7e1..0a12a0d66 100644 --- a/testing-unit-ts/index.ts +++ b/testing-unit-ts/index.ts @@ -10,10 +10,19 @@ export const group = new aws.ec2.SecurityGroup("web-secgrp", { ], }); +const amiId = aws.getAmi({ + mostRecent: true, + owners: ["099720109477"], + filters: [{ + name: "name", + values: ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"], + }], +}).then(ami => ami.id); + export const server = new aws.ec2.Instance("web-server-www", { instanceType: "t2.micro", - securityGroups: [ group.name ], // reference the group object above - ami: "ami-c55673a0", // AMI for us-east-2 (Ohio), + vpcSecurityGroupIds: [ group.id ], // reference the group object above + ami: amiId, // comment to fail a test: tags: { Name: "www-server" }, // name tag // uncomment to fail a test: