Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests to templates #861

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aws-go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ go 1.20
require (
github.com/pulumi/pulumi-aws/sdk/v6 v6.37.1
github.com/pulumi/pulumi/sdk/v3 v3.117.0
github.com/stretchr/testify v1.9.0
)
27 changes: 23 additions & 4 deletions aws-go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,35 @@ import (
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

type infrastructure struct {
bucket *s3.BucketV2
}

func createInfrastructure(ctx *pulumi.Context) (*infrastructure, error) {
// Create an AWS resource (S3 Bucket) with tags.
bucket, err := s3.NewBucketV2(ctx, "my-bucket", &s3.BucketV2Args{
Tags: pulumi.StringMap{
"Name": pulumi.String("My bucket"),
},
})
if err != nil {
return nil, err
}

return &infrastructure{
bucket: bucket,
}, nil
}

func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Create an AWS resource (S3 Bucket)
bucket, err := s3.NewBucketV2(ctx, "my-bucket", nil)
infra, err := createInfrastructure(ctx)
if err != nil {
return err
}

// Export the name of the bucket
ctx.Export("bucketName", bucket.ID())
// Export the name of the bucket.
ctx.Export("bucketName", infra.bucket.ID())
return nil
})
}
50 changes: 50 additions & 0 deletions aws-go/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package main

import (
"sync"
"testing"

"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/stretchr/testify/assert"
)

type mocks int

// Mock calls to create new resources and return a canned response.
func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
// Here, we're returning a same-shaped object for all resource types.
// We could, however, use the arguments passed into this function to
// customize the mocked-out properties of a particular resource.
// See the unit-testing docs for details:
// https://www.pulumi.com/docs/iac/concepts/testing/unit/
return args.Name + "_id", args.Inputs, nil
}

// Mock function calls and return an empty response.
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
return resource.PropertyMap{}, nil
}

func TestInfrastructure(t *testing.T) {
err := pulumi.RunErr(func(ctx *pulumi.Context) error {
var wg sync.WaitGroup

// Example test. To run, uncomment and run `go test`.
// infra, err := createInfrastructure(ctx)
// assert.NoError(t, err)

// wg.Add(1)
// infra.bucket.Tags.ApplyT(func(tags map[string]string) error {
// assert.NotNil(t, tags)
// assert.Contains(t, tags, "Name")

// wg.Done()
// return nil
// })

wg.Wait()
return nil
}, pulumi.WithMocks("project", "stack", mocks(0)))
assert.NoError(t, err)
}
3 changes: 3 additions & 0 deletions aws-python/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
*.pyc
__pycache__
.pytest_cache
venv/
.venv/
10 changes: 3 additions & 7 deletions aws-python/__main__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
"""An AWS Python Pulumi program"""

import pulumi
from pulumi_aws import s3

# Create an AWS resource (S3 Bucket)
bucket = s3.BucketV2('my-bucket')
import infra

# Export the name of the bucket
pulumi.export('bucket_name', bucket.id)
# Export the name of the bucket.
pulumi.export("bucket_name", infra.bucket.id)
9 changes: 9 additions & 0 deletions aws-python/infra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import pulumi
from pulumi_aws import s3

# Create an AWS resource (S3 Bucket) with tags.
bucket = s3.BucketV2("my-bucket",
tags={
"Name": "My bucket",
},
)
1 change: 1 addition & 0 deletions aws-python/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pulumi>=3.0.0,<4.0.0
pulumi-aws>=6.0.2,<7.0.0
pytest
Empty file added aws-python/tests/__init__.py
Empty file.
42 changes: 42 additions & 0 deletions aws-python/tests/test_infra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import asyncio
from typing import TypeVar

import pulumi


# Test helper to convert a Pulumi Output to a Future.
# This should only be used in tests.
T = TypeVar("T")
def future_of(output: pulumi.Output[T]) -> asyncio.Future[T]:
loop = asyncio.get_running_loop()
future = loop.create_future()
output.apply(lambda x: future.set_result(x))
return future


