diff --git a/codegen/module.go b/codegen/module.go index 4b16ae7af..43ba360f9 100644 --- a/codegen/module.go +++ b/codegen/module.go @@ -51,19 +51,21 @@ const jsonConfigSuffix = "-config.json" const yamlConfigSuffix = "-config.yaml" // NewModuleSystem returns a new module system -func NewModuleSystem(postGenHook ...PostGenHook) *ModuleSystem { +func NewModuleSystem(moduleSearchPaths []string, postGenHook ...PostGenHook) *ModuleSystem { return &ModuleSystem{ - classes: map[string]*ModuleClass{}, - classOrder: []string{}, - postGenHook: postGenHook, + classes: map[string]*ModuleClass{}, + classOrder: []string{}, + postGenHook: postGenHook, + moduleSearchPaths: moduleSearchPaths, } } // ModuleSystem defines the module classes and their type generators type ModuleSystem struct { - classes map[string]*ModuleClass - classOrder []string - postGenHook []PostGenHook + classes map[string]*ModuleClass + classOrder []string + postGenHook []PostGenHook + moduleSearchPaths []string } // PostGenHook provides a way to do work after the build is generated, @@ -78,19 +80,12 @@ func (system *ModuleSystem) RegisterClass(class ModuleClass) error { return errors.Errorf("A module class name must not be empty") } - if system.classes[name] != nil { - return errors.Errorf("Module class %q is already defined", name) - } - - for i, dir := range class.Directories { - class.Directories[i] = filepath.Clean(dir) + if class.NamePlural == "" { + return errors.Errorf("A module class name plural must not be empty") } - class.Directories = dedup(class.Directories) - for _, dir := range class.Directories { - if err := system.validateClassDir(&class, dir); err != nil { - return err - } + if system.classes[name] != nil { + return errors.Errorf("Module class %q is already defined", name) } class.types = map[string]BuildGenerator{} @@ -134,26 +129,10 @@ func (system *ModuleSystem) validateClassDir(class *ModuleClass, dir string) err // RegisterClassDir adds the given dir to the directories of the module class with given className. // This method allows projects built on zanzibar to have arbitrary directories to host module class // configs, therefore is mainly intended for external use. +// +// Deprecated: Module search paths deprecates this function. func (system *ModuleSystem) RegisterClassDir(className string, dir string) error { - dir = filepath.Clean(dir) - for _, class := range system.classes { - if className != class.Name { - continue - } - - if err := system.validateClassDir(class, dir); err != nil { - return err - } - - for _, registered := range class.Directories { - if dir == registered { - return nil - } - } - class.Directories = append(class.Directories, dir) - return nil - } - return errors.Errorf("Module class %q is not found", className) + return nil } // RegisterClassType registers a type generator for a specific module class @@ -218,6 +197,8 @@ func (system *ModuleSystem) populateResolvedDependencies( } if dependencyInstance == nil { + fmt.Printf("known module instances: %+v", resolvedModules) + return errors.Errorf( "Unknown %q class depdendency %q"+ "in dependencies for %q %q", @@ -290,10 +271,22 @@ func (system *ModuleSystem) populateRecursiveDependencies( continue } - classInstance.DependencyOrder = append( - classInstance.DependencyOrder, - className, - ) + // If a glob pattern matches the same module class multiple times, make sure that DependencyOrder + // remains the unique list of classes. + + found := false + for _, dependencyOrderClassName := range classInstance.DependencyOrder { + if dependencyOrderClassName == className { + found = true + break + } + } + if !found { + classInstance.DependencyOrder = append( + classInstance.DependencyOrder, + className, + ) + } moduleList := make([]*ModuleInstance, len(moduleMap)) index := 0 @@ -534,6 +527,31 @@ func (system *ModuleSystem) resolveClassOrder() error { return nil } +// Given a module instance name like "app/foo/clients/bar", strip the "clients" part, i.e. usually the +// second to last path part. +func stripModuleClassName(classType, moduleDir string) string { + parts := strings.Split(moduleDir, string(filepath.Separator)) + + if len(parts) == 1 { + return moduleDir + } + + for i := len(parts) - 1; i >= 0; i-- { + if parts[i] == classType { + + // Shift parts left starting with ith element, overwriting parts[i] + for j := i + 1; j < len(parts); j++ { + parts[j-1] = parts[j] + } + + parts = parts[0 : len(parts)-1] + + break + } + } + return strings.Join(parts, string(filepath.Separator)) +} + // ResolveModules resolves the module instances from the config on disk // Using the system class and type definitions, the class directories are // walked, and a module instance is initialized for each identified module in @@ -550,56 +568,85 @@ func (system *ModuleSystem) ResolveModules( resolvedModules := map[string][]*ModuleInstance{} - for _, className := range system.classOrder { - class := system.classes[className] - classInstances := []*ModuleInstance{} + for _, moduleDirectoryGlob := range system.moduleSearchPaths { + moduleDirectoriesAbs, err := filepath.Glob(filepath.Join(baseDirectory, moduleDirectoryGlob)) + if err != nil { + return nil, errors.Wrapf(err, "Error globbing %q", moduleDirectoryGlob) + } + + // We don't know until reading the configuration file what the class name will be. For consistency we will + // continue to assume that all of the instances that match a glob pattern are the same class name, so + // once we've read the first instance we can populate this. + className := "" + + for _, moduleDirAbs := range moduleDirectoriesAbs { + stat, err := os.Stat(moduleDirAbs) + if err != nil { + return nil, errors.Wrapf( + err, + "internal error: cannot stat %q", + moduleDirAbs, + ) + } - for _, dir := range class.Directories { + if !stat.IsDir() { + // If a *-config.yaml file, or any other metadata file also matched the glob, skip it, since we are + // interested only in the containing directories. + continue + } - fullInstanceDirectory := filepath.Join(baseDirectory, dir) - if class.ClassType == SingleModule { - instance, instanceErr := system.readInstance( - packageRoot, + moduleDir, err := filepath.Rel(baseDirectory, moduleDirAbs) + if err != nil { + return nil, errors.Wrapf( + err, + "internal error: cannot make %q relative to %q", + moduleDirAbs, baseDirectory, - targetGenDir, - className, - dir, ) - if instanceErr != nil { + } + + instance, instanceErr := system.readInstance( + packageRoot, + baseDirectory, + targetGenDir, + moduleDir, + ) + if instanceErr != nil { + if _, ok := instanceErr.(inferError); ok { + // It could be the case that a glob pattern like "endpoints/*" matches a folder that is later + // matched by a longer glob pattern like "endpoints/tchannel/*", so merely print a warning here + // rather than failing to generate. It will fail at a later step if no globbing pattern matches + // the wanted instance. + fmt.Printf("warn: globbing pattern %q: %s\n", moduleDirectoryGlob, instanceErr.Error()) + continue + } else { return nil, errors.Wrapf( instanceErr, - "Error reading single instance %q in %q", - className, - dir, + "Error reading multi instance %q", + moduleDir, ) } - classInstances = append(classInstances, instance) - } else { - instances, err := system.resolveMultiModules( - packageRoot, - baseDirectory, - targetGenDir, - fullInstanceDirectory, - className, - class, - ) + } - if err != nil { - return nil, errors.Wrapf(err, - "Error reading resolving multi modules of %q", - className, - ) - } + resolvedModules[instance.ClassName] = append(resolvedModules[instance.ClassName], instance) - classInstances = append(classInstances, instances...) + // For consistency with prior zanzibar behavior of assuming all instances in a multi-module directory + // are of the same class name, we will return an error in this case. + if className == "" { + className = instance.ClassName + } else if className != instance.ClassName { + return nil, fmt.Errorf( + "invariant: all instances in a multi-module directory %q are of type %q (violated by %q)", + moduleDirectoryGlob, + className, + moduleDir, + ) } } - resolvedModules[className] = classInstances - // Resolve dependencies for all classes resolveErr := system.populateResolvedDependencies( - classInstances, + resolvedModules[className], resolvedModules, ) if resolveErr != nil { @@ -607,7 +654,7 @@ func (system *ModuleSystem) ResolveModules( } // Resolved recursive dependencies for all classes - recursiveErr := system.populateRecursiveDependencies(classInstances) + recursiveErr := system.populateRecursiveDependencies(resolvedModules[className]) if recursiveErr != nil { return nil, recursiveErr } @@ -616,113 +663,56 @@ func (system *ModuleSystem) ResolveModules( return resolvedModules, nil } -func getConfigFilePath(dir, name string) (string, string, string) { - yamlFileName := name + yamlConfigSuffix - jsonFileName := "" - path := filepath.Join(dir, yamlFileName) - if _, err := os.Stat(path); os.IsNotExist(err) { - // Cannot find yaml file, try json file instead - jsonFileName = name + jsonConfigSuffix - yamlFileName = jsonFileName - path = filepath.Join(dir, jsonFileName) - if _, err := os.Stat(path); os.IsNotExist(err) { - // Cannot find any config file - path = "" - jsonFileName = "" - yamlFileName = "" - } - } +type inferError struct { + InstanceDirectory string +} - return path, yamlFileName, jsonFileName +func (i inferError) Error() string { + return fmt.Sprintf("could not infer class name for %q", i.InstanceDirectory) } -func (system *ModuleSystem) resolveMultiModules( +func (system *ModuleSystem) readInstance( packageRoot string, baseDirectory string, targetGenDir string, - classDir string, // full path - className string, - class *ModuleClass, -) ([]*ModuleInstance, error) { - relClassDir, err := filepath.Rel(baseDirectory, classDir) - if err != nil { - return nil, errors.Wrapf(err, - "Error relative class directory for %q", - className, - ) - } - - configFile, _, _ := getConfigFilePath(classDir, className) - - if configFile != "" { - instance, instanceErr := system.readInstance( - packageRoot, - baseDirectory, - targetGenDir, - className, - relClassDir, - ) - if instanceErr != nil { - return nil, errors.Wrapf( - instanceErr, - "Error reading multi instance %q in %q", - className, - relClassDir, - ) - } - return []*ModuleInstance{instance}, nil - } - - classInstances := []*ModuleInstance{} - files, err := ioutil.ReadDir(classDir) + instanceDirectory string, +) (*ModuleInstance, error) { + classConfigDir := filepath.Join(baseDirectory, instanceDirectory) + // Try to infer the class name based on what *-config.yaml files exist. + instanceFiles, err := ioutil.ReadDir(classConfigDir) if err != nil { - // TODO: We should accumulate errors and list them all here - // Expected $path to be a class directory return nil, errors.Wrapf( err, - "Error reading module instance directory %q", - classDir, + "error scanning %q for ClassConfig", + classConfigDir, ) } - for _, file := range files { - if !file.IsDir() { - continue + var ( + className, jsonFileName, yamlFileName, classConfigPath string + ) + for _, instanceFile := range instanceFiles { + if strings.HasSuffix(instanceFile.Name(), yamlConfigSuffix) { + className = strings.TrimSuffix(instanceFile.Name(), yamlConfigSuffix) + yamlFileName = instanceFile.Name() + // TODO(jacobg): Is this necessary? + // jsonFileName = instanceFile.Name() + classConfigPath = filepath.Join(classConfigDir, yamlFileName) + break } - instances, err := system.resolveMultiModules( - packageRoot, - baseDirectory, - targetGenDir, - filepath.Join(classDir, file.Name()), - className, - class, - ) - if err != nil { - return nil, errors.Wrapf(err, - "Error reading subdir of multi instance %q in %q", - className, - filepath.Join(relClassDir, file.Name()), - ) + if strings.HasSuffix(instanceFile.Name(), jsonConfigSuffix) { + className = strings.TrimSuffix(instanceFile.Name(), jsonConfigSuffix) + jsonFileName = instanceFile.Name() + classConfigPath = filepath.Join(classConfigDir, jsonFileName) + break } - classInstances = append(classInstances, instances...) } - return classInstances, nil -} - -func (system *ModuleSystem) readInstance( - packageRoot string, - baseDirectory string, - targetGenDir string, - className string, - instanceDirectory string, -) (*ModuleInstance, error) { - - classConfigDir := filepath.Join(baseDirectory, instanceDirectory) - classConfigPath, yamlFileName, jsonFileName := getConfigFilePath( - classConfigDir, className) + if classConfigPath == "" { + return nil, inferError{InstanceDirectory: instanceDirectory} + } raw, readErr := ioutil.ReadFile(classConfigPath) if readErr != nil { @@ -769,13 +759,20 @@ func (system *ModuleSystem) readInstance( ) } + var classPlural string + for _, moduleClass := range system.classes { + if moduleClass.Name == className { + classPlural = moduleClass.NamePlural + } + } + return &ModuleInstance{ PackageInfo: packageInfo, ClassName: className, ClassType: config.Type, BaseDirectory: baseDirectory, Directory: instanceDirectory, - InstanceName: config.Name, + InstanceName: stripModuleClassName(classPlural, instanceDirectory), Dependencies: dependencies, ResolvedDependencies: map[string][]*ModuleInstance{}, RecursiveDependencies: map[string][]*ModuleInstance{}, @@ -1215,8 +1212,11 @@ func FormatGoFile(filePath string) error { // THis could be something like an Endpoint class which contains multiple // endpoint configurations, or a Lib class, that is itself a module instance type ModuleClass struct { - Name string - ClassType moduleClassType + Name string + NamePlural string + ClassType moduleClassType + + // Deprecated: Hard coded list of directory names is replaced with dynamic module search path in build.yaml. Directories []string DependsOn []string DependedBy []string @@ -1362,6 +1362,10 @@ type ModuleInstance struct { YAMLFileRaw []byte } +func (instance *ModuleInstance) String() string { + return fmt.Sprintf("[instance %q %q]", instance.ClassType, instance.InstanceName) +} + // GeneratedSpec returns the last spec result returned for the module instance func (instance *ModuleInstance) GeneratedSpec() interface{} { return instance.genSpec diff --git a/codegen/module_system.go b/codegen/module_system.go index fb18f4650..287c3096f 100644 --- a/codegen/module_system.go +++ b/codegen/module_system.go @@ -258,7 +258,7 @@ func NewDefaultModuleSystem( h *PackageHelper, hooks ...PostGenHook, ) (*ModuleSystem, error) { - system := NewModuleSystem(hooks...) + system := NewModuleSystem(h.moduleSearchPaths, hooks...) tmpl, err := NewDefaultTemplate() if err != nil { @@ -267,9 +267,9 @@ func NewDefaultModuleSystem( // Register client module class and type generators if err := system.RegisterClass(ModuleClass{ - Name: "client", - Directories: []string{"clients"}, - ClassType: MultiModule, + Name: "client", + NamePlural: "clients", + ClassType: MultiModule, }); err != nil { return nil, errors.Wrapf(err, "Error registering client class") } @@ -305,10 +305,10 @@ func NewDefaultModuleSystem( } if err := system.RegisterClass(ModuleClass{ - Name: "middleware", - Directories: []string{"middlewares"}, - ClassType: MultiModule, - DependsOn: []string{"client"}, + Name: "middleware", + NamePlural: "middlewares", + ClassType: MultiModule, + DependsOn: []string{"client"}, }); err != nil { return nil, errors.Wrapf( err, @@ -338,10 +338,10 @@ func NewDefaultModuleSystem( // Register endpoint module class and type generators if err := system.RegisterClass(ModuleClass{ - Name: "endpoint", - Directories: []string{"endpoints"}, - ClassType: MultiModule, - DependsOn: []string{"client", "middleware"}, + Name: "endpoint", + NamePlural: "endpoints", + ClassType: MultiModule, + DependsOn: []string{"client", "middleware"}, }); err != nil { return nil, errors.Wrapf(err, "Error registering endpoint class") } @@ -367,10 +367,10 @@ func NewDefaultModuleSystem( } if err := system.RegisterClass(ModuleClass{ - Name: "service", - Directories: []string{"services"}, - ClassType: MultiModule, - DependsOn: []string{"endpoint"}, + Name: "service", + NamePlural: "services", + ClassType: MultiModule, + DependsOn: []string{"endpoint"}, }); err != nil { return nil, errors.Wrapf( err, diff --git a/codegen/module_test.go b/codegen/module_test.go index 86198968b..0b90d369e 100644 --- a/codegen/module_test.go +++ b/codegen/module_test.go @@ -76,13 +76,23 @@ func (*TestHTTPEndpointGenerator) Generate( } func TestExampleService(t *testing.T) { - moduleSystem := NewModuleSystem() + moduleSystem := NewModuleSystem( + []string{ + "clients/*", + "endpoints/*", + "middlewares/*", + "services/*", + "another/*", + "more-endpoints/*", + "endpoints/*/*", + }, + ) var err error err = moduleSystem.RegisterClass(ModuleClass{ - Name: "client", - ClassType: MultiModule, - Directories: []string{"clients"}, + Name: "client", + NamePlural: "clients", + ClassType: MultiModule, }) if err != nil { t.Errorf("Unexpected error registering client class: %s", err) @@ -106,26 +116,16 @@ func TestExampleService(t *testing.T) { t.Errorf("Unexpected error registering tchannel client class type: %s", err) } - err = moduleSystem.RegisterClassDir("endpoint", "another") - if err == nil { - t.Error("Registering class dir for endpoint class should have errored") - } - err = moduleSystem.RegisterClass(ModuleClass{ - Name: "endpoint", - ClassType: MultiModule, - DependsOn: []string{"client"}, - Directories: []string{"endpoints", "more-endpoints"}, + Name: "endpoint", + NamePlural: "endpoints", + ClassType: MultiModule, + DependsOn: []string{"client"}, }) if err != nil { t.Errorf("Unexpected error registering endpoint class: %s", err) } - err = moduleSystem.RegisterClassDir("endpoint", "another") - if err != nil { - t.Errorf("Unexpected error registering endpoint class dir: %s", err) - } - err = moduleSystem.RegisterClassType( "endpoint", "http", @@ -145,9 +145,9 @@ func TestExampleService(t *testing.T) { } err = moduleSystem.RegisterClass(ModuleClass{ - Name: "client", - ClassType: MultiModule, - Directories: []string{"clients"}, + Name: "client", + NamePlural: "clients", + ClassType: MultiModule, }) if err == nil { t.Errorf("Expected double definition of client class to error") @@ -158,15 +158,6 @@ func TestExampleService(t *testing.T) { t.Error("Unexpected error registering dir for client class") } - err = moduleSystem.RegisterClass(ModuleClass{ - Name: "newClient", - ClassType: MultiModule, - Directories: []string{"./clients/../../../foo"}, - }) - if err == nil { - t.Errorf("Expected registering a module in an external directory to throw") - } - currentDir := getTestDirName() testServiceDir := path.Join(currentDir, "test-service") @@ -277,7 +268,7 @@ func TestExampleService(t *testing.T) { Directory: "endpoints/health", InstanceName: "health", JSONFileName: "endpoint-config.json", - YAMLFileName: "endpoint-config.json", + YAMLFileName: "", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -313,7 +304,7 @@ func TestExampleService(t *testing.T) { ClassName: "endpoint", ClassType: "http", Directory: "more-endpoints/foo", - InstanceName: "foo", + InstanceName: "more-endpoints/foo", JSONFileName: "", YAMLFileName: "endpoint-config.yaml", PackageInfo: &PackageInfo{ @@ -351,7 +342,7 @@ func TestExampleService(t *testing.T) { ClassName: "endpoint", ClassType: "http", Directory: "another/bar", - InstanceName: "bar", + InstanceName: "another/bar", JSONFileName: "", YAMLFileName: "endpoint-config.yaml", PackageInfo: &PackageInfo{ @@ -389,10 +380,11 @@ func TestExampleService(t *testing.T) { &expectedClientDependency, &expectedEmbeddedClient, } + // Note: Stable ordering is not required by POSIX expectedEndpoints := []*ModuleInstance{ &expectedHealthEndpointInstance, - &expectedFooEndpointInstance, &expectedBarEndpointInstance, + &expectedFooEndpointInstance, } for className, classInstances := range instances { @@ -436,11 +428,12 @@ func TestExampleService(t *testing.T) { } func TestExampleServiceIncremental(t *testing.T) { - moduleSystem := NewModuleSystem() + moduleSystem := NewModuleSystem([]string{}) var err error err = moduleSystem.RegisterClass(ModuleClass{ Name: "client", + NamePlural: "clients", ClassType: MultiModule, Directories: []string{"clients"}, }) @@ -466,13 +459,9 @@ func TestExampleServiceIncremental(t *testing.T) { t.Errorf("Unexpected error registering tchannel client class type: %s", err) } - err = moduleSystem.RegisterClassDir("endpoint", "another") - if err == nil { - t.Error("Registering class dir for endpoint class should have errored") - } - err = moduleSystem.RegisterClass(ModuleClass{ Name: "endpoint", + NamePlural: "endpoints", ClassType: MultiModule, DependsOn: []string{"client"}, Directories: []string{"endpoints", "more-endpoints"}, @@ -506,6 +495,7 @@ func TestExampleServiceIncremental(t *testing.T) { err = moduleSystem.RegisterClass(ModuleClass{ Name: "client", + NamePlural: "clients", ClassType: MultiModule, Directories: []string{"clients"}, }) @@ -518,15 +508,6 @@ func TestExampleServiceIncremental(t *testing.T) { t.Error("Unexpected error registering dir for client class") } - err = moduleSystem.RegisterClass(ModuleClass{ - Name: "newClient", - ClassType: MultiModule, - Directories: []string{"./clients/../../../foo"}, - }) - if err == nil { - t.Errorf("Expected registering a module in an external directory to throw") - } - currentDir := getTestDirName() testServiceDir := path.Join(currentDir, "test-service") @@ -642,7 +623,7 @@ func TestExampleServiceIncremental(t *testing.T) { Directory: "endpoints/health", InstanceName: "health", JSONFileName: "endpoint-config.json", - YAMLFileName: "endpoint-config.json", + YAMLFileName: "", PackageInfo: &PackageInfo{ ExportName: "NewEndpoint", ExportType: "Endpoint", @@ -678,7 +659,7 @@ func TestExampleServiceIncremental(t *testing.T) { ClassName: "endpoint", ClassType: "http", Directory: "more-endpoints/foo", - InstanceName: "foo", + InstanceName: "more-endpoints/foo", JSONFileName: "", YAMLFileName: "endpoint-config.yaml", PackageInfo: &PackageInfo{ @@ -801,13 +782,16 @@ func TestExampleServiceIncremental(t *testing.T) { } func TestExampleServiceCycles(t *testing.T) { - moduleSystem := NewModuleSystem() + moduleSystem := NewModuleSystem([]string{ + "clients/*", + "endpoints/*", + }) var err error err = moduleSystem.RegisterClass(ModuleClass{ - Name: "client", - ClassType: MultiModule, - Directories: []string{"clients"}, + Name: "client", + NamePlural: "clients", + ClassType: MultiModule, }) if err != nil { t.Errorf("Unexpected error registering client class: %s", err) @@ -823,10 +807,10 @@ func TestExampleServiceCycles(t *testing.T) { } err = moduleSystem.RegisterClass(ModuleClass{ - Name: "endpoint", - ClassType: MultiModule, - DependsOn: []string{"client"}, - Directories: []string{"endpoints"}, + Name: "endpoint", + NamePlural: "endpoints", + ClassType: MultiModule, + DependsOn: []string{"client"}, }) if err != nil { t.Errorf("Unexpected error registering endpoint class: %s", err) @@ -911,14 +895,16 @@ func TestSortDependencies(t *testing.T) { } func TestSortModuleClasses(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", DependsOn: []string{"a"}, DependedBy: []string{"c"}, Directories: []string{"b"}, @@ -926,12 +912,14 @@ func TestSortModuleClasses(t *testing.T) { assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "c", + NamePlural: "cs", DependsOn: []string{"b"}, Directories: []string{"c"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "d", + NamePlural: "ds", DependsOn: []string{"a"}, DependedBy: []string{"c"}, Directories: []string{"d"}, @@ -944,24 +932,28 @@ func TestSortModuleClasses(t *testing.T) { } func TestSortModuleClassesNoDeps(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", Directories: []string{"b"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "c", + NamePlural: "cs", Directories: []string{"c"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "d", + NamePlural: "ds", Directories: []string{"d"}, }) assert.NoError(t, err) @@ -972,15 +964,17 @@ func TestSortModuleClassesNoDeps(t *testing.T) { } func TestSortModuleClassesUndefined(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", DependsOn: []string{"c"}, Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", DependsOn: []string{"a"}, Directories: []string{"b"}, }) @@ -991,15 +985,17 @@ func TestSortModuleClassesUndefined(t *testing.T) { } func TestSortModuleClassesUndefined2(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", DependedBy: []string{"c"}, Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", DependedBy: []string{"a"}, Directories: []string{"b"}, }) @@ -1010,15 +1006,17 @@ func TestSortModuleClassesUndefined2(t *testing.T) { } func TestSortableModuleClassCycle(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", DependsOn: []string{"b"}, Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", DependsOn: []string{"a"}, Directories: []string{"b"}, }) @@ -1030,15 +1028,17 @@ func TestSortableModuleClassCycle(t *testing.T) { } func TestSortableModuleClassCycle2(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", DependedBy: []string{"b"}, Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", DependedBy: []string{"a"}, Directories: []string{"b"}, }) @@ -1050,21 +1050,24 @@ func TestSortableModuleClassCycle2(t *testing.T) { } func TestSortModuleClassesIndirectCycle(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", DependsOn: []string{"b"}, Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", DependsOn: []string{"c"}, Directories: []string{"b"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "c", + NamePlural: "cs", DependsOn: []string{"a"}, Directories: []string{"c"}, }) @@ -1075,21 +1078,24 @@ func TestSortModuleClassesIndirectCycle(t *testing.T) { } func TestSortModuleClassesIndirectCycle2(t *testing.T) { - ms := NewModuleSystem() + ms := NewModuleSystem([]string{}) err := ms.RegisterClass(ModuleClass{ Name: "a", + NamePlural: "as", DependedBy: []string{"b"}, Directories: []string{"a"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "b", + NamePlural: "bs", DependedBy: []string{"c"}, Directories: []string{"b"}, }) assert.NoError(t, err) err = ms.RegisterClass(ModuleClass{ Name: "c", + NamePlural: "cs", DependedBy: []string{"a"}, Directories: []string{"c"}, }) @@ -1222,7 +1228,9 @@ func compareInstances( ) { if actual.ClassName != expected.ClassName { t.Errorf( - "Expected class name to be %s but found %s", + "Expected class name of %q %q to be %q but found %q", + expected.ClassName, + expected.InstanceName, expected.ClassName, actual.ClassName, ) @@ -1230,8 +1238,9 @@ func compareInstances( if actual.BaseDirectory != expected.BaseDirectory { t.Errorf( - "Expected %s base directory to be %s but found %s", + "Expected %q %q base directory to be %q but found %q", expected.ClassName, + expected.InstanceName, expected.BaseDirectory, actual.BaseDirectory, ) @@ -1239,17 +1248,19 @@ func compareInstances( if actual.ClassType != expected.ClassType { t.Errorf( - "Expected %s class type to be %s but found %s", + "Expected %q %q class type to be %q but found %q", expected.ClassName, - expected.ClassType, - actual.ClassType, + expected.InstanceName, + expected.ClassName, + actual.ClassName, ) } if len(actual.Dependencies) != len(expected.Dependencies) { t.Errorf( - "Expected %s to have %d dependencies but found %d", + "Expected %q %q to have %d dependencies but found %d", expected.ClassName, + expected.InstanceName, len(expected.Dependencies), len(actual.Dependencies), ) @@ -1260,8 +1271,9 @@ func compareInstances( if actualDependency.ClassName != expectedDependency.ClassName { t.Errorf( - "Expected %s dependency %d class name to be %s but found %s", + "Expected %q %q dependency %d class name to be %s but found %s", expected.ClassName, + expected.InstanceName, di, expectedDependency.ClassName, actualDependency.ClassName, @@ -1270,7 +1282,8 @@ func compareInstances( if actualDependency.InstanceName != expectedDependency.InstanceName { t.Errorf( - "Expected %s dependency %d instance name to be %s but found %s", + "Expected %q %q dependency %d instance name to be %s but found %s", + expected.ClassName, expected.InstanceName, di, expectedDependency.InstanceName, @@ -1281,8 +1294,9 @@ func compareInstances( if actual.Directory != expected.Directory { t.Errorf( - "Expected %s directory to be %s but found %s", + "Expected %q %q directory to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.Directory, actual.Directory, ) @@ -1290,17 +1304,19 @@ func compareInstances( if actual.InstanceName != expected.InstanceName { t.Errorf( - "Expected %s instance name to be %s but found %s", + "Expected %q %q instance name to be %s but found %s", expected.ClassName, expected.InstanceName, + expected.InstanceName, actual.InstanceName, ) } if actual.YAMLFileName != expected.YAMLFileName { t.Errorf( - "Expected %s yaml file name to be %s but found %s", + "Expected %q %q yaml file name to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.YAMLFileName, actual.YAMLFileName, ) @@ -1308,8 +1324,9 @@ func compareInstances( if actual.JSONFileName != expected.JSONFileName { t.Errorf( - "Expected %s json file name to be %s but found %s", + "Expected %q %q json file name to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.JSONFileName, actual.JSONFileName, ) @@ -1317,8 +1334,9 @@ func compareInstances( if actual.PackageInfo.ExportName != expected.PackageInfo.ExportName { t.Errorf( - "Expected %s package export name to be %s but found %s", + "Expected %q %q package export name to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.ExportName, actual.PackageInfo.ExportName, ) @@ -1326,8 +1344,9 @@ func compareInstances( if actual.PackageInfo.ExportType != expected.PackageInfo.ExportType { t.Errorf( - "Expected %s package export type to be %s but found %s", + "Expected %q %q package export type to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.ExportType, actual.PackageInfo.ExportType, ) @@ -1335,8 +1354,9 @@ func compareInstances( if actual.PackageInfo.GeneratedPackageAlias != expected.PackageInfo.GeneratedPackageAlias { t.Errorf( - "Expected %s generated package alias to be %s but found %s", + "Expected %q %q generated package alias to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.GeneratedPackageAlias, actual.PackageInfo.GeneratedPackageAlias, ) @@ -1344,8 +1364,9 @@ func compareInstances( if actual.PackageInfo.GeneratedPackagePath != expected.PackageInfo.GeneratedPackagePath { t.Errorf( - "Expected %s generated package path to be %s but found %s", + "Expected %q %q generated package path to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.GeneratedPackagePath, actual.PackageInfo.GeneratedPackagePath, ) @@ -1353,8 +1374,9 @@ func compareInstances( if actual.PackageInfo.IsExportGenerated != expected.PackageInfo.IsExportGenerated { t.Errorf( - "Expected %s IsExportGenerated to be %t but found %t", + "Expected %q %q IsExportGenerated to be %t but found %t", expected.ClassName, + expected.InstanceName, expected.PackageInfo.IsExportGenerated, actual.PackageInfo.IsExportGenerated, ) @@ -1362,8 +1384,9 @@ func compareInstances( if actual.PackageInfo.PackageAlias != expected.PackageInfo.PackageAlias { t.Errorf( - "Expected %s package alias to be %s but found %s", + "Expected %q %q package alias to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.PackageAlias, actual.PackageInfo.PackageAlias, ) @@ -1371,8 +1394,9 @@ func compareInstances( if actual.PackageInfo.PackageName != expected.PackageInfo.PackageName { t.Errorf( - "Expected %s package name to be %s but found %s", + "Expected %q %q package name to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.PackageName, actual.PackageInfo.PackageName, ) @@ -1380,8 +1404,9 @@ func compareInstances( if actual.PackageInfo.PackagePath != expected.PackageInfo.PackagePath { t.Errorf( - "Expected %s package path to be %s but found %s", + "Expected %q %q package path to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.PackagePath, actual.PackageInfo.PackagePath, ) @@ -1389,8 +1414,9 @@ func compareInstances( if actual.PackageInfo.ExportName != expected.PackageInfo.ExportName { t.Errorf( - "Expected %s package export name to be %s but found %s", + "Expected %q %q package export name to be %s but found %s", expected.ClassName, + expected.InstanceName, expected.PackageInfo.ExportName, actual.PackageInfo.ExportName, ) @@ -1398,9 +1424,9 @@ func compareInstances( if len(expected.ResolvedDependencies) != len(actual.ResolvedDependencies) { t.Errorf( - "Expected %s %s to have %d resolved dependency class names but found %d", - expected.InstanceName, + "Expected %q %q to have %d resolved dependency class names but found %d", expected.ClassName, + expected.InstanceName, len(expected.ResolvedDependencies), len(actual.ResolvedDependencies), ) @@ -1482,3 +1508,50 @@ func compareInstances( } } } + +func TestModulePathStripping(t *testing.T) { + assert.Equal(t, "foo", stripModuleClassName("clients", "clients/foo")) + assert.Equal(t, "a/b/d", stripModuleClassName("c", "a/b/c/d")) + assert.Equal(t, "tchannel/foo", stripModuleClassName("endpoints", "endpoints/tchannel/foo")) +} + +func TestModuleSearchDuplicateGlobs(t *testing.T) { + moduleSystem := NewModuleSystem([]string{ + "clients/*", + "clients/*", + }) + var err error + + err = moduleSystem.RegisterClass(ModuleClass{ + Name: "client", + NamePlural: "clients", + ClassType: MultiModule, + }) + assert.NoError(t, err) + + err = moduleSystem.RegisterClassType( + "client", + "http", + &TestHTTPClientGenerator{}, + ) + assert.NoError(t, err) + + currentDir := getTestDirName() + testServiceDir := path.Join(currentDir, "test-service") + + defer func() { + err := os.Remove(path.Join(testServiceDir, "build", serializedModuleTreePath)) + if err != nil { + panic(errors.Wrap(err, "error removing serialized module tree")) + } + }() + instances, err := moduleSystem.GenerateBuild( + "github.com/uber/zanzibar/codegen/test-service", + testServiceDir, + path.Join(testServiceDir, "build"), + false, + ) + assert.NoError(t, err) + + assert.Equal(t, []string{"client"}, instances["client"][0].DependencyOrder) +} diff --git a/codegen/package.go b/codegen/package.go index 0d6c1c1c8..84a299888 100644 --- a/codegen/package.go +++ b/codegen/package.go @@ -57,6 +57,8 @@ type PackageHelper struct { deputyReqHeader string // traceKey is the key for unique trace id that identifies request / response pair traceKey string + // moduleSearchPaths is a list of glob patterns for folders that contain *-config.yaml files + moduleSearchPaths []string } //NewDefaultPackageHelperOptions returns a new default PackageHelperOptions, all optional fields are set as default. @@ -88,6 +90,8 @@ type PackageHelperOptions struct { DeputyReqHeader string // header key to uniquely identifies request/response pair, defaults to "x-trace-id" TraceKey string + // ModuleSearchPaths is a list of glob patterns for folders that contain *-config.yaml files + ModuleSearchPaths []string } func (p *PackageHelperOptions) relTargetGenDir() string { @@ -193,6 +197,7 @@ func NewPackageHelper( stagingReqHeader: options.stagingReqHeader(), deputyReqHeader: options.deputyReqHeader(), traceKey: options.traceKey(), + moduleSearchPaths: options.ModuleSearchPaths, } return p, nil } diff --git a/codegen/runner/runner.go b/codegen/runner/runner.go index a9df043cb..b0b3ea720 100644 --- a/codegen/runner/runner.go +++ b/codegen/runner/runner.go @@ -91,6 +91,9 @@ func main() { if config.ContainsKey("deputyReqHeader") { deputyReqHeader = config.MustGetString("deputyReqHeader") } + + searchPaths := make([]string, 0) + config.MustGetStruct("moduleSearchPaths", &searchPaths) options := &codegen.PackageHelperOptions{ RelThriftRootDir: config.MustGetString("thriftRootDir"), RelTargetGenDir: config.MustGetString("targetGenDir"), @@ -101,6 +104,7 @@ func main() { StagingReqHeader: stagingReqHeader, DeputyReqHeader: deputyReqHeader, TraceKey: config.MustGetString("traceKey"), + ModuleSearchPaths: searchPaths, } packageHelper, err := codegen.NewPackageHelper( diff --git a/examples/example-gateway/app/demo/endpoints/abc/abc.go b/examples/example-gateway/app/demo/endpoints/abc/abc.go new file mode 100644 index 000000000..1ad726f18 --- /dev/null +++ b/examples/example-gateway/app/demo/endpoints/abc/abc.go @@ -0,0 +1,20 @@ +package abc + +import ( + "context" + "github.com/uber/zanzibar/runtime" + + module "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/module" + workflow "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/workflow" +) + +// NewAppDemoServiceCallWorkflow creates the demo app service callback workflow. +func NewAppDemoServiceCallWorkflow(deps *module.Dependencies) workflow.AppDemoServiceCallWorkflow { + return &demo{} +} + +type demo struct{} + +func (h *demo) Handle(ctx context.Context, reqHeaders zanzibar.Header) (int32, zanzibar.Header, error) { + return 0, nil, nil +} diff --git a/examples/example-gateway/app/demo/endpoints/abc/call.yaml b/examples/example-gateway/app/demo/endpoints/abc/call.yaml new file mode 100644 index 000000000..c87572af0 --- /dev/null +++ b/examples/example-gateway/app/demo/endpoints/abc/call.yaml @@ -0,0 +1,8 @@ +endpointId: appDemoAbc +endpointType: tchannel +handleId: call +thriftFile: endpoints/app/demo/endpoints/abc.thrift +thriftFileSha: '{{placeholder}}' +thriftMethodName: AppDemoService::Call +workflowImportPath: github.com/uber/zanzibar/examples/example-gateway/app/demo/endpoints/abc +workflowType: custom diff --git a/examples/example-gateway/app/demo/endpoints/abc/endpoint-config.yaml b/examples/example-gateway/app/demo/endpoints/abc/endpoint-config.yaml new file mode 100644 index 000000000..eaa0f72d9 --- /dev/null +++ b/examples/example-gateway/app/demo/endpoints/abc/endpoint-config.yaml @@ -0,0 +1,8 @@ +config: + endpoints: + - call.yaml +dependencies: + client: + - baz +name: appDemoAbc +type: tchannel diff --git a/examples/example-gateway/app/demo/services/xyz/service-config.yaml b/examples/example-gateway/app/demo/services/xyz/service-config.yaml new file mode 100644 index 000000000..34dbe912f --- /dev/null +++ b/examples/example-gateway/app/demo/services/xyz/service-config.yaml @@ -0,0 +1,7 @@ +config: {} +dependencies: + endpoint: + - bar + - app/demo/abc +name: xyz +type: gateway diff --git a/examples/example-gateway/build.yaml b/examples/example-gateway/build.yaml index 22b3b0205..6435bc850 100644 --- a/examples/example-gateway/build.yaml +++ b/examples/example-gateway/build.yaml @@ -9,3 +9,12 @@ packageRoot: github.com/uber/zanzibar/examples/example-gateway targetGenDir: ./build thriftRootDir: ./idl traceKey: x-trace-id +moduleSearchPaths: +- clients/* +- middlewares/* +- endpoints/* +- endpoints/tchannel/* +- services/* +- app/*/clients/* +- app/*/endpoints/* +- app/*/services/* diff --git a/examples/example-gateway/build/app/demo/endpoints/abc/abc_appdemoservice_method_call_tchannel.go b/examples/example-gateway/build/app/demo/endpoints/abc/abc_appdemoservice_method_call_tchannel.go new file mode 100644 index 000000000..cabc40471 --- /dev/null +++ b/examples/example-gateway/build/app/demo/endpoints/abc/abc_appdemoservice_method_call_tchannel.go @@ -0,0 +1,111 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package appdemoabcendpoint + +import ( + "context" + "runtime/debug" + + "github.com/pkg/errors" + zanzibar "github.com/uber/zanzibar/runtime" + "go.uber.org/thriftrw/wire" + "go.uber.org/zap" + + customAbc "github.com/uber/zanzibar/examples/example-gateway/app/demo/endpoints/abc" + endpointsAppDemoEndpointsAbc "github.com/uber/zanzibar/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/abc" + + module "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/module" +) + +// NewAppDemoServiceCallHandler creates a handler to be registered with a thrift server. +func NewAppDemoServiceCallHandler(deps *module.Dependencies) *AppDemoServiceCallHandler { + handler := &AppDemoServiceCallHandler{ + Deps: deps, + } + handler.endpoint = zanzibar.NewTChannelEndpoint( + "appDemoAbc", "call", "AppDemoService::Call", + handler, + ) + + return handler +} + +// AppDemoServiceCallHandler is the handler for "AppDemoService::Call". +type AppDemoServiceCallHandler struct { + Deps *module.Dependencies + endpoint *zanzibar.TChannelEndpoint +} + +// Register adds the tchannel handler to the gateway's tchannel router +func (h *AppDemoServiceCallHandler) Register(g *zanzibar.Gateway) error { + return g.TChannelRouter.Register(h.endpoint) +} + +// Handle handles RPC call of "AppDemoService::Call". +func (h *AppDemoServiceCallHandler) Handle( + ctx context.Context, + reqHeaders map[string]string, + wireValue *wire.Value, +) (isSuccessful bool, response zanzibar.RWTStruct, headers map[string]string, e error) { + defer func() { + if r := recover(); r != nil { + stacktrace := string(debug.Stack()) + e = errors.Errorf("enpoint panic: %v, stacktrace: %v", r, stacktrace) + h.Deps.Default.ContextLogger.Error( + ctx, + "Endpoint failure: endpoint panic", + zap.Error(e), + zap.String("stacktrace", stacktrace), + zap.String("endpoint", h.endpoint.EndpointID)) + + h.Deps.Default.ContextMetrics.IncCounter(ctx, zanzibar.MetricEndpointPanics, 1) + isSuccessful = false + response = nil + headers = nil + } + }() + + wfReqHeaders := zanzibar.ServerTChannelHeader(reqHeaders) + + var res endpointsAppDemoEndpointsAbc.AppDemoService_Call_Result + + workflow := customAbc.NewAppDemoServiceCallWorkflow(h.Deps) + + r, wfResHeaders, err := workflow.Handle(ctx, wfReqHeaders) + + resHeaders := map[string]string{} + if wfResHeaders != nil { + for _, key := range wfResHeaders.Keys() { + resHeaders[key], _ = wfResHeaders.Get(key) + } + } + + if err != nil { + h.Deps.Default.ContextLogger.Error(ctx, "Endpoint failure: handler returned error", zap.Error(err)) + return false, nil, resHeaders, err + } + res.Success = &r + + return err == nil, &res, resHeaders, nil +} diff --git a/examples/example-gateway/build/app/demo/endpoints/abc/endpoint.go b/examples/example-gateway/build/app/demo/endpoints/abc/endpoint.go new file mode 100644 index 000000000..e2d99208f --- /dev/null +++ b/examples/example-gateway/build/app/demo/endpoints/abc/endpoint.go @@ -0,0 +1,56 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package appdemoabcendpoint + +import ( + module "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/module" + zanzibar "github.com/uber/zanzibar/runtime" +) + +// Endpoint registers a request handler on a gateway +type Endpoint interface { + Register(*zanzibar.Gateway) error +} + +// NewEndpoint returns a collection of endpoints that can be registered on +// a gateway +func NewEndpoint(deps *module.Dependencies) Endpoint { + return &EndpointHandlers{ + AppDemoServiceCallHandler: NewAppDemoServiceCallHandler(deps), + } +} + +// EndpointHandlers is a collection of individual endpoint handlers +type EndpointHandlers struct { + AppDemoServiceCallHandler *AppDemoServiceCallHandler +} + +// Register registers the endpoint handlers with the gateway +func (handlers *EndpointHandlers) Register(gateway *zanzibar.Gateway) error { + err0 := handlers.AppDemoServiceCallHandler.Register(gateway) + if err0 != nil { + return err0 + } + return nil +} diff --git a/examples/example-gateway/build/app/demo/endpoints/abc/mock-workflow/appdemoservice_call_workflow_mock.go b/examples/example-gateway/build/app/demo/endpoints/abc/mock-workflow/appdemoservice_call_workflow_mock.go new file mode 100644 index 000000000..8271f78cb --- /dev/null +++ b/examples/example-gateway/build/app/demo/endpoints/abc/mock-workflow/appdemoservice_call_workflow_mock.go @@ -0,0 +1,68 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package mockappdemoabcworkflow + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/uber-go/tally" + zanzibar "github.com/uber/zanzibar/runtime" + "go.uber.org/zap" + + appdemoabcendpointstatic "github.com/uber/zanzibar/examples/example-gateway/app/demo/endpoints/abc" + module "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/module" + workflow "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/workflow" + bazclientgeneratedmock "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz/mock-client" +) + +// NewAppDemoServiceCallWorkflowMock creates a workflow with mock clients +func NewAppDemoServiceCallWorkflowMock(t *testing.T) (workflow.AppDemoServiceCallWorkflow, *MockClientNodes) { + ctrl := gomock.NewController(t) + + initializedDefaultDependencies := &zanzibar.DefaultDependencies{ + Logger: zap.NewNop(), + Scope: tally.NewTestScope("", make(map[string]string)), + } + initializedDefaultDependencies.ContextLogger = zanzibar.NewContextLogger(initializedDefaultDependencies.Logger) + contextExtractors := &zanzibar.ContextExtractors{} + initializedDefaultDependencies.ContextExtractor = contextExtractors.MakeContextExtractor() + + initializedClientDependencies := &clientDependenciesNodes{} + mockClientNodes := &MockClientNodes{ + Baz: bazclientgeneratedmock.NewMockClient(ctrl), + } + initializedClientDependencies.Baz = mockClientNodes.Baz + + w := appdemoabcendpointstatic.NewAppDemoServiceCallWorkflow( + &module.Dependencies{ + Default: initializedDefaultDependencies, + Client: &module.ClientDependencies{ + Baz: initializedClientDependencies.Baz, + }, + }, + ) + + return w, mockClientNodes +} diff --git a/examples/example-gateway/build/app/demo/endpoints/abc/mock-workflow/type.go b/examples/example-gateway/build/app/demo/endpoints/abc/mock-workflow/type.go new file mode 100644 index 000000000..2e0145690 --- /dev/null +++ b/examples/example-gateway/build/app/demo/endpoints/abc/mock-workflow/type.go @@ -0,0 +1,39 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package mockappdemoabcworkflow + +import ( + bazclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz" + bazclientgeneratedmock "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz/mock-client" +) + +// MockClientNodes contains mock client dependencies for the app/demo/abc endpoint module +type MockClientNodes struct { + Baz *bazclientgeneratedmock.MockClient +} + +// clientDependenciesNodes contains client dependencies +type clientDependenciesNodes struct { + Baz bazclientgenerated.Client +} diff --git a/examples/example-gateway/build/app/demo/endpoints/abc/module/dependencies.go b/examples/example-gateway/build/app/demo/endpoints/abc/module/dependencies.go new file mode 100644 index 000000000..f9bb38ecb --- /dev/null +++ b/examples/example-gateway/build/app/demo/endpoints/abc/module/dependencies.go @@ -0,0 +1,41 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package module + +import ( + bazclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz" + + zanzibar "github.com/uber/zanzibar/runtime" +) + +// Dependencies contains dependencies for the app/demo/abc endpoint module +type Dependencies struct { + Default *zanzibar.DefaultDependencies + Client *ClientDependencies +} + +// ClientDependencies contains client dependencies +type ClientDependencies struct { + Baz bazclientgenerated.Client +} diff --git a/examples/example-gateway/build/app/demo/endpoints/abc/workflow/abc_appdemoservice_method_call_tchannel.go b/examples/example-gateway/build/app/demo/endpoints/abc/workflow/abc_appdemoservice_method_call_tchannel.go new file mode 100644 index 000000000..cf4b24d4b --- /dev/null +++ b/examples/example-gateway/build/app/demo/endpoints/abc/workflow/abc_appdemoservice_method_call_tchannel.go @@ -0,0 +1,38 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package workflow + +import ( + "context" + + zanzibar "github.com/uber/zanzibar/runtime" +) + +// AppDemoServiceCallWorkflow defines the interface for AppDemoServiceCall workflow +type AppDemoServiceCallWorkflow interface { + Handle( + ctx context.Context, + reqHeaders zanzibar.Header, + ) (int32, zanzibar.Header, error) +} diff --git a/examples/example-gateway/build/app/demo/services/xyz/main/main.go b/examples/example-gateway/build/app/demo/services/xyz/main/main.go new file mode 100644 index 000000000..f2de3276e --- /dev/null +++ b/examples/example-gateway/build/app/demo/services/xyz/main/main.go @@ -0,0 +1,116 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "flag" + "os" + "os/signal" + "strings" + "syscall" + + _ "go.uber.org/automaxprocs" + "go.uber.org/fx" + "go.uber.org/zap" + + "github.com/uber/zanzibar/config" + zanzibar "github.com/uber/zanzibar/runtime" + + app "github.com/uber/zanzibar/examples/example-gateway" + service "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/services/xyz" +) + +var configFiles *string + +func getConfig() *zanzibar.StaticConfig { + var files []string + + if configFiles == nil { + files = []string{} + } else { + files = strings.Split(*configFiles, ";") + } + + return config.NewRuntimeConfigOrDie(files, nil) +} + +func createGateway() (*zanzibar.Gateway, error) { + config := getConfig() + + gateway, _, err := service.CreateGateway(config, app.AppOptions) + if err != nil { + return nil, err + } + + return gateway, nil +} + +func logAndWait(server *zanzibar.Gateway) { + server.Logger.Info("Started AppDemoXyz", + zap.String("realHTTPAddr", server.RealHTTPAddr), + zap.String("realTChannelAddr", server.RealTChannelAddr), + zap.Any("config", server.InspectOrDie()), + ) + + go func() { + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) + <-sig + server.WaitGroup.Add(1) + server.Shutdown() + server.WaitGroup.Done() + }() + server.Wait() +} + +func readFlags() { + configFiles = flag.String( + "config", + "", + "an ordered, semi-colon separated list of configuration files to use", + ) + flag.Parse() +} + +func main() { + app := fx.New( + fx.Invoke(zanzibarMain), + ) + app.Run() +} + +func zanzibarMain() { + readFlags() + server, err := createGateway() + if err != nil { + panic(err) + } + + err = server.Bootstrap() + if err != nil { + panic(err) + } + + logAndWait(server) +} diff --git a/examples/example-gateway/build/app/demo/services/xyz/main/main_test.go b/examples/example-gateway/build/app/demo/services/xyz/main/main_test.go new file mode 100644 index 000000000..89f22277c --- /dev/null +++ b/examples/example-gateway/build/app/demo/services/xyz/main/main_test.go @@ -0,0 +1,93 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "os" + "os/signal" + "syscall" + "testing" + + zanzibar "github.com/uber/zanzibar/runtime" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var cachedServer *zanzibar.Gateway + +func TestMain(m *testing.M) { + readFlags() + if os.Getenv("GATEWAY_RUN_CHILD_PROCESS_TEST") != "" { + listenOnSignals() + + code := m.Run() + os.Exit(code) + } else { + os.Exit(0) + } +} + +func listenOnSignals() { + sigs := make(chan os.Signal, 1) + + signal.Notify(sigs, syscall.SIGUSR2) + + go func() { + <-sigs + + if cachedServer != nil { + cachedServer.Close() + } + }() +} + +func TestStartGateway(t *testing.T) { + testLogger := zap.New( + zapcore.NewCore( + zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), + os.Stderr, + zap.InfoLevel, + ), + ) + + gateway, err := createGateway() + if err != nil { + testLogger.Error( + "Failed to CreateGateway in TestStartGateway()", + zap.Error(err), + ) + return + } + + cachedServer = gateway + err = gateway.Bootstrap() + if err != nil { + testLogger.Error( + "Failed to Bootstrap in TestStartGateway()", + zap.Error(err), + ) + return + } + logAndWait(gateway) +} diff --git a/examples/example-gateway/build/app/demo/services/xyz/mock-service/mock_init.go b/examples/example-gateway/build/app/demo/services/xyz/mock-service/mock_init.go new file mode 100644 index 000000000..6d9f0131f --- /dev/null +++ b/examples/example-gateway/build/app/demo/services/xyz/mock-service/mock_init.go @@ -0,0 +1,111 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package xyzservicegeneratedmock + +import ( + "github.com/golang/mock/gomock" + module "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/services/xyz/module" + zanzibar "github.com/uber/zanzibar/runtime" + + appdemoabcendpointgenerated "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc" + appdemoabcendpointmodule "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/module" + barclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/bar/mock-client" + bazclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz/mock-client" + barendpointgenerated "github.com/uber/zanzibar/examples/example-gateway/build/endpoints/bar" + barendpointmodule "github.com/uber/zanzibar/examples/example-gateway/build/endpoints/bar/module" + examplemiddlewaregenerated "github.com/uber/zanzibar/examples/example-gateway/build/middlewares/example" + examplemiddlewaremodule "github.com/uber/zanzibar/examples/example-gateway/build/middlewares/example/module" +) + +// MockClientNodes contains mock client dependencies +type MockClientNodes struct { + Bar *barclientgenerated.MockClient + Baz *bazclientgenerated.MockClient +} + +// InitializeDependenciesMock fully initializes all dependencies in the dep tree +// for the app/demo/xyz service with leaf nodes being mocks +func InitializeDependenciesMock( + g *zanzibar.Gateway, + ctrl *gomock.Controller, +) (*module.DependenciesTree, *module.Dependencies, *MockClientNodes) { + tree := &module.DependenciesTree{} + + initializedDefaultDependencies := &zanzibar.DefaultDependencies{ + ContextExtractor: g.ContextExtractor, + ContextMetrics: g.ContextMetrics, + ContextLogger: g.ContextLogger, + Logger: g.Logger, + Scope: g.RootScope, + Config: g.Config, + Channel: g.Channel, + Tracer: g.Tracer, + } + + mockClientNodes := &MockClientNodes{ + Bar: barclientgenerated.NewMockClient(ctrl), + Baz: bazclientgenerated.NewMockClient(ctrl), + } + initializedClientDependencies := &module.ClientDependenciesNodes{} + tree.Client = initializedClientDependencies + initializedClientDependencies.Bar = mockClientNodes.Bar + initializedClientDependencies.Baz = mockClientNodes.Baz + + initializedMiddlewareDependencies := &module.MiddlewareDependenciesNodes{} + tree.Middleware = initializedMiddlewareDependencies + initializedMiddlewareDependencies.Example = examplemiddlewaregenerated.NewMiddleware(&examplemiddlewaremodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &examplemiddlewaremodule.ClientDependencies{ + Baz: initializedClientDependencies.Baz, + }, + }) + + initializedEndpointDependencies := &module.EndpointDependenciesNodes{} + tree.Endpoint = initializedEndpointDependencies + initializedEndpointDependencies.AppDemoAbc = appdemoabcendpointgenerated.NewEndpoint(&appdemoabcendpointmodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &appdemoabcendpointmodule.ClientDependencies{ + Baz: initializedClientDependencies.Baz, + }, + }) + initializedEndpointDependencies.Bar = barendpointgenerated.NewEndpoint(&barendpointmodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &barendpointmodule.ClientDependencies{ + Bar: initializedClientDependencies.Bar, + }, + Middleware: &barendpointmodule.MiddlewareDependencies{ + Example: initializedMiddlewareDependencies.Example, + }, + }) + + dependencies := &module.Dependencies{ + Default: initializedDefaultDependencies, + Endpoint: &module.EndpointDependencies{ + AppDemoAbc: initializedEndpointDependencies.AppDemoAbc, + Bar: initializedEndpointDependencies.Bar, + }, + } + + return tree, dependencies, mockClientNodes +} diff --git a/examples/example-gateway/build/app/demo/services/xyz/mock-service/mock_service.go b/examples/example-gateway/build/app/demo/services/xyz/mock-service/mock_service.go new file mode 100644 index 000000000..8941547bd --- /dev/null +++ b/examples/example-gateway/build/app/demo/services/xyz/mock-service/mock_service.go @@ -0,0 +1,195 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package xyzservicegeneratedmock + +import ( + "context" + "errors" + "io" + "net/http" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/uber/zanzibar/config" + zanzibar "github.com/uber/zanzibar/runtime" + + service "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/services/xyz" +) + +// MockService interface +type MockService interface { + MakeHTTPRequest( + method string, + url string, + headers map[string]string, + body io.Reader, + ) (*http.Response, error) + MakeTChannelRequest( + ctx context.Context, + thriftService string, + method string, + headers map[string]string, + req, resp zanzibar.RWTStruct, + ) (bool, map[string]string, error) + MockClients() *MockClientNodes + Server() *zanzibar.Gateway + Start() + Stop() +} + +type mockService struct { + started bool + server *zanzibar.Gateway + ctrl *gomock.Controller + mockClients *MockClientNodes + httpClient *http.Client + tChannelClient zanzibar.TChannelCaller +} + +// MustCreateTestService creates a new MockService, panics if it fails doing so. +func MustCreateTestService(t *testing.T) MockService { + _, file, _, _ := runtime.Caller(0) + currentDir := zanzibar.GetDirnameFromRuntimeCaller(file) + testConfigPath := filepath.Join(currentDir, "../../../../config/test.yaml") + c := config.NewRuntimeConfigOrDie([]string{testConfigPath}, nil) + + server, err := zanzibar.CreateGateway(c, nil) + if err != nil { + panic(err) + } + + ctrl := gomock.NewController(t) + _, dependencies, mockNodes := InitializeDependenciesMock(server, ctrl) + registerErr := service.RegisterDeps(server, dependencies) + if registerErr != nil { + panic(registerErr) + } + + httpClient := &http.Client{ + Transport: &http.Transport{ + DisableKeepAlives: false, + MaxIdleConns: 500, + MaxIdleConnsPerHost: 500, + }, + } + + timeout := time.Duration(10000) * time.Millisecond + timeoutPerAttempt := time.Duration(2000) * time.Millisecond + + tchannelClient := zanzibar.NewRawTChannelClient( + server.Channel, + server.Logger, + server.RootScope, + &zanzibar.TChannelClientOption{ + ServiceName: server.ServiceName, + ClientID: "TestClient", + Timeout: timeout, + TimeoutPerAttempt: timeoutPerAttempt, + }, + ) + + return &mockService{ + server: server, + ctrl: ctrl, + mockClients: mockNodes, + httpClient: httpClient, + tChannelClient: tchannelClient, + } +} + +// Server returns the mock server +func (m *mockService) Server() *zanzibar.Gateway { + return m.server +} + +// Start starts the mock server, panics if fails doing so +func (m *mockService) Start() { + if err := m.server.Bootstrap(); err != nil { + panic(err) + } + m.started = true +} + +// Stop stops the mock server +func (m *mockService) Stop() { + // m.ctrl.Finish() calls runtime.Goexit() on errors + // put it in defer so cleanup is always done + defer func() { + m.server.Close() + m.started = false + }() + m.ctrl.Finish() +} + +// MockClients returns the mock clients +func (m *mockService) MockClients() *MockClientNodes { + return m.mockClients +} + +// MakeHTTPRequest makes a HTTP request to the mock server +func (m *mockService) MakeHTTPRequest( + method string, + url string, + headers map[string]string, + body io.Reader, +) (*http.Response, error) { + if !m.started { + return nil, errors.New("mock server is not started") + } + + client := m.httpClient + + fullURL := "http://" + m.server.RealHTTPAddr + url + + req, err := http.NewRequest(method, fullURL, body) + for headerName, headerValue := range headers { + req.Header.Set(headerName, headerValue) + } + + if err != nil { + return nil, err + } + + return client.Do(req) +} + +// MakeTChannelRequest makes a TChannel request to the mock server +func (m *mockService) MakeTChannelRequest( + ctx context.Context, + thriftService string, + method string, + headers map[string]string, + req, res zanzibar.RWTStruct, +) (bool, map[string]string, error) { + if !m.started { + return false, nil, errors.New("mock server is not started") + } + + sc := m.server.Channel.GetSubChannel(m.server.ServiceName) + sc.Peers().Add(m.server.RealTChannelAddr) + return m.tChannelClient.Call(ctx, thriftService, method, headers, req, res) +} diff --git a/examples/example-gateway/build/app/demo/services/xyz/module/dependencies.go b/examples/example-gateway/build/app/demo/services/xyz/module/dependencies.go new file mode 100644 index 000000000..c8f410c26 --- /dev/null +++ b/examples/example-gateway/build/app/demo/services/xyz/module/dependencies.go @@ -0,0 +1,43 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package module + +import ( + appdemoabcendpointgenerated "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc" + barendpointgenerated "github.com/uber/zanzibar/examples/example-gateway/build/endpoints/bar" + + zanzibar "github.com/uber/zanzibar/runtime" +) + +// Dependencies contains dependencies for the app/demo/xyz service module +type Dependencies struct { + Default *zanzibar.DefaultDependencies + Endpoint *EndpointDependencies +} + +// EndpointDependencies contains endpoint dependencies +type EndpointDependencies struct { + AppDemoAbc appdemoabcendpointgenerated.Endpoint + Bar barendpointgenerated.Endpoint +} diff --git a/examples/example-gateway/build/app/demo/services/xyz/module/init.go b/examples/example-gateway/build/app/demo/services/xyz/module/init.go new file mode 100644 index 000000000..704ace302 --- /dev/null +++ b/examples/example-gateway/build/app/demo/services/xyz/module/init.go @@ -0,0 +1,128 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package module + +import ( + appdemoabcendpointgenerated "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc" + appdemoabcendpointmodule "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/endpoints/abc/module" + barclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/bar" + barclientmodule "github.com/uber/zanzibar/examples/example-gateway/build/clients/bar/module" + bazclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz" + bazclientmodule "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz/module" + barendpointgenerated "github.com/uber/zanzibar/examples/example-gateway/build/endpoints/bar" + barendpointmodule "github.com/uber/zanzibar/examples/example-gateway/build/endpoints/bar/module" + examplemiddlewaregenerated "github.com/uber/zanzibar/examples/example-gateway/build/middlewares/example" + examplemiddlewaremodule "github.com/uber/zanzibar/examples/example-gateway/build/middlewares/example/module" + + zanzibar "github.com/uber/zanzibar/runtime" +) + +// DependenciesTree contains all deps for this service. +type DependenciesTree struct { + Client *ClientDependenciesNodes + Middleware *MiddlewareDependenciesNodes + Endpoint *EndpointDependenciesNodes +} + +// ClientDependenciesNodes contains client dependencies +type ClientDependenciesNodes struct { + Bar barclientgenerated.Client + Baz bazclientgenerated.Client +} + +// MiddlewareDependenciesNodes contains middleware dependencies +type MiddlewareDependenciesNodes struct { + Example examplemiddlewaregenerated.Middleware +} + +// EndpointDependenciesNodes contains endpoint dependencies +type EndpointDependenciesNodes struct { + AppDemoAbc appdemoabcendpointgenerated.Endpoint + Bar barendpointgenerated.Endpoint +} + +// InitializeDependencies fully initializes all dependencies in the dep tree +// for the app/demo/xyz service +func InitializeDependencies( + g *zanzibar.Gateway, +) (*DependenciesTree, *Dependencies) { + tree := &DependenciesTree{} + + initializedDefaultDependencies := &zanzibar.DefaultDependencies{ + Logger: g.Logger, + ContextExtractor: g.ContextExtractor, + ContextLogger: g.ContextLogger, + ContextMetrics: zanzibar.NewContextMetrics(g.RootScope), + Scope: g.RootScope, + Tracer: g.Tracer, + Config: g.Config, + Channel: g.Channel, + } + + initializedClientDependencies := &ClientDependenciesNodes{} + tree.Client = initializedClientDependencies + initializedClientDependencies.Bar = barclientgenerated.NewClient(&barclientmodule.Dependencies{ + Default: initializedDefaultDependencies, + }) + initializedClientDependencies.Baz = bazclientgenerated.NewClient(&bazclientmodule.Dependencies{ + Default: initializedDefaultDependencies, + }) + + initializedMiddlewareDependencies := &MiddlewareDependenciesNodes{} + tree.Middleware = initializedMiddlewareDependencies + initializedMiddlewareDependencies.Example = examplemiddlewaregenerated.NewMiddleware(&examplemiddlewaremodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &examplemiddlewaremodule.ClientDependencies{ + Baz: initializedClientDependencies.Baz, + }, + }) + + initializedEndpointDependencies := &EndpointDependenciesNodes{} + tree.Endpoint = initializedEndpointDependencies + initializedEndpointDependencies.AppDemoAbc = appdemoabcendpointgenerated.NewEndpoint(&appdemoabcendpointmodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &appdemoabcendpointmodule.ClientDependencies{ + Baz: initializedClientDependencies.Baz, + }, + }) + initializedEndpointDependencies.Bar = barendpointgenerated.NewEndpoint(&barendpointmodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &barendpointmodule.ClientDependencies{ + Bar: initializedClientDependencies.Bar, + }, + Middleware: &barendpointmodule.MiddlewareDependencies{ + Example: initializedMiddlewareDependencies.Example, + }, + }) + + dependencies := &Dependencies{ + Default: initializedDefaultDependencies, + Endpoint: &EndpointDependencies{ + AppDemoAbc: initializedEndpointDependencies.AppDemoAbc, + Bar: initializedEndpointDependencies.Bar, + }, + } + + return tree, dependencies +} diff --git a/examples/example-gateway/build/app/demo/services/xyz/service.go b/examples/example-gateway/build/app/demo/services/xyz/service.go new file mode 100644 index 000000000..5f8c2b4a2 --- /dev/null +++ b/examples/example-gateway/build/app/demo/services/xyz/service.go @@ -0,0 +1,68 @@ +// Code generated by zanzibar +// @generated + +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package xyzservicegenerated + +import ( + zanzibar "github.com/uber/zanzibar/runtime" + + module "github.com/uber/zanzibar/examples/example-gateway/build/app/demo/services/xyz/module" +) + +// DependenciesTree re-exported for convenience. +type DependenciesTree module.DependenciesTree + +// CreateGateway creates a new instances of the app/demo/xyz +// service with the specified config +func CreateGateway( + config *zanzibar.StaticConfig, + opts *zanzibar.Options, +) (*zanzibar.Gateway, interface{}, error) { + gateway, err := zanzibar.CreateGateway(config, opts) + if err != nil { + return nil, nil, err + } + + tree, dependencies := module.InitializeDependencies(gateway) + registerErr := RegisterDeps(gateway, dependencies) + if registerErr != nil { + return nil, nil, registerErr + } + + return gateway, (*DependenciesTree)(tree), nil +} + +// RegisterDeps registers direct dependencies of the service +func RegisterDeps(g *zanzibar.Gateway, deps *module.Dependencies) error { + //lint:ignore S1021 allow less concise variable declaration for ease of code generation + var err error + err = deps.Endpoint.AppDemoAbc.Register(g) + if err != nil { + return err + } + err = deps.Endpoint.Bar.Register(g) + if err != nil { + return err + } + return nil +} diff --git a/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_call_workflow_mock.go b/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_call_workflow_mock.go index 4ab88cdab..4b9b10468 100644 --- a/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_call_workflow_mock.go +++ b/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_call_workflow_mock.go @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package mockbaztchannelworkflow +package mocktchannelbazworkflow import ( "testing" diff --git a/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_echo_workflow_mock.go b/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_echo_workflow_mock.go index d2049ceb6..320d739ea 100644 --- a/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_echo_workflow_mock.go +++ b/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/simpleservice_echo_workflow_mock.go @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package mockbaztchannelworkflow +package mocktchannelbazworkflow import ( "testing" diff --git a/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/type.go b/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/type.go index 1aa283b62..4fac6152d 100644 --- a/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/type.go +++ b/examples/example-gateway/build/endpoints/tchannel/baz/mock-workflow/type.go @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package mockbaztchannelworkflow +package mocktchannelbazworkflow import ( bazclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz" @@ -31,7 +31,7 @@ import ( quuxclientstatic "github.com/uber/zanzibar/examples/example-gateway/clients/quux" ) -// MockClientNodes contains mock client dependencies for the bazTChannel endpoint module +// MockClientNodes contains mock client dependencies for the tchannel/baz endpoint module type MockClientNodes struct { Baz *bazclientgeneratedmock.MockClient Quux *quuxclientgeneratedmock.MockClientWithFixture diff --git a/examples/example-gateway/build/endpoints/tchannel/baz/module/dependencies.go b/examples/example-gateway/build/endpoints/tchannel/baz/module/dependencies.go index 65b90fbbe..74975508a 100644 --- a/examples/example-gateway/build/endpoints/tchannel/baz/module/dependencies.go +++ b/examples/example-gateway/build/endpoints/tchannel/baz/module/dependencies.go @@ -31,7 +31,7 @@ import ( zanzibar "github.com/uber/zanzibar/runtime" ) -// Dependencies contains dependencies for the bazTChannel endpoint module +// Dependencies contains dependencies for the tchannel/baz endpoint module type Dependencies struct { Default *zanzibar.DefaultDependencies Client *ClientDependencies diff --git a/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/echo_echo_workflow_mock.go b/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/echo_echo_workflow_mock.go index e41861a99..6e10422e6 100644 --- a/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/echo_echo_workflow_mock.go +++ b/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/echo_echo_workflow_mock.go @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package mockechoworkflow +package mocktchannelechoworkflow import ( "testing" diff --git a/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/type.go b/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/type.go index deb3dffc6..c7736f344 100644 --- a/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/type.go +++ b/examples/example-gateway/build/endpoints/tchannel/echo/mock-workflow/type.go @@ -21,8 +21,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package mockechoworkflow +package mocktchannelechoworkflow -// MockNodes contains mock dependencies for the echo endpoint module +// MockNodes contains mock dependencies for the tchannel/echo endpoint module type MockNodes struct { } diff --git a/examples/example-gateway/build/endpoints/tchannel/echo/module/dependencies.go b/examples/example-gateway/build/endpoints/tchannel/echo/module/dependencies.go index 23a846971..82c25546a 100644 --- a/examples/example-gateway/build/endpoints/tchannel/echo/module/dependencies.go +++ b/examples/example-gateway/build/endpoints/tchannel/echo/module/dependencies.go @@ -27,7 +27,7 @@ import ( zanzibar "github.com/uber/zanzibar/runtime" ) -// Dependencies contains dependencies for the echo endpoint module +// Dependencies contains dependencies for the tchannel/echo endpoint module type Dependencies struct { Default *zanzibar.DefaultDependencies } diff --git a/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/simpleservice_anothercall_workflow_mock.go b/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/simpleservice_anothercall_workflow_mock.go index 509d778fe..a1797b236 100644 --- a/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/simpleservice_anothercall_workflow_mock.go +++ b/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/simpleservice_anothercall_workflow_mock.go @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package mockpanictchannelworkflow +package mocktchannelpanicworkflow import ( "testing" diff --git a/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/type.go b/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/type.go index f0d073b2e..c5b1f0ba3 100644 --- a/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/type.go +++ b/examples/example-gateway/build/endpoints/tchannel/panic/mock-workflow/type.go @@ -21,14 +21,14 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package mockpanictchannelworkflow +package mocktchannelpanicworkflow import ( bazclientgenerated "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz" bazclientgeneratedmock "github.com/uber/zanzibar/examples/example-gateway/build/clients/baz/mock-client" ) -// MockClientNodes contains mock client dependencies for the panicTChannel endpoint module +// MockClientNodes contains mock client dependencies for the tchannel/panic endpoint module type MockClientNodes struct { Baz *bazclientgeneratedmock.MockClient } diff --git a/examples/example-gateway/build/endpoints/tchannel/panic/module/dependencies.go b/examples/example-gateway/build/endpoints/tchannel/panic/module/dependencies.go index be51c61a3..7eefed7a1 100644 --- a/examples/example-gateway/build/endpoints/tchannel/panic/module/dependencies.go +++ b/examples/example-gateway/build/endpoints/tchannel/panic/module/dependencies.go @@ -29,7 +29,7 @@ import ( zanzibar "github.com/uber/zanzibar/runtime" ) -// Dependencies contains dependencies for the panicTChannel endpoint module +// Dependencies contains dependencies for the tchannel/panic endpoint module type Dependencies struct { Default *zanzibar.DefaultDependencies Client *ClientDependencies diff --git a/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/abc/appdemoservice_call.go b/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/abc/appdemoservice_call.go new file mode 100644 index 000000000..eb6332aeb --- /dev/null +++ b/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/abc/appdemoservice_call.go @@ -0,0 +1,376 @@ +// Code generated by thriftrw v1.14.0. DO NOT EDIT. +// @generated + +package abc + +import ( + "errors" + "fmt" + "go.uber.org/thriftrw/wire" + "go.uber.org/zap/zapcore" + "strings" +) + +// AppDemoService_Call_Args represents the arguments for the AppDemoService.Call function. +// +// The arguments for Call are sent and received over the wire as this struct. +type AppDemoService_Call_Args struct { +} + +// ToWire translates a AppDemoService_Call_Args struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *AppDemoService_Call_Args) ToWire() (wire.Value, error) { + var ( + fields [0]wire.Field + i int = 0 + ) + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +// FromWire deserializes a AppDemoService_Call_Args struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a AppDemoService_Call_Args struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v AppDemoService_Call_Args +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *AppDemoService_Call_Args) FromWire(w wire.Value) error { + + for _, field := range w.GetStruct().Fields { + switch field.ID { + } + } + + return nil +} + +// String returns a readable string representation of a AppDemoService_Call_Args +// struct. +func (v *AppDemoService_Call_Args) String() string { + if v == nil { + return "" + } + + var fields [0]string + i := 0 + + return fmt.Sprintf("AppDemoService_Call_Args{%v}", strings.Join(fields[:i], ", ")) +} + +// Equals returns true if all the fields of this AppDemoService_Call_Args match the +// provided AppDemoService_Call_Args. +// +// This function performs a deep comparison. +func (v *AppDemoService_Call_Args) Equals(rhs *AppDemoService_Call_Args) bool { + if v == nil { + return rhs == nil + } else if rhs == nil { + return false + } + + return true +} + +// MarshalLogObject implements zapcore.ObjectMarshaler, enabling +// fast logging of AppDemoService_Call_Args. +func (v *AppDemoService_Call_Args) MarshalLogObject(enc zapcore.ObjectEncoder) (err error) { + if v == nil { + return nil + } + return err +} + +// MethodName returns the name of the Thrift function as specified in +// the IDL, for which this struct represent the arguments. +// +// This will always be "Call" for this struct. +func (v *AppDemoService_Call_Args) MethodName() string { + return "Call" +} + +// EnvelopeType returns the kind of value inside this struct. +// +// This will always be Call for this struct. +func (v *AppDemoService_Call_Args) EnvelopeType() wire.EnvelopeType { + return wire.Call +} + +// AppDemoService_Call_Helper provides functions that aid in handling the +// parameters and return values of the AppDemoService.Call +// function. +var AppDemoService_Call_Helper = struct { + // Args accepts the parameters of Call in-order and returns + // the arguments struct for the function. + Args func() *AppDemoService_Call_Args + + // IsException returns true if the given error can be thrown + // by Call. + // + // An error can be thrown by Call only if the + // corresponding exception type was mentioned in the 'throws' + // section for it in the Thrift file. + IsException func(error) bool + + // WrapResponse returns the result struct for Call + // given its return value and error. + // + // This allows mapping values and errors returned by + // Call into a serializable result struct. + // WrapResponse returns a non-nil error if the provided + // error cannot be thrown by Call + // + // value, err := Call(args) + // result, err := AppDemoService_Call_Helper.WrapResponse(value, err) + // if err != nil { + // return fmt.Errorf("unexpected error from Call: %v", err) + // } + // serialize(result) + WrapResponse func(int32, error) (*AppDemoService_Call_Result, error) + + // UnwrapResponse takes the result struct for Call + // and returns the value or error returned by it. + // + // The error is non-nil only if Call threw an + // exception. + // + // result := deserialize(bytes) + // value, err := AppDemoService_Call_Helper.UnwrapResponse(result) + UnwrapResponse func(*AppDemoService_Call_Result) (int32, error) +}{} + +func init() { + AppDemoService_Call_Helper.Args = func() *AppDemoService_Call_Args { + return &AppDemoService_Call_Args{} + } + + AppDemoService_Call_Helper.IsException = func(err error) bool { + switch err.(type) { + default: + return false + } + } + + AppDemoService_Call_Helper.WrapResponse = func(success int32, err error) (*AppDemoService_Call_Result, error) { + if err == nil { + return &AppDemoService_Call_Result{Success: &success}, nil + } + + return nil, err + } + AppDemoService_Call_Helper.UnwrapResponse = func(result *AppDemoService_Call_Result) (success int32, err error) { + + if result.Success != nil { + success = *result.Success + return + } + + err = errors.New("expected a non-void result") + return + } + +} + +// AppDemoService_Call_Result represents the result of a AppDemoService.Call function call. +// +// The result of a Call execution is sent and received over the wire as this struct. +// +// Success is set only if the function did not throw an exception. +type AppDemoService_Call_Result struct { + // Value returned by Call after a successful execution. + Success *int32 `json:"success,omitempty"` +} + +// ToWire translates a AppDemoService_Call_Result struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *AppDemoService_Call_Result) ToWire() (wire.Value, error) { + var ( + fields [1]wire.Field + i int = 0 + w wire.Value + err error + ) + + if v.Success != nil { + w, err = wire.NewValueI32(*(v.Success)), error(nil) + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 0, Value: w} + i++ + } + + if i != 1 { + return wire.Value{}, fmt.Errorf("AppDemoService_Call_Result should have exactly one field: got %v fields", i) + } + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +// FromWire deserializes a AppDemoService_Call_Result struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a AppDemoService_Call_Result struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v AppDemoService_Call_Result +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *AppDemoService_Call_Result) FromWire(w wire.Value) error { + var err error + + for _, field := range w.GetStruct().Fields { + switch field.ID { + case 0: + if field.Value.Type() == wire.TI32 { + var x int32 + x, err = field.Value.GetI32(), error(nil) + v.Success = &x + if err != nil { + return err + } + + } + } + } + + count := 0 + if v.Success != nil { + count++ + } + if count != 1 { + return fmt.Errorf("AppDemoService_Call_Result should have exactly one field: got %v fields", count) + } + + return nil +} + +// String returns a readable string representation of a AppDemoService_Call_Result +// struct. +func (v *AppDemoService_Call_Result) String() string { + if v == nil { + return "" + } + + var fields [1]string + i := 0 + if v.Success != nil { + fields[i] = fmt.Sprintf("Success: %v", *(v.Success)) + i++ + } + + return fmt.Sprintf("AppDemoService_Call_Result{%v}", strings.Join(fields[:i], ", ")) +} + +func _I32_EqualsPtr(lhs, rhs *int32) bool { + if lhs != nil && rhs != nil { + + x := *lhs + y := *rhs + return (x == y) + } + return lhs == nil && rhs == nil +} + +// Equals returns true if all the fields of this AppDemoService_Call_Result match the +// provided AppDemoService_Call_Result. +// +// This function performs a deep comparison. +func (v *AppDemoService_Call_Result) Equals(rhs *AppDemoService_Call_Result) bool { + if v == nil { + return rhs == nil + } else if rhs == nil { + return false + } + if !_I32_EqualsPtr(v.Success, rhs.Success) { + return false + } + + return true +} + +// MarshalLogObject implements zapcore.ObjectMarshaler, enabling +// fast logging of AppDemoService_Call_Result. +func (v *AppDemoService_Call_Result) MarshalLogObject(enc zapcore.ObjectEncoder) (err error) { + if v == nil { + return nil + } + if v.Success != nil { + enc.AddInt32("success", *v.Success) + } + return err +} + +// GetSuccess returns the value of Success if it is set or its +// zero value if it is unset. +func (v *AppDemoService_Call_Result) GetSuccess() (o int32) { + if v.Success != nil { + return *v.Success + } + + return +} + +// IsSetSuccess returns true if Success is not nil. +func (v *AppDemoService_Call_Result) IsSetSuccess() bool { + return v.Success != nil +} + +// MethodName returns the name of the Thrift function as specified in +// the IDL, for which this struct represent the result. +// +// This will always be "Call" for this struct. +func (v *AppDemoService_Call_Result) MethodName() string { + return "Call" +} + +// EnvelopeType returns the kind of value inside this struct. +// +// This will always be Reply for this struct. +func (v *AppDemoService_Call_Result) EnvelopeType() wire.EnvelopeType { + return wire.Reply +} diff --git a/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/abc/simpleservice_call.go b/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/abc/simpleservice_call.go new file mode 100644 index 000000000..e469c79c2 --- /dev/null +++ b/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/abc/simpleservice_call.go @@ -0,0 +1,296 @@ +// Code generated by thriftrw v1.14.0. DO NOT EDIT. +// @generated + +package abc + +import ( + "fmt" + "go.uber.org/thriftrw/wire" + "go.uber.org/zap/zapcore" + "strings" +) + +// SimpleService_Call_Args represents the arguments for the SimpleService.Call function. +// +// The arguments for Call are sent and received over the wire as this struct. +type SimpleService_Call_Args struct { +} + +// ToWire translates a SimpleService_Call_Args struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *SimpleService_Call_Args) ToWire() (wire.Value, error) { + var ( + fields [0]wire.Field + i int = 0 + ) + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +// FromWire deserializes a SimpleService_Call_Args struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a SimpleService_Call_Args struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v SimpleService_Call_Args +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *SimpleService_Call_Args) FromWire(w wire.Value) error { + + for _, field := range w.GetStruct().Fields { + switch field.ID { + } + } + + return nil +} + +// String returns a readable string representation of a SimpleService_Call_Args +// struct. +func (v *SimpleService_Call_Args) String() string { + if v == nil { + return "" + } + + var fields [0]string + i := 0 + + return fmt.Sprintf("SimpleService_Call_Args{%v}", strings.Join(fields[:i], ", ")) +} + +// Equals returns true if all the fields of this SimpleService_Call_Args match the +// provided SimpleService_Call_Args. +// +// This function performs a deep comparison. +func (v *SimpleService_Call_Args) Equals(rhs *SimpleService_Call_Args) bool { + if v == nil { + return rhs == nil + } else if rhs == nil { + return false + } + + return true +} + +// MarshalLogObject implements zapcore.ObjectMarshaler, enabling +// fast logging of SimpleService_Call_Args. +func (v *SimpleService_Call_Args) MarshalLogObject(enc zapcore.ObjectEncoder) (err error) { + if v == nil { + return nil + } + return err +} + +// MethodName returns the name of the Thrift function as specified in +// the IDL, for which this struct represent the arguments. +// +// This will always be "Call" for this struct. +func (v *SimpleService_Call_Args) MethodName() string { + return "Call" +} + +// EnvelopeType returns the kind of value inside this struct. +// +// This will always be Call for this struct. +func (v *SimpleService_Call_Args) EnvelopeType() wire.EnvelopeType { + return wire.Call +} + +// SimpleService_Call_Helper provides functions that aid in handling the +// parameters and return values of the SimpleService.Call +// function. +var SimpleService_Call_Helper = struct { + // Args accepts the parameters of Call in-order and returns + // the arguments struct for the function. + Args func() *SimpleService_Call_Args + + // IsException returns true if the given error can be thrown + // by Call. + // + // An error can be thrown by Call only if the + // corresponding exception type was mentioned in the 'throws' + // section for it in the Thrift file. + IsException func(error) bool + + // WrapResponse returns the result struct for Call + // given the error returned by it. The provided error may + // be nil if Call did not fail. + // + // This allows mapping errors returned by Call into a + // serializable result struct. WrapResponse returns a + // non-nil error if the provided error cannot be thrown by + // Call + // + // err := Call(args) + // result, err := SimpleService_Call_Helper.WrapResponse(err) + // if err != nil { + // return fmt.Errorf("unexpected error from Call: %v", err) + // } + // serialize(result) + WrapResponse func(error) (*SimpleService_Call_Result, error) + + // UnwrapResponse takes the result struct for Call + // and returns the erorr returned by it (if any). + // + // The error is non-nil only if Call threw an + // exception. + // + // result := deserialize(bytes) + // err := SimpleService_Call_Helper.UnwrapResponse(result) + UnwrapResponse func(*SimpleService_Call_Result) error +}{} + +func init() { + SimpleService_Call_Helper.Args = func() *SimpleService_Call_Args { + return &SimpleService_Call_Args{} + } + + SimpleService_Call_Helper.IsException = func(err error) bool { + switch err.(type) { + default: + return false + } + } + + SimpleService_Call_Helper.WrapResponse = func(err error) (*SimpleService_Call_Result, error) { + if err == nil { + return &SimpleService_Call_Result{}, nil + } + + return nil, err + } + SimpleService_Call_Helper.UnwrapResponse = func(result *SimpleService_Call_Result) (err error) { + return + } + +} + +// SimpleService_Call_Result represents the result of a SimpleService.Call function call. +// +// The result of a Call execution is sent and received over the wire as this struct. +type SimpleService_Call_Result struct { +} + +// ToWire translates a SimpleService_Call_Result struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *SimpleService_Call_Result) ToWire() (wire.Value, error) { + var ( + fields [0]wire.Field + i int = 0 + ) + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +// FromWire deserializes a SimpleService_Call_Result struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a SimpleService_Call_Result struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v SimpleService_Call_Result +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *SimpleService_Call_Result) FromWire(w wire.Value) error { + + for _, field := range w.GetStruct().Fields { + switch field.ID { + } + } + + return nil +} + +// String returns a readable string representation of a SimpleService_Call_Result +// struct. +func (v *SimpleService_Call_Result) String() string { + if v == nil { + return "" + } + + var fields [0]string + i := 0 + + return fmt.Sprintf("SimpleService_Call_Result{%v}", strings.Join(fields[:i], ", ")) +} + +// Equals returns true if all the fields of this SimpleService_Call_Result match the +// provided SimpleService_Call_Result. +// +// This function performs a deep comparison. +func (v *SimpleService_Call_Result) Equals(rhs *SimpleService_Call_Result) bool { + if v == nil { + return rhs == nil + } else if rhs == nil { + return false + } + + return true +} + +// MarshalLogObject implements zapcore.ObjectMarshaler, enabling +// fast logging of SimpleService_Call_Result. +func (v *SimpleService_Call_Result) MarshalLogObject(enc zapcore.ObjectEncoder) (err error) { + if v == nil { + return nil + } + return err +} + +// MethodName returns the name of the Thrift function as specified in +// the IDL, for which this struct represent the result. +// +// This will always be "Call" for this struct. +func (v *SimpleService_Call_Result) MethodName() string { + return "Call" +} + +// EnvelopeType returns the kind of value inside this struct. +// +// This will always be Reply for this struct. +func (v *SimpleService_Call_Result) EnvelopeType() wire.EnvelopeType { + return wire.Reply +} diff --git a/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/baz/simpleservice_call.go b/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/baz/simpleservice_call.go new file mode 100644 index 000000000..642a2eaf0 --- /dev/null +++ b/examples/example-gateway/build/gen-code/endpoints/app/demo/endpoints/baz/simpleservice_call.go @@ -0,0 +1,296 @@ +// Code generated by thriftrw v1.14.0. DO NOT EDIT. +// @generated + +package baz + +import ( + "fmt" + "go.uber.org/thriftrw/wire" + "go.uber.org/zap/zapcore" + "strings" +) + +// SimpleService_Call_Args represents the arguments for the SimpleService.Call function. +// +// The arguments for Call are sent and received over the wire as this struct. +type SimpleService_Call_Args struct { +} + +// ToWire translates a SimpleService_Call_Args struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *SimpleService_Call_Args) ToWire() (wire.Value, error) { + var ( + fields [0]wire.Field + i int = 0 + ) + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +// FromWire deserializes a SimpleService_Call_Args struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a SimpleService_Call_Args struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v SimpleService_Call_Args +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *SimpleService_Call_Args) FromWire(w wire.Value) error { + + for _, field := range w.GetStruct().Fields { + switch field.ID { + } + } + + return nil +} + +// String returns a readable string representation of a SimpleService_Call_Args +// struct. +func (v *SimpleService_Call_Args) String() string { + if v == nil { + return "" + } + + var fields [0]string + i := 0 + + return fmt.Sprintf("SimpleService_Call_Args{%v}", strings.Join(fields[:i], ", ")) +} + +// Equals returns true if all the fields of this SimpleService_Call_Args match the +// provided SimpleService_Call_Args. +// +// This function performs a deep comparison. +func (v *SimpleService_Call_Args) Equals(rhs *SimpleService_Call_Args) bool { + if v == nil { + return rhs == nil + } else if rhs == nil { + return false + } + + return true +} + +// MarshalLogObject implements zapcore.ObjectMarshaler, enabling +// fast logging of SimpleService_Call_Args. +func (v *SimpleService_Call_Args) MarshalLogObject(enc zapcore.ObjectEncoder) (err error) { + if v == nil { + return nil + } + return err +} + +// MethodName returns the name of the Thrift function as specified in +// the IDL, for which this struct represent the arguments. +// +// This will always be "Call" for this struct. +func (v *SimpleService_Call_Args) MethodName() string { + return "Call" +} + +// EnvelopeType returns the kind of value inside this struct. +// +// This will always be Call for this struct. +func (v *SimpleService_Call_Args) EnvelopeType() wire.EnvelopeType { + return wire.Call +} + +// SimpleService_Call_Helper provides functions that aid in handling the +// parameters and return values of the SimpleService.Call +// function. +var SimpleService_Call_Helper = struct { + // Args accepts the parameters of Call in-order and returns + // the arguments struct for the function. + Args func() *SimpleService_Call_Args + + // IsException returns true if the given error can be thrown + // by Call. + // + // An error can be thrown by Call only if the + // corresponding exception type was mentioned in the 'throws' + // section for it in the Thrift file. + IsException func(error) bool + + // WrapResponse returns the result struct for Call + // given the error returned by it. The provided error may + // be nil if Call did not fail. + // + // This allows mapping errors returned by Call into a + // serializable result struct. WrapResponse returns a + // non-nil error if the provided error cannot be thrown by + // Call + // + // err := Call(args) + // result, err := SimpleService_Call_Helper.WrapResponse(err) + // if err != nil { + // return fmt.Errorf("unexpected error from Call: %v", err) + // } + // serialize(result) + WrapResponse func(error) (*SimpleService_Call_Result, error) + + // UnwrapResponse takes the result struct for Call + // and returns the erorr returned by it (if any). + // + // The error is non-nil only if Call threw an + // exception. + // + // result := deserialize(bytes) + // err := SimpleService_Call_Helper.UnwrapResponse(result) + UnwrapResponse func(*SimpleService_Call_Result) error +}{} + +func init() { + SimpleService_Call_Helper.Args = func() *SimpleService_Call_Args { + return &SimpleService_Call_Args{} + } + + SimpleService_Call_Helper.IsException = func(err error) bool { + switch err.(type) { + default: + return false + } + } + + SimpleService_Call_Helper.WrapResponse = func(err error) (*SimpleService_Call_Result, error) { + if err == nil { + return &SimpleService_Call_Result{}, nil + } + + return nil, err + } + SimpleService_Call_Helper.UnwrapResponse = func(result *SimpleService_Call_Result) (err error) { + return + } + +} + +// SimpleService_Call_Result represents the result of a SimpleService.Call function call. +// +// The result of a Call execution is sent and received over the wire as this struct. +type SimpleService_Call_Result struct { +} + +// ToWire translates a SimpleService_Call_Result struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *SimpleService_Call_Result) ToWire() (wire.Value, error) { + var ( + fields [0]wire.Field + i int = 0 + ) + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +// FromWire deserializes a SimpleService_Call_Result struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a SimpleService_Call_Result struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v SimpleService_Call_Result +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *SimpleService_Call_Result) FromWire(w wire.Value) error { + + for _, field := range w.GetStruct().Fields { + switch field.ID { + } + } + + return nil +} + +// String returns a readable string representation of a SimpleService_Call_Result +// struct. +func (v *SimpleService_Call_Result) String() string { + if v == nil { + return "" + } + + var fields [0]string + i := 0 + + return fmt.Sprintf("SimpleService_Call_Result{%v}", strings.Join(fields[:i], ", ")) +} + +// Equals returns true if all the fields of this SimpleService_Call_Result match the +// provided SimpleService_Call_Result. +// +// This function performs a deep comparison. +func (v *SimpleService_Call_Result) Equals(rhs *SimpleService_Call_Result) bool { + if v == nil { + return rhs == nil + } else if rhs == nil { + return false + } + + return true +} + +// MarshalLogObject implements zapcore.ObjectMarshaler, enabling +// fast logging of SimpleService_Call_Result. +func (v *SimpleService_Call_Result) MarshalLogObject(enc zapcore.ObjectEncoder) (err error) { + if v == nil { + return nil + } + return err +} + +// MethodName returns the name of the Thrift function as specified in +// the IDL, for which this struct represent the result. +// +// This will always be "Call" for this struct. +func (v *SimpleService_Call_Result) MethodName() string { + return "Call" +} + +// EnvelopeType returns the kind of value inside this struct. +// +// This will always be Reply for this struct. +func (v *SimpleService_Call_Result) EnvelopeType() wire.EnvelopeType { + return wire.Reply +} diff --git a/examples/example-gateway/build/services/example-gateway/mock-service/mock_init.go b/examples/example-gateway/build/services/example-gateway/mock-service/mock_init.go index 249224f81..735692592 100644 --- a/examples/example-gateway/build/services/example-gateway/mock-service/mock_init.go +++ b/examples/example-gateway/build/services/example-gateway/mock-service/mock_init.go @@ -133,16 +133,6 @@ func InitializeDependenciesMock( Baz: initializedClientDependencies.Baz, }, }) - initializedEndpointDependencies.BazTChannel = baztchannelendpointgenerated.NewEndpoint(&baztchannelendpointmodule.Dependencies{ - Default: initializedDefaultDependencies, - Client: &baztchannelendpointmodule.ClientDependencies{ - Baz: initializedClientDependencies.Baz, - Quux: initializedClientDependencies.Quux, - }, - Middleware: &baztchannelendpointmodule.MiddlewareDependencies{ - ExampleTchannel: initializedMiddlewareDependencies.ExampleTchannel, - }, - }) initializedEndpointDependencies.Contacts = contactsendpointgenerated.NewEndpoint(&contactsendpointmodule.Dependencies{ Default: initializedDefaultDependencies, Client: &contactsendpointmodule.ClientDependencies{ @@ -167,6 +157,16 @@ func InitializeDependenciesMock( Multi: initializedClientDependencies.Multi, }, }) + initializedEndpointDependencies.BazTChannel = baztchannelendpointgenerated.NewEndpoint(&baztchannelendpointmodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &baztchannelendpointmodule.ClientDependencies{ + Baz: initializedClientDependencies.Baz, + Quux: initializedClientDependencies.Quux, + }, + Middleware: &baztchannelendpointmodule.MiddlewareDependencies{ + ExampleTchannel: initializedMiddlewareDependencies.ExampleTchannel, + }, + }) initializedEndpointDependencies.PanicTChannel = panictchannelendpointgenerated.NewEndpoint(&panictchannelendpointmodule.Dependencies{ Default: initializedDefaultDependencies, Client: &panictchannelendpointmodule.ClientDependencies{ @@ -179,11 +179,11 @@ func InitializeDependenciesMock( Endpoint: &module.EndpointDependencies{ Bar: initializedEndpointDependencies.Bar, Baz: initializedEndpointDependencies.Baz, - BazTChannel: initializedEndpointDependencies.BazTChannel, Contacts: initializedEndpointDependencies.Contacts, Googlenow: initializedEndpointDependencies.Googlenow, Multi: initializedEndpointDependencies.Multi, Panic: initializedEndpointDependencies.Panic, + BazTChannel: initializedEndpointDependencies.BazTChannel, PanicTChannel: initializedEndpointDependencies.PanicTChannel, }, } diff --git a/examples/example-gateway/build/services/example-gateway/module/dependencies.go b/examples/example-gateway/build/services/example-gateway/module/dependencies.go index 40ce4b173..0328bdf92 100644 --- a/examples/example-gateway/build/services/example-gateway/module/dependencies.go +++ b/examples/example-gateway/build/services/example-gateway/module/dependencies.go @@ -46,10 +46,10 @@ type Dependencies struct { type EndpointDependencies struct { Bar barendpointgenerated.Endpoint Baz bazendpointgenerated.Endpoint - BazTChannel baztchannelendpointgenerated.Endpoint Contacts contactsendpointgenerated.Endpoint Googlenow googlenowendpointgenerated.Endpoint Multi multiendpointgenerated.Endpoint Panic panicendpointgenerated.Endpoint + BazTChannel baztchannelendpointgenerated.Endpoint PanicTChannel panictchannelendpointgenerated.Endpoint } diff --git a/examples/example-gateway/build/services/example-gateway/module/init.go b/examples/example-gateway/build/services/example-gateway/module/init.go index 8f36b6b9b..d8479731c 100644 --- a/examples/example-gateway/build/services/example-gateway/module/init.go +++ b/examples/example-gateway/build/services/example-gateway/module/init.go @@ -87,11 +87,11 @@ type MiddlewareDependenciesNodes struct { type EndpointDependenciesNodes struct { Bar barendpointgenerated.Endpoint Baz bazendpointgenerated.Endpoint - BazTChannel baztchannelendpointgenerated.Endpoint Contacts contactsendpointgenerated.Endpoint Googlenow googlenowendpointgenerated.Endpoint Multi multiendpointgenerated.Endpoint Panic panicendpointgenerated.Endpoint + BazTChannel baztchannelendpointgenerated.Endpoint PanicTChannel panictchannelendpointgenerated.Endpoint } @@ -163,16 +163,6 @@ func InitializeDependencies( Baz: initializedClientDependencies.Baz, }, }) - initializedEndpointDependencies.BazTChannel = baztchannelendpointgenerated.NewEndpoint(&baztchannelendpointmodule.Dependencies{ - Default: initializedDefaultDependencies, - Client: &baztchannelendpointmodule.ClientDependencies{ - Baz: initializedClientDependencies.Baz, - Quux: initializedClientDependencies.Quux, - }, - Middleware: &baztchannelendpointmodule.MiddlewareDependencies{ - ExampleTchannel: initializedMiddlewareDependencies.ExampleTchannel, - }, - }) initializedEndpointDependencies.Contacts = contactsendpointgenerated.NewEndpoint(&contactsendpointmodule.Dependencies{ Default: initializedDefaultDependencies, Client: &contactsendpointmodule.ClientDependencies{ @@ -197,6 +187,16 @@ func InitializeDependencies( Multi: initializedClientDependencies.Multi, }, }) + initializedEndpointDependencies.BazTChannel = baztchannelendpointgenerated.NewEndpoint(&baztchannelendpointmodule.Dependencies{ + Default: initializedDefaultDependencies, + Client: &baztchannelendpointmodule.ClientDependencies{ + Baz: initializedClientDependencies.Baz, + Quux: initializedClientDependencies.Quux, + }, + Middleware: &baztchannelendpointmodule.MiddlewareDependencies{ + ExampleTchannel: initializedMiddlewareDependencies.ExampleTchannel, + }, + }) initializedEndpointDependencies.PanicTChannel = panictchannelendpointgenerated.NewEndpoint(&panictchannelendpointmodule.Dependencies{ Default: initializedDefaultDependencies, Client: &panictchannelendpointmodule.ClientDependencies{ @@ -209,11 +209,11 @@ func InitializeDependencies( Endpoint: &EndpointDependencies{ Bar: initializedEndpointDependencies.Bar, Baz: initializedEndpointDependencies.Baz, - BazTChannel: initializedEndpointDependencies.BazTChannel, Contacts: initializedEndpointDependencies.Contacts, Googlenow: initializedEndpointDependencies.Googlenow, Multi: initializedEndpointDependencies.Multi, Panic: initializedEndpointDependencies.Panic, + BazTChannel: initializedEndpointDependencies.BazTChannel, PanicTChannel: initializedEndpointDependencies.PanicTChannel, }, } diff --git a/examples/example-gateway/build/services/example-gateway/service.go b/examples/example-gateway/build/services/example-gateway/service.go index 1fb7ad0e8..220fe9bb2 100644 --- a/examples/example-gateway/build/services/example-gateway/service.go +++ b/examples/example-gateway/build/services/example-gateway/service.go @@ -64,10 +64,6 @@ func RegisterDeps(g *zanzibar.Gateway, deps *module.Dependencies) error { if err != nil { return err } - err = deps.Endpoint.BazTChannel.Register(g) - if err != nil { - return err - } err = deps.Endpoint.Contacts.Register(g) if err != nil { return err @@ -84,6 +80,10 @@ func RegisterDeps(g *zanzibar.Gateway, deps *module.Dependencies) error { if err != nil { return err } + err = deps.Endpoint.BazTChannel.Register(g) + if err != nil { + return err + } err = deps.Endpoint.PanicTChannel.Register(g) if err != nil { return err diff --git a/examples/example-gateway/idl/endpoints/app/demo/endpoints/abc.thrift b/examples/example-gateway/idl/endpoints/app/demo/endpoints/abc.thrift new file mode 100644 index 000000000..6550d2a3f --- /dev/null +++ b/examples/example-gateway/idl/endpoints/app/demo/endpoints/abc.thrift @@ -0,0 +1,6 @@ +namespace java com.uber.zanzibar.app.demo + +service AppDemoService { + i32 Call() +} + diff --git a/examples/example-gateway/middlewares/headers-propagate/_middleware-config.yaml b/examples/example-gateway/middlewares/headers-propagate/middleware-config.yaml similarity index 100% rename from examples/example-gateway/middlewares/headers-propagate/_middleware-config.yaml rename to examples/example-gateway/middlewares/headers-propagate/middleware-config.yaml diff --git a/examples/example-gateway/middlewares/transform-request/_middleware-config.yaml b/examples/example-gateway/middlewares/transform-request/middleware-config.yaml similarity index 100% rename from examples/example-gateway/middlewares/transform-request/_middleware-config.yaml rename to examples/example-gateway/middlewares/transform-request/middleware-config.yaml diff --git a/examples/example-gateway/middlewares/transform-response/_middleware-config.yaml b/examples/example-gateway/middlewares/transform-response/middleware-config.yaml similarity index 100% rename from examples/example-gateway/middlewares/transform-response/_middleware-config.yaml rename to examples/example-gateway/middlewares/transform-response/middleware-config.yaml diff --git a/examples/example-gateway/services/echo-gateway/service-config.yaml b/examples/example-gateway/services/echo-gateway/service-config.yaml index ba77f5865..17f902803 100644 --- a/examples/example-gateway/services/echo-gateway/service-config.yaml +++ b/examples/example-gateway/services/echo-gateway/service-config.yaml @@ -1,6 +1,6 @@ +name: echo-gateway +type: gateway config: {} dependencies: endpoint: - - echo -name: echo-gateway -type: gateway + - tchannel/echo diff --git a/examples/example-gateway/services/example-gateway/service-config.yaml b/examples/example-gateway/services/example-gateway/service-config.yaml index a18453a03..277455e13 100644 --- a/examples/example-gateway/services/example-gateway/service-config.yaml +++ b/examples/example-gateway/services/example-gateway/service-config.yaml @@ -1,3 +1,5 @@ +name: example-gateway +type: gateway config: {} dependencies: endpoint: @@ -5,9 +7,7 @@ dependencies: - baz - contacts - googlenow - - bazTChannel + - tchannel/baz - multi - panic - - panicTChannel -name: example-gateway -type: gateway + - tchannel/panic