Merge pull request #120 from hasLeland/service-name-proposal
Implement service folder name change proposal #106
This commit is contained in:
Коммит
c248479dbc
|
@ -14,8 +14,8 @@ in a sane way, even for requests not made with the generated HTTP client.
|
|||
|
||||
The test harness works as follows:
|
||||
|
||||
- Runs truss against `transport/transport-test.proto`, which generates `transport/transport-service`
|
||||
- Copy `transport/handlers` into `transport/transport-service`
|
||||
- Runs truss against `transport/transport-test.proto`, which generates `transport/transportpermutations-service`
|
||||
- Copy `transport/handlers` into `transport/transportpermutations-service`
|
||||
- Run `go test -v`
|
||||
- Runs truss again against `transport/transport-test.proto` (for regeneration tests)
|
||||
- Run `go test -v`
|
||||
|
|
|
@ -135,7 +135,7 @@ func truss(path string, options ...string) (string, error) {
|
|||
return string(out), err
|
||||
}
|
||||
|
||||
// buildTestService builds a truss service with the package TEST
|
||||
// buildTestService builds a truss service with the package "test"
|
||||
// into the `serviceDir`/bin directory
|
||||
func buildTestService(serviceDir string) (err error) {
|
||||
|
||||
|
@ -156,14 +156,14 @@ func buildTestService(serviceDir string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
const serverPath = "/TEST-service/TEST-server"
|
||||
const clientPath = "/TEST-service/TEST-cli-client"
|
||||
const serverPath = "/test-service/test-server"
|
||||
const clientPath = "/test-service/test-cli-client"
|
||||
|
||||
// Build server and client
|
||||
errChan := make(chan error)
|
||||
|
||||
go goBuild("TEST-server", binDir, filepath.Join(relDir, serverPath), errChan)
|
||||
go goBuild("TEST-cli-client", binDir, filepath.Join(relDir, clientPath), errChan)
|
||||
go goBuild("test-server", binDir, filepath.Join(relDir, serverPath), errChan)
|
||||
go goBuild("test-cli-client", binDir, filepath.Join(relDir, clientPath), errChan)
|
||||
|
||||
err = <-errChan
|
||||
if err != nil {
|
||||
|
@ -218,12 +218,12 @@ func goBuild(name, outputPath, relCodePath string, errChan chan error) {
|
|||
errChan <- nil
|
||||
}
|
||||
|
||||
// runServerAndClient execs a TEST-server and TEST-client and puts a
|
||||
// runServerAndClient execs a test-server and test-client and puts a
|
||||
// runReference to their interaction on the runRefs channel
|
||||
func runServerAndClient(path string, port int, debugPort int) runReference {
|
||||
// From within a folder with a truss `service`
|
||||
// These are the paths to the compiled binaries
|
||||
const relativeServerPath = "/bin/TEST-server"
|
||||
const relativeServerPath = "/bin/test-server"
|
||||
|
||||
// Output buffer for the server Stdout and Stderr
|
||||
serverOut := bytes.NewBuffer(nil)
|
||||
|
@ -299,7 +299,7 @@ func runServerAndClient(path string, port int, debugPort int) runReference {
|
|||
}
|
||||
|
||||
func runClient(path string, trans string, port int) ([]byte, bool) {
|
||||
const relativeClientPath = "/bin/TEST-cli-client"
|
||||
const relativeClientPath = "/bin/test-cli-client"
|
||||
|
||||
var client *exec.Cmd
|
||||
switch trans {
|
||||
|
@ -354,7 +354,7 @@ func cleanTests(servicesDir string) {
|
|||
// removeTestFiles removes all files created by running truss and building the
|
||||
// service from a single definition directory
|
||||
func removeTestFiles(defDir string) {
|
||||
os.RemoveAll(filepath.Join(defDir, "TEST-service"))
|
||||
os.RemoveAll(filepath.Join(defDir, "test-service"))
|
||||
os.RemoveAll(filepath.Join(defDir, "bin"))
|
||||
os.RemoveAll(filepath.Join(defDir, "pbout"))
|
||||
os.MkdirAll(filepath.Join(defDir, "pbout"), 0777)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package basic;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service Basic {
|
||||
service TEST {
|
||||
rpc GetBasic (BasicTypeRequest) returns (BasicTypeResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/1"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package multifile;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
import "imported.proto";
|
||||
|
||||
service Basic {
|
||||
service TEST {
|
||||
rpc GetBasic (BasicTypeRequest) returns (BasicTypeResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/1"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package multifile;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package Repeated;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service Repeated {
|
||||
service TEST {
|
||||
rpc GetRepeated (RepeatedTypeRequest) returns (RepeatedTypeResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/1"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package nested;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service Nested {
|
||||
service TEST {
|
||||
rpc GetNested (NestedTypeRequest) returns (NestedTypeResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/1"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package map;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service Map {
|
||||
service TEST {
|
||||
rpc GetMap (MapTypeRequest) returns (MapTypeResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/1"
|
||||
|
|
|
@ -14,7 +14,7 @@ all: test
|
|||
test:
|
||||
@echo -e '$(TRUSS_MSG)'
|
||||
truss transport-test.proto
|
||||
cp -r handlers transport-service
|
||||
cp -r handlers transportpermutations-service
|
||||
@echo -e '$(TEST_RUNNING_MSG)'
|
||||
go test -v
|
||||
@echo -e '$(TRUSS_AGAIN_MSG)'
|
||||
|
@ -24,4 +24,4 @@ test:
|
|||
$(MAKE) clean
|
||||
|
||||
clean:
|
||||
rm -rf transport-service
|
||||
rm -rf transportpermutations-service
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service"
|
||||
grpcclient "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service/generated/client/grpc"
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service"
|
||||
grpcclient "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service/generated/client/grpc"
|
||||
)
|
||||
|
||||
var grpcAddr string
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service"
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service"
|
||||
)
|
||||
|
||||
// NewService returns a naïve, stateless implementation of Service.
|
||||
|
|
|
@ -13,8 +13,8 @@ import (
|
|||
// 3d Party
|
||||
"golang.org/x/net/context"
|
||||
// This Service
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service"
|
||||
httpclient "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service/generated/client/http"
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service"
|
||||
httpclient "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service/generated/client/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
|
@ -14,9 +14,9 @@ import (
|
|||
// Go Kit
|
||||
"github.com/go-kit/kit/log"
|
||||
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service"
|
||||
svc "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service/generated"
|
||||
handler "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transport-service/handlers/server"
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service"
|
||||
svc "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service/generated"
|
||||
handler "github.com/TuneLab/go-truss/cmd/_integration-tests/transport/transportpermutations-service/handlers/server"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
"github.com/TuneLab/go-truss/truss"
|
||||
"github.com/TuneLab/go-truss/truss/execprotoc"
|
||||
"github.com/TuneLab/go-truss/truss/parsepkgname"
|
||||
"github.com/TuneLab/go-truss/truss/parsesvcname"
|
||||
|
||||
"github.com/TuneLab/go-truss/deftree"
|
||||
"github.com/TuneLab/go-truss/gendoc"
|
||||
|
@ -111,13 +111,10 @@ func parseInput() (*truss.Config, error) {
|
|||
}
|
||||
|
||||
// Service Path
|
||||
defFile, err := os.Open(cfg.DefPaths[0])
|
||||
svcName, err := parsesvcname.FromPaths(cfg.GoPath, cfg.DefPaths)
|
||||
svcName = strings.ToLower(svcName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot open package file %q", cfg.DefPaths[0])
|
||||
}
|
||||
svcName, err := parsepkgname.FromReader(defFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot parse package name from file %q", cfg.DefPaths[0])
|
||||
return nil, errors.Wrap(err, "cannot parse service name from the provided definition files")
|
||||
}
|
||||
svcFolderName := svcName + "-service"
|
||||
|
||||
|
|
|
@ -7,8 +7,19 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/TuneLab/go-truss/deftree"
|
||||
"github.com/golang/protobuf/protoc-gen-go/generator"
|
||||
)
|
||||
|
||||
func findServiceName(md *deftree.MicroserviceDefinition) string {
|
||||
rv := "default"
|
||||
for _, f := range md.Files {
|
||||
for _, svc := range f.Services {
|
||||
rv = svc.GetName()
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
// GenerateDocs accepts a deftree that represents an ast of a group of
|
||||
// protofiles and returns map[string]io.Reader that represents a relative
|
||||
// filestructure of generated docs
|
||||
|
@ -23,7 +34,10 @@ func GenerateDocs(dt deftree.Deftree) map[string]io.Reader {
|
|||
}
|
||||
|
||||
files := make(map[string]io.Reader)
|
||||
files[dt.GetName()+"-service/docs/docs.md"] = strings.NewReader(response)
|
||||
md := dt.(*deftree.MicroserviceDefinition)
|
||||
// Normalize the service to prevent diversion from convention
|
||||
svcname := strings.ToLower(generator.CamelCase(findServiceName(md)))
|
||||
files[svcname+"-service/docs/docs.md"] = strings.NewReader(response)
|
||||
|
||||
return files
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"go/format"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
@ -30,8 +31,12 @@ func GenerateGokit(sd *svcdef.Svcdef, conf gengokit.Config) (map[string]io.Reade
|
|||
|
||||
codeGenFiles := make(map[string]io.Reader)
|
||||
|
||||
// Remove the suffix "-service" since it's added back in by templatePathToActual
|
||||
svcname := strings.TrimSuffix(path.Base(conf.GoPackage), "-service")
|
||||
for _, templPath := range templFiles.AssetNames() {
|
||||
actualPath := templatePathToActual(templPath, sd.PkgName)
|
||||
// Re-derive the actual path for this file based on the service output
|
||||
// path provided by the truss main.go
|
||||
actualPath := templatePathToActual(templPath, svcname)
|
||||
file, err := generateResponseFile(templPath, data, conf.PreviousFiles[actualPath])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot render template")
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
Package parsepkgname provides functions for extracting the name of a package
|
||||
from a protocol buffer definition file. For example, given a protocol buffer 3
|
||||
file like this:
|
||||
|
||||
// A comment about this proto file
|
||||
package examplepackage;
|
||||
|
||||
// and the rest of the file goes here
|
||||
|
||||
The functions in this package would extract the name "examplepackage" as the
|
||||
name of the protobuf package.
|
||||
*/
|
||||
package parsepkgname
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unicode"
|
||||
|
||||
"github.com/TuneLab/go-truss/deftree/svcparse"
|
||||
)
|
||||
|
||||
type token int
|
||||
|
||||
const (
|
||||
ident token = iota
|
||||
whitespaceToken
|
||||
comment
|
||||
other
|
||||
)
|
||||
|
||||
type Scanner interface {
|
||||
// ReadUnit must return groups of runes representing at least the following
|
||||
// lexical groups:
|
||||
//
|
||||
// ident
|
||||
// comments (c++ style single line comments and block comments)
|
||||
// whitespace
|
||||
//
|
||||
// If you need a scanner which provides these out of the box, see the
|
||||
// SvcScanner struct in github.com/TuneLab/go-truss/deftree/svcparse
|
||||
ReadUnit() ([]rune, error)
|
||||
}
|
||||
|
||||
func categorize(unit []rune) token {
|
||||
rv := other
|
||||
r := unit[0]
|
||||
switch {
|
||||
case unicode.IsLetter(r):
|
||||
rv = ident
|
||||
case unicode.IsDigit(r):
|
||||
rv = ident
|
||||
case r == '_':
|
||||
rv = ident
|
||||
case unicode.IsSpace(r):
|
||||
rv = whitespaceToken
|
||||
case r == '/' && len(unit) > 1:
|
||||
rv = comment
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
// FromReader accepts an io.Reader, the contents of which should be a
|
||||
// valid proto3 file, and returns the name of the protobuf package which that
|
||||
// file belongs to.
|
||||
func FromReader(protofile io.Reader) (string, error) {
|
||||
scanner := svcparse.NewSvcScanner(protofile)
|
||||
return FromScanner(scanner)
|
||||
}
|
||||
|
||||
// FromScanner accepts a Scanner for a protobuf file and returns the name of
|
||||
// the protobuf package that the file belongs to.
|
||||
func FromScanner(scanner Scanner) (string, error) {
|
||||
foundpackage := false
|
||||
|
||||
// A nice way to ignore comments. Recursively calls itself until it
|
||||
// recieves a unit from the scanner which is not a comment.
|
||||
var readIgnoreComment func(Scanner) (token, []rune, error)
|
||||
readIgnoreComment = func(scn Scanner) (token, []rune, error) {
|
||||
unit, err := scn.ReadUnit()
|
||||
if err != nil {
|
||||
return other, nil, err
|
||||
}
|
||||
tkn := categorize(unit)
|
||||
if tkn == comment {
|
||||
return readIgnoreComment(scn)
|
||||
}
|
||||
return tkn, unit, err
|
||||
}
|
||||
|
||||
// A tiny state machine to find two sequential idents: the ident "package"
|
||||
// and the ident immediately following. That second ident will be the name
|
||||
// of the package.
|
||||
for {
|
||||
tkn, unit, err := readIgnoreComment(scanner)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if foundpackage {
|
||||
if tkn == ident {
|
||||
return string(unit), nil
|
||||
} else if tkn == whitespaceToken {
|
||||
continue
|
||||
} else {
|
||||
foundpackage = false
|
||||
}
|
||||
} else {
|
||||
if tkn == ident && string(unit) == "package" {
|
||||
foundpackage = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package parsepkgname
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testScanner struct {
|
||||
contents [][]rune
|
||||
position int
|
||||
}
|
||||
|
||||
func (t *testScanner) ReadUnit() ([]rune, error) {
|
||||
if t.position < len(t.contents) {
|
||||
rv := t.contents[t.position]
|
||||
t.position += 1
|
||||
return rv, nil
|
||||
}
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
func NewTestScanner(units []string) *testScanner {
|
||||
rv := testScanner{position: 0}
|
||||
for _, u := range units {
|
||||
rv.contents = append(rv.contents, []rune(u))
|
||||
}
|
||||
return &rv
|
||||
}
|
||||
|
||||
func TestFromScanner_simple(t *testing.T) {
|
||||
basicContents := []string{
|
||||
"\n",
|
||||
"package",
|
||||
" ",
|
||||
"examplename",
|
||||
";",
|
||||
"\n",
|
||||
}
|
||||
scn := NewTestScanner(basicContents)
|
||||
want := "examplename"
|
||||
got, err := FromScanner(scn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != want {
|
||||
t.Fatalf("Got %q for package name, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromScanner_mid_comment(t *testing.T) {
|
||||
contents := []string{
|
||||
"\n",
|
||||
"package",
|
||||
" ",
|
||||
"/* comment in the middle of the declaration */",
|
||||
"examplename",
|
||||
";",
|
||||
"\n",
|
||||
}
|
||||
scn := NewTestScanner(contents)
|
||||
want := "examplename"
|
||||
got, err := FromScanner(scn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != want {
|
||||
t.Fatalf("Got %q for package name, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromReader(t *testing.T) {
|
||||
code := `
|
||||
// A comment about this proto file
|
||||
package /* some mid-definition comment */ examplepackage;
|
||||
|
||||
// and the rest of the file goes here
|
||||
`
|
||||
name, err := FromReader(strings.NewReader(code))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := name
|
||||
want := "examplepackage"
|
||||
if got != want {
|
||||
t.Fatalf("Got %q for package name, want %q", got, want)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Package parsesvcname will parse the service name of a protobuf package. The
|
||||
// name returned will always be camelcased according to the conventions
|
||||
// outlined in github.com/golang/protobuf/protoc-gen-go/generator.CamelCase.
|
||||
package parsesvcname
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/TuneLab/go-truss/svcdef"
|
||||
"github.com/TuneLab/go-truss/truss/execprotoc"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// FromPaths accepts the paths of protobuf definition files and returns the
|
||||
// name of the service in that protobuf definition file.
|
||||
func FromPaths(gopath []string, protoDefPaths []string) (string, error) {
|
||||
td, err := ioutil.TempDir("", "parsesvcname")
|
||||
defer os.RemoveAll(td)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to create temporary directory for .pb.go files")
|
||||
}
|
||||
err = execprotoc.GeneratePBDotGo(protoDefPaths, gopath, td)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to generate .pb.go files from protobuf definition files")
|
||||
}
|
||||
|
||||
// Get path names of .pb.go files
|
||||
pbgoPaths := []string{}
|
||||
for _, p := range protoDefPaths {
|
||||
base := filepath.Base(p)
|
||||
barename := strings.TrimSuffix(base, filepath.Ext(p))
|
||||
pbgp := filepath.Join(td, barename+".pb.go")
|
||||
pbgoPaths = append(pbgoPaths, pbgp)
|
||||
}
|
||||
|
||||
// Open all .pb.go files and store in map to be passed to svcdef.New()
|
||||
openFiles := func(paths []string) (map[string]io.Reader, error) {
|
||||
rv := map[string]io.Reader{}
|
||||
for _, p := range paths {
|
||||
reader, err := os.Open(p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot open file %q", p)
|
||||
}
|
||||
rv[p] = reader
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
pbgoFiles, err := openFiles(pbgoPaths)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "cannot open all .pb.go files")
|
||||
}
|
||||
pbFiles, err := openFiles(protoDefPaths)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "cannot open all .proto files")
|
||||
}
|
||||
|
||||
sd, err := svcdef.New(pbgoFiles, pbFiles)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to create service definition; did you pass ALL the protobuf files to truss?")
|
||||
}
|
||||
|
||||
return sd.Service.Name, nil
|
||||
}
|
||||
|
||||
func FromReaders(gopath []string, protoDefReaders []io.Reader) (string, error) {
|
||||
protoDir, err := ioutil.TempDir("", "parsesvcname-fromreaders")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to create temporary directory for protobuf files")
|
||||
}
|
||||
// Ensures all the temporary files are removed
|
||||
defer os.RemoveAll(protoDir)
|
||||
|
||||
protoDefPaths := []string{}
|
||||
for _, rdr := range protoDefReaders {
|
||||
f, err := ioutil.TempFile(protoDir, "parsesvcname-fromreader")
|
||||
_, err = io.Copy(f, rdr)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "couldn't copy contents of our proto file into the os.File: ")
|
||||
}
|
||||
path := f.Name()
|
||||
f.Close()
|
||||
protoDefPaths = append(protoDefPaths, path)
|
||||
}
|
||||
return FromPaths(gopath, protoDefPaths)
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package parsesvcname
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Provide a basic proto file to test that FromPaths returns the name of the
|
||||
// service in the file at the provided path.
|
||||
func TestFromPaths(t *testing.T) {
|
||||
protoStr := `
|
||||
syntax = "proto3";
|
||||
package echo;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service BounceEcho {
|
||||
rpc Echo (EchoRequest) returns (EchoResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/echo"
|
||||
};
|
||||
}
|
||||
}
|
||||
message EchoRequest {
|
||||
string In = 1;
|
||||
}
|
||||
message EchoResponse {
|
||||
string Out = 1;
|
||||
}
|
||||
`
|
||||
protoDir, err := ioutil.TempDir("", "parsesvcname-test")
|
||||
if err != nil {
|
||||
t.Fatal("cannot create temp directory to store proto definition: ", err)
|
||||
}
|
||||
defer os.RemoveAll(protoDir)
|
||||
f, err := ioutil.TempFile(protoDir, "trusstest")
|
||||
_, err = io.Copy(f, strings.NewReader(protoStr))
|
||||
if err != nil {
|
||||
t.Fatal("couldn't copy contents of our proto file into the os.File: ", err)
|
||||
}
|
||||
path := f.Name()
|
||||
f.Close()
|
||||
|
||||
svcname, err := FromPaths([]string{os.Getenv("GOPATH")}, []string{path})
|
||||
if err != nil {
|
||||
t.Fatal("failed to get service name from path: ", err)
|
||||
}
|
||||
|
||||
if got, want := svcname, "BounceEcho"; got != want {
|
||||
t.Fatalf("got != want; got = %q, want = %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Provide a basic protobuf file to FromReader to ensure it returns the service
|
||||
// name we expect.
|
||||
func TestFromReader(t *testing.T) {
|
||||
protoStr := `
|
||||
syntax = "proto3";
|
||||
package echo;
|
||||
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service BounceEcho {
|
||||
rpc Echo (EchoRequest) returns (EchoResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/echo"
|
||||
};
|
||||
}
|
||||
}
|
||||
message EchoRequest {
|
||||
string In = 1;
|
||||
}
|
||||
message EchoResponse {
|
||||
string Out = 1;
|
||||
}
|
||||
`
|
||||
svcname, err := FromReaders([]string{os.Getenv("GOPATH")}, []io.Reader{strings.NewReader(protoStr)})
|
||||
if err != nil {
|
||||
t.Fatal("failed to get service name from path: ", err)
|
||||
}
|
||||
|
||||
if got, want := svcname, "BounceEcho"; got != want {
|
||||
t.Fatalf("got != want; got = %q, want = %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that passing a protobuf file that's not importing google annotations
|
||||
// will function properly.
|
||||
func TestNoAnnotations(t *testing.T) {
|
||||
protoStr := `
|
||||
syntax = "proto3";
|
||||
package echo;
|
||||
|
||||
service BounceEcho {
|
||||
rpc Echo (EchoRequest) returns (EchoResponse) {}
|
||||
}
|
||||
message EchoRequest {
|
||||
string In = 1;
|
||||
}
|
||||
message EchoResponse {
|
||||
string Out = 1;
|
||||
}
|
||||
`
|
||||
svcname, err := FromReaders([]string{os.Getenv("GOPATH")}, []io.Reader{strings.NewReader(protoStr)})
|
||||
if err != nil {
|
||||
t.Fatal("failed to get service name from path: ", err)
|
||||
}
|
||||
|
||||
if got, want := svcname, "BounceEcho"; got != want {
|
||||
t.Fatalf("got != want; got = %q, want = %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that having a service name which includes an underscore doesn't cause
|
||||
// problems.
|
||||
func TestUnderscoreService(t *testing.T) {
|
||||
protoStr := `
|
||||
syntax = "proto3";
|
||||
package echo;
|
||||
|
||||
service foo_bar_test {
|
||||
rpc Echo (EchoRequest) returns (EchoResponse) {}
|
||||
}
|
||||
message EchoRequest {
|
||||
string In = 1;
|
||||
}
|
||||
message EchoResponse {
|
||||
string Out = 1;
|
||||
}
|
||||
`
|
||||
svcname, err := FromReaders([]string{os.Getenv("GOPATH")}, []io.Reader{strings.NewReader(protoStr)})
|
||||
if err != nil {
|
||||
t.Fatal("failed to get service name from path: ", err)
|
||||
}
|
||||
|
||||
if got, want := svcname, "FooBarTest"; got != want {
|
||||
t.Fatalf("got != want; got = %q, want = %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that having a service name which starts with an underscore doesn't
|
||||
// cause problems.
|
||||
func TestLeadingUnderscoreService(t *testing.T) {
|
||||
protoStr := `
|
||||
syntax = "proto3";
|
||||
package echo;
|
||||
|
||||
service _Foo_Bar {
|
||||
rpc Echo (EchoRequest) returns (EchoResponse) {}
|
||||
}
|
||||
message EchoRequest {
|
||||
string In = 1;
|
||||
}
|
||||
message EchoResponse {
|
||||
string Out = 1;
|
||||
}
|
||||
`
|
||||
svcname, err := FromReaders([]string{os.Getenv("GOPATH")}, []io.Reader{strings.NewReader(protoStr)})
|
||||
if err != nil {
|
||||
t.Fatal("failed to get service name from path: ", err)
|
||||
}
|
||||
|
||||
if got, want := svcname, "XFoo_Bar"; got != want {
|
||||
t.Fatalf("got != want; got = %q, want = %q", got, want)
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче