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]