Skip to content

Commit

Permalink
feat: Add gRPC exmaple using provider state injected values with meta…
Browse files Browse the repository at this point in the history
…data
  • Loading branch information
rholshausen committed Aug 8, 2024
1 parent 9615409 commit 0d71168
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@
import com.google.protobuf.InvalidProtocolBufferException;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

import static area_calculator.CalculatorGrpc.newBlockingStub;
import static au.com.dius.pact.consumer.dsl.PactBuilder.filePath;
import static io.grpc.Metadata.ASCII_STRING_MARSHALLER;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;

Expand All @@ -48,6 +52,10 @@ V4Pact calculateRectangleArea(PactBuilder builder) {
"width", "matching(number, fromProviderState('${rectangleWidth}', 3))"
)),

"requestMetadata", Map.of(
"Auth", "matching(equalTo, fromProviderState('${Auth}', 'AST00004'))"
),

"response", List.of(
Map.of(
"value", "matching(number, 12)"
Expand All @@ -61,8 +69,15 @@ V4Pact calculateRectangleArea(PactBuilder builder) {
@PactTestFor(pactMethod = "calculateRectangleArea")
@MockServerConfig(implementation = MockServerImplementation.Plugin, registryEntry = "protobuf/transport/grpc")
void calculateRectangleArea(MockServer mockServer, V4Interaction.SynchronousMessages interaction) throws InvalidProtocolBufferException {
io.grpc.Metadata.Key<String> authKey = io.grpc.Metadata.Key.of("Auth", ASCII_STRING_MARSHALLER);
io.grpc.Metadata metadata = new io.grpc.Metadata();
metadata.put(authKey, "AST00004");
AtomicReference<Metadata> headers = new AtomicReference<>(null);
AtomicReference<io.grpc.Metadata> trailers = new AtomicReference<>(null);
ManagedChannel channel = ManagedChannelBuilder.forTarget("127.0.0.1:" + mockServer.getPort())
.usePlaintext()
.intercept(MetadataUtils.newAttachHeadersInterceptor(metadata))
.intercept(MetadataUtils.newCaptureMetadataInterceptor(headers, trailers))
.build();
CalculatorGrpc.CalculatorBlockingStub stub = newBlockingStub(channel);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@ package io.pact.example.grpc.provider

import area_calculator.AreaCalculator
import area_calculator.CalculatorGrpcKt
import io.grpc.Metadata
import io.grpc.ServerBuilder
import io.grpc.ServerCall
import io.grpc.ServerCallHandler
import io.grpc.ServerInterceptor
import io.grpc.Status
import mu.KLogging
import java.util.regex.Pattern
import kotlin.math.PI
import kotlin.math.pow
import kotlin.math.sqrt

class Server {
private val server = ServerBuilder.forPort(0).addService(CalculatorService()).build()
private val server = ServerBuilder.forPort(0)
.intercept(CalculatorInterceptor())
.addService(CalculatorService()).build()

fun start() {
server.start()
Expand All @@ -34,6 +42,36 @@ class Server {
fun serverPort() = server.port
}

class CalculatorInterceptor : ServerInterceptor {
val authKey: Metadata.Key<String> = Metadata.Key.of("Auth", Metadata.ASCII_STRING_MARSHALLER)
val authCheckPatten: Pattern = Pattern.compile("[A-Z]{3}\\d{3}")

override fun <ReqT : Any?, RespT : Any?> interceptCall(
call: ServerCall<ReqT, RespT>,
headers: Metadata?,
next: ServerCallHandler<ReqT, RespT>?
): ServerCall.Listener<ReqT> {
val auth = headers?.get(authKey)
return if (auth.isNullOrEmpty()) {
call.close(Status.UNAUTHENTICATED, Metadata())
NoOpListener()
} else {
if (authCheckPatten.matcher(auth).matches()) {
if (next != null) {
next.startCall(call, headers)
} else {
NoOpListener()
}
} else {
call.close(Status.UNAUTHENTICATED, Metadata())
NoOpListener()
}
}
}
}

class NoOpListener<ReqT> : ServerCall.Listener<ReqT>()

class CalculatorService : CalculatorGrpcKt.CalculatorCoroutineImplBase() {
override suspend fun calculateOne(request: AreaCalculator.ShapeMessage): AreaCalculator.AreaResponse {
val area = when (request.shapeCase) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ void pactVerificationTestTemplate(PactVerificationContext context) {
@State("a rectangle")
Map<String, Object> rectangleState() {
LOGGER.debug("!!! rectangleState state called !!!");
return Map.of("rectangleWidth", 5, "rectangleLength", 10);
return Map.of(
"rectangleWidth", 5,
"rectangleLength", 10,
"Auth", "CCV001"
);
}
}

0 comments on commit 0d71168

Please sign in to comment.