Как имитировать ресурсы Pulumi в модульных тестах Go?

У меня есть функция, которая принимает входные данные ресурса AWS OpenIdConnectProvider Pulumi и создает роль IAM с прикрепленной AssumeRolePolicy, которая содержит информацию от этого поставщика OIDC.

Проблема: я пытаюсь написать тест для этой функции и имитировать провайдера OIDC, который будет использоваться в качестве входных данных для вызова функции. У меня возникли проблемы с пониманием того, как правильно издеваться над этим, чтобы выходные данные теста показывали то, что я ожидаю, в настоящее время кажется, что имитированные данные не появляются, как я ожидал.

Кажется, я неправильно использую мокап, но я ушел от примера здесь

Дополнительные документы здесь

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
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
123
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы хотите имитировать ресурсы Pulumi в модульных тестах Go, вы можете использовать пакет «mock», предоставляемый Pulumi SDK. Вот общие шаги, которые вы можете выполнить:

Создайте новый файл Go для своего теста и импортируйте необходимые пакеты, включая пакеты «testing» и «github.com/pulumi/pulumi/sdk/v3/go/pulumi/mock».

Определите структуру, реализующую интерфейс Pulumi Resource. Эта структура будет действовать как макет для фактического ресурса. Вы можете установить для полей структуры значения, которые хотите использовать в своем тесте.

type mockResource struct {
    pulumi.ResourceState
    Field1 string
    Field2 int
}

Создайте новый экземпляр mockResource struct и задайте для его полей значения, которые вы хотите использовать в своем тесте.

mock := &mockResource{
    Field1: "test",
    Field2: 123,
}

Используйте функцию mock.NewResourceMock, чтобы создать нового фиктивного поставщика ресурсов. Этот провайдер вернет экземпляр mockResource при вызове.

provider := mock.NewResourceMock(t, "test", "aws:ec2/instance:Instance", mock)

Создайте новый экземпляр ресурса, который вы хотите протестировать, и передайте фиктивному провайдеру.

instance := &ec2.Instance{}
err := instance.Create(ctx, "test", ec2.InstanceArgs{
    // set args here
}, pulumi.Provider(provider))

Напишите свой тестовый код, чтобы убедиться, что ресурс ведет себя так, как ожидалось.


// assert that the resource was created successfully
assert.Nil(t, err)

// assert that the resource has the expected values
assert.Equal(t, mock.Field1, instance.Field1)
assert.Equal(t, mock.Field2, instance.Field2)

Вот и все! Следуя этим шагам, вы можете легко имитировать ресурсы Pulumi в модульных тестах Go с помощью Pulumi SDK.

github.com/pulumi/pulumi/sdk/v3/go/pulumi/mock не является импортируемым пакетом
ebellefontaine 26.04.2023 17:04
❯ go get -u github.com/pulumi/pulumi/sdk/v3/go/pulumi/mock go: module github.com/pulumi/pulumi/sdk/v3@upgrade found (v3.64.0), but does not contain package github.com/pulumi/pulumi/sdk/v3/go/pulumi/mock
ebellefontaine 26.04.2023 17:04

Отмечен как бесполезный, поскольку этот ответ, похоже, не использует ничего, описанного в pulumi SDK или справочниках по API. pulumi.com/docs/reference/pkg/nodejs/pulumi/pulumi/runtime/… pkg.go.dev/github.com/pulumi/pulumi/sdk/v3/go/pulumi Есть ли у вас в наличии информация об источнике документации ваша ссылка или полностью рабочий пример кода?

ebellefontaine 26.04.2023 18:17
Ответ принят как подходящий

Оказывается, я использовал NewResource неправильно.

Когда GetOpenIdConnectProvider вызывается в тестовой функции, она переходит к чтению ресурса и созданию нового вывода ресурса, который запускает вызов mocks.NewResource.

Исправление заключалось в том, чтобы вместо этого определить оператор if для типа ресурса, возвращаемого GetOpenIdConnectProvider openIdConnectProvider, в вызове функции NewResource с имитацией выходных данных.

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
}

В приведенном ниже фрагменте кода я изменил assert, чтобы он не мог показать, как теперь выглядит разница с изменениями, внесенными в NewResource выше

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

Другие вопросы по теме