From 77ac5c3f0c386c7e712e87f86984641563cd94db Mon Sep 17 00:00:00 2001 From: Lingfeng Wang Date: Tue, 18 Sep 2018 15:37:03 -0400 Subject: [PATCH] Replace JSON parser with YAML parser for *-configs --- benchmarks/runner/main.go | 12 +- codegen/gateway.go | 220 +++++++++--------- codegen/gateway_test.go | 6 +- codegen/module.go | 101 ++++---- codegen/module_system.go | 126 +++++----- codegen/module_test.go | 26 ++- codegen/post_gen_hooks.go | 22 +- codegen/template.go | 7 - .../bar_bar_method_argnotstruct_test.gogen | 2 +- .../bar/bar_bar_method_argnotstruct_test.go | 2 +- test/lib/test_gateway/test_gateway_cover.go | 11 +- 11 files changed, 282 insertions(+), 253 deletions(-) diff --git a/benchmarks/runner/main.go b/benchmarks/runner/main.go index 6ac475107..ca2474136 100644 --- a/benchmarks/runner/main.go +++ b/benchmarks/runner/main.go @@ -23,7 +23,6 @@ package main import ( "bufio" "bytes" - "encoding/json" "flag" "io/ioutil" "os" @@ -37,6 +36,7 @@ import ( "github.com/uber/zanzibar/test/lib/util" "go.uber.org/zap" "go.uber.org/zap/zapcore" + yaml "gopkg.in/yaml.v2" ) var logger = zap.New( @@ -69,23 +69,23 @@ func spawnBenchServer(dirName string) *exec.Cmd { } func writeConfigToFile(config map[string]interface{}) (string, error) { - tempConfigDir, err := ioutil.TempDir("", "zanzibar-bench-config-json") + tempConfigDir, err := ioutil.TempDir("", "zanzibar-bench-config-yaml") if err != nil { return "", err } - jsonFile := path.Join(tempConfigDir, "production.json") - configBytes, err := json.Marshal(config) + yamlFile := path.Join(tempConfigDir, "production.json") + configBytes, err := yaml.Marshal(config) if err != nil { return "", err } - err = ioutil.WriteFile(jsonFile, configBytes, os.ModePerm) + err = ioutil.WriteFile(yamlFile, configBytes, os.ModePerm) if err != nil { return "", err } - return jsonFile, nil + return yamlFile, nil } func spawnGateway(dirName string) *exec.Cmd { diff --git a/codegen/gateway.go b/codegen/gateway.go index 59f84aa94..d9b91d2a7 100644 --- a/codegen/gateway.go +++ b/codegen/gateway.go @@ -21,7 +21,6 @@ package codegen import ( - "encoding/json" "fmt" "io/ioutil" "net/textproto" @@ -35,6 +34,7 @@ import ( "github.com/pkg/errors" "github.com/uber/zanzibar/runtime" "go.uber.org/thriftrw/compile" + yaml "gopkg.in/yaml.v2" ) func getDirName() string { @@ -74,7 +74,9 @@ type ClientSpec struct { // ModuleSpec holds the thrift module information ModuleSpec *ModuleSpec // JSONFile for this spec - JSONFile string + JSONFile string // Deprecated + // YAMLFile for this spec + YAMLFile string // ClientType, currently "http", "tchannel" and "custom" are supported ClientType string // If "custom" then where to import custom code from @@ -104,40 +106,40 @@ type ClientSpec struct { SidecarRouter string } -// ModuleClassConfig represents the generic JSON config for +// ModuleClassConfig represents the generic YAML config for // all modules. This will be provided by the module package. type ModuleClassConfig struct { - Name string `json:"name"` - Type string `json:"type"` - Config interface{} `json:"config"` + Name string `yaml:"name" json:"name"` + Type string `yaml:"type" json:"type"` + Config interface{} `yaml:"config" json:"config"` } // ClientClassConfig represents the specific config for // a client. This is a downcast of the moduleClassConfig. type ClientClassConfig struct { - Name string `json:"name"` - Type string `json:"type"` - Config map[string]interface{} `json:"config"` - Dependencies Dependencies `json:"dependencies"` + Name string `yaml:"name" json:"name"` + Type string `yaml:"type" json:"type"` + Config map[string]interface{} `yaml:"config" json:"config"` + Dependencies Dependencies `yaml:"dependencies" json:"dependencies"` } // Dependencies lists all dependencies of a module type Dependencies struct { - Client []string `json:"client"` - // Service []string `json:"service"` // example extension + Client []string `yaml:"client" json:"client"` + // Service []string `yaml:"service"` // example extension } -// MiddlewareConfigConfig is the inner config object as prescribed by module_system json conventions +// MiddlewareConfigConfig is the inner config object as prescribed by module_system yaml conventions type MiddlewareConfigConfig struct { - OptionsSchemaFile string `json:"schema"` - ImportPath string `json:"path"` + OptionsSchemaFile string `yaml:"schema" json:"schema"` + ImportPath string `yaml:"path" json:"path"` } -// MiddlewareConfig represents configuration for a middleware as is written in the json file +// MiddlewareConfig represents configuration for a middleware as is written in the yaml file type MiddlewareConfig struct { - Name string `json:"name"` - Dependencies *Dependencies `json:"dependencies,omitempty"` - Config *MiddlewareConfigConfig `json:"config"` + Name string `yaml:"name" json:"name"` + Dependencies *Dependencies `yaml:"dependencies,omitempty" json:"dependencies,omitempty"` + Config *MiddlewareConfigConfig `yaml:"config" json:"config"` } // Validate the config spec attributes @@ -162,34 +164,34 @@ func (mid *MiddlewareConfig) Validate(configDirName string) error { bytes, err := ioutil.ReadFile(schPath) if err != nil { return errors.Wrapf( - err, "Cannot read middleware json schema: %s", + err, "Cannot read middleware yaml schema: %s", schPath, ) } var midOptSchema map[string]interface{} - err = json.Unmarshal(bytes, &midOptSchema) + err = yaml.Unmarshal(bytes, &midOptSchema) if err != nil { return errors.Wrapf( - err, "Cannot parse json schema for middleware options: %s", + err, "Cannot parse yaml schema for middleware options: %s", schPath, ) } return nil } -// NewClientSpec creates a client spec from a json file. +// NewClientSpec creates a client spec from a yaml file. func NewClientSpec( instance *ModuleInstance, h *PackageHelper, ) (*ClientSpec, error) { clientConfig := &ClientClassConfig{} - if err := json.Unmarshal(instance.JSONFileRaw, &clientConfig); err != nil { + if err := yaml.Unmarshal(instance.YAMLFileRaw, &clientConfig); err != nil { return nil, errors.Wrapf( err, - "Could not parse class config json file: %s", - instance.JSONFileName, + "Could not parse class config yaml file: %s", + instance.YAMLFileName, ) } @@ -203,7 +205,7 @@ func NewClientSpec( default: return nil, errors.Errorf( "Cannot support unknown clientType for client %q", - instance.JSONFileName, + instance.YAMLFileName, ) } } @@ -217,7 +219,7 @@ func NewHTTPClientSpec( return newClientSpec(instance, clientConfig, true, h) } -// NewTChannelClientSpec creates a client spec from a json file whose type is tchannel +// NewTChannelClientSpec creates a client spec from a yaml file whose type is tchannel func NewTChannelClientSpec( instance *ModuleInstance, clientConfig *ClientClassConfig, @@ -226,7 +228,7 @@ func NewTChannelClientSpec( return newClientSpec(instance, clientConfig, false, h) } -// NewCustomClientSpec creates a client spec from a json file whose type is custom +// NewCustomClientSpec creates a client spec from a yaml file whose type is custom func NewCustomClientSpec( instance *ModuleInstance, clientConfig *ClientClassConfig, @@ -236,13 +238,14 @@ func NewCustomClientSpec( if _, ok := clientConfig.Config[f]; !ok { return nil, errors.Errorf( "client config %q must have %q field for type custom", - instance.JSONFileName, + instance.YAMLFileName, f, ) } } clientSpec := &ClientSpec{ + YAMLFile: instance.YAMLFileName, JSONFile: instance.JSONFileName, ImportPackagePath: instance.PackageInfo.ImportPackagePath(), ImportPackageAlias: instance.PackageInfo.ImportPackageAlias(), @@ -268,7 +271,7 @@ func newClientSpec( fieldName := mandatoryClientFields[i] if _, ok := config[fieldName]; !ok { return nil, errors.Errorf( - "client config %q must have %q field", instance.JSONFileName, fieldName, + "client config %q must have %q field", instance.YAMLFileName, fieldName, ) } } @@ -287,6 +290,7 @@ func newClientSpec( cspec := &ClientSpec{ ModuleSpec: mspec, + YAMLFile: instance.YAMLFileName, JSONFile: instance.JSONFileName, ClientType: clientConfig.Type, ImportPackagePath: instance.PackageInfo.ImportPackagePath(), @@ -303,26 +307,27 @@ func newClientSpec( cspec.SidecarRouter = sidecarRouter } - exposedMethods, ok := clientConfig.Config["exposedMethods"].(map[string]interface{}) + exposedMethods, ok := clientConfig.Config["exposedMethods"].(map[interface{}]interface{}) if !ok || len(exposedMethods) == 0 { return nil, errors.Errorf( "No methods are exposed in client config: %s", - instance.JSONFileName, + instance.YAMLFileName, ) } cspec.ExposedMethods = make(map[string]string, len(exposedMethods)) reversed := make(map[string]string, len(exposedMethods)) for key, val := range exposedMethods { v := val.(string) - cspec.ExposedMethods[key] = v + k := key.(string) + cspec.ExposedMethods[k] = v if _, ok := reversed[v]; ok { return nil, errors.Errorf( "value %q of the exposedMethods is not unique: %s", v, - instance.JSONFileName, + instance.YAMLFileName, ) } - reversed[v] = key + reversed[v] = k } return cspec, nil @@ -333,14 +338,14 @@ type MiddlewareSpec struct { // The middleware package name. Name string // Middleware specific configuration options. - Options map[string]interface{} + Options map[interface{}]interface{} // Options pretty printed for template initialization PrettyOptions map[string]string // Module Dependencies, clients etc. Dependencies *Dependencies // Go Import Path for MiddlewareHandle implementation ImportPath string - // Location of JSON Schema file for the configured endpoint options + // Location of yaml Schema file for the configured endpoint options OptionsSchemaFile string } @@ -366,8 +371,8 @@ type TypedHeader struct { type EndpointSpec struct { // ModuleSpec holds the thrift module info ModuleSpec *ModuleSpec - // JSONFile for this endpoint spec - JSONFile string + // YAMLFile for this endpoint spec + YAMLFile string // GoStructsFileName is where structs are generated GoStructsFileName string // GoFolderName is the folder where all the endpoints @@ -419,58 +424,58 @@ type EndpointSpec struct { ClientSpec *ClientSpec } -func ensureFields(config map[string]interface{}, mandatoryFields []string, jsonFile string) error { +func ensureFields(config map[interface{}]interface{}, mandatoryFields []string, yamlFile string) error { for i := 0; i < len(mandatoryFields); i++ { fieldName := mandatoryFields[i] if _, ok := config[fieldName]; !ok { return errors.Errorf( - "config %q must have %q field", jsonFile, fieldName, + "config %q must have %q field", yamlFile, fieldName, ) } } return nil } -// NewEndpointSpec creates an endpoint spec from a json file. +// NewEndpointSpec creates an endpoint spec from a yaml file. func NewEndpointSpec( - jsonFile string, + yamlFile string, h *PackageHelper, midSpecs map[string]*MiddlewareSpec, ) (*EndpointSpec, error) { - _, err := os.Stat(jsonFile) + _, err := os.Stat(yamlFile) if err != nil { - return nil, errors.Wrapf(err, "Could not find file %s: ", jsonFile) + return nil, errors.Wrapf(err, "Could not find file %s: ", yamlFile) } - bytes, err := ioutil.ReadFile(jsonFile) + bytes, err := ioutil.ReadFile(yamlFile) if err != nil { return nil, errors.Wrapf( - err, "Could not read json file %s: ", jsonFile, + err, "Could not read yaml file %s: ", yamlFile, ) } - endpointConfigObj := map[string]interface{}{} - err = json.Unmarshal(bytes, &endpointConfigObj) + endpointConfigObj := map[interface{}]interface{}{} + err = yaml.Unmarshal(bytes, &endpointConfigObj) if err != nil { return nil, errors.Wrapf( - err, "Could not parse json file: %s", jsonFile, + err, "Could not parse yaml file: %s", yamlFile, ) } - if err := ensureFields(endpointConfigObj, mandatoryEndpointFields, jsonFile); err != nil { + if err := ensureFields(endpointConfigObj, mandatoryEndpointFields, yamlFile); err != nil { return nil, err } endpointType := endpointConfigObj["endpointType"] if endpointType == "http" { - if err := ensureFields(endpointConfigObj, mandatoryHTTPEndpointFields, jsonFile); err != nil { + if err := ensureFields(endpointConfigObj, mandatoryHTTPEndpointFields, yamlFile); err != nil { return nil, err } } if endpointType != "http" && endpointType != "tchannel" { return nil, errors.Errorf( - "Cannot support unknown endpointType for endpoint: %s", jsonFile, + "Cannot support unknown endpointType for endpoint: %s", yamlFile, ) } @@ -494,7 +499,7 @@ func NewEndpointSpec( iclientID, ok := endpointConfigObj["clientId"] if !ok { return nil, errors.Errorf( - "endpoint config %q must have clientName field", jsonFile, + "endpoint config %q must have clientName field", yamlFile, ) } clientID = iclientID.(string) @@ -502,7 +507,7 @@ func NewEndpointSpec( iclientMethod, ok := endpointConfigObj["clientMethod"] if !ok { return nil, errors.Errorf( - "endpoint config %q must have clientMethod field", jsonFile, + "endpoint config %q must have clientMethod field", yamlFile, ) } clientMethod = iclientMethod.(string) @@ -511,20 +516,20 @@ func NewEndpointSpec( if !ok { return nil, errors.Errorf( "endpoint config %q must have workflowImportPath field", - jsonFile, + yamlFile, ) } workflowImportPath = iworkflowImportPath.(string) } else { return nil, errors.Errorf( "Invalid workflowType %q for endpoint %q", - workflowType, jsonFile, + workflowType, yamlFile, ) } - dirName, err := filepath.Rel(h.ConfigRoot(), filepath.Dir(jsonFile)) + dirName, err := filepath.Rel(h.ConfigRoot(), filepath.Dir(yamlFile)) if err != nil { - return nil, errors.Errorf("Config file is out of config root: %s", jsonFile) + return nil, errors.Errorf("Config file is out of config root: %s", yamlFile) } goFolderName := filepath.Join(h.CodeGenTargetPath(), dirName) @@ -541,14 +546,14 @@ func NewEndpointSpec( parts := strings.Split(thriftInfo, "::") if len(parts) != 2 { return nil, errors.Errorf( - "Cannot read thriftMethodName %q for endpoint json file: %s", - thriftInfo, jsonFile, + "Cannot read thriftMethodName %q for endpoint yaml file: %s", + thriftInfo, yamlFile, ) } espec := &EndpointSpec{ ModuleSpec: mspec, - JSONFile: jsonFile, + YAMLFile: yamlFile, GoStructsFileName: goStructsFileName, GoFolderName: goFolderName, GoPackageName: goPackageName, @@ -567,21 +572,21 @@ func NewEndpointSpec( return augmentEndpointSpec(espec, endpointConfigObj, midSpecs) } -func testFixtures(endpointConfigObj map[string]interface{}) (map[string]*EndpointTestFixture, error) { +func testFixtures(endpointConfigObj map[interface{}]interface{}) (map[string]*EndpointTestFixture, error) { field, ok := endpointConfigObj["testFixtures"] if !ok { return nil, errors.Errorf("missing testFixtures field") } - testFixturesRaw, err := json.Marshal(field) + testFixturesRaw, err := yaml.Marshal(field) if err != nil { return nil, err } var ret map[string]*EndpointTestFixture - err = json.Unmarshal(testFixturesRaw, &ret) + err = yaml.Unmarshal(testFixturesRaw, &ret) return ret, err } -func loadHeadersFromConfig(endpointCfgObj map[string]interface{}, key string) (map[string]string, error) { +func loadHeadersFromConfig(endpointCfgObj map[interface{}]interface{}, key string) (map[string]string, error) { // TODO define endpointConfigObj to avoid type assertion headers, ok := endpointCfgObj[key] @@ -589,10 +594,10 @@ func loadHeadersFromConfig(endpointCfgObj map[string]interface{}, key string) (m return nil, errors.Errorf("unable to parse %q", key) } headersMap := make(map[string]string) - for key, val := range headers.(map[string]interface{}) { + for key, val := range headers.(map[interface{}]interface{}) { switch value := val.(type) { case string: - headersMap[textproto.CanonicalMIMEHeaderKey(key)] = value + headersMap[textproto.CanonicalMIMEHeaderKey(key.(string))] = value default: return nil, errors.Errorf( "unable to parse string %q in headers %q", value, headers) @@ -616,7 +621,7 @@ func sortedHeaders(headerMap map[string]*TypedHeader, filterRequired bool) []str func resolveHeaders( espec *EndpointSpec, - endpointConfigObj map[string]interface{}, + endpointConfigObj map[interface{}]interface{}, key string, ) error { var ( @@ -744,7 +749,7 @@ func resolveHeaderModels(ms *ModuleSpec, modelPath string) (map[string]*TypedHea func augmentEndpointSpec( espec *EndpointSpec, - endpointConfigObj map[string]interface{}, + endpointConfigObj map[interface{}]interface{}, midSpecs map[string]*MiddlewareSpec, ) (*EndpointSpec, error) { if _, ok := endpointConfigObj["middlewares"]; ok { @@ -756,7 +761,7 @@ func augmentEndpointSpec( } var middlewares []MiddlewareSpec for _, middleware := range endpointMids { - middlewareObj, ok := middleware.(map[string]interface{}) + middlewareObj, ok := middleware.(map[interface{}]interface{}) if !ok { return nil, errors.Errorf( "Unable to parse middleware %s", @@ -804,13 +809,14 @@ func augmentEndpointSpec( } // TODO(sindelar): Validate Options against middleware spec and support // nested typed objects. - opts, ok := middlewareObj["options"].(map[string]interface{}) + opts, ok := middlewareObj["options"].(map[interface{}]interface{}) if !ok { - opts = make(map[string]interface{}) + opts = make(map[interface{}]interface{}) } prettyOpts := map[string]string{} - for key, value := range opts { + for k, value := range opts { + key := k.(string) rValue := reflect.ValueOf(value) kind := rValue.Kind() @@ -871,9 +877,9 @@ func augmentEndpointSpec( return espec, nil } -func setPropagateMiddleware(middlewareObj map[string]interface{}) (map[string]FieldMapperEntry, error) { +func setPropagateMiddleware(middlewareObj map[interface{}]interface{}) (map[string]FieldMapperEntry, error) { fieldMap := make(map[string]FieldMapperEntry) - opts, ok := middlewareObj["options"].(map[string]interface{}) + opts, ok := middlewareObj["options"].(map[interface{}]interface{}) if !ok { return nil, errors.New( "missing or invalid options for propagate middleware", @@ -882,7 +888,7 @@ func setPropagateMiddleware(middlewareObj map[string]interface{}) (map[string]Fi propagates := opts["propagate"].([]interface{}) dest := make(map[string]string) for _, propagate := range propagates { - propagateMap := propagate.(map[string]interface{}) + propagateMap := propagate.(map[interface{}]interface{}) fromField, ok := propagateMap["from"].(string) if !ok { return nil, errors.New( @@ -909,9 +915,9 @@ func setPropagateMiddleware(middlewareObj map[string]interface{}) (map[string]Fi return fieldMap, nil } -func setTransformMiddleware(middlewareObj map[string]interface{}) (map[string]FieldMapperEntry, error) { +func setTransformMiddleware(middlewareObj map[interface{}]interface{}) (map[string]FieldMapperEntry, error) { fieldMap := make(map[string]FieldMapperEntry) - opts, ok := middlewareObj["options"].(map[string]interface{}) + opts, ok := middlewareObj["options"].(map[interface{}]interface{}) if !ok { return nil, errors.Errorf( "transform middleware found with no options.", @@ -919,7 +925,7 @@ func setTransformMiddleware(middlewareObj map[string]interface{}) (map[string]Fi } transforms := opts["transforms"].([]interface{}) for _, transform := range transforms { - transformMap := transform.(map[string]interface{}) + transformMap := transform.(map[interface{}]interface{}) fromField, ok := transformMap["from"].(string) if !ok { return nil, errors.New( @@ -971,7 +977,7 @@ func (e *EndpointSpec) TargetEndpointTestPath( // EndpointTestConfigPath generates a filepath for each endpoint test config func (e *EndpointSpec) EndpointTestConfigPath() string { - return strings.TrimSuffix(e.JSONFile, filepath.Ext(e.JSONFile)) + "_test.json" + return strings.TrimSuffix(e.YAMLFile, filepath.Ext(e.YAMLFile)) + "_test.json" } // SetDownstream configures the downstream client for this endpoint spec @@ -993,9 +999,9 @@ func (e *EndpointSpec) SetDownstream( if clientSpec == nil { return errors.Errorf( - "When parsing endpoint json %q, "+ + "When parsing endpoint yaml %q, "+ "could not find client %q in gateway", - e.JSONFile, e.ClientID, + e.YAMLFile, e.ClientID, ) } @@ -1007,47 +1013,47 @@ func (e *EndpointSpec) SetDownstream( // EndpointClassConfig represents the specific config for // an endpoint group. This is a downcast of the moduleClassConfig. type EndpointClassConfig struct { - Name string `json:"name"` - Type string `json:"type"` + Name string `yaml:"name" json:"name"` + Type string `yaml:"type" json:"type"` Config struct { - Ratelimit int32 `json:"rateLimit"` - Endpoints []string `json:"endpoints"` - } `json:"config"` - Dependencies map[string][]string `json:"dependencies"` + Ratelimit int32 `yaml:"rateLimit" json:"rateLimit"` + Endpoints []string `yaml:"endpoints" json:"endpoints"` + } `yaml:"config" json:"config"` + Dependencies map[string][]string `yaml:"dependencies" json:"dependencies"` } -func parseEndpointJsons( - endpointGroupJsons []string, +func parseEndpointYamls( + endpointGroupYamls []string, ) ([]string, error) { - endpointJsons := []string{} + endpointYamls := []string{} - for _, endpointGroupJSON := range endpointGroupJsons { - bytes, err := ioutil.ReadFile(endpointGroupJSON) + for _, endpointGroupYAML := range endpointGroupYamls { + bytes, err := ioutil.ReadFile(endpointGroupYAML) if err != nil { return nil, errors.Wrapf( - err, "Cannot read endpoint group json: %s", - endpointGroupJSON, + err, "Cannot read endpoint group yaml: %s", + endpointGroupYAML, ) } var endpointConfig EndpointClassConfig - err = json.Unmarshal(bytes, &endpointConfig) + err = yaml.Unmarshal(bytes, &endpointConfig) if err != nil { return nil, errors.Wrapf( - err, "Cannot parse json for endpoint group config: %s", - endpointGroupJSON, + err, "Cannot parse yaml for endpoint group config: %s", + endpointGroupYAML, ) } - endpointConfigDir := filepath.Dir(endpointGroupJSON) + endpointConfigDir := filepath.Dir(endpointGroupYAML) for _, fileName := range endpointConfig.Config.Endpoints { - endpointJsons = append( - endpointJsons, filepath.Join(endpointConfigDir, fileName), + endpointYamls = append( + endpointYamls, filepath.Join(endpointConfigDir, fileName), ) } } - return endpointJsons, nil + return endpointYamls, nil } func parseMiddlewareConfig( @@ -1081,15 +1087,15 @@ func parseMiddlewareConfig( continue } else if err != nil { return nil, errors.Wrapf( - err, "Cannot read middleware config json: %s", + err, "Cannot read middleware config yaml: %s", instanceConfig, ) } var mid MiddlewareConfig - err = json.Unmarshal(bytes, &mid) + err = yaml.Unmarshal(bytes, &mid) if err != nil { return nil, errors.Wrapf( - err, "Cannot parse json for middleware config json: %s", + err, "Cannot parse yaml for middleware config yaml: %s", instanceConfig, ) } diff --git a/codegen/gateway_test.go b/codegen/gateway_test.go index 8e25c0780..e61c5a4c3 100644 --- a/codegen/gateway_test.go +++ b/codegen/gateway_test.go @@ -21,7 +21,6 @@ package codegen import ( - "encoding/json" "testing" "github.com/stretchr/testify/assert" @@ -29,6 +28,7 @@ import ( benchGateway "github.com/uber/zanzibar/test/lib/bench_gateway" testGateway "github.com/uber/zanzibar/test/lib/test_gateway" "github.com/uber/zanzibar/test/lib/util" + yaml "gopkg.in/yaml.v2" ) var defaultTestOptions = &testGateway.Options{ @@ -56,8 +56,8 @@ func TestHeadersPropagateMultiDest(t *testing.T) { ] } }` - middlewareObj := make(map[string]interface{}) - err := json.Unmarshal([]byte(cfg), &middlewareObj) + middlewareObj := make(map[interface{}]interface{}) + err := yaml.Unmarshal([]byte(cfg), &middlewareObj) assert.Nil(t, err) _, err = setPropagateMiddleware(middlewareObj) assert.NotNil(t, err) diff --git a/codegen/module.go b/codegen/module.go index 1dd419ab1..8a629d77e 100644 --- a/codegen/module.go +++ b/codegen/module.go @@ -21,7 +21,6 @@ package codegen import ( - "encoding/json" "fmt" "io/ioutil" "os" @@ -32,6 +31,7 @@ import ( "strings" "github.com/pkg/errors" + yaml "gopkg.in/yaml.v2" ) // moduleType enum defines whether a ModuleClass is a singleton or contains @@ -698,76 +698,77 @@ func (system *ModuleSystem) readInstance( instanceDirectory string, ) (*ModuleInstance, error) { - jsonFileName := className + configSuffix + yamlFileName := className + configSuffix classConfigPath := filepath.Join( baseDirectory, instanceDirectory, - jsonFileName, + yamlFileName, ) - jsonConfig := JSONClassConfig{} - raw, err := jsonConfig.Read(classConfigPath) + yamlConfig := yamlClassConfig{} + raw, err := yamlConfig.Read(classConfigPath) if err != nil { // TODO: We should accumulate errors and list them all here - // Expected $class-config.json to exist in ... + // Expected $class-config.yaml to exist in ... return nil, errors.Wrapf( err, - "Error reading JSON Config %q", + "Error reading Config %q", classConfigPath, ) } - dependencies := readDeps(jsonConfig.Dependencies) + dependencies := readDeps(yamlConfig.Dependencies) packageInfo, err := readPackageInfo( packageRoot, baseDirectory, targetGenDir, className, instanceDirectory, - &jsonConfig, + &yamlConfig, dependencies, ) if err != nil { // TODO: We should accumulate errors and list them all here - // Expected $class-config.json to exist in ... + // Expected $class-config.yaml to exist in ... return nil, errors.Wrapf( err, "Error reading class package info for %q %q", className, - jsonConfig.Name, + yamlConfig.Name, ) } return &ModuleInstance{ PackageInfo: packageInfo, ClassName: className, - ClassType: jsonConfig.Type, + ClassType: yamlConfig.Type, BaseDirectory: baseDirectory, Directory: instanceDirectory, - InstanceName: jsonConfig.Name, + InstanceName: yamlConfig.Name, Dependencies: dependencies, ResolvedDependencies: map[string][]*ModuleInstance{}, RecursiveDependencies: map[string][]*ModuleInstance{}, DependencyOrder: []string{}, - JSONFileName: jsonFileName, - JSONFileRaw: raw, - Config: jsonConfig.Config, + JSONFileName: "", + YAMLFileName: yamlFileName, + YAMLFileRaw: raw, + Config: yamlConfig.Config, }, nil } -func readDeps(jsonDeps map[string][]string) []ModuleDependency { +func readDeps(yamlDeps map[string][]string) []ModuleDependency { depCount := 0 - for _, depsList := range jsonDeps { + for _, depsList := range yamlDeps { depCount += len(depsList) } deps := make([]ModuleDependency, depCount) depIndex := 0 - for className, depsList := range jsonDeps { + for className, depsList := range yamlDeps { for _, instanceName := range depsList { deps[depIndex] = ModuleDependency{ ClassName: className, @@ -786,11 +787,11 @@ func readPackageInfo( targetGenDir string, className string, instanceDirectory string, - jsonConfig *JSONClassConfig, + yamlConfig *yamlClassConfig, dependencies []ModuleDependency, ) (*PackageInfo, error) { qualifiedClassName := strings.Title(CamelCase(className)) - qualifiedInstanceName := strings.Title(CamelCase(jsonConfig.Name)) + qualifiedInstanceName := strings.Title(CamelCase(yamlConfig.Name)) defaultAlias := packageName(qualifiedInstanceName + qualifiedClassName) relativeGeneratedPath, err := filepath.Rel(baseDirectory, targetGenDir) @@ -806,16 +807,16 @@ func readPackageInfo( // type. We should really extrapolate from the class type info what the // default export type is for this instance var isExportGenerated bool - if jsonConfig.Type == "custom" { - if jsonConfig.IsExportGenerated == nil { + if yamlConfig.Type == "custom" { + if yamlConfig.IsExportGenerated == nil { isExportGenerated = false } else { - isExportGenerated = *jsonConfig.IsExportGenerated + isExportGenerated = *yamlConfig.IsExportGenerated } - } else if jsonConfig.IsExportGenerated == nil { + } else if yamlConfig.IsExportGenerated == nil { isExportGenerated = true } else { - isExportGenerated = *jsonConfig.IsExportGenerated + isExportGenerated = *yamlConfig.IsExportGenerated } return &PackageInfo{ @@ -987,7 +988,7 @@ func (system *ModuleSystem) GenerateIncrementalBuild( return nil, err } - serializedModules, err := json.Marshal(resolvedModules) + serializedModules, err := yaml.Marshal(resolvedModules) if err != nil { return nil, errors.Wrap(err, "error serializing module tree") } @@ -1300,13 +1301,13 @@ type ModuleInstance struct { // Directory is the relative instance directory Directory string // InstanceName is the name of the instance as configured in the instance's - // json file + // YAML/JSON file InstanceName string - // Config is a reference to the instance "config" key in the instances json + // Config is a reference to the instance "config" key in the instances YAML //file. Config map[string]interface{} // Dependencies is a list of dependent modules as defined in the instances - // json file + // YAML file Dependencies []ModuleDependency // Resolved dependencies is a list of direct dependent modules after processing // (fully resolved) @@ -1318,10 +1319,12 @@ type ModuleInstance struct { // DependencyOrder is the bottom to top order in which the recursively // resolved dependency class names can depend on each other DependencyOrder []string - // The JSONFileName is file name of the instance json file - JSONFileName string - // JSONFileRaw is the raw JSON file read as bytes used for future parsing - JSONFileRaw []byte + // The JSONFileName is file name of the instance JSON file + JSONFileName string // Deprecated + // The YAMLFileName is file name of the instance YAML file + YAMLFileName string + // YAMLFileRaw is the raw YAML file read as bytes used for future parsing + YAMLFileRaw []byte } // GeneratedSpec returns the last spec result returned for the module instance @@ -1337,28 +1340,28 @@ type ModuleDependency struct { InstanceName string } -// JSONClassConfig maps onto a json configuration for a class type -type JSONClassConfig struct { +// yamlClassConfig maps onto a YAML configuration for a class type +type yamlClassConfig struct { // Name is the class instance name used to identify the module as a // dependency. The combination of the class Name and this instance name // is unique. - Name string `json:"name"` + Name string `yaml:"name" json:"name"` // The configuration map for this class instance. This depends on the // class name and class type, and is interpreted by each module generator. - Config map[string]interface{} `json:"config"` + Config map[string]interface{} `yaml:"config" json:"config"` // Dependencies is a map of class name to a list of instance names. This // infers the dependencies struct generated for the initializer - Dependencies map[string][]string `json:"dependencies"` + Dependencies map[string][]string `yaml:"dependencies" json:"dependencies"` // Type refers to the class type used to generate the dependency - Type string `json:"type"` + Type string `yaml:"type" json:"type"` // IsExportGenerated determines whether or not the export lives in // IsExportGenerated defaults to true if not set. - IsExportGenerated *bool `json:"IsExportGenerated"` + IsExportGenerated *bool `yaml:"IsExportGenerated" json:"IsExportGenerated"` } -// Read will read a class configuration json file into a jsonClassConfig struct +// Read will read a class configuration yaml file into a yamlClassConfig struct // or return an error if it cannot be unmarshaled into the struct -func (jsonConfig *JSONClassConfig) Read( +func (yamlConfig *yamlClassConfig) Read( classConfigPath string, ) ([]byte, error) { configFile, readErr := ioutil.ReadFile(classConfigPath) @@ -1370,32 +1373,32 @@ func (jsonConfig *JSONClassConfig) Read( ) } - parseErr := json.Unmarshal(configFile, &jsonConfig) + parseErr := yaml.Unmarshal(configFile, &yamlConfig) if parseErr != nil { return nil, errors.Wrapf( parseErr, - "Error JSON parsing clss config %q", + "Error yaml parsing clss config %q", configFile, ) } - if jsonConfig.Name == "" { + if yamlConfig.Name == "" { return nil, errors.Errorf( "Error reading instance name from %q", classConfigPath, ) } - if jsonConfig.Type == "" { + if yamlConfig.Type == "" { return nil, errors.Errorf( "Error reading instance type from %q", classConfigPath, ) } - if jsonConfig.Dependencies == nil { - jsonConfig.Dependencies = map[string][]string{} + if yamlConfig.Dependencies == nil { + yamlConfig.Dependencies = map[string][]string{} } return configFile, nil diff --git a/codegen/module_system.go b/codegen/module_system.go index 0ab989416..a620f3a0d 100644 --- a/codegen/module_system.go +++ b/codegen/module_system.go @@ -29,6 +29,7 @@ import ( "github.com/pkg/errors" "go.uber.org/thriftrw/compile" + yaml "gopkg.in/yaml.v2" ) // EndpointMeta saves meta data used to render an endpoint. @@ -69,7 +70,7 @@ type StructMeta struct { type EndpointTestMeta struct { Instance *ModuleInstance Method *MethodSpec - TestFixtures map[string]*EndpointTestFixture `json:"testFixtures"` + TestFixtures map[string]*EndpointTestFixture `yaml:"testFixtures" json:"testFixtures"` ReqHeaders map[string]*TypedHeader ResHeaders map[string]*TypedHeader ClientName string @@ -78,13 +79,29 @@ type EndpointTestMeta struct { IncludedPackages []GoPackageImport } -// FixtureBlob is map[string]interface{} that implements default string -// used for headers and (http | tchannel) request/response -type FixtureBlob map[string]interface{} +// FixtureBlob implements default string used for (http | tchannel) +// request/response +type FixtureBlob map[interface{}]interface{} + +func toStringMap(i map[interface{}]interface{}) map[string]interface{} { + m := make(map[string]interface{}, len(i)) + for k, v := range i { + key := k.(string) + switch val := v.(type) { + case map[interface{}]interface{}: + m[key] = toStringMap(val) + case FixtureBlob: + m[key] = toStringMap(val) + default: + m[key] = v + } + } + return m +} // String convert FixtureBlob to string func (fb *FixtureBlob) String() string { - str, err := json.Marshal(fb) + str, err := json.Marshal(toStringMap(*fb)) if err != nil { panic(err) } @@ -102,9 +119,9 @@ type HTTPMethodType string // FixtureBody is used to create http body in test fixtures type FixtureBody struct { - BodyType BodyType `json:"bodyType,omitempty"` - BodyString string `json:"bodyString,omitempty"` // set BodyString if response body is string - BodyJSON *FixtureBlob `json:"bodyJson,omitempty"` // set BodyJSON if response body is object + BodyType BodyType `yaml:"bodyType,omitempty" json:"bodyType,omitempty"` + BodyString string `yaml:"bodyString,omitempty" json:"bodyString,omitempty"` // set BodyString if response body is string + BodyJSON *FixtureBlob `yaml:"bodyJson,omitempty" json:"bodyJson,omitempty"` // set Body if response body is object } // String convert FixtureBody to string @@ -126,15 +143,15 @@ func (fb *FixtureBody) String() string { // FixtureHTTPResponse is test fixture for http response type FixtureHTTPResponse struct { - StatusCode int `json:"statusCode"` - Body *FixtureBody `json:"body,omitempty"` + StatusCode int `yaml:"statusCode" json:"statusCode"` + Body *FixtureBody `yaml:"body,omitempty" json:"body,omitempty"` } // FixtureResponse is test fixture for client/endpoint response type FixtureResponse struct { - ResponseType ProtocalType `json:"responseType"` - HTTPResponse *FixtureHTTPResponse `json:"httpResponse,omitempty"` - TChannelResponse FixtureBlob `json:"tchannelResponse,omitempty"` + ResponseType ProtocalType `yaml:"responseType" json:"responseType"` + HTTPResponse *FixtureHTTPResponse `yaml:"httpResponse,omitempty" json:"httpResponse,omitempty"` + TChannelResponse FixtureBlob `yaml:"tchannelResponse,omitempty" json:"tchannelResponse,omitempty"` } // Body returns the string representation of FixtureResponse @@ -155,15 +172,15 @@ func (fr *FixtureResponse) Body() string { // FixtureHTTPRequest is test fixture for client/endpoint request type FixtureHTTPRequest struct { - Method HTTPMethodType `json:"method,omitempty"` - Body *FixtureBody `json:"body,omitempty"` + Method HTTPMethodType `yaml:"method,omitempty" json:"method,omitempty"` + Body *FixtureBody `yaml:"body,omitempty" json:"body,omitempty"` } // FixtureRequest is test fixture for client/endpoint request type FixtureRequest struct { - RequestType ProtocalType `json:"requestType"` - HTTPRequest *FixtureHTTPRequest `json:"httpRequest,omitempty"` - TChannelRequest FixtureBlob `json:"tchannelRequest,omitempty"` + RequestType ProtocalType `yaml:"requestType" json:"requestType"` + HTTPRequest *FixtureHTTPRequest `yaml:"httpRequest,omitempty" json:"httpRequest,omitempty"` + TChannelRequest FixtureBlob `yaml:"tchannelRequest,omitempty" json:"tchannelRequest,omitempty"` } // Body returns the string representation of FixtureRequest @@ -182,27 +199,30 @@ func (fr *FixtureRequest) Body() string { } } +// FixtureHeaders implements default string used for headers +type FixtureHeaders map[string]interface{} + // EndpointTestFixture saves mocked requests/responses for an endpoint test. type EndpointTestFixture struct { - TestName string `json:"testName"` - EndpointID string `json:"endpointId"` - HandleID string `json:"handleId"` - EndpointRequest FixtureRequest `json:"endpointRequest"` // there's no difference between http or tchannel request - EndpointReqHeaders FixtureBlob `json:"endpointReqHeaders"` - EndpointResponse FixtureResponse `json:"endpointResponse"` - EndpointResHeaders FixtureBlob `json:"endpointResHeaders"` - ClientTestFixtures map[string]*ClientTestFixture `json:"clientTestFixtures"` - TestServiceName string `json:"testServiceName"` // The service module that mounts the endpoint + TestName string `yaml:"testName" json:"testName"` + EndpointID string `yaml:"endpointId" json:"endpointId"` + HandleID string `yaml:"handleId" json:"handleId"` + EndpointRequest FixtureRequest `yaml:"endpointRequest" json:"endpointRequest"` // there's no difference between http or tchannel request + EndpointReqHeaders FixtureHeaders `yaml:"endpointReqHeaders" json:"endpointReqHeaders"` + EndpointResponse FixtureResponse `yaml:"endpointResponse" json:"endpointResponse"` + EndpointResHeaders FixtureHeaders `yaml:"endpointResHeaders" json:"endpointResHeaders"` + ClientTestFixtures map[string]*ClientTestFixture `yaml:"clientTestFixtures" json:"clientTestFixtures"` + TestServiceName string `yaml:"testServiceName" json:"testServiceName"` // The service module that mounts the endpoint } // ClientTestFixture saves mocked client request/response for an endpoint test. type ClientTestFixture struct { - ClientID string `json:"clientId"` - ClientMethod string `json:"clientMethod"` - ClientRequest FixtureRequest `json:"clientRequest"` // there's no difference between http or tchannel request - ClientReqHeaders FixtureBlob `json:"clientReqHeaders"` - ClientResponse FixtureResponse `json:"clientResponse"` - ClientResHeaders FixtureBlob `json:"clientResHeaders"` + ClientID string `yaml:"clientId" json:"clientId"` + ClientMethod string `yaml:"clientMethod" json:"clientMethod"` + ClientRequest FixtureRequest `yaml:"clientRequest" json:"clientRequest"` // there's no difference between http or tchannel request + ClientReqHeaders FixtureHeaders `yaml:"clientReqHeaders" json:"clientReqHeaders"` + ClientResponse FixtureResponse `yaml:"clientResponse" json:"clientResponse"` + ClientResHeaders FixtureHeaders `yaml:"clientResHeaders" json:"clientResHeaders"` } // NewDefaultModuleSystemWithMockHook creates a fresh instance of the default zanzibar @@ -371,7 +391,7 @@ func NewDefaultModuleSystem( func readClientConfig(rawConfig []byte) (*ClientClassConfig, error) { var clientConfig ClientClassConfig - if err := json.Unmarshal(rawConfig, &clientConfig); err != nil { + if err := yaml.Unmarshal(rawConfig, &clientConfig); err != nil { return nil, errors.Wrapf( err, "Error reading config for client instance", @@ -384,7 +404,7 @@ func readClientConfig(rawConfig []byte) (*ClientClassConfig, error) { func readEndpointConfig(rawConfig []byte) (*EndpointClassConfig, error) { var endpointConfig EndpointClassConfig - if err := json.Unmarshal(rawConfig, &endpointConfig); err != nil { + if err := yaml.Unmarshal(rawConfig, &endpointConfig); err != nil { return nil, errors.Wrapf( err, "Error reading config for endpoint instance", @@ -407,12 +427,12 @@ type HTTPClientGenerator struct { func (g *HTTPClientGenerator) ComputeSpec( instance *ModuleInstance, ) (interface{}, error) { - // Parse the client config from the endpoint JSON file - clientConfig, err := readClientConfig(instance.JSONFileRaw) + // Parse the client config from the endpoint YAML file + clientConfig, err := readClientConfig(instance.YAMLFileRaw) if err != nil { return nil, errors.Wrapf( err, - "Error reading HTTP client %q JSON config", + "Error reading HTTP client %q YAML config", instance.InstanceName, ) } @@ -525,12 +545,12 @@ type TChannelClientGenerator struct { func (g *TChannelClientGenerator) ComputeSpec( instance *ModuleInstance, ) (interface{}, error) { - // Parse the client config from the endpoint JSON file - clientConfig, err := readClientConfig(instance.JSONFileRaw) + // Parse the client config from the endpoint YAML file + clientConfig, err := readClientConfig(instance.YAMLFileRaw) if err != nil { return nil, errors.Wrapf( err, - "Error reading TChannel client %q JSON config", + "Error reading TChannel client %q YAML config", instance.InstanceName, ) } @@ -695,12 +715,12 @@ type CustomClientGenerator struct { func (g *CustomClientGenerator) ComputeSpec( instance *ModuleInstance, ) (interface{}, error) { - // Parse the client config from the endpoint JSON file - clientConfig, err := readClientConfig(instance.JSONFileRaw) + // Parse the client config from the endpoint YAML file + clientConfig, err := readClientConfig(instance.YAMLFileRaw) if err != nil { return nil, errors.Wrapf( err, - "Error reading custom client %q JSON config", + "Error reading custom client %q YAML config", instance.InstanceName, ) } @@ -779,15 +799,15 @@ type EndpointGenerator struct { func (g *EndpointGenerator) ComputeSpec( instance *ModuleInstance, ) (interface{}, error) { - endpointJsons := []string{} + endpointYamls := []string{} endpointSpecs := []*EndpointSpec{} clientSpecs := readClientDependencySpecs(instance) - endpointConfig, err := readEndpointConfig(instance.JSONFileRaw) + endpointConfig, err := readEndpointConfig(instance.YAMLFileRaw) if err != nil { return nil, errors.Wrapf( err, - "Error reading HTTP endpoint %q JSON config", + "Error reading HTTP endpoint %q YAML config", instance.InstanceName, ) } @@ -797,15 +817,15 @@ func (g *EndpointGenerator) ComputeSpec( instance.Directory, ) for _, fileName := range endpointConfig.Config.Endpoints { - endpointJsons = append( - endpointJsons, filepath.Join(endpointConfigDir, fileName), + endpointYamls = append( + endpointYamls, filepath.Join(endpointConfigDir, fileName), ) } - for _, jsonFile := range endpointJsons { - espec, err := NewEndpointSpec(jsonFile, g.packageHelper, g.packageHelper.MiddlewareSpecs()) + for _, yamlFile := range endpointYamls { + espec, err := NewEndpointSpec(yamlFile, g.packageHelper, g.packageHelper.MiddlewareSpecs()) if err != nil { return nil, errors.Wrapf( - err, "Error parsing endpoint json file: %s", jsonFile, + err, "Error parsing endpoint yaml file: %s", yamlFile, ) } @@ -814,7 +834,7 @@ func (g *EndpointGenerator) ComputeSpec( err = espec.SetDownstream(clientSpecs, g.packageHelper) if err != nil { return nil, errors.Wrapf( - err, "Error parsing downstream info for endpoint: %s", jsonFile, + err, "Error parsing downstream info for endpoint: %s", yamlFile, ) } } diff --git a/codegen/module_test.go b/codegen/module_test.go index f8b682b67..f18ac8724 100644 --- a/codegen/module_test.go +++ b/codegen/module_test.go @@ -194,7 +194,7 @@ func TestExampleService(t *testing.T) { ClassType: "tchannel", Directory: "clients/example-dependency", InstanceName: "example-dependency", - JSONFileName: "client-config.json", + YAMLFileName: "client-config.json", PackageInfo: &PackageInfo{ ExportName: "NewClient", ExportType: "Client", @@ -216,7 +216,7 @@ func TestExampleService(t *testing.T) { ClassType: "http", Directory: "clients/example", InstanceName: "example", - JSONFileName: "client-config.json", + YAMLFileName: "client-config.json", PackageInfo: &PackageInfo{ ExportName: "NewClient", ExportType: "Client", @@ -251,7 +251,7 @@ func TestExampleService(t *testing.T) { ClassType: "http", Directory: "endpoints/health/embedded-client", InstanceName: "embedded-client", - JSONFileName: "client-config.json", + YAMLFileName: "client-config.json", PackageInfo: &PackageInfo{ ExportName: "NewClient", ExportType: "Client", @@ -273,7 +273,7 @@ func TestExampleService(t *testing.T) { ClassType: "http", Directory: "endpoints/health", InstanceName: "health", - JSONFileName: "endpoint-config.json", + YAMLFileName: "endpoint-config.json", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -310,7 +310,7 @@ func TestExampleService(t *testing.T) { ClassType: "http", Directory: "more-endpoints/foo", InstanceName: "foo", - JSONFileName: "endpoint-config.json", + YAMLFileName: "endpoint-config.json", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -347,7 +347,7 @@ func TestExampleService(t *testing.T) { ClassType: "http", Directory: "another/bar", InstanceName: "bar", - JSONFileName: "endpoint-config.json", + YAMLFileName: "endpoint-config.json", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -554,6 +554,7 @@ func TestExampleServiceIncremental(t *testing.T) { Directory: "clients/example-dependency", InstanceName: "example-dependency", JSONFileName: "client-config.json", + YAMLFileName: "client-config.json", PackageInfo: &PackageInfo{ ExportName: "NewClient", ExportType: "Client", @@ -576,6 +577,7 @@ func TestExampleServiceIncremental(t *testing.T) { Directory: "clients/example", InstanceName: "example", JSONFileName: "client-config.json", + YAMLFileName: "client-config.json", PackageInfo: &PackageInfo{ ExportName: "NewClient", ExportType: "Client", @@ -611,6 +613,7 @@ func TestExampleServiceIncremental(t *testing.T) { Directory: "endpoints/health/embedded-client", InstanceName: "embedded-client", JSONFileName: "client-config.json", + YAMLFileName: "client-config.json", PackageInfo: &PackageInfo{ ExportName: "NewClient", ExportType: "Client", @@ -633,6 +636,7 @@ func TestExampleServiceIncremental(t *testing.T) { Directory: "endpoints/health", InstanceName: "health", JSONFileName: "endpoint-config.json", + YAMLFileName: "endpoint-config.json", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -670,6 +674,7 @@ func TestExampleServiceIncremental(t *testing.T) { Directory: "more-endpoints/foo", InstanceName: "foo", JSONFileName: "endpoint-config.json", + YAMLFileName: "endpoint-config.json", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -707,6 +712,7 @@ func TestExampleServiceIncremental(t *testing.T) { Directory: "another/bar", InstanceName: "bar", JSONFileName: "endpoint-config.json", + YAMLFileName: "endpoint-config.json", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -1134,7 +1140,7 @@ func createTestInstance(name string, depInstances ...*ModuleInstance) *ModuleIns ClassType: "http", Directory: "clients/example", InstanceName: name, - JSONFileName: "client-config.json", + YAMLFileName: "client-config.json", PackageInfo: &PackageInfo{ ExportName: "NewClient", ExportType: "Client", @@ -1285,12 +1291,12 @@ func compareInstances( ) } - if actual.JSONFileName != expected.JSONFileName { + if actual.YAMLFileName != expected.YAMLFileName { t.Errorf( "Expected %s json file name to be %s but found %s", expected.ClassName, - expected.JSONFileName, - actual.JSONFileName, + expected.YAMLFileName, + actual.YAMLFileName, ) } diff --git a/codegen/post_gen_hooks.go b/codegen/post_gen_hooks.go index b9541c0cc..de7b975c0 100644 --- a/codegen/post_gen_hooks.go +++ b/codegen/post_gen_hooks.go @@ -21,7 +21,6 @@ package codegen import ( - "encoding/json" "fmt" "path" "path/filepath" @@ -31,6 +30,7 @@ import ( "sync/atomic" "github.com/pkg/errors" + yaml "gopkg.in/yaml.v2" ) const ( @@ -40,22 +40,22 @@ const ( // helper struct to pull out the fixture config type moduleConfig struct { - Config *config `json:"config"` + Config *config `yaml:"config"` } -// config is the struct corresponding to the config field in client-config.json +// config is the struct corresponding to the config field in client-config.yaml type config struct { - CustomImportPath string `json:"customImportPath"` - Fixture *Fixture `json:"fixture"` + CustomImportPath string `yaml:"customImportPath"` + Fixture *Fixture `yaml:"fixture"` } // Fixture specifies client fixture import path and all scenarios type Fixture struct { // ImportPath is the package where the user-defined Fixture global variable is contained. // The Fixture object defines, for a given client, the standardized list of fixture scenarios for that client - ImportPath string `json:"importPath"` + ImportPath string `yaml:"importPath" json:"importPath"` // Scenarios is a map from zanzibar's exposed method name to a list of user-defined fixture scenarios for a client - Scenarios map[string][]string `json:"scenarios"` + Scenarios map[string][]string `yaml:"scenarios" json:"scenarios"` } // Validate the fixture configuration @@ -89,10 +89,10 @@ func ClientMockGenHook(h *PackageHelper, t *Template) (PostGenHook, error) { for _, instance := range clientInstances { key := instance.ClassType + instance.InstanceName var mc moduleConfig - if err := json.Unmarshal(instance.JSONFileRaw, &mc); err != nil { + if err := yaml.Unmarshal(instance.YAMLFileRaw, &mc); err != nil { return errors.Wrapf( err, - "error parsing client-config.json for client %q", + "error parsing client-config for client %q", instance.InstanceName, ) } @@ -316,10 +316,10 @@ func FindClientsWithFixture(instance *ModuleInstance) (map[string]string, error) clientsWithFixture := map[string]string{} for _, leaf := range instance.RecursiveDependencies["client"] { var mc moduleConfig - if err := json.Unmarshal(leaf.JSONFileRaw, &mc); err != nil { + if err := yaml.Unmarshal(leaf.YAMLFileRaw, &mc); err != nil { return nil, errors.Wrapf( err, - "error parsing client-config.json for client %q", + "error parsing client-config for client %q", instance.InstanceName, ) } diff --git a/codegen/template.go b/codegen/template.go index 07381c9ac..5bc47babf 100644 --- a/codegen/template.go +++ b/codegen/template.go @@ -22,7 +22,6 @@ package codegen import ( "bytes" - "encoding/json" "io" "os" "path/filepath" @@ -60,7 +59,6 @@ var defaultFuncMap = tmpl.FuncMap{ "dec": decrement, "basePath": filepath.Base, "pascal": PascalCase, - "jsonMarshal": jsonMarshal, "isPointerType": IsPointerType, "unref": Unref, "lintAcronym": LintAcronym, @@ -78,11 +76,6 @@ func decrement(num int) int { return num - 1 } -func jsonMarshal(jsonObj map[string]interface{}) (string, error) { - str, err := json.Marshal(jsonObj) - return string(str), err -} - // IsPointerType determines if the passed in string is a string for a pointer func IsPointerType(t string) bool { return strings.HasPrefix(t, "*") diff --git a/codegen/test_data/endpoint_tests/bar_bar_method_argnotstruct_test.gogen b/codegen/test_data/endpoint_tests/bar_bar_method_argnotstruct_test.gogen index 142ece216..7bf94e5a5 100755 --- a/codegen/test_data/endpoint_tests/bar_bar_method_argnotstruct_test.gogen +++ b/codegen/test_data/endpoint_tests/bar_bar_method_argnotstruct_test.gogen @@ -73,7 +73,7 @@ func TestArgNotStructSuccessfulRequestOKResponse(t *testing.T) { w.WriteHeader(200) - payload := []byte(`null`) + payload := []byte(`{}`) // TODO(zw): generate client response. if _, err := w.Write(payload); err != nil { diff --git a/examples/example-gateway/build/endpoints/bar/bar_bar_method_argnotstruct_test.go b/examples/example-gateway/build/endpoints/bar/bar_bar_method_argnotstruct_test.go index 142ece216..7bf94e5a5 100644 --- a/examples/example-gateway/build/endpoints/bar/bar_bar_method_argnotstruct_test.go +++ b/examples/example-gateway/build/endpoints/bar/bar_bar_method_argnotstruct_test.go @@ -73,7 +73,7 @@ func TestArgNotStructSuccessfulRequestOKResponse(t *testing.T) { w.WriteHeader(200) - payload := []byte(`null`) + payload := []byte(`{}`) // TODO(zw): generate client response. if _, err := w.Write(payload); err != nil { diff --git a/test/lib/test_gateway/test_gateway_cover.go b/test/lib/test_gateway/test_gateway_cover.go index 9a3d9c107..d45cc18ff 100644 --- a/test/lib/test_gateway/test_gateway_cover.go +++ b/test/lib/test_gateway/test_gateway_cover.go @@ -33,6 +33,7 @@ import ( "strings" "github.com/pkg/errors" + yaml "gopkg.in/yaml.v2" ) var cachedBinaryFile *testBinaryInfo @@ -70,23 +71,23 @@ func (info *testBinaryInfo) Cleanup() { } func writeConfigToFile(config map[string]interface{}) (string, error) { - tempConfigDir, err := ioutil.TempDir("", "example-gateway-config-json") + tempConfigDir, err := ioutil.TempDir("", "example-gateway-config-yaml") if err != nil { return "", err } - jsonFile := path.Join(tempConfigDir, "test.json") - configBytes, err := json.Marshal(config) + yamlFile := path.Join(tempConfigDir, "test.json") + configBytes, err := yaml.Marshal(config) if err != nil { return "", err } - err = ioutil.WriteFile(jsonFile, configBytes, os.ModePerm) + err = ioutil.WriteFile(yamlFile, configBytes, os.ModePerm) if err != nil { return "", err } - return jsonFile, nil + return yamlFile, nil } func makeRandStr() (string, error) {