Pass metadata to grpc client in integration tests

Hello!

I have an integration test

class FooIntegrationSpec ... {
  val testKit = KalixTestKit(new KalixProvider().get()).start()
  val client = testKit.getGrpcClient(classOf[Foo])
  ...
    val didSomething = client.doSomething(request).futureValue
  ...
}

It seems that it’s not possible to attach metadata to the doSomething call?

Unit tests allow this.

class FooSpec ... {
  val testKit = FooTestKit(new Foo))
  ...
    val metadata = Metadata.empty.set("user", "boo")
    val didSomething = foo.doSomething(request, metadata)
  ...
}

The use case is that I’m sending the user via metadata, rather than having a user field in all messages.

Is this pattern not recommended, and is the reason why integration tests don’t support metadata? Or is it possible but I’m missing something?

Thank you.

PS: Say I use JWTs and extract the user from the bearer token. Then, how do I pass a bearer token to a client call in an integration test?

Actually, I was able to do the following:

val client = FooClient(testKit.grpcClientSettings)(testKit.system)
...
client.doSomething().addHeader("user", "boo").invoke(request).futureValue

Would this be the way?

For the testing side of things did you see this part of the docs about running locally with JWT: Using JWTs :: Kalix Documentation ?

I don’t think we have any current way to inject JWT_DEV_SECRET_ISSUER in tests, but the default dev key and none signing algorithm should apply.

Hi @johanandren,

Yup I’ve read the JWTs docs a few times. I will try that soon, but let’s say it works using the dev issuer and none algorithm.

How do I inject the bearer token in integration tests?

Is using the generated FooClient directly along with the testKit.grpcClientSettings the only way, like above? I’m asking because it uses deprecated API (testKit.grpcClientSettings) which may be removed in the future.

How do I inject the bearer token in integration tests?

Ah, I think I looked at the problem the wrong way. A bearer token would come via a field in the message:

string my_token_field = 1 [(kalix.field).jwt = {
  token: true
}];

Which would then be validated and have its claims available in the metadata.

rpc MyMethod(MyRequest) returns (MyResponse) {
  option (kalix.method).jwt = {
    validate: MESSAGE
  };
};

Let me try this.

Finally made it work. However, the main question still stands:

What is the best way to send a bearer token in an integration test? More generally, what’s the best way to attach metadata to a request for integration tests?

For readers out there Googleing their way here:

  • In an integration test use the generated client class like below.
val token = JWT.create().withIssuer("dev").withSubject("user").sign(Algorithm.none())
val client = FooClient(testKit.grpcClientSettings)(testKit.system)
...
client.doSomething().addHeader("Authorization", s"Bearer $token").invoke(request).futureValue
  • Message fields are used for extracting value from the bearer token. So for instance the field below would have the value of the token on execution.
string bearer_token = 1 [(kalix.field).jwt.token = true];
  • The above solution seems temporary because testKit.grpcClientSettings is deprecated and may be removed in the future.

Not a super clean solution, but the returned client from testKit.getGrpcClient(classOf[MyService]) is actually a MyServiceClient so you can safely cast it, without touching additional API.

You must still look it up based on the service interface though.

Understood, thanks @johanandren