pulumi/pkg/codegen/internal/test/sdk_driver.go
2021-09-21 10:00:44 -07:00

182 lines
5.2 KiB
Go

package test
import (
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pulumi/pulumi/pkg/v3/codegen"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)
type ThenFunc func(t *testing.T, testDir string)
type sdkTest struct {
Directory string
Description string
SkipCompileCheck codegen.StringSet
Then map[string]ThenFunc
}
const (
nodejs = "nodejs"
dotnet = "dotnet"
golang = "go"
)
var sdkTests = []sdkTest{
{
Directory: "input-collision",
Description: "Schema with types that could potentially produce collisions (go).",
},
{
Directory: "dash-named-schema",
Description: "Simple schema with a two part name (foo-bar)",
},
{
Directory: "external-resource-schema",
Description: "External resource schema",
SkipCompileCheck: codegen.NewStringSet(nodejs, golang),
},
{
Directory: "nested-module",
Description: "Nested module",
SkipCompileCheck: codegen.NewStringSet(dotnet, nodejs),
},
{
Directory: "nested-module-thirdparty",
Description: "Third-party nested module",
SkipCompileCheck: codegen.NewStringSet(dotnet, nodejs),
},
{
Directory: "plain-schema-gh6957",
Description: "Repro for #6957",
},
{
Directory: "resource-args-python",
Description: "Resource args with same named resource and type",
Then: map[string]ThenFunc{
"go": func(t *testing.T, testDir string) {
cmd := exec.Command("go", "test", "./...")
cmd.Dir = filepath.Join(testDir, "go-program")
out, err := cmd.CombinedOutput()
if !assert.NoError(t, err) {
t.Logf("output: %v", string(out))
}
},
},
},
{
Directory: "simple-enum-schema",
Description: "Simple schema with enum types",
},
{
Directory: "simple-plain-schema",
Description: "Simple schema with plain properties",
},
{
Directory: "simple-plain-schema-with-root-package",
Description: "Simple schema with root package set",
},
{
Directory: "simple-resource-schema",
Description: "Simple schema with local resource properties",
},
{
Directory: "simple-resource-schema-custom-pypackage-name",
Description: "Simple schema with local resource properties and custom Python package name",
},
{
Directory: "simple-methods-schema",
Description: "Simple schema with methods",
SkipCompileCheck: codegen.NewStringSet(nodejs, dotnet, golang),
},
{
Directory: "simple-yaml-schema",
Description: "Simple schema encoded using YAML",
},
{
Directory: "provider-config-schema",
Description: "Simple provider config schema",
SkipCompileCheck: codegen.NewStringSet(dotnet),
},
{
Directory: "replace-on-change",
Description: "Simple use of replaceOnChange in schema",
SkipCompileCheck: codegen.NewStringSet(golang),
},
{
Directory: "resource-property-overlap",
Description: "A resource with the same name as it's property",
SkipCompileCheck: codegen.NewStringSet(dotnet, nodejs),
},
{
Directory: "hyphen-url",
Description: "A resource url with a hyphen in it's path",
},
}
type checkPackageSignature = func(t *testing.T, pwd string)
// TestSDKCodegen runs the complete set of SDK code generation tests against a particular language's code
// generator. It also verifies that the generated code is structurally sound.
//
// An SDK code generation test consists of a schema and a set of expected outputs for each language. Each test is
// structured as a directory that contains that information:
//
// test-directory/
// schema.(json|yaml)
// language-0
// ...
// language-n
//
// The schema is the only piece that must be manually authored. Once the schema has been written, the expected outputs
// can be generated by running `PULUMI_ACCEPT=true go test ./..." from the `pkg/codegen` directory.
//nolint: revive
func TestSDKCodegen(t *testing.T, language string, genPackage GenPkgSignature, checkPackage checkPackageSignature) {
testDir := filepath.Join("..", "internal", "test", "testdata")
for _, tt := range sdkTests {
t.Run(tt.Description, func(t *testing.T) {
dirPath := filepath.Join(testDir, filepath.FromSlash(tt.Directory))
schemaPath := filepath.Join(dirPath, "schema.json")
if _, err := os.Stat(schemaPath); err != nil && os.IsNotExist(err) {
schemaPath = filepath.Join(dirPath, "schema.yaml")
}
files, err := GeneratePackageFilesFromSchema(schemaPath, genPackage)
require.NoError(t, err)
// Check output is valid code (will type-check). If code will not
// type-check, we don't allow the user to run PULUMI_ACCEPT=true and
// replace the test files.
if !tt.SkipCompileCheck.Has(language) {
typeCheckPath := filepath.Join(dirPath, "typecheck")
langTypeCheckPath := filepath.Join(typeCheckPath, language)
contract.IgnoreError(os.RemoveAll(langTypeCheckPath))
WriteTestFiles(t, typeCheckPath, language, files)
checkPackage(t, langTypeCheckPath)
}
if !RewriteFilesWhenPulumiAccept(t, dirPath, language, files) {
expectedFiles, err := LoadBaseline(dirPath, language)
require.NoError(t, err)
if !ValidateFileEquality(t, files, expectedFiles) {
return
}
}
if then, ok := tt.Then[language]; ok {
then(t, dirPath)
}
})
}
}