Skip to main content

Example JVM provider project

Source Code

https://github.com/pact-foundation/pact-plugins/tree/main/examples

Pre-Reqs

  • Java 11

Outline

This example project has a server implementation in Kotlin for the area calculator service call:

  rpc calculate (ShapeMessage) returns (AreaResponse) {}

The Gradle Protobuf plugin is used to generate the gRPC classes for the calculate service call and the Kotlin Server class implements the calculate method.

gRPC plugin

To run the test in this project, it requires the gRPC plugin to be installed. See the documentation on that plugin.

Pact verification test

There is a Pact verification test written in Java and JUint 5 that can verify the Kotlin server using a Pact file from one of the consumer projects.

./gradlew clean test

Verifying the gRPC server using Verifier CLI

The server can also be verified by using the Pact Verifier CLI.

For this to work, the server first needs to be started. Then the pact_verifier_cli can be used with one of the Pact files from the consumer projects to verify the server.

First, start the server

We can use the Gradle run task for that:

./gradlew run
gRPC/area_calculator/provider-jvm: 
❯ ./gradlew run
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :server:run
14:21:59.427 [main] DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
14:21:59.439 [main] DEBUG io.netty.util.internal.PlatformDependent0 - -Dio.netty.noUnsafe: false
14:21:59.439 [main] DEBUG io.netty.util.internal.PlatformDependent0 - Java version: 11
14:21:59.441 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
14:21:59.442 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
14:21:59.442 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
14:21:59.444 [main] DEBUG io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable
java.lang.UnsupportedOperationException: Reflective setAccessible(true) disabled
at io.netty.util.internal.ReflectionUtil.trySetAccessible(ReflectionUtil.java:31)
at io.netty.util.internal.PlatformDependent0$4.run(PlatformDependent0.java:239)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at io.netty.util.internal.PlatformDependent0.<clinit>(PlatformDependent0.java:233)
at io.netty.util.internal.PlatformDependent.isAndroid(PlatformDependent.java:294)
at io.netty.util.internal.PlatformDependent.<clinit>(PlatformDependent.java:93)
at io.netty.util.AsciiString.<init>(AsciiString.java:223)
at io.netty.util.AsciiString.<init>(AsciiString.java:210)
at io.netty.util.AsciiString.cached(AsciiString.java:1401)
at io.netty.util.AsciiString.<clinit>(AsciiString.java:48)
at io.grpc.netty.Utils.<clinit>(Utils.java:78)
at io.grpc.netty.NettyServerBuilder.<clinit>(NettyServerBuilder.java:83)
at io.grpc.netty.NettyServerProvider.builderForPort(NettyServerProvider.java:40)
at io.grpc.netty.NettyServerProvider.builderForPort(NettyServerProvider.java:25)
at io.grpc.ServerBuilder.forPort(ServerBuilder.java:44)
at io.pact.example.grpc.provider.Server.<init>(Server.kt:12)
at io.pact.example.grpc.provider.ServerKt.main(Server.kt:71)
at io.pact.example.grpc.provider.ServerKt.main(Server.kt)
14:21:59.445 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: available, true
14:21:59.446 [main] DEBUG io.netty.util.internal.PlatformDependent0 - jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable
java.lang.IllegalAccessException: class io.netty.util.internal.PlatformDependent0$6 cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @f0f2775
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
at java.base/java.lang.reflect.Method.invoke(Method.java:558)
at io.netty.util.internal.PlatformDependent0$6.run(PlatformDependent0.java:353)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at io.netty.util.internal.PlatformDependent0.<clinit>(PlatformDependent0.java:344)
at io.netty.util.internal.PlatformDependent.isAndroid(PlatformDependent.java:294)
at io.netty.util.internal.PlatformDependent.<clinit>(PlatformDependent.java:93)
at io.netty.util.AsciiString.<init>(AsciiString.java:223)
at io.netty.util.AsciiString.<init>(AsciiString.java:210)
at io.netty.util.AsciiString.cached(AsciiString.java:1401)
at io.netty.util.AsciiString.<clinit>(AsciiString.java:48)
at io.grpc.netty.Utils.<clinit>(Utils.java:78)
at io.grpc.netty.NettyServerBuilder.<clinit>(NettyServerBuilder.java:83)
at io.grpc.netty.NettyServerProvider.builderForPort(NettyServerProvider.java:40)
at io.grpc.netty.NettyServerProvider.builderForPort(NettyServerProvider.java:25)
at io.grpc.ServerBuilder.forPort(ServerBuilder.java:44)
at io.pact.example.grpc.provider.Server.<init>(Server.kt:12)
at io.pact.example.grpc.provider.ServerKt.main(Server.kt:71)
at io.pact.example.grpc.provider.ServerKt.main(Server.kt)
14:21:59.447 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.DirectByteBuffer.<init>(long, int): unavailable
14:21:59.447 [main] DEBUG io.netty.util.internal.PlatformDependent - sun.misc.Unsafe: available
14:21:59.464 [main] DEBUG io.netty.util.internal.PlatformDependent - maxDirectMemory: 8350859264 bytes (maybe)
14:21:59.464 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.tmpdir: /tmp (java.io.tmpdir)
14:21:59.464 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.bitMode: 64 (sun.arch.data.model)
14:21:59.466 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.maxDirectMemory: -1 bytes
14:21:59.466 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.uninitializedArrayAllocationThreshold: -1
14:21:59.466 [main] DEBUG io.netty.util.internal.CleanerJava9 - java.nio.ByteBuffer.cleaner(): available
14:21:59.467 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false
14:21:59.558 [main] DEBUG io.netty.channel.MultithreadEventLoopGroup - -Dio.netty.eventLoopThreads: 32
14:21:59.573 [main] DEBUG io.netty.util.internal.InternalThreadLocalMap - -Dio.netty.threadLocalMap.stringBuilder.initialSize: 1024
14:21:59.573 [main] DEBUG io.netty.util.internal.InternalThreadLocalMap - -Dio.netty.threadLocalMap.stringBuilder.maxSize: 4096
14:21:59.578 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
14:21:59.578 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
14:21:59.592 [main] DEBUG io.netty.util.internal.PlatformDependent - org.jctools-core.MpscChunkedArrayQueue: available
14:21:59.618 [main] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
14:21:59.618 [main] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.targetRecords: 4
14:21:59.619 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 32
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 32
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 11
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 16777216
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimIntervalMillis: 0
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.useCacheForAllThreads: true
14:21:59.620 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedByteBuffersPerChunk: 1023
14:21:59.660 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.processId: 139445 (auto-detected)
14:21:59.662 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv4Stack: false
14:21:59.662 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv6Addresses: false
14:21:59.663 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.util.NetUtilInitializations - Loopback interface: lo (lo, 0:0:0:0:0:0:0:1%lo)
14:21:59.664 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.util.NetUtil - /proc/sys/net/core/somaxconn: 4096
14:21:59.665 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 9c:b6:d0:ff:fe:3f:8e:1a (auto-detected)
14:21:59.683 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
14:21:59.683 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 0
14:21:59.683 [grpc-nio-boss-ELG-1-1] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
Started calculator service on 37757
<===========--> 87% EXECUTING [30s]
> :server:run

