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

Add CEL rules for stubs #9

Closed
sudorandom opened this issue Oct 13, 2024 · 2 comments · Fixed by #17
Closed

Add CEL rules for stubs #9

sudorandom opened this issue Oct 13, 2024 · 2 comments · Fixed by #17
Labels
enhancement New feature or request

Comments

@sudorandom
Copy link
Owner

It would be neat if you could specify CEL rules that would decide if a stub is used. Like if you're stubbing a GET call, you could have a stub that looks like this:

id: "user1234"
target: my.v1.app.UserService/getUser
rules:
 - req.id == "1234"
json: {...}

Then when you call my.v1.app.UserService/getUser looking for the user with id 1234 you would receive the given mocked response. This would allow fairly complex testing scenarios.

Also, for debugging purposes the selected stub ID should be returned as a return header value.

@sudorandom sudorandom added the enhancement New feature or request label Nov 16, 2024
@KenxinKun
Copy link

KenxinKun commented Nov 22, 2024

This would be a very welcome feature! I'm coming from trying out gripmock which does have CEL rules but I would much rather work with fauxrpc's approach to using proto descriptors and its compatibility with the buf ecosystem and test containers.

On the note of adding stubs: I would like to use this framework for service/integration testing in the backend. Usually I expect to make a call to my tested service and it will in turn call out one or more stubbed gRPC dependencies. CEL rules would be very useful here to:

  1. Do some minimal validation that the tested service is sending the correct requests out to the stubbed dependencies.
  2. If more than one request is sent out, to receive the correct stubbed response.

In the current state of fauxrpc, if say I was using test containers and added a stub, would it just return that one? Would it return later randomised ones? Having CEL control over this and nice examples would be extremely useful.

@sudorandom
Copy link
Owner Author

sudorandom commented Nov 24, 2024

In the current state of fauxrpc, if say I was using test containers and added a stub, would it just return that one? Would it return later randomised ones?

Yeah, if you added a stub it will just return that one. If you add multiple for the same type it will randomly pick amongst them.

Having CEL control over this and nice examples would be extremely useful.

I've worked on this a bit yesterday and today: https://github.com/sudorandom/fauxrpc/tree/cel-rules

There's still more work to do, but there's several improvements already:

  • An --only-stubs server option that will return an error if there is no registered stub instead of generating fake data
  • Loading stubs from config files (in addition to the CLI and grpc service)
  • An active_if field for each stub which is a CEL expression that if it returns true it will be used
  • fauxrpc stub add now has a --active-if option
  • Preliminary work on being able to define values of fields using CEL expressions
		ds, err := protocel.NewDynamicMessage(md, map[string]protocel.Node{
			"double_value":   protocel.CEL(`1000.0+10.12`),
			"float_value":    protocel.CEL(`2000.0+10.12`),
			"int32_value":    protocel.CEL(`1+2`),
			"int64_value":    protocel.CEL(`2+2`),
			"uint32_value":   protocel.CEL(`uint(1+2)`),
			"uint64_value":   protocel.CEL(`uint(2+2)`),
			"sint32_value":   protocel.CEL(`1+2`),
			"sint64_value":   protocel.CEL(`2+2`),
			"fixed32_value":  protocel.CEL(`uint(1+2)`),
			"fixed64_value":  protocel.CEL(`uint(2+2)`),
			"sfixed32_value": protocel.CEL(`1+2`),
			"sfixed64_value": protocel.CEL(`2+2`),
			"bool_value":     protocel.CEL(`true`),
			"string_value":   protocel.CEL(`"hello"`),
			"bytes_value":    protocel.CEL(`b"ÿ"`),
		})

This works for scalar fields, message fields, and repeated fields. There are also gen_X() CEL functions that match all of the types:

		ds, err := protocel.NewDynamicMessage(md, map[string]protocel.Node{
			"double_value":   protocel.CEL(`gen_float64()`),
			"float_value":    protocel.CEL(`gen_float32()`),
			"int32_value":    protocel.CEL(`gen_int32()`),
			"int64_value":    protocel.CEL(`gen_int64()`),
			"uint32_value":   protocel.CEL(`gen_uint32()`),
			"uint64_value":   protocel.CEL(`gen_uint64()`),
			"sint32_value":   protocel.CEL(`gen_sint32()`),
			"sint64_value":   protocel.CEL(`gen_sint64()`),
			"fixed32_value":  protocel.CEL(`gen_fixed32()`),
			"fixed64_value":  protocel.CEL(`gen_fixed64()`),
			"sfixed32_value": protocel.CEL(`gen_sfixed32()`),
			"sfixed64_value": protocel.CEL(`gen_sfixed64()`),
			"bool_value":     protocel.CEL(`gen_bool()`),
			"string_value":   protocel.CEL(`gen_string()`),
			"bytes_value":    protocel.CEL(`gen_bytes()`),

What's left to do:

  • Add support for map fields to protocel library
  • support for priority when defining stubs. Highest priority will be given preference over lower. You will get random stubs within the same priority if multiple match
  • organize and document the input for the CEL expressions
  • Adding protocel functionality to the stubs.proto and support in the backend

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

Successfully merging a pull request may close this issue.

2 participants