Home > Enterprise >  .NET Grpc unit test CallContext
.NET Grpc unit test CallContext

Time:01-22

I am using the packages Grpc.Core and ProtoBuf.Grpc because I want to use both: Code-First gRPC with gRPC ClientFactory. Now I have an interface of form Task<Response> MyMethod(Request request, CallContext context) with CallContext coming from ProtoBuf.Grpc.

In the implementation of the interface I get the authorized (calling) user like this:

var user = httpContext.User.Claims.Where(x => x.Type == JwtRegisteredClaimNames.Name).FirstOrDefault();

Now I want to unit test my implementation of MyMethod but I do not know how to create the correct context for CallContext with a test user.

How can I test my implementation MyMethod with a predefined user in the CallContext?

Edit:

It seems possible to create and pass an instance of CallContext by calling the constructor

public CallContext(object server, ServerCallContext context)

I can create the ServerCallContext object via TestServerCallContext.Create(), see here. However I do not know what to pass for object server. Does anyone have an example for me?

CodePudding user response:

For unit testing gRPC with authentication and user context the following approach was my solution:

public static ProtoBuf.Grpc.CallContext TestCallContext(Guid user)
{
    var serverCallContext = TestServerCallContext.Create(
                                            method: nameof(IGrpcGreetingService.Greeting)
                                        , host: "localhost"
                                        , deadline: DateTime.Now.AddMinutes(30)
                                        , requestHeaders: new Metadata()
                                        , cancellationToken: CancellationToken.None
                                        , peer: "10.0.0.25:5001"
                                        , authContext: null
                                        , contextPropagationToken: null
                                        , writeHeadersFunc: (metadata) => Task.CompletedTask
                                        , writeOptionsGetter: () => new WriteOptions()
                                        , writeOptionsSetter: (writeOptions) => { }
                                        );

    var claims = new[] {
            new Claim(JwtRegisteredClaimNames.Sub, "some subject"),
            new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
            new Claim(JwtRegisteredClaimNames.Name, user.ToString())
        };
    var claimsIdentity = new ClaimsIdentity(claims);

    var httpContext = new DefaultHttpContext();
    httpContext.User = new ClaimsPrincipal(claimsIdentity);
    serverCallContext.UserState["__HttpContext"] = httpContext;

    return new ProtoBuf.Grpc.CallContext("", serverCallContext);
}

With arguments for TestServerCallContext.Create from here.

Maybe this can help somebody else save some hours or days :)

  • Related