Home > Backend Development > Golang > How to mock Pulumi resources in Go unit tests?

How to mock Pulumi resources in Go unit tests?

WBOY
Release: 2024-02-06 09:24:04
forward
658 people have browsed it

如何在 Go 单元测试中模拟 Pulumi 资源?

Question content

I have a function that takes input from the aws openidconnectprovider pulumi resource and creates an iam role and attaches an include from that oidc provider The assumerolepolicy of the supplier's information.

Question: I'm trying to write a test for this function and mock the oidc provider as input to the function call. I can't figure out how to simulate it correctly so that the test output shows what I expect, currently it seems the simulated data isn't coming out as I expect.

Looks like I'm not using mocking correctly, but I'm giving up on the example here

More documentation 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
}

Copy after login
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
Copy after login
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
Copy after login
Copy after login


Correct answer


It turns out that I used newresource wrong.

When getopenidconnectprovider is called in a test function, it reads the resource and creates a new resource output, triggering a call to mocks.newresource

The fix is ​​to use mock output to define an if statement in the newresource function call for the resource type returned by getopenidconnectprovider openidconnectprovider.

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
}
Copy after login

The code snippet below is where I changed assert so that it doesn't show the difference now compared to the changes made to newresource above

Diff:
                            --- Expected
                             Actual
                            @@ -8,3 +8,3 @@
                                                "StringEquals": {
                            -                       "b:sub": [
                            +                       "someurl:sub": [
                                                        "system:serviceaccount:kube-system:*",
Copy after login

The above is the detailed content of How to mock Pulumi resources in Go unit tests?. For more information, please follow other related articles on the PHP Chinese website!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template