### Application-level installation with Application.mokksy(server) Source: https://mokksy.dev/docs/mokksy/ktor Installs SSE, DoubleReceive, and ContentNegotiation automatically and mounts a catch-all route that dispatches every request through the stub registry. Use this overload when Mokksy owns the entire application and you want the simplest possible setup. ```Kotlin import dev.mokksy.mokksy.MokksyServer import dev.mokksy.mokksy.mokksy import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty val server = MokksyServer() server.get { path("/ping") } respondsWith { body = "pong" } embeddedServer(Netty, port = 8080) { mokksy(server) }.start(wait = true) ``` -------------------------------- ### Stub and call an HTTP endpoint (Kotlin) Source: https://mokksy.dev/docs/mokksy/quick-start Starts Mokksy, registers a stub for GET /accounts/42, and verifies the response using a real HTTP client. The example uses Ktor client and Kotlin test assertions. ```kotlin // before SUT starts val mokksy = Mokksy(verbose = true).start() // SUT setup val client = HttpClient { install(DefaultRequest) { url(mokksy.baseUrl()) } } // Given - before test mokksy.get { path("/accounts/42") } respondsWith { body = """{"id":"42","status":"active"}""" httpStatus = HttpStatusCode.OK } // When val response = client.get("/accounts/42") // Then response.status shouldBe HttpStatusCode.OK response.bodyAsText() shouldBe """{"id":"42","status":"active"}""" ``` -------------------------------- ### Stub and call an HTTP endpoint (Java) Source: https://mokksy.dev/docs/mokksy/quick-start Starts Mokksy, registers a stub for GET /accounts/42, and verifies the response using a real HTTP client. The example uses java.net.http.HttpClient and JUnit assertions. ```java // before SUT starts var mokksy = Mokksy.create().start(); // Given - before test mokksy.get(spec -> spec.path("/accounts/42")) .respondsWith(response -> response .body("{\"id\":\"42\",\"status\":\"active\"}") .status(200)); // When var httpClient = HttpClient.newHttpClient(); var response = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/accounts/42")) .GET() .build(), HttpResponse.BodyHandlers.ofString() ); // Then assertThat(response.statusCode()).isEqualTo(200); assertThat(response.body()).isEqualTo("{\"id\":\"42\",\"status\":\"active\"}"); // after SUT stop (or never) mokksy.shutdown(); ``` -------------------------------- ### Start the container with Docker Source: https://mokksy.dev/docs/mokksy/docker Run the Mokksy container by mounting the stubs file to the default configuration path. ```bash docker run -p 8080:8080 \ -v ./stubs.yaml:/config/stubs.yaml \ mokksy/server-jvm:snapshot ``` -------------------------------- ### Basic MockOllama setup Source: https://mokksy.dev/docs/ai-mocks/ollama Instantiate a MockOllama server with verbose logging enabled and retrieve its base URL for making requests. ```kotlin // Create a mock Ollama server val ollama = MockOllama(verbose = true) // Get the base URL of the mock server val baseUrl = ollama.baseUrl() ``` -------------------------------- ### Initialize MockAgentServer Source: https://mokksy.dev/docs/ai-mocks/a2a Initialize the server instance. It starts on a random free port by default, which can be retrieved via baseUrl(). ```kotlin val a2aServer = MockAgentServer(verbose = true) ``` -------------------------------- ### Route-level installation with Route.mokksy(server) Source: https://mokksy.dev/docs/mokksy/ktor Mounts the stub handler inside an existing route scope. Does not install plugins; you must install SSE, DoubleReceive, and ContentNegotiation on the surrounding application. Suitable when Mokksy stubs coexist with real routes. ```Kotlin routing { get("/health") { call.respondText("OK") } mokksy(server) } ``` -------------------------------- ### Integration test example in Kotlin Source: https://mokksy.dev/docs/mokksy/first-integration-test Demonstrates setting up a Mokksy server, configuring an HTTP client, defining a stub, and verifying the response in Kotlin. ```kotlin val mokksy = Mokksy(verbose = true).start() val client = HttpClient { install(DefaultRequest) { url(mokksy.baseUrl()) } } mokksy.post { path("/risk/check") bodyContains("customer-123") } respondsWith { httpStatus = HttpStatusCode.Accepted body = """{"decision":"review"}""" } val response = client.post("/risk/check") { contentType(ContentType.Application.Json) setBody("""{"customerId":"customer-123","amount":2500}""") } response.status shouldBe HttpStatusCode.Accepted response.bodyAsText() shouldBe """{"decision":"review"}""" mokksy.verifyNoUnexpectedRequests() mokksy.verifyNoUnmatchedStubs() ``` -------------------------------- ### Integration test example in Java Source: https://mokksy.dev/docs/mokksy/first-integration-test Demonstrates setting up a Mokksy server, defining a stub, executing an HTTP request, and verifying the response in Java. ```java var mokksy = Mokksy.create().start(); var httpClient = HttpClient.newHttpClient(); try { mokksy.post(spec -> spec .path("/risk/check") .bodyContains("customer-123") ).respondsWith(response -> response .status(202) .body("{\"decision\":\"review\"}")); var response = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/risk/check")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString( "{\"customerId\":\"customer-123\",\"amount\":2500}" )) .build(), HttpResponse.BodyHandlers.ofString() ); assertThat(response.statusCode()).isEqualTo(202); assertThat(response.body()).isEqualTo("{\"decision\":\"review\"}"); mokksy.verifyNoUnexpectedRequests(); } finally { mokksy.shutdown(); } ``` -------------------------------- ### Load stubs from file (Kotlin/Java) Source: https://mokksy.dev/docs/mokksy/file-config Loads a YAML stub file at startup and starts the server. The Kotlin and Java variants are equivalent; both call `loadStubsFromFile` after starting the server. ```kotlin val mokksy = Mokksy().start() mokksy.loadStubsFromFile("/path/to/stubs.yaml") ``` ```java Mokksy mokksy = Mokksy.create().start(); mokksy.loadStubsFromFile("/path/to/stubs.yaml"); ``` -------------------------------- ### Path matchers Source: https://mokksy.dev/docs/mokksy/request-matching Examples of path matching using direct string comparison or Kotest matchers. ```kotlin path("/things") ``` ```kotlin path = beEqual("/things") ``` -------------------------------- ### Client call for Get Task endpoint Source: https://mokksy.dev/docs/ai-mocks/a2a Demonstrates creating a request, sending a POST request to the endpoint, and parsing the response. ```kotlin 1// Create a GetTaskRequest object 2val jsonRpcRequest = GetTaskRequest( 3 id = "1", 4 params = TaskQueryParams( 5 id = UUID.randomUUID().toString(), 6 historyLength = 2, 7 ), 8) 9 10// Make a POST request to the Get Task endpoint 11val response = a2aClient 12 .post("/") { 13 contentType(ContentType.Application.Json) 14 setBody(Json.encodeToString(jsonRpcRequest)) 15 }.call 16 .response 17 18// Parse the response into a GetTaskResponse object 19val body = response.body() 20val payload = Json.decodeFromString(body) ``` -------------------------------- ### Kotlin: Stub GET request with header and respond with JSON Source: https://mokksy.dev/docs/mokksy/stubbing Stubs a GET endpoint `/ping` expecting a header `Foo: bar` and returning a JSON body. The example shows the full flow: stub definition, client request, and verification of status and body. ```kotlin // given val expectedResponse = // language=json """ { "response": "Pong" } """.trimIndent() mokksy.get { path = beEqual("/ping") containsHeader("Foo", "bar") } respondsWith { body = expectedResponse } // when val result = client.get("/ping") { headers.append("Foo", "bar") } // then result.status shouldBe HttpStatusCode.OK result.bodyAsText() shouldBe expectedResponse ``` -------------------------------- ### Load stubs from environment (Kotlin/Java/CLI) Source: https://mokksy.dev/docs/mokksy/file-config Shows how to load stubs from the environment in Kotlin, Java, and via command-line configuration. `loadStubsFromEnv()` checks `MOKKSY_CONFIG` first, then the `-Dmokksy.config` system property; when either is set, `start()` loads stubs automatically. ```kotlin // explicit load — useful when MOKKSY_CONFIG is not in the environment val mokksy = Mokksy().start() mokksy.loadStubsFromEnv() ``` ```java // explicit load — useful when MOKKSY_CONFIG is not in the environment Mokksy mokksy = Mokksy.create().start(); mokksy.loadStubsFromEnv(); ``` ```shell # via environment variable — stubs are loaded automatically on start() MOKKSY_CONFIG=/app/stubs.yaml java -jar app.jar # via system property java -Dmokksy.config=/app/stubs.yaml -jar app.jar ``` -------------------------------- ### Define streaming mock responses for generate and chat endpoints Source: https://mokksy.dev/docs/ai-mocks/ollama Shows how to configure streaming mock responses for both the generate and chat endpoints. The generate example matches a user message containing 'Tell me a story' and streams response chunks with a 100 millisecond delay. The chat example streams greeting chunks with the same delay. Both use the 'respondsStream' function. ```Kotlin // Define streaming mock response for generate endpoint ollama.generate { model = "llama3" stream = true userMessageContains("Tell me a story") } respondsStream { responseChunks = listOf( "Once upon a time", " in a land far, far away", " there lived a programmer", " who never had to debug in production." ) delayBetweenChunks = 100.milliseconds } // Define streaming mock response for chat endpoint ollama.chat { model = "llama3" stream = true } respondsStream { responseChunks = listOf( "Hello", ", how can I", " help you today?" ) delayBetweenChunks = 100.milliseconds } ``` -------------------------------- ### Initialize MockAnthropic server Source: https://mokksy.dev/docs/ai-mocks/anthropic Creates a MockAnthropic instance with verbose logging. The server starts on a random free port by default; retrieve the base URL via anthropic.baseUrl(). ```kotlin val anthropic = MockAnthropic(verbose = true) ``` -------------------------------- ### Configure mock server for Get Task success Source: https://mokksy.dev/docs/ai-mocks/a2a Configures the mock server to return a task with a completed state and an artifact. ```kotlin 1// Configure the mock server to respond with a task 2a2aServer.getTask() responds { 3 id = 1 4 result { 5 id = "tid_12345" 6 contextId = "ctx_12345" 7 status { 8 state = "completed" 9 } 10 artifacts += artifact { 11 name = "joke" 12 parts += textPart { 13 text = "This is a joke" 14 } 15 } 16 } 17} ``` -------------------------------- ### Define SSE endpoint and verify response (Java) Source: https://mokksy.dev/docs/mokksy/streaming Java equivalent of the Kotlin SSE example, using mokksy's Java API to define the endpoint and verify the response. ```java mokksy.post(spec -> spec.path("/sse")) .respondsWithSseStream(builder -> builder .chunk(SseEvent.data("One")) .chunk(SseEvent.data("Two"))); var response = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/sse")) .POST(HttpRequest.BodyPublishers.noBody()) .build(), HttpResponse.BodyHandlers.ofString() ); assertThat(response.statusCode()).isEqualTo(200); assertThat(response.body()).isEqualTo("data: One\r\n\r\ndata: Two\r\n\r\n"); ``` -------------------------------- ### POST request stub in Java Source: https://mokksy.dev/docs/mokksy/stubbing Java example using Mokksy's lambda-based API to stub a POST request to /things, respond with 201 and headers, then verify the client's response. ```java 1// given 2var expectedBody = "{\"id\":\"42\",\"name\":\"thing-42\"}"; 3 4mokksy.post(spec -> { 5 spec.path("/things"); 6 spec.bodyContains("\"42\""); 7}).respondsWith(builder -> builder 8 .body(expectedBody) 9 .status(201) 10 .header("Location", "/things/42") 11 .header("Foo", "bar")); 12 13// when 14var response = httpClient.send( 15 HttpRequest.newBuilder() 16 .uri(URI.create(mokksy.baseUrl() + "/things")) 17 .header("Content-Type", "application/json") 18 .POST(HttpRequest.BodyPublishers.ofString("{\"id\":\"42\"}")) 19 .build(), 20 HttpResponse.BodyHandlers.ofString() 21); 22 23// then 24assertThat(response.statusCode()).isEqualTo(201); 25assertThat(response.body()).isEqualTo(expectedBody); 26assertThat(response.headers().firstValue("Location")).hasValue("/things/42"); 27assertThat(response.headers().firstValue("Foo")).hasValue("bar"); ``` -------------------------------- ### Java: Stub specificity with path and bodyContains Source: https://mokksy.dev/docs/mokksy/request-matching Java equivalent of the stub specificity example. Defines a generic stub and a specific stub with bodyContains("admin"), then sends HTTP requests with Java's HttpClient to verify that the specific stub returns "admin user" and the generic stub returns "any user". ```java // Generic: matches any POST to /users mokksy.post(spec -> spec.path("/users")) .respondsWith(response -> response.body("any user")); // Specific: matches only requests whose body contains "admin" mokksy.post(spec -> spec .path("/users") .bodyContains("admin") ).respondsWith(response -> response.body("admin user")); var adminResult = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/users")) .POST(HttpRequest.BodyPublishers.ofString("admin")) .build(), HttpResponse.BodyHandlers.ofString() ); assertThat(adminResult.body()).isEqualTo("admin user"); var genericResult = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/users")) .POST(HttpRequest.BodyPublishers.ofString("regular")) .build(), HttpResponse.BodyHandlers.ofString() ); assertThat(genericResult.body()).isEqualTo("any user"); ``` -------------------------------- ### Kotlin: GET request with unmatched header returns 404 Source: https://mokksy.dev/docs/mokksy/stubbing Shows that when a request does not match the stub criteria (e.g., wrong header value), the server returns `404 (Not Found)`. This example sends a GET to `/ping` with header `Foo: baz` and verifies the status. ```kotlin 1val notFoundResult = client.get("/ping") { 2 headers.append("Foo", "baz") 3} 4 5notFoundResult.status shouldBe HttpStatusCode.NotFound ``` -------------------------------- ### Mokksy: Simple POST in Java Source: https://mokksy.dev/docs Demonstrates creating a mock server and stubbing a POST endpoint with body matching in Java. ```java 1// Create mock server 2var mokksy = Mokksy.create(); 3mokksy.start(); 4 5// Stub a POST endpoint 6mokksy.post(spec -> spec.path("/items")) 7 .respondsWith(builder -> builder 8 .body("{\"id\":\"42\"}") 9 .status(201) 10 .header("Location", "/items/42")); 11 12// Call the server - response streams as text/event-stream 13var response = httpClient.send( 14 HttpRequest.newBuilder() 15 .uri(URI.create(mokksy.baseUrl() + "/items")) 16 .POST(BodyPublishers.ofString("{\"name\":\"widget\"}")) 17 .build(), 18 BodyHandlers.ofString()); 19System.out.println(response.body()); // {"id":"42"} ``` -------------------------------- ### Test Spring-AI integration with MockGemini Source: https://mokksy.dev/docs/ai-mocks/gemini Shows how to create a MockGemini server, build a Spring-AI ChatClient using the custom VertexAI client, set up a mock response, and verify the chat response. The mock expects a system message containing 'You are a helpful pirate' and a user message 'Just say Hello!', and returns a specific content and finish reason. ```Kotlin // create mock server val gemini = MockGemini(verbose = true) // Create a VertexAI client that connects to the mock server val vertexAI = createTestVertexAI( endpoint = gemini.baseUrl(), projectId = "your-project-id", location = "us-central1", timeout = 5.seconds, ) // create Spring-AI client val chatClient = ChatClient .builder( VertexAiGeminiChatModel .builder() .vertexAI(vertexAI) .build(), ).build() // Set up a mock for the LLM call gemini.generateContent { temperature = 0.7 model = "gemini-2.0-flash" project = "your-project-id" location = "us-central1" systemMessageContains("You are a helpful pirate") userMessageContains("Just say 'Hello!'") } responds { content = "Ahoy there, matey! Hello!" finishReason = "stop" delay = 42.milliseconds } // Configure Spring-AI client call val response = chatClient .prompt() .system("You are a helpful pirate") .user("Just say 'Hello!'") .options(VertexAiGeminiChatOptions.builder().temperature(0.7).build()) // Make a call .call() .chatResponse() // Verify the response response shouldNotBeNull { result shouldNotBeNull { metadata.finishReason shouldBe "STOP" output.text shouldBe "Ahoy there, matey! Hello!" } } ``` -------------------------------- ### Configure Mock Server for Get Task Push Notification Source: https://mokksy.dev/docs/ai-mocks/a2a Defines a TaskPushNotificationConfig object and configures the a2aServer to return this configuration when the Get Task Push Notification endpoint is called. ```kotlin 1// Create a TaskPushNotificationConfig object 2val taskId: TaskId = "task_12345" 3val config = TaskPushNotificationConfig( 4 id = taskId, 5 pushNotificationConfig = PushNotificationConfig( 6 url = "https://example.com/callback", 7 token = "abc.def.jk", 8 authentication = AuthenticationInfo( 9 schemes = listOf("Bearer"), 10 ), 11 ), 12) 13 14// Configure the mock server to respond with the config 15a2aServer.getTaskPushNotification() responds { 16 id = 1 17 result = config 18} ``` -------------------------------- ### Mokksy: Simple POST in Kotlin Source: https://mokksy.dev/docs Demonstrates creating a mock server and stubbing a POST endpoint with body matching in Kotlin. ```kotlin 1// Create mock server 2val mokksy = Mokksy().start() 3 4// Stub a POST endpoint 5mokksy.post { 6 path("/items") 7 bodyContains("widget") 8} respondsWith { 9 body = """{"id":"42"}""" 10 httpStatus = HttpStatusCode.Created 11} 12 13// Call the server 14val response = client.post(mokksy.baseUrl() + "/items") { 15 setBody("""{"name":"widget"}""") 16} 17println(response.bodyAsText()) // {"id":"42"} ``` -------------------------------- ### Priority example: higher priority stub wins (Kotlin and Java) Source: https://mokksy.dev/docs/mokksy/request-matching Shows how the `priority` property resolves conflicts when multiple stubs match with the same specificity score. The Kotlin example uses `mokksy.get` with `contain` and `beEqual` path matchers; the Java example uses `mokksy.post` with `bodyMatchesPredicate` and `bodyContains`. In both, the stub with the higher positive priority wins over the lower negative priority catch-all. ```kotlin // Catch-all stub with low priority (negative value) mokksy.get { path = contain("/things") priority = -1 } respondsWith { body = "Generic Thing" } // Specific stub with high priority (positive value) mokksy.get { path = beEqual("/things/special") priority = 1 } respondsWith { body = "Special Thing" } // when val generic = client.get("/things/123") val special = client.get("/things/special") // then generic.bodyAsText() shouldBe "Generic Thing" special.bodyAsText() shouldBe "Special Thing" ``` ```java // Catch-all stub: matches any POST, returns 400 mokksy.post(spec -> { spec.path("/v1/chat/completions"); spec.bodyMatchesPredicate(body -> true); spec.priority(-1); }).respondsWith(builder -> builder .body("{\"error\":\"unsupported request\"}") .status(400)); // Specific stub: matches only when body contains "gpt-4", returns 200 mokksy.post(spec -> { spec.path("/v1/chat/completions"); spec.bodyContains("gpt-4"); spec.priority(1); }).respondsWith(builder -> builder .body("{\"model\":\"gpt-4\"}") .status(200)); // Specific request → specific stub wins var specific = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/v1/chat/completions")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString("{\"model\":\"gpt-4\"}")) .build(), HttpResponse.BodyHandlers.ofString() ); assertThat(specific.statusCode()).isEqualTo(200); // Unmatched request → catch-all fallback kicks in var fallback = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/v1/chat/completions")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString("{\"model\":\"other\"}")) .build(), HttpResponse.BodyHandlers.ofString() ); assertThat(fallback.statusCode()).isEqualTo(400); ``` -------------------------------- ### Mock OpenAI chat completion with Kotlin and OpenAI SDK Source: https://mokksy.dev/docs Creates a mock OpenAI server, stubs a chat completion for the model gpt-4o-mini that responds with "Hello!", and then uses the official OpenAI SDK to send a chat request. The output prints "Hello!". ```kotlin 1// Create a mock OpenAI server 2val openai = MockOpenai() 3 4// Stub a chat completion 5openai.completion { 6 model = "gpt-4o-mini" 7 userMessageContains("say 'Hello!'") 8} responds { 9 assistantContent = "Hello!" 10 finishReason = "stop" 11} 12 13// Use the official OpenAI SDK 14val client = OpenAIOkHttpClient.builder() 15 .apiKey("test-key") 16 .baseUrl(openai.baseUrl()) 17 .build() 18 19val result = client.chat().completions().create( 20 ChatCompletionCreateParams.builder() 21 .model(ChatModel.GPT_4O_MINI) 22 .messages(listOf( 23 ChatCompletionMessageParam.ofUser( 24 ChatCompletionUserMessageParam.builder() 25 .content("Just say 'Hello!'") 26 .build()))) 27 .build()) 28 29println(result.choices().first().message().content()) // Hello! ``` -------------------------------- ### Minimal stub YAML file Source: https://mokksy.dev/docs/mokksy/file-config Minimal YAML stub definition with a single GET endpoint. The `path` field is required and must match exactly; `method` defaults to `GET` and `status` defaults to `200`. ```yaml stubs: - name: ping method: GET path: /ping response: body: '{"response":"Pong"}' status: 200 ``` -------------------------------- ### Configure OpenAI Java SDK client with AI-Mocks Source: https://mokksy.dev/docs/integrations/openai-sdk Instantiate MockOpenai and build an OpenAIOkHttpClient with a dummy API key and the mock base URL. The API key is required by the SDK builder, but requests are routed to the local mock server, so no live OpenAI credential is used. ```kotlin 1import com.openai.client.OpenAIClient 2import com.openai.client.okhttp.OpenAIOkHttpClient 3import dev.mokksy.aimocks.openai.MockOpenai 4 5val openai = MockOpenai(verbose = true) 6 7val client: OpenAIClient = 8 com.openai.client.okhttp.OpenAIOkHttpClient.builder() 9 .apiKey("dummy-key-for-tests") 10 .baseUrl(openai.baseUrl()) 11 .responseValidation(true) 12 .build() ``` ```java import com.openai.client.OpenAIClient; import com.openai.client.okhttp.OpenAIOkHttpClient; import dev.mokksy.aimocks.openai.MockOpenai; var openai = new MockOpenai(); OpenAIClient client = OpenAIOkHttpClient.builder() .apiKey("dummy-key-for-tests") .baseUrl(openai.baseUrl()) .build(); ``` -------------------------------- ### Java: Stub GET response with header and path Source: https://mokksy.dev/docs/mokksy/stubbing Stubs a GET endpoint `/ping` expecting a path and header, returns a JSON body. Shows the Java builder API for stubbing, a client request using `java.net.http.HttpClient`, and assertions on status and body. ```java // given 1var expectedResponse = "{\"response\": \"Pong\"}"; 2 3mokksy.get(spec -> { 4 spec.path("/ping"); 5 spec.containsHeader("Foo", "bar"); 6}).respondsWith(builder -> builder.body(expectedResponse)); 7 8// when 9var response = httpClient.send( 10 HttpRequest.newBuilder() 11 .uri(URI.create(mokksy.baseUrl() + "/ping")) 12 .header("Foo", "bar") 13 .GET() 14 .build(), 15 HttpResponse.BodyHandlers.ofString() 16); 17 18// then 19assertThat(response.statusCode()).isEqualTo(200); 20assertThat(response.body()).isEqualTo(expectedResponse); ``` -------------------------------- ### Create MockOpenai instance Source: https://mokksy.dev/docs/ai-mocks/openai Instantiate the MockOpenai mock server with verbose logging enabled. ```kotlin val openai = MockOpenai(verbose = true) ``` -------------------------------- ### Recommended AfterEach setup with verifyNoUnexpectedRequests() and verifyNoUnmatchedStubs() Source: https://mokksy.dev/docs/mokksy/verification Recommended AfterEach setup: run verifyNoUnexpectedRequests() in @AfterEach to catch requests that arrived with no matching stub. For verifyNoUnmatchedStubs(), placement depends on fixture strategy: per-test instance (PER_METHOD or fresh server) call both in @AfterEach; shared instance (PER_CLASS or companion-object server) call verifyNoUnmatchedStubs() in @AfterAll immediately before shutdown(). ```kotlin @TestInstance(TestInstance.Lifecycle.PER_CLASS) class MyTest { val mokksy = Mokksy(verbose = true) lateinit var client: HttpClient @BeforeAll suspend fun setup() { mokksy.startSuspend() mokksy.awaitStarted() // port() and baseUrl() are safe after this point client = HttpClient { install(DefaultRequest) { url(mokksy.baseUrl()) } } } @Test suspend fun testSomething() { mokksy.get { path("/hi") } respondsWith { delay = 100.milliseconds // wait 100ms, then reply body = "Hello" } // when val response = client.get("/hi") // then response.status shouldBe HttpStatusCode.OK response.bodyAsText() shouldBe "Hello" } @AfterEach fun afterEach() { mokksy.verifyNoUnexpectedRequests() } @AfterAll suspend fun afterAll() { client.close() mokksy.verifyNoUnmatchedStubs() // shared instance: check once, after all tests ran mokksy.shutdownSuspend() } } ``` ```java @TestInstance(TestInstance.Lifecycle.PER_CLASS) class MyTest { private final Mokksy mokksy = Mokksy.create().start(); private final HttpClient httpClient = HttpClient.newHttpClient(); @Test void testSomething() throws Exception { mokksy.get(spec -> spec.path("/hi")) .respondsWith(response -> response .delayMillis(100) .body("Hello")); var response = httpClient.send( HttpRequest.newBuilder() .uri(URI.create(mokksy.baseUrl() + "/hi")) .GET() .build(), HttpResponse.BodyHandlers.ofString() ); assertThat(response.statusCode()).isEqualTo(200); assertThat(response.body()).isEqualTo("Hello"); } @AfterEach void afterEach() { mokksy.verifyNoUnexpectedRequests(); } @AfterAll void afterAll() { mokksy.verifyNoUnmatchedStubs(); mokksy.shutdown(); } } ``` -------------------------------- ### Define Request and Response Data Classes Source: https://mokksy.dev/docs/mokksy/stubbing Data structures used for request and response bodies in the examples. ```kotlin 1@Serializable 2@JvmRecord 3data class CreateItemRequest(val name: String, val quantity: Int) 4 5@Serializable 6@JvmRecord 7data class CreateItemResponse(val message: String) ``` ```java 1record CreateItemRequest(String name, int quantity) {} 2record CreateItemResponse(String message) {} ``` -------------------------------- ### Set up mock response for regular content generation Source: https://mokksy.dev/docs/ai-mocks/gemini Configures a mock response for a regular (non-streaming) content generation request using `generateContent` and `responds`. The mock matches on system and user message content and returns a fixed response with a delay. ```Kotlin gemini.generateContent { temperature = 0.7 seed = 42 model = "gemini-2.0-flash" project = "your-project-id" location = "us-central1" apiVersion = "v1beta1" systemMessageContains("You are a helpful pirate") userMessageContains("Just say 'Hello!'") } responds { content = "Ahoy there, matey! Hello!" delay = 60.milliseconds } ``` -------------------------------- ### Create a stubs file Source: https://mokksy.dev/docs/mokksy/docker Define the mock server behavior in a YAML file. ```yaml stubs: - name: ping method: GET path: /ping response: body: '{"response":"Pong"}' status: 200 ``` -------------------------------- ### Configure mock server for Get Task error Source: https://mokksy.dev/docs/ai-mocks/a2a Configures the mock server to return a task not found error. ```kotlin 1// Configure the mock server to respond with a task not found error 2a2aServer.getTask() responds { 3 id = 1 4 error = taskNotFoundError() 5} ``` -------------------------------- ### Configure the AnthropicOkHttpClient Source: https://mokksy.dev/docs/integrations/anthropic-sdk Construct the Anthropic client using a dummy API key and point the base URL to the local mock server instance. ```kotlin import com.anthropic.client.AnthropicClient import com.anthropic.client.okhttp.AnthropicOkHttpClient import dev.mokksy.aimocks.anthropic.MockAnthropic val anthropic = MockAnthropic(verbose = true) val client: AnthropicClient = AnthropicOkHttpClient.builder() .apiKey("dummy-key-for-tests") .baseUrl(anthropic.baseUrl()) .responseValidation(true) .build() ``` -------------------------------- ### Spring-AI Integration Test with MockOpenai Source: https://mokksy.dev/docs/ai-mocks/openai Sets up a MockOpenai server, configures a Spring-AI ChatClient with OpenAiChatModel, mocks a completion with specific parameters, makes a chat call, and verifies the response. Requires a mock server and a Spring-AI client. ```kotlin 1// create mock server 2val openai = MockOpenai(verbose = true) 3 4// create Spring-AI client 5val chatClient = 6 ChatClient 7 .builder( 8 org.springframework.ai.openai.OpenAiChatModel 9 .builder() 10 .openAiApi( 11 OpenAiApi 12 .builder() 13 .apiKey("demo-key") 14 .baseUrl(openai.baseUrl()) 15 .build(), 16 ).build(), 17 ).build() 18 19// Set up a mock for the LLM call 20openai.completion { 21 temperature = 0.7 22 seed = 42 23 model = "gpt-4o-mini" 24 maxTokens = 100 25 topP = 0.95 26 topK = 40 27 systemMessageContains("helpful pirate") 28 userMessageContains("say 'Hello!'") 29} responds { 30 assistantContent = "Ahoy there, matey! Hello!" 31 finishReason = "stop" 32 delay = 200.milliseconds 33} 34 // Configure Spring-AI client call 35val response = 36 chatClient 37 .prompt() 38 .system("You are a helpful pirate") 39 .user("Just say 'Hello!'") 40 .options( 41 OpenAiChatOptions 42 .builder() 43 .maxCompletionTokens(100) 44 .temperature(0.7) 45 .topP(0.95) 46 .model("gpt-4o-mini") 47 .seed(42) 48 .build(), 49 ) 50 // Make a call 51 .call() 52 .chatResponse() 53 // Verify the response 54response?.result shouldNotBe null 55response?.result?.apply { 56metadata.finishReason shouldBe "STOP" 57output.text shouldBe "Ahoy there, matey! Hello!" 58} ``` -------------------------------- ### Retrieve and Parse Agent Card Source: https://mokksy.dev/docs/ai-mocks/a2a Performs a GET request to the /.well-known/agent-card.json endpoint and deserializes the response body into an AgentCard object. ```kotlin 1// Make a GET request to the Agent Card endpoint 2val response = a2aClient 3 .get("/.well-known/agent-card.json") { 4 }.call 5 .response 6 .body() 7 8// Parse the response into an AgentCard object 9val receivedCard = Json.decodeFromString(response) ``` -------------------------------- ### Configure mock messages endpoint and response Source: https://mokksy.dev/docs/ai-mocks/anthropic Sets up a mock 'messages' endpoint with request expectations (temperature, model, maxTokens, topP, topK, userId, systemMessageContains, userMessageContains) and defines the response (messageId, assistantContent, delay, stopReason). The messages block defines the incoming request; the responds block defines the mock server's return. ```kotlin anthropic.messages { temperature = 0.42 model = "claude-3-7-sonnet-latest" maxTokens = 100 topP = 0.95 topK = 40 userId = "user123" systemMessageContains("helpful assistant") userMessageContains("say 'Hello!'") } responds { messageId = "msg_1234567890" assistantContent = "Hello" // response content delay = 200.milliseconds // simulate delay stopReason = "end_turn" // reason for stopping } ``` -------------------------------- ### List Task Push Notification Config Client Request Source: https://mokksy.dev/docs/ai-mocks/a2a Demonstrates how to build a JSON-RPC request, send it via POST, and parse the resulting response. ```Kotlin 1// Build a ListTaskPushNotificationConfigRequest 2val jsonRpcRequest = ListTaskPushNotificationConfigRequest( 3 id = "1", 4 params = ListTaskPushNotificationConfigParams.create { 5 limit(10) 6 offset(0) 7 }, 8) 9 10// Make a POST request to the List Task Push Notification Config endpoint 11val response = a2aClient 12 .post("/") { 13 contentType(ContentType.Application.Json) 14 setBody(Json.encodeToString(jsonRpcRequest)) 15 }.call 16 .response 17 18// Parse the response 19val body = response.body() 20val payload = Json.decodeFromString(body) ``` -------------------------------- ### Access Task Notification History Source: https://mokksy.dev/docs/ai-mocks/a2a Use the getTaskNotifications method to retrieve the notification history for a specific task. The example verifies that the history is initially empty. ```kotlin val taskId: TaskId = "task_12345" val notificationHistory = a2aServer.getTaskNotifications(taskId) // Verify that the history is initially empty notificationHistory.events() shouldHaveSize 0 ``` -------------------------------- ### Restrict multipart form encoding (Java) Source: https://mokksy.dev/docs/mokksy/multipart Java equivalent of the Kotlin example. Uses FormEncoding.MULTIPART to enforce multipart/form-data on the stub, rejecting urlencoded submissions with 404. ```Java mokksy.post(spec -> spec .path("/multipart-only") .body(body -> body.form(FormEncoding.MULTIPART, form -> form .field("key", "value") )) ).respondsWith(rb -> rb.body("multipart-only-ok")); ``` -------------------------------- ### Integrate with LangChain4J using OpenAiChatModel Source: https://mokksy.dev/docs/ai-mocks/openai Shows how to use LangChain4J Kotlin extensions with AI-Mocks. Builds an OpenAiChatModel pointing at the mock's base URL and sends a chat request with temperature, model, max tokens, topP, and seed parameters. ```Kotlin val model: OpenAiChatModel = OpenAiChatModel .builder() .apiKey("dummy-api-key") .baseUrl(openai.baseUrl()) .build() val result = model.chat { parameters = OpenAiChatRequestParameters .builder() .temperature(0.7) .modelName("gpt-4o-mini") .maxCompletionTokens(100) .topP(0.95) .seed(42) .build() messages += userMessage("Say Hello") } println(result) ``` -------------------------------- ### Set up mock response for streaming content generation Source: https://mokksy.dev/docs/ai-mocks/gemini Configures a mock response for a streaming content generation request using `generateContentStream` and `respondsStream`. The mock returns a flow of chunks with delays between them. ```Kotlin gemini.generateContentStream { temperature = 0.7 apiVersion = "v1beta1" location = "us-central1" maxOutputTokens(100) model = "gemini-2.0-flash" project = "your-project-id" seed = 42 systemMessageContains("You are a helpful pirate") userMessageContains("Just say 'Hello!'") } respondsStream { responseFlow = flow { emit("Ahoy") emit(" there,") delay(100.milliseconds) emit(" matey!") emit(" Hello!") } delay = 60.milliseconds delayBetweenChunks = 15.milliseconds } ``` -------------------------------- ### Execute Client Request for Get Task Push Notification Source: https://mokksy.dev/docs/ai-mocks/a2a Demonstrates creating a GetTaskPushNotificationRequest, sending a POST request via a2aClient, and parsing the resulting JSON response. ```kotlin 1// Create a GetTaskPushNotificationRequest object 2val jsonRpcRequest = GetTaskPushNotificationRequest( 3 id = "1", 4 params = TaskIdParams( 5 id = taskId, 6 ), 7) 8 9// Make a POST request to the Get Task Push Notification endpoint 10val response = a2aClient 11 .post("/") { 12 contentType(ContentType.Application.Json) 13 setBody(Json.encodeToString(jsonRpcRequest)) 14 }.call 15 .response 16 17// Parse the response into a GetTaskPushNotificationResponse object 18val body = response.body() 19val payload = Json.decodeFromString(body) ``` -------------------------------- ### Combine file configuration with Kotlin DSL stubs Source: https://mokksy.dev/docs/mokksy/file-config Demonstrates loading shared stubs from a YAML file while adding test-specific stubs using the Kotlin DSL. ```kotlin 1val mokksy = Mokksy().start() 2 3// load shared stubs from file 4mokksy.loadStubsFromFile("shared-stubs.yaml") 5 6// add test-specific stubs via DSL 7mokksy.get { path("/health") } respondsWithStatus HttpStatusCode.OK ``` -------------------------------- ### Configure mock server to respond with a Task (Kotlin) Source: https://mokksy.dev/docs/ai-mocks/a2a Creates a Task object with id, contextId, status, and artifact parts, then configures the mock server's sendMessage() to respond with that task. Use this to simulate a server response for testing the Send Message endpoint. ```Kotlin // Create a Task object val task = Task.create { id = "tid_12345" contextId = "ctx_12345" status { state = "completed" } artifact { name = "joke" parts += text { "This is a joke" } parts += file { uri = "https://example.com/readme.md" } parts += file { bytes = "1234".toByteArray() } parts += data { mapOf("foo" to "bar") } } } // Configure the mock server to respond with the task a2aServer.sendMessage() responds { id = 1 result = task } ``` -------------------------------- ### Authenticated stub routes with authenticate block Source: https://mokksy.dev/docs/mokksy/ktor Places stubs behind an authentication check. Requires installing SSE, DoubleReceive, ContentNegotiation, and Authentication plugins, then wrapping mokksy in an authenticate block. ```Kotlin install(SSE) install(DoubleReceive) install(ContentNegotiation) { json() } install(Authentication) { basic("auth-basic") { validate { credentials -> if (credentials.name == "user" && credentials.password == "pass") { UserIdPrincipal(credentials.name) } else null } } } routing { authenticate("auth-basic") { mokksy(server) } } ``` -------------------------------- ### Injecting MockOpenai into Koog and Spring Boot Source: https://mokksy.dev/docs/integrations/koog This snippet defines a TestEnvironment object to configure mock embeddings and a Server object to inject the mock base URL into Koog before starting the Spring Boot application. ```kotlin 1object TestEnvironment { 2 val mockOpenai = MockOpenai(verbose = true) 3 4 init { 5 System.setProperty("OPENAI_API_KEY", "dummyOpenAIKey") 6 System.setProperty("spring.profiles.active", "test") 7 8 listOf( 9 "Care for Magical Trees", 10 "Valley of Light", 11 "Magical Bow", 12 "Morning Pine Elixir", 13 "Teleportation and Portals", 14 ).forEach { 15 mockOpenai.embeddings { 16 inputContains(it) 17 } responds { 18 delay = 1.milliseconds 19 } 20 } 21 } 22} 23 24object Server { 25 init { 26 System.setProperty("ai.koog.openai.base-url", TestEnvironment.mockOpenai.baseUrl()) 27 28 SpringApplication.run( 29 com.example.app.Application::class.java, 30 "--server.port=0", 31 "--spring.profiles.active=test", 32 ) 33 } 34} ``` -------------------------------- ### Create VertexAI client for mock server Source: https://mokksy.dev/docs/ai-mocks/gemini Defines a function that creates a VertexAI client configured to use an arbitrary server endpoint and dummy credentials. It sets up transport channels and clients for LLM utility and prediction services, with timeouts applied to all unary methods. Throws RuntimeException on IOException. ```Kotlin internal fun createTestVertexAI( endpoint: String, projectId: String, location: String, timeout: Duration, ): VertexAI { try { val channelProvider = LlmUtilityServiceStubSettings .defaultHttpJsonTransportProviderBuilder() .setEndpoint(endpoint) .build() val newHttpJsonBuilder = LlmUtilityServiceStubSettings.newHttpJsonBuilder() newHttpJsonBuilder.unaryMethodSettingsBuilders().forEach { builder -> builder.setSimpleTimeoutNoRetriesDuration(timeout.toJavaDuration()) } val llmUtilityServiceStubSettings = newHttpJsonBuilder .setEndpoint(endpoint) .setCredentialsProvider(NoCredentialsProvider.create()) .setTransportChannelProvider(channelProvider) .build() val llmUtilityServiceClient = LlmUtilityServiceClient.create( LlmUtilityServiceSettings.create(llmUtilityServiceStubSettings), ) val predictionServiceSettingsBuilder = PredictionServiceSettings .newHttpJsonBuilder() .setEndpoint(endpoint) .setCredentialsProvider(NoCredentialsProvider.create()) .applyToAllUnaryMethods { updater -> updater.setSimpleTimeoutNoRetriesDuration(timeout.toJavaDuration()) as? Void? } val predictionServiceSettings = predictionServiceSettingsBuilder.build() val predictionClient = PredictionServiceClient.create(predictionServiceSettings) return VertexAI .Builder() .setTransport(Transport.REST) .setProjectId(projectId) .setLocation(location) .setLlmClientSupplier { llmUtilityServiceClient } .setPredictionClientSupplier { predictionClient } .setCredentials(ApiKeyCredentials.create("dummy-key")) .build() } catch (e: IOException) { throw RuntimeException(e) } } ```