I have a function that takes an input of an AWS OpenIdConnectProvider Pulumi Resource and creates a IAM Role with an AssumeRolePolicy attached that contains info from that OIDC provider.
The Problem: I am trying to write a test for this function and mock out a OIDC provider to feed in as input for the function call. I'm having trouble understanding how to properly mock this so that the test output shows what I expect, currently it appears that the mocked data isn't coming up like I'd expect.
It seems like I'm not using the mock correctly, but I went off the example here
package myPkg
import (
"github.com/pulumi/pulumi-aws/sdk/v5/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func CreateMyCustomRole(ctx *pulumi.Context, name string, oidcProvider *iam.OpenIdConnectProvider, opts ...pulumi.ResourceOption) (*iam.Role, error) {
role := &iam.Role{}
componentURN := fmt.Sprintf("%s-custom-role", name)
err := ctx.RegisterComponentResource("pkg:aws:MyCustomRole", componentURN, role, opts...)
if err != nil {
return nil, err
}
url := oidc.Url.ApplyT(func(s string) string {
return fmt.Sprint(strings.ReplaceAll(s, "https://", ""), ":sub")
}).(pulumi.StringOutput)
assumeRolePolicy := pulumi.Sprintf(`{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Federated": "%s" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"%s": [
"system:serviceaccount:kube-system:*",
"system:serviceaccount:kube-system:cluster-autoscaler"
]
}
}
}]
}`, oidcProvider.Arn, url)
roleURN := fmt.Sprintf("%s-custom-role", name)
role, err = iam.NewRole(ctx, roleURN, &iam.RoleArgs{
Name: pulumi.String(roleURN),
Description: pulumi.String("Create Custom Role"),
AssumeRolePolicy: assumeRolePolicy,
Tags: pulumi.ToStringMap(map[string]string{"project": "test"}),
})
if err != nil {
return nil, err
}
return role, nil
}
package myPkg
import (
"sync"
"testing"
"github.com/pulumi/pulumi-aws/sdk/v5/go/aws/iam"
"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
func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
return args.Name + "_id", args.Inputs, nil
}
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
outputs := map[string]interface{}{}
if args.Token == "aws:iam/getOpenidConnectProvider:getOpenidConnectProvider" {
outputs["arn"] = "arn:aws:iam::123:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/abc"
outputs["id"] = "abc"
outputs["url"] = "https://someurl"
}
return resource.NewPropertyMapFromMap(outputs), nil
}
func TestCreateMyCustomRole(t *testing.T) {
err := pulumi.RunErr(func(ctx *pulumi.Context) error {
// Gets the mocked OIDC provider to use as input for the CreateDefaultAutoscalerRole
oidc, err := iam.GetOpenIdConnectProvider(ctx, "get-test-oidc-provider", pulumi.ID("abc"), &iam.OpenIdConnectProviderState{})
assert.NoError(t, err)
infra, err := CreateMyCustomRole(ctx, "role1", oidc})
assert.NoError(t, err)
var wg sync.WaitGroup
wg.Add(1)
// check 1: Assume Role Policy is formatted correctly
pulumi.All(infra.URN(), infra.AssumeRolePolicy).ApplyT(func(all []interface{}) error {
urn := all[0].(pulumi.URN)
assumeRolePolicy := all[1].(string)
assert.Equal(t, `{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::123:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/abc" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"someurl:sub": [
"system:serviceaccount:kube-system:*",
"system:serviceaccount:kube-system:cluster-autoscaler"
]
}
}
}]
}`, assumeRolePolicy)
wg.Done()
return nil
})
wg.Wait()
return nil
}, pulumi.WithMocks("project", "stack", mocks(0)))
assert.NoError(t, err)
}
Output
Diff:
--- Expected
+++ Actual
@@ -4,3 +4,3 @@
"Effect": "Allow",
- "Principal": { "Federated": "arn:aws:iam::123:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/abc" },
+ "Principal": { "Federated": "" },
"Action": "sts:AssumeRoleWithWebIdentity",
@@ -8,3 +8,3 @@
"StringEquals": {
- "someurl:sub": [
+ ":sub": [
"system:serviceaccount:kube-system:*",
Test: TestCreateMyCustomRole
Turns out I was using the NewResource
wrong.
When GetOpenIdConnectProvider
is called in the test function it goes to read a resource and create a new resource output which triggers the call to mocks.NewResource
The fix was to instead define an if statement for the resource type returned by the GetOpenIdConnectProvider openIdConnectProvider
in the NewResource function call with the mocked outputs.
func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
pulumi.Printf(args.TypeToken)
outputs := args.Inputs.Mappable()
if args.TypeToken == "aws:iam/openIdConnectProvider:OpenIdConnectProvider" {
outputs["arn"] = "arn:aws:iam::123:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/abc"
outputs["id"] = "abc"
outputs["url"] = "https://someurl"
}
return args.Name + "_id", resource.NewPropertyMapFromMap(outputs), nil
}
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
outputs := map[string]interface{}{}
return resource.NewPropertyMapFromMap(outputs), nil
}
Is this below code snippet I changed the assert
so that it fails to show what the diff now looks like with the changes made to NewResource above
Diff:
--- Expected
+++ Actual
@@ -8,3 +8,3 @@
"StringEquals": {
- "b:sub": [
+ "someurl:sub": [
"system:serviceaccount:kube-system:*",