class MyMocks(pulumi.runtime.Mocks):
# Mock calls to create new resources and return a canned response.
def new_resource(self, args: pulumi.runtime.MockResourceArgs):
# Here, we're returning a same-shaped object for all resource types.
# We could, however, use the arguments passed into this function to
# customize the mocked-out properties of a particular resource.
# See the unit-testing docs for details:
# https://www.pulumi.com/docs/iac/concepts/testing/unit/
return [args.name + "_id", args.inputs]

# Mock function calls and return an empty response.
def call(self, args: pulumi.runtime.MockCallArgs):
return {}

# Put Pulumi in unit-test mode, mocking all calls to cloud-provider APIs.
pulumi.runtime.set_mocks(MyMocks())

# Now import the code that creates resources, and then test it.
import infra

# Example test. To run, uncomment and run `python -m pytest --disable-pytest-warnings`.
# @pulumi.runtime.test
# async def test_bucket_tags():
# tags = await future_of(infra.bucket.tags)
# assert tags, "bucket must have tags"
# assert "Name" in tags, "bucket must have a Name tag"
11 changes: 3 additions & 8 deletions aws-typescript/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
import * as infra from "./infra";

// Create an AWS resource (S3 Bucket)
const bucket = new aws.s3.BucketV2("my-bucket");

// Export the name of the bucket
export const bucketName = bucket.id;
// Export the name of the bucket.
export const bucketName = infra.bucket.id;
10 changes: 10 additions & 0 deletions aws-typescript/infra.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

// Create an AWS resource (S3 Bucket) with tags.
export const bucket = new aws.s3.BucketV2("my-bucket", {
tags: {
"Name": "My bucket",
},
});
7 changes: 7 additions & 0 deletions aws-typescript/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
testEnvironment: "node",
transform: {
"^.+.tsx?$": ["ts-jest",{}],
},
};
6 changes: 6 additions & 0 deletions aws-typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
"name": "${PROJECT}",
"main": "index.ts",
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^18",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"typescript": "^5.0.0"
},
"dependencies": {
"@pulumi/aws": "^6.0.0",
"@pulumi/awsx": "^2.0.2",
"@pulumi/pulumi": "^3.113.0"
},
"scripts": {
"test": "jest"
}
}
51 changes: 51 additions & 0 deletions aws-typescript/tests/infra.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as pulumi from "@pulumi/pulumi";
import "jest";

// Test helper to convert a Pulumi Output to a Promise.
// This should only be used in tests.
function promiseOf<T>(output: pulumi.Output<T>): Promise<T> {
return new Promise(resolve => output.apply(resolve));
}

describe("infrastructure", () => {
// Define the infra variable as a type whose shape matches the that of the
// to-be-defined infra module.
let infra: typeof import("../infra");

beforeAll(() => {
// Put Pulumi in unit-test mode, mocking all calls to cloud-provider APIs.
pulumi.runtime.setMocks({
// Mock calls to create new resources and return a canned response.
newResource: (args: pulumi.runtime.MockResourceArgs) => {
// Here, we're returning a same-shaped object for all resource types.
// We could, however, use the arguments passed into this function to
// customize the mocked-out properties of a particular resource.
// See the unit-testing docs for details:
// https://www.pulumi.com/docs/iac/concepts/testing/unit/
return {
id: `${args.name}-id`,
state: args.inputs,
};
},

// Mock function calls and return an empty response.
call: (args: pulumi.runtime.MockCallArgs) => {
return {};
},
});
});

beforeEach(async () => {
// Dynamically import the infra module.
infra = await import("../infra");
});

// Example test. To run, uncomment and run `npm test`.
// describe("bucket", () => {
// it("must have a name tag", async () => {
// const tags = await promiseOf(infra.bucket.tags);
// expect(tags).toBeDefined();
// expect(tags).toHaveProperty("Name");
// });
// });
});
5 changes: 1 addition & 4 deletions aws-typescript/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,5 @@
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.ts"
]
}
}
Loading