pulumi/pkg/codegen/go/gen_test.go
Ian Wahbe e1f0976667
Use importBasePath before name if specified (#8159)
* Use importBasePath before name if specified

This is a go specific code change. We should clarify in the docs how
`name`, `importBasePath` and `rootPackageName` interact.

* Update CHANGELOG_PENDING.md

* Test package naming

* Explain test and remove debugging print

* Comply with linter
2021-10-07 11:56:44 -07:00

215 lines
6.3 KiB
Go

package gen
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"sort"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pulumi/pulumi/pkg/v3/codegen/internal/test"
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/executable"
)
func TestInputUsage(t *testing.T) {
pkg := &pkgContext{}
arrayUsage := pkg.getInputUsage("FooArray")
assert.Equal(
t,
"FooArrayInput is an input type that accepts FooArray and FooArrayOutput values.\nYou can construct a "+
"concrete instance of `FooArrayInput` via:\n\n\t\t FooArray{ FooArgs{...} }\n ",
arrayUsage)
mapUsage := pkg.getInputUsage("FooMap")
assert.Equal(
t,
"FooMapInput is an input type that accepts FooMap and FooMapOutput values.\nYou can construct a concrete"+
" instance of `FooMapInput` via:\n\n\t\t FooMap{ \"key\": FooArgs{...} }\n ",
mapUsage)
ptrUsage := pkg.getInputUsage("FooPtr")
assert.Equal(
t,
"FooPtrInput is an input type that accepts FooArgs, FooPtr and FooPtrOutput values.\nYou can construct a "+
"concrete instance of `FooPtrInput` via:\n\n\t\t FooArgs{...}\n\n or:\n\n\t\t nil\n ",
ptrUsage)
usage := pkg.getInputUsage("Foo")
assert.Equal(
t,
"FooInput is an input type that accepts FooArgs and FooOutput values.\nYou can construct a concrete instance"+
" of `FooInput` via:\n\n\t\t FooArgs{...}\n ",
usage)
}
func TestGoPackageName(t *testing.T) {
assert.Equal(t, "aws", goPackage("aws"))
assert.Equal(t, "azure", goPackage("azure-nextgen"))
assert.Equal(t, "plant", goPackage("plant-provider"))
assert.Equal(t, "", goPackage(""))
}
func TestGeneratePackage(t *testing.T) {
generatePackage := func(tool string, pkg *schema.Package, files map[string][]byte) (map[string][]byte, error) {
for f := range files {
t.Logf("Ignoring extraFile %s", f)
}
return GeneratePackage(tool, pkg)
}
test.TestSDKCodegen(t, &test.SDKCodegenOptions{
Language: "go",
GenPackage: generatePackage,
Checks: map[string]test.CodegenCheck{
"go/compile": typeCheckGeneratedPackage,
"go/test": testGeneratedPackage,
},
})
}
func inferModuleName(codeDir string) string {
// For example for this path:
//
// codeDir = "../internal/test/testdata/external-resource-schema/go/"
//
// We will generate "$codeDir/go.mod" using
// `external-resource-schema` as the module name so that it
// can compile independently.
return filepath.Base(filepath.Dir(codeDir))
}
func typeCheckGeneratedPackage(t *testing.T, codeDir string) {
sdk, err := filepath.Abs(filepath.Join("..", "..", "..", "sdk"))
require.NoError(t, err)
goExe, err := executable.FindExecutable("go")
require.NoError(t, err)
goMod := filepath.Join(codeDir, "go.mod")
alreadyHaveGoMod, err := test.PathExists(goMod)
require.NoError(t, err)
if alreadyHaveGoMod {
t.Logf("Found an existing go.mod, leaving as is")
} else {
test.RunCommand(t, "go_mod_init", codeDir, goExe, "mod", "init", inferModuleName(codeDir))
replacement := fmt.Sprintf("github.com/pulumi/pulumi/sdk/v3=%s", sdk)
test.RunCommand(t, "go_mod_edit", codeDir, goExe, "mod", "edit", "-replace", replacement)
}
test.RunCommand(t, "go_mod_tidy", codeDir, goExe, "mod", "tidy")
test.RunCommand(t, "go_build", codeDir, goExe, "build", "-v", "all")
}
func testGeneratedPackage(t *testing.T, codeDir string) {
goExe, err := executable.FindExecutable("go")
require.NoError(t, err)
test.RunCommand(t, "go-test", codeDir, goExe, "test", fmt.Sprintf("%s/...", inferModuleName(codeDir)))
}
func TestGenerateTypeNames(t *testing.T) {
test.TestTypeNameCodegen(t, "go", func(pkg *schema.Package) test.TypeNameGeneratorFunc {
err := pkg.ImportLanguages(map[string]schema.Language{"go": Importer})
require.NoError(t, err)
var goPkgInfo GoPackageInfo
if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
goPkgInfo = goInfo
}
packages := generatePackageContextMap("test", pkg, goPkgInfo)
root, ok := packages[""]
require.True(t, ok)
return func(t schema.Type) string {
return root.typeString(t)
}
})
}
func readSchemaFile(file string) *schema.Package {
// Read in, decode, and import the schema.
schemaBytes, err := ioutil.ReadFile(filepath.Join("..", "internal", "test", "testdata", file))
if err != nil {
panic(err)
}
var pkgSpec schema.PackageSpec
if err = json.Unmarshal(schemaBytes, &pkgSpec); err != nil {
panic(err)
}
pkg, err := schema.ImportSpec(pkgSpec, map[string]schema.Language{"go": Importer})
if err != nil {
panic(err)
}
return pkg
}
// We test the naming/module structure of generated packages.
func TestPackageNaming(t *testing.T) {
testCases := []struct {
importBasePath string
rootPackageName string
name string
expectedRoot string
}{
{
importBasePath: "github.com/pulumi/pulumi-azure-quickstart-acr-geo-replication/sdk/go/acr",
expectedRoot: "acr",
},
{
importBasePath: "github.com/ihave/animport",
rootPackageName: "root",
expectedRoot: "",
},
{
name: "named-package",
expectedRoot: "named",
},
}
for _, tt := range testCases {
t.Run(tt.expectedRoot, func(t *testing.T) {
// This schema is arbitrary. We just needed a filled out schema. All
// path decisions should be made based off of the Name and
// Language[go] fields (which we set after import).
schema := readSchemaFile(filepath.Join("schema", "good-enum-1.json"))
if tt.name != "" {
// We want there to be a name, so if one isn't provided we
// default to the schema.
schema.Name = tt.name
}
schema.Language = map[string]interface{}{
"go": GoPackageInfo{
ImportBasePath: tt.importBasePath,
RootPackageName: tt.rootPackageName,
},
}
files, err := GeneratePackage("test", schema)
require.NoError(t, err)
ordering := make([]string, len(files))
var i int
for k := range files {
ordering[i] = k
i++
}
ordering = sort.StringSlice(ordering)
require.NotEmpty(t, files, "This test only works when files are generated")
for _, k := range ordering {
root := strings.Split(k, "/")[0]
if tt.expectedRoot != "" {
require.Equal(t, tt.expectedRoot, root, "Root should precede all cases. Got file %s", k)
}
// We should work on a way to assert this is one level higher then it otherwise would be.
}
})
}
}