driftctl/test/mocks/MockGoldenTerraformProvider.go

178 lines
4.1 KiB
Go

package mocks
import (
gojson "encoding/json"
"errors"
"fmt"
"sort"
"github.com/snyk/driftctl/test/goldenfile"
"github.com/hashicorp/terraform/providers"
"github.com/snyk/driftctl/pkg/terraform"
"github.com/zclconf/go-cty/cty"
ctyjson "github.com/zclconf/go-cty/cty/json"
)
type MockedGoldenTFProvider struct {
name string
realProvider terraform.TerraformProvider
update bool
}
func NewMockedGoldenTFProvider(name string, realProvider terraform.TerraformProvider, update bool) *MockedGoldenTFProvider {
return &MockedGoldenTFProvider{name: name, realProvider: realProvider, update: update}
}
func (m *MockedGoldenTFProvider) Schema() map[string]providers.Schema {
if m.update {
schema := m.realProvider.Schema()
m.writeSchema(schema)
return schema
}
return m.readSchema()
}
func (m *MockedGoldenTFProvider) ReadResource(args terraform.ReadResourceArgs) (*cty.Value, error) {
if m.update {
readResource, err := m.realProvider.ReadResource(args)
m.writeReadResource(args, readResource, err)
return readResource, err
}
return m.readReadResource(args)
}
func (m *MockedGoldenTFProvider) writeSchema(schema map[string]providers.Schema) {
marshal, err := gojson.Marshal(schema)
if err != nil {
panic(err)
}
goldenfile.WriteFile(m.name, marshal, "schema.golden.json")
}
func (m *MockedGoldenTFProvider) readSchema() map[string]providers.Schema {
content := goldenfile.ReadFile(m.name, "schema.golden.json")
var schema map[string]providers.Schema
if err := gojson.Unmarshal(content, &schema); err != nil {
panic(err)
}
return schema
}
func (m *MockedGoldenTFProvider) writeReadResource(args terraform.ReadResourceArgs, readResource *cty.Value, err error) {
var readRes = ReadResource{
Value: readResource,
Err: err,
}
marshalled, err := gojson.Marshal(&readRes)
if err != nil {
panic(err)
}
fileName := getFileName(args)
goldenfile.WriteFile(m.name, marshalled, fileName)
}
func (m *MockedGoldenTFProvider) readReadResource(args terraform.ReadResourceArgs) (*cty.Value, error) {
fileName := getFileName(args)
// TODO I'm putting this here for compatibility reason...
if !goldenfile.FileExists(m.name, fileName) {
fileName = fmt.Sprintf("%s-%s.res.golden.json", args.Ty, args.ID)
}
content := goldenfile.ReadFile(m.name, fileName)
var readRes ReadResource
if err := gojson.Unmarshal(content, &readRes); err != nil {
panic(err)
}
return readRes.Value, readRes.Err
}
type ReadResource struct {
Value *cty.Value
Err error
}
func (m *ReadResource) UnmarshalJSON(bytes []byte) error {
var unm struct {
Typ []byte
Val []byte
Err *string
}
if err := gojson.Unmarshal(bytes, &unm); err != nil {
return err
}
if unm.Typ != nil {
unmarshalType, err := ctyjson.UnmarshalType(unm.Typ)
if err != nil {
return err
}
if unm.Val != nil {
unmarshal, err := ctyjson.Unmarshal(unm.Val, unmarshalType)
if err != nil {
return err
}
m.Value = &unmarshal
}
}
if unm.Err != nil {
m.Err = errors.New(*unm.Err)
}
return nil
}
func (m *ReadResource) MarshalJSON() ([]byte, error) {
var unm struct {
Typ []byte
Val []byte
Err *string
}
if m.Value != nil {
var err error
unm.Typ, err = ctyjson.MarshalType(m.Value.Type())
if err != nil {
return nil, err
}
unm.Val, err = ctyjson.Marshal(*m.Value, m.Value.Type())
if err != nil {
return nil, err
}
}
if m.Err != nil {
e := m.Err.Error()
unm.Err = &e
}
return gojson.Marshal(unm)
}
func getFileName(args terraform.ReadResourceArgs) string {
suffix := getFileNameSuffix(args)
fileName := fmt.Sprintf("%s-%s%s.res.golden.json", args.Ty, args.ID, suffix)
return fileName
}
func getFileNameSuffix(args terraform.ReadResourceArgs) string {
suffix := ""
keys := make([]string, 0, len(args.Attributes))
for k := range args.Attributes {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
suffix = fmt.Sprintf("%s-%s", suffix, args.Attributes[k])
}
return suffix
}
func (p MockedGoldenTFProvider) Cleanup() {}
func (p *MockedGoldenTFProvider) Name() string {
return p.realProvider.Name()
}
func (p *MockedGoldenTFProvider) Version() string {
return p.realProvider.Version()
}