Fix tests for notifications (#446)

<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->
This commit is contained in:
Maria Tigina 2025-12-08 13:09:41 +01:00 • committed by GitHub
commit 274089a6da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 43 additions and 46 deletions

View file

@ -348,7 +348,7 @@ internal class FeatureNotificationService(
job.start()
}
/** Returns the current timestamp in milliseconds. */
/** Returns the current timestamp in milliseconds since Unix epoch. */
@OptIn(ExperimentalTime::class)
private fun getCurrentTimestamp(): Long = clock.now().toEpochMilliseconds()

View file

@ -23,9 +23,9 @@ class ServerPromptsNotificationTest : AbstractServerFeaturesTest() {
@Test
fun `addPrompt should send notification`() = runTest {
// Configure notification handler
var promptListChangedNotificationReceived = false
val notifications = mutableListOf<PromptListChangedNotification>()
client.setNotificationHandler<PromptListChangedNotification>(Method.Defined.NotificationsPromptsListChanged) {
promptListChangedNotificationReceived = true
notifications.add(it)
CompletableDeferred(Unit)
}
@ -46,16 +46,16 @@ class ServerPromptsNotificationTest : AbstractServerFeaturesTest() {
// Verify that the notification was sent
await untilAsserted {
assertTrue(promptListChangedNotificationReceived, "Notification should be sent when prompt is added")
assertTrue(notifications.isNotEmpty(), "Notification should be sent when prompt is added")
}
}
@Test
fun `removePrompts should remove multiple prompts and send two notifications`() = runTest {
// Configure notification handler
var promptListChangedNotificationReceivedCount = 0
val notifications = mutableListOf<PromptListChangedNotification>()
client.setNotificationHandler<PromptListChangedNotification>(Method.Defined.NotificationsPromptsListChanged) {
promptListChangedNotificationReceivedCount += 1
notifications.add(it)
CompletableDeferred(Unit)
}
@ -86,7 +86,7 @@ class ServerPromptsNotificationTest : AbstractServerFeaturesTest() {
await untilAsserted {
assertEquals(
4,
promptListChangedNotificationReceivedCount,
notifications.size,
"Two notifications should be sent when prompts are added and two when removed",
)
}
@ -95,9 +95,9 @@ class ServerPromptsNotificationTest : AbstractServerFeaturesTest() {
@Test
fun `notification should not be send when removed prompt does not exists`() = runTest {
// Track notifications
var promptListChangedNotificationReceived = false
val notifications = mutableListOf<PromptListChangedNotification>()
client.setNotificationHandler<PromptListChangedNotification>(Method.Defined.NotificationsPromptsListChanged) {
promptListChangedNotificationReceived = true
notifications.add(it)
CompletableDeferred(Unit)
}
@ -107,8 +107,8 @@ class ServerPromptsNotificationTest : AbstractServerFeaturesTest() {
// Verify the result
assertFalse(result, "Removing non-existent prompt should return false")
await untilAsserted {
assertFalse(
promptListChangedNotificationReceived,
assertTrue(
notifications.isEmpty(),
"No notification should be sent when prompt doesn't exist",
)
}

View file

@ -2,7 +2,6 @@ package io.modelcontextprotocol.kotlin.sdk.server
import io.modelcontextprotocol.kotlin.sdk.types.Method
import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceResult
import io.modelcontextprotocol.kotlin.sdk.types.ResourceListChangedNotification
import io.modelcontextprotocol.kotlin.sdk.types.ResourceUpdatedNotification
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.SubscribeRequest
@ -13,7 +12,6 @@ import kotlinx.coroutines.test.runTest
import org.awaitility.kotlin.await
import org.awaitility.kotlin.untilAsserted
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -52,8 +50,6 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
)
}
client.subscribeResource(SubscribeRequest(SubscribeRequestParams(uri = testResourceUri1)))
server.addResource(
uri = testResourceUri2,
name = "Test Resource 2",
@ -71,6 +67,8 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
)
}
client.subscribeResource(SubscribeRequest(SubscribeRequestParams(uri = testResourceUri1)))
// Remove the resource
val result = server.removeResource(testResourceUri1)
@ -79,9 +77,11 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
// Verify that the notification was sent
await untilAsserted {
assertEquals(1, notifications.size, "Notification should be sent when resource 1 was deleted")
assertTrue(
notifications.any { it.params.uri == testResourceUri1 },
"Notification should be sent when resource 1 was deleted",
)
}
assertEquals(testResourceUri1, notifications[0].params.uri, "Notification should contain the resource 1 URI")
}
@Test
@ -144,9 +144,8 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
println(notifications.map { it.params.uri })
// Verify that the notification was sent
await untilAsserted {
assertEquals(
2,
notifications.size,
assertTrue(
notifications.any { it.params.uri == testResourceUri1 },
"Notification should be sent when resource 1 and resource 2 was deleted",
)
}
@ -165,11 +164,9 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
@Test
fun `notification should not be send when removed resource does not exists`() = runTest {
// Track notifications
var resourceListChangedNotificationReceived = false
client.setNotificationHandler<ResourceListChangedNotification>(
Method.Defined.NotificationsResourcesListChanged,
) {
resourceListChangedNotificationReceived = true
val notifications = mutableListOf<ResourceUpdatedNotification>()
client.setNotificationHandler<ResourceUpdatedNotification>(Method.Defined.NotificationsResourcesUpdated) {
notifications.add(it)
CompletableDeferred(Unit)
}
@ -178,8 +175,8 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
// Verify the result
assertFalse(result, "Removing non-existent resource should return false")
assertFalse(
resourceListChangedNotificationReceived,
assertTrue(
notifications.isEmpty(),
"No notification should be sent when resource doesn't exist",
)
}

View file

@ -23,11 +23,11 @@ class ServerResourcesNotificationTest : AbstractServerFeaturesTest() {
@Test
fun `addResource should send notification`() = runTest {
// Configure notification handler
var resourceListChangedNotificationReceived = false
val notifications = mutableListOf<ResourceListChangedNotification>()
client.setNotificationHandler<ResourceListChangedNotification>(
Method.Defined.NotificationsResourcesListChanged,
) {
resourceListChangedNotificationReceived = true
notifications.add(it)
CompletableDeferred(Unit)
}
@ -58,18 +58,18 @@ class ServerResourcesNotificationTest : AbstractServerFeaturesTest() {
// Verify that the notification was sent
await untilAsserted {
assertTrue(resourceListChangedNotificationReceived, "Notification should be sent when resource is added")
assertTrue(notifications.isNotEmpty(), "Notification should be sent when resource is added")
}
}
@Test
fun `removeResources should remove multiple resources and send two notifications`() = runTest {
// Configure notification handler
var resourceListChangedNotificationReceivedCount = 0
val notifications = mutableListOf<ResourceListChangedNotification>()
client.setNotificationHandler<ResourceListChangedNotification>(
Method.Defined.NotificationsResourcesListChanged,
) {
resourceListChangedNotificationReceivedCount += 1
notifications.add(it)
CompletableDeferred(Unit)
}
@ -120,7 +120,7 @@ class ServerResourcesNotificationTest : AbstractServerFeaturesTest() {
await untilAsserted {
assertEquals(
4,
resourceListChangedNotificationReceivedCount,
notifications.size,
"Two notifications should be sent when resources are added and two when removed",
)
}
@ -129,11 +129,11 @@ class ServerResourcesNotificationTest : AbstractServerFeaturesTest() {
@Test
fun `notification should not be send when removed resource does not exists`() = runTest {
// Track notifications
var resourceListChangedNotificationReceived = false
val notifications = mutableListOf<ResourceListChangedNotification>()
client.setNotificationHandler<ResourceListChangedNotification>(
Method.Defined.NotificationsResourcesListChanged,
) {
resourceListChangedNotificationReceived = true
notifications.add(it)
CompletableDeferred(Unit)
}
@ -142,8 +142,8 @@ class ServerResourcesNotificationTest : AbstractServerFeaturesTest() {
// Verify the result
assertFalse(result, "Removing non-existent resource should return false")
assertFalse(
resourceListChangedNotificationReceived,
assertTrue(
notifications.isEmpty(),
"No notification should be sent when resource doesn't exist",
)
}

View file

@ -24,9 +24,9 @@ class ServerToolsNotificationTest : AbstractServerFeaturesTest() {
@Test
fun `addTool should send notification`() = runTest {
// Configure notification handler
var toolListChangedNotificationReceived = false
val notifications = mutableListOf<ToolListChangedNotification>()
client.setNotificationHandler<ToolListChangedNotification>(Method.Defined.NotificationsToolsListChanged) {
toolListChangedNotificationReceived = true
notifications.add(it)
CompletableDeferred(Unit)
}
@ -43,16 +43,16 @@ class ServerToolsNotificationTest : AbstractServerFeaturesTest() {
// Verify that the notification was sent
await untilAsserted {
assertTrue(toolListChangedNotificationReceived, "Notification should be sent when tool is added")
assertTrue(notifications.isNotEmpty(), "Notification should be sent when tool is added")
}
}
@Test
fun `removeTools should remove multiple tools and send two notifications`() = runTest {
// Configure notification handler
var toolListChangedNotificationReceivedCount = 0
val notifications = mutableListOf<ToolListChangedNotification>()
client.setNotificationHandler<ToolListChangedNotification>(Method.Defined.NotificationsToolsListChanged) {
toolListChangedNotificationReceivedCount += 1
notifications.add(it)
CompletableDeferred(Unit)
}
@ -73,7 +73,7 @@ class ServerToolsNotificationTest : AbstractServerFeaturesTest() {
await untilAsserted {
assertEquals(
4,
toolListChangedNotificationReceivedCount,
notifications.size,
"Two notifications should be sent when tools are added and two when removed",
)
}
@ -82,9 +82,9 @@ class ServerToolsNotificationTest : AbstractServerFeaturesTest() {
@Test
fun `notification should not be send when removed tool does not exists`() = runTest {
// Track notifications
var toolListChangedNotificationReceived = false
val notifications = mutableListOf<ToolListChangedNotification>()
client.setNotificationHandler<ToolListChangedNotification>(Method.Defined.NotificationsToolsListChanged) {
toolListChangedNotificationReceived = true
notifications.add(it)
CompletableDeferred(Unit)
}
@ -95,6 +95,6 @@ class ServerToolsNotificationTest : AbstractServerFeaturesTest() {
// Verify the result
assertFalse(result, "Removing non-existent tool should return false")
assertFalse(toolListChangedNotificationReceived, "No notification should be sent when tool doesn't exist")
assertTrue(notifications.isEmpty(), "No notification should be sent when tool doesn't exist")
}
}