Note the port that is printed out above (37757), we need to pass that on to the verifier CLI.

Second, run the pact_verifier_cli

We use the Pact file from the consumer project and the port from the step above.

pact_verifier_cli -f ../consumer-jvm/build/pacts/grpc-consumer-jvm-area-calculator-provider.json -p 37757 -l none
gRPC/area_calculator/provider-jvm: 
❯ pact_verifier_cli -f ../consumer-jvm/build/pacts/grpc-consumer-jvm-area-calculator-provider.json -p 37757 -l none
2022-05-02T04:29:36.636972Z INFO main pact_verifier: Pact file requires plugins, will load those now
2022-05-02T04:29:36.638556Z WARN tokio-runtime-worker pact_plugin_driver::metrics:

Please note:
We are tracking this plugin load anonymously to gather important usage statistics.
To disable tracking, set the 'pact_do_not_track' environment variable to 'true'.


2022-05-02T04:29:36.873435Z INFO main pact_verifier: Running provider verification for 'calculate rectangle area request'

Verifying a pact between protobuf-consumer and area-calculator-provider

calculate rectangle area request

Test Name: io.pact.example.grpc.consumer.PactConsumerTest.calculateRectangleArea(MockServer, SynchronousMessages)

Given a Calculator/calculate request
with an input .area_calculator.ShapeMessage message
will return an output .area_calculator.AreaResponse message [OK]