Merge branch 'master' into granular_endpoint_middlewares
This commit is contained in:
Коммит
b341b59948
|
@ -18,9 +18,10 @@ before_install:
|
|||
- export PATH=$HOME/bin/:$PATH
|
||||
|
||||
# golang/protobuf contains protoc-gen-go which generates the .pb.go files
|
||||
- go get -v github.com/golang/protobuf/...
|
||||
#- go get -v github.com/golang/protobuf/... || true
|
||||
- go get -v github.com/golang/protobuf/protoc-gen-go
|
||||
# For http annotation support
|
||||
- go get -v google.golang.org/genproto/...
|
||||
- go get -v github.com/TuneLab/go-genproto/... || true
|
||||
# go-bindata is used to create binary data from template files
|
||||
- go get -v github.com/jteeuwen/go-bindata/...
|
||||
|
||||
|
|
4
Makefile
4
Makefile
|
@ -8,12 +8,12 @@ default: truss
|
|||
|
||||
dependencies:
|
||||
go get github.com/go-kit/kit
|
||||
go get google.golang.org/genproto
|
||||
go get github.com/TuneLab/go-genproto
|
||||
go get github.com/golang/protobuf/{proto,protoc-gen-go}
|
||||
|
||||
update-dependencies:
|
||||
go get -u github.com/go-kit/kit
|
||||
go get -u google.golang.org/genproto
|
||||
go get -u github.com/TuneLab/go-genproto
|
||||
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
|
||||
|
||||
# Generate go files containing the all template files in []byte form
|
||||
|
|
|
@ -21,15 +21,15 @@ To install this software, you must:
|
|||
download a release from [github](https://github.com/google/protobuf/releases)
|
||||
and add to `$PATH`.
|
||||
Otherwise [install from source.](https://github.com/google/protobuf)
|
||||
1. Install the `proto` and `protoc-gen-go` packages. (`protoc-gen-go` must be in `$PATH`)
|
||||
1. Install the `protoc-gen-go` package (must be in `$PATH`).
|
||||
|
||||
```
|
||||
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
|
||||
go get -u github.com/golang/protobuf/protoc-gen-go
|
||||
```
|
||||
1. Install HTTP Annotations
|
||||
|
||||
```
|
||||
go get -u google.golang.org/genproto
|
||||
go get -u github.com/TuneLab/go-genproto
|
||||
```
|
||||
1. Install Truss with
|
||||
|
||||
|
|
|
@ -34,8 +34,9 @@ message LouderRequest {
|
|||
}
|
||||
```
|
||||
The RPC calls can be annotated with HTTP transport option (endpoint name and type of request). For this we must import the google annotations library.
|
||||
|
||||
```
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service Echo {
|
||||
...
|
||||
|
@ -185,4 +186,4 @@ Executing this command will place the *.pb.go files into `$GOPATH/truss-demo/int
|
|||
|
||||
## Middlewares
|
||||
|
||||
TODO
|
||||
TODO
|
||||
|
|
|
@ -8,7 +8,7 @@ syntax = "proto3";
|
|||
// for `package echo;` truss will create the directory "echo-service".
|
||||
package echo;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service Echo {
|
||||
// Echo "echos" the incoming string
|
||||
|
|
|
@ -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 "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
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 "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
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,8 +1,8 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package multifile;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
message BasicTypeRequest {
|
||||
double A = 1;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package TEST;
|
||||
package Repeated;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
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 "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
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 "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
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) {
|
||||
|
|
|
@ -2,7 +2,7 @@ syntax = "proto3";
|
|||
|
||||
package transport;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service TransportPermutations {
|
||||
rpc GetWithQuery (GetWithQueryRequest) returns (GetWithQueryResponse) {
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -195,16 +192,15 @@ func parseServiceDefinition(cfg *truss.Config) (deftree.Deftree, *svcdef.Svcdef,
|
|||
return nil, nil, errors.Wrap(err, "cannot create .pb.go files")
|
||||
}
|
||||
|
||||
// Open all .pb.go files and store in slice to be passed to svcdef.New()
|
||||
//var openFiles func([]string) ([]io.Reader, error)
|
||||
openFiles := func(paths []string) ([]io.Reader, error) {
|
||||
rv := []io.Reader{}
|
||||
// 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 = append(rv, reader)
|
||||
rv[p] = reader
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
@ -228,7 +224,7 @@ func parseServiceDefinition(cfg *truss.Config) (deftree.Deftree, *svcdef.Svcdef,
|
|||
// Create the svcdef
|
||||
sd, err := svcdef.New(pbgoFiles, pbFiles)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "cannot create svcdef")
|
||||
return nil, nil, errors.Wrapf(err, "failed to create service definition; did you pass ALL the protobuf files to truss?")
|
||||
}
|
||||
|
||||
// Create the Deftree
|
||||
|
|
|
@ -28,7 +28,7 @@ func TestNewFromString(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ func TestNewClientServiceArgs(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
message SumRequest {
|
||||
repeated int64 a = 1;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -49,7 +49,7 @@ func TestApplyTemplateFromPath(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
@ -141,7 +141,7 @@ func TestAllTemplates(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
@ -171,7 +171,7 @@ func TestAllTemplates(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestNewData(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
|
|
@ -38,7 +38,7 @@ func TestServerMethsTempl(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
@ -98,7 +98,7 @@ func TestApplyServerTempl(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
@ -190,7 +190,7 @@ func TestIsValidFunc(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
@ -257,7 +257,7 @@ func TestPruneDecls(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
@ -384,7 +384,7 @@ func TestUpdateMethods(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
|
|
@ -28,7 +28,7 @@ func TestNewMethod(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
message SumRequest {
|
||||
int64 a = 1;
|
||||
|
|
|
@ -217,7 +217,7 @@ func generalService() (*svcdef.Svcdef, *gengokit.Data, error) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
// RequestMessage is so foo
|
||||
message RequestMessage {
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -36,7 +36,7 @@ func isEOF(err error) bool {
|
|||
// each `HTTPBinding` will have a populated list of all the http parameters
|
||||
// that that binding requires, where that parameter should be located, and the
|
||||
// type of each parameter.
|
||||
func consolidateHTTP(sd *Svcdef, protoFiles []io.Reader) error {
|
||||
func consolidateHTTP(sd *Svcdef, protoFiles map[string]io.Reader) error {
|
||||
for _, pfile := range protoFiles {
|
||||
lex := svcparse.NewSvcLexer(pfile)
|
||||
protosvc, err := svcparse.ParseService(lex)
|
||||
|
|
|
@ -56,7 +56,7 @@ type MapServer interface {
|
|||
protoCode := `
|
||||
syntax = "proto3";
|
||||
package TEST;
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
enum EnumType {
|
||||
A = 0;
|
||||
|
@ -84,7 +84,7 @@ service Map {
|
|||
}
|
||||
}`
|
||||
// From code, build our SvcDef
|
||||
sd, err := New([]io.Reader{strings.NewReader(goCode)}, []io.Reader{strings.NewReader(protoCode)})
|
||||
sd, err := New(map[string]io.Reader{"/tmp/notreal": strings.NewReader(goCode)}, map[string]io.Reader{"/tmp/alsonotreal": strings.NewReader(protoCode)})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,13 @@ func NewFromString(def string, gopath []string) (*Svcdef, error) {
|
|||
}
|
||||
pbgo := string(buf)
|
||||
|
||||
sd, err := New([]io.Reader{strings.NewReader(pbgo)}, []io.Reader{strings.NewReader(def)})
|
||||
pbgoMap := map[string]io.Reader{
|
||||
"/tmp/doesntexist.pb.go": strings.NewReader(pbgo),
|
||||
}
|
||||
pFileMap := map[string]io.Reader{
|
||||
"/tmp/doesntexist.proto": strings.NewReader(def),
|
||||
}
|
||||
sd, err := New(pbgoMap, pFileMap)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create new svcdef from pb.go and definition")
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ func basicFromString(t *testing.T) *Svcdef {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
message SumRequest {
|
||||
int64 a = 1;
|
||||
|
@ -158,7 +158,7 @@ func TestNoHTTPBinding(t *testing.T) {
|
|||
// General package
|
||||
package general;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
message SumRequest {
|
||||
int64 a = 1;
|
||||
|
|
|
@ -17,6 +17,7 @@ the path of an HTTP annotation.
|
|||
package svcdef
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
|
@ -135,16 +136,65 @@ func retrieveTypeSpecs(f *ast.File) ([]*ast.TypeSpec, error) {
|
|||
return rv, nil
|
||||
}
|
||||
|
||||
// DebugInfo contains context necessary for many functions to provide useful
|
||||
// debugging output when encountering errors. All DebugInfo methods are
|
||||
// implemented such that calling them with `nil` recievers means they'll return
|
||||
// empty values. And since DebugInfo is used PURELY for creating nice error
|
||||
// messages and no actual business logic depends on them, this means you can
|
||||
// safely pass 'nil' DebugInfo structs to functions and you'll just get
|
||||
// unhelpful error messages out, it won't break things. This is done to make
|
||||
// the code more testable.
|
||||
type DebugInfo struct {
|
||||
Fset *token.FileSet
|
||||
Path string
|
||||
}
|
||||
|
||||
func (di *DebugInfo) Position(pos token.Pos) string {
|
||||
if di == nil {
|
||||
return ""
|
||||
} else {
|
||||
return fmt.Sprintf("%s", di.Fset.Position(pos))
|
||||
}
|
||||
}
|
||||
|
||||
// LocationError is a special kind of error, carrying special information about
|
||||
// where the error was encountered within a file.
|
||||
type LocationError struct {
|
||||
Path string
|
||||
Position string
|
||||
Err string
|
||||
}
|
||||
|
||||
func NewLocationError(err string, path string, pos string) LocationError {
|
||||
return LocationError{
|
||||
Path: path,
|
||||
Position: pos,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (le LocationError) Error() string {
|
||||
return fmt.Sprintf("%s in file %q at line %s", le.Err, le.Path, le.Position)
|
||||
}
|
||||
|
||||
func (le LocationError) Location() string {
|
||||
return le.Position
|
||||
}
|
||||
|
||||
// New creates a Svcdef by parsing the provided Go and Protobuf source files to
|
||||
// derive type information, gRPC service data, and HTTP annotations.
|
||||
func New(goFiles []io.Reader, protoFiles []io.Reader) (*Svcdef, error) {
|
||||
func New(goFiles map[string]io.Reader, protoFiles map[string]io.Reader) (*Svcdef, error) {
|
||||
rv := Svcdef{}
|
||||
|
||||
for _, gofile := range goFiles {
|
||||
for path, gofile := range goFiles {
|
||||
fset := token.NewFileSet()
|
||||
fileAst, err := parser.ParseFile(fset, "", gofile, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "couldn't parse go file to create Svcdef")
|
||||
return nil, errors.Wrapf(err, "couldn't parse go file %q to create Svcdef", path)
|
||||
}
|
||||
debugInfo := &DebugInfo{
|
||||
Path: path,
|
||||
Fset: fset,
|
||||
}
|
||||
rv.PkgName = fileAst.Name.Name
|
||||
|
||||
|
@ -180,7 +230,7 @@ func New(goFiles []io.Reader, protoFiles []io.Reader) (*Svcdef, error) {
|
|||
if strings.HasSuffix("Client", t.Name.Name) {
|
||||
break
|
||||
}
|
||||
nsvc, err := NewService(t)
|
||||
nsvc, err := NewService(t, debugInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error parsing service %q", t.Name.Name)
|
||||
}
|
||||
|
@ -263,13 +313,13 @@ func NewMap(m ast.Expr) (*Map, error) {
|
|||
|
||||
// NewService returns a new Service struct derived from an *ast.TypeSpec with a
|
||||
// Type of *ast.InterfaceType representing an "{SVCNAME}Server" interface.
|
||||
func NewService(s *ast.TypeSpec) (*Service, error) {
|
||||
func NewService(s *ast.TypeSpec, info *DebugInfo) (*Service, error) {
|
||||
rv := &Service{
|
||||
Name: strings.TrimSuffix(s.Name.Name, "Server"),
|
||||
}
|
||||
asvc := s.Type.(*ast.InterfaceType)
|
||||
for _, m := range asvc.Methods.List {
|
||||
nmeth, err := NewServiceMethod(m)
|
||||
nmeth, err := NewServiceMethod(m, info)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Couldn't create service method %q of service %q", m.Names[0].Name, rv.Name)
|
||||
}
|
||||
|
@ -281,13 +331,15 @@ func NewService(s *ast.TypeSpec) (*Service, error) {
|
|||
// NewServiceMethod returns a new ServiceMethod derived from a method of a
|
||||
// Service interface. This is accepted in the form of an *ast.Field which
|
||||
// contains the name of the method.
|
||||
func NewServiceMethod(m *ast.Field) (*ServiceMethod, error) {
|
||||
func NewServiceMethod(m *ast.Field, info *DebugInfo) (*ServiceMethod, error) {
|
||||
rv := &ServiceMethod{
|
||||
Name: m.Names[0].Name,
|
||||
}
|
||||
ft, ok := m.Type.(*ast.FuncType)
|
||||
if !ok {
|
||||
return nil, errors.New("Provided *ast.Field.Type is not of type *ast.FuncType; cannot proceed")
|
||||
return nil, NewLocationError("Provided *ast.Field.Type is not of type "+
|
||||
"*ast.FuncType; cannot proceed",
|
||||
info.Path, info.Position(m.Pos()))
|
||||
}
|
||||
|
||||
input := ft.Params.List
|
||||
|
@ -308,11 +360,15 @@ func NewServiceMethod(m *ast.Field) (*ServiceMethod, error) {
|
|||
makeFieldType := func(in *ast.Field) (*FieldType, error) {
|
||||
star, ok := in.Type.(*ast.StarExpr)
|
||||
if !ok {
|
||||
return nil, errors.New("could not create FieldType, in.Type is not *ast.StarExpr")
|
||||
return nil, NewLocationError("could not create FieldType, in.Type "+
|
||||
"is not *ast.StarExpr",
|
||||
info.Path, info.Position(in.Pos()))
|
||||
}
|
||||
ident, ok := star.X.(*ast.Ident)
|
||||
if !ok {
|
||||
return nil, errors.New("could not create FieldType, star.Type is not *ast.Ident")
|
||||
return nil, NewLocationError("could not create FieldType, "+
|
||||
"star.Type is not *ast.Ident",
|
||||
info.Path, info.Position(star.Pos()))
|
||||
}
|
||||
return &FieldType{
|
||||
Name: ident.Name,
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestSvcdef(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sd, err := New([]io.Reader{gf}, []io.Reader{pf})
|
||||
sd, err := New(map[string]io.Reader{"./test-go.txt": gf}, map[string]io.Reader{"./test-proto.txt": pf})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ type NestedTypeRequest struct {
|
|||
B []*NestedMessageB
|
||||
C EnumType
|
||||
}`
|
||||
sd, err := New([]io.Reader{strings.NewReader(caseCode)}, nil)
|
||||
sd, err := New(map[string]io.Reader{"/tmp/notreal": strings.NewReader(caseCode)}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ type MsgWithMap struct {
|
|||
Beta map[int64]*NestedMessageC
|
||||
}
|
||||
`
|
||||
sd, err := New([]io.Reader{strings.NewReader(caseCode)}, nil)
|
||||
sd, err := New(map[string]io.Reader{"/tmp/notreal": strings.NewReader(caseCode)}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ syntax = "proto3";
|
|||
|
||||
package TEST;
|
||||
|
||||
import "google.golang.org/genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
import "github.com/TuneLab/go-genproto/googleapis/api/serviceconfig/annotations.proto";
|
||||
|
||||
service Map {
|
||||
rpc GetMap (MapTypeRequest) returns (MapTypeResponse) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче