Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gRPC mocking with ~pony~ jig #1

Closed
juliaogris opened this issue Dec 2, 2021 · 5 comments
Closed

gRPC mocking with ~pony~ jig #1

juliaogris opened this issue Dec 2, 2021 · 5 comments

Comments

@juliaogris
Copy link
Member

Notes from brainstorming session.
PXL_20211126_092657633

@juliaogris
Copy link
Member Author

juliaogris commented Dec 2, 2021

Cam's poc generating jsonnet from protos:

package main
​
import (
	"fmt"
	"log"
	"os"
	"text/template""google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/reflect/protodesc"
	"google.golang.org/protobuf/reflect/protoreflect"
	"google.golang.org/protobuf/types/descriptorpb"
)
​
func main() {
	if len(os.Args) == 1 {
		log.Fatal("Missing file argument\n")
	} else if len(os.Args) > 2 {
		log.Fatal("Too many file arguments\n")
	}
	b, err := os.ReadFile(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	fds := &descriptorpb.FileDescriptorSet{}
	if err := proto.Unmarshal(b, fds); err != nil {
		log.Fatal(err)
	}
	files, err := protodesc.NewFiles(fds)
	if err != nil {
		log.Fatal(err)
	}
	files.RangeFiles(printMethods)
}
​
func printMethods(fd protoreflect.FileDescriptor) bool {
	sds := fd.Services()
	for i := 0; i < sds.Len(); i++ {
		sd := sds.Get(i)
		mds := sd.Methods()
		for j := 0; j < mds.Len(); j++ {
			printResponseJsonnet(mds.Get(j))
		}
	}
	return true
}
​
func printResponseJsonnet(md protoreflect.MethodDescriptor) {
	err := tmpl.Execute(os.Stdout, md)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}
​
var tmplStr = `
// {{.ParentFile.Package}}.{{.Parent.Name}}.{{.Name}}
function(input) {
  response: {
  {{- range (fields .Output.Fields) }}
    {{ .JSONName }}:
  {{ end -}}
  },
  error: null,
}

`var tmpl = template.Must(template.New("").Funcs(map[string]interface{}{"fields": fields}).Parse(tmplStr[1:]))
​
func fields(flds protoreflect.FieldDescriptors) []protoreflect.FieldDescriptor {
	result := make([]protoreflect.FieldDescriptor, flds.Len())
	for i := 0; i < flds.Len(); i++ {
		result[i] = flds.Get(i)
	}
	return result
}

@camh-
Copy link
Member

camh- commented Dec 2, 2021

image

@camh-
Copy link
Member

camh- commented Dec 2, 2021

suggested jsonnet structure:

input = {
  request: ...
  metadata: ...
}

output = {
  response: ...
  error: ...
  metadata: ... ?
}

Thinking about the original pony, it could proxy to another service, doing data translation in the middle. It would be nice to be able to do this, in which case the output would need to be more flexible. For example:

output = {
  respond: {
    message: {...} | error: {...}
    metadata: {...}
  }
}

or

output = {
  call: {
    address: foo.com:1234
    method: pkg.svc.method
    input: {
      message: {...}
      metadata: {...}
    }
  }
}

Not suggesting this right away, but we should consider the output format to be able to make it possible.

@juliaogris
Copy link
Member Author

juliaogris commented Dec 2, 2021

pony grpc mocking would be run as:

pony servegrpc -p proto.pb [-m method_dir]

with method_dir defaulting to .

The method dir has got a jsonnet file each for a method to be mocked as:

<pkg>.<service>.<method>.jsonnet 

@camh- camh- changed the title gRPC mocking with pony gRPC mocking with ~pony~ jig Dec 19, 2021
@juliaogris
Copy link
Member Author

Well that got done quicker than expected. Thank you @camh-

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants