Add examples of mocks to unit tests
MODIFY
testing-unit-cs/Testing.cs
testing-unit-cs/Testing.cs
// 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<string, object> inputs, string? provider, string? id)
+ {
+ var outputs = ImmutableDictionary.CreateBuilder<string, object>();
+
+ // 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<object> CallAsync(string token, ImmutableDictionary<string, object> inputs, string? provider)
+ {
+ var outputs = ImmutableDictionary.CreateBuilder<string, object>();
+
+ if (token == "aws:index/getAmi:getAmi")
+ {
+ outputs.Add("architecture", "x86_64");
+ outputs.Add("id", "ami-0eb1f3cdeeb8eed2a");
+ }
+
+ return Task.FromResult((object)outputs);
+ }
+ }
+
/// <summary>
/// Helper methods to streamlines unit testing experience.
/// </summary>
@@ -19,13 +52,7 @@ namespace UnitTesting
/// </summary>
public static Task<ImmutableArray<Resource>> RunAsync<T>() where T : Stack, new()
{
- var mocks = new Mock<IMocks>();
- mocks.Setup(m => m.NewResourceAsync(It.IsAny<string>(), It.IsAny<string>(),
- It.IsAny<ImmutableDictionary<string, object>>(), It.IsAny<string>(), It.IsAny<string>()))
- .ReturnsAsync((string type, string name, ImmutableDictionary<string, object> inputs, string? provider, string? id) => (name + "_id", inputs));
- mocks.Setup(m => m.CallAsync(It.IsAny<string>(), It.IsAny<ImmutableDictionary<string, object>>(), It.IsAny<string>()))
- .ReturnsAsync((string token, ImmutableDictionary<string, object> args, string? provider) => args);
- return Deployment.TestAsync<T>(mocks.Object, new TestOptions { IsPreview = false });
+ return Deployment.TestAsync<T>(new Mocks(), new TestOptions { IsPreview = false });
}
/// <summary>

MODIFY
testing-unit-cs/UnitTesting.csproj
testing-unit-cs/UnitTesting.csproj
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
- <PackageReference Include="Moq" Version="4.13.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Pulumi.Aws" Version="3.*" />

MODIFY
testing-unit-cs/WebserverStack.cs
testing-unit-cs/WebserverStack.cs
// Copyright 2016-2020, Pulumi Corporation
using Pulumi;
+using Pulumi.Aws;
using Pulumi.Aws.Ec2;
using Pulumi.Aws.Ec2.Inputs;
+using Pulumi.Aws.Inputs;
/// <summary>
/// A simple stack to be tested.
@@ -21,13 +23,26 @@ public class WebserverStack : Stack
}
});
+ 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:

MODIFY
testing-unit-go/main.go
testing-unit-go/main.go
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)
+ 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
})

MODIFY
testing-unit-go/main_test.go
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()

MODIFY
testing-unit-py/infra.py
testing-unit-py/infra.py
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 @@ group = ec2.SecurityGroup('web-secgrp', ingress=[
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)
# Uncomment to fail a test:
#user_data=user_data) # start a simple web server
+ ami=ami_id)

MODIFY
testing-unit-py/test_ec2.py
testing-unit-py/test_ec2.py
@@ -2,9 +2,21 @@ import unittest
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())

MODIFY
testing-unit-ts/ec2tests.ts
testing-unit-ts/ec2tests.ts
@@ -40,7 +40,15 @@ pulumi.runtime.setMocks({
}
},
call: function(token: string, args: any, provider?: string) {
+ switch (token) {
+ case "aws:index/getAmi:getAmi":
+ return {
+ "architecture": "x86_64",
+ "id": "ami-0eb1f3cdeeb8eed2a",
+ };
+ default:
return args;
+ }
},
});

MODIFY
testing-unit-ts/index.ts
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:

Add examples of mocks to unit tests (#807)