Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -738,10 +738,18 @@ actual interface PubNub : StatusEmitter, EventEmitter {
* The count returned is the number of messages in history with a timetoken value greater
* than the passed value in the [MessageCounts.channelsTimetoken] parameter.
*
* **Important:** The timetoken represents an exclusive boundary. Messages with timetokens
* greater than (but not equal to) the specified timetoken are counted. To count messages
* from a specific message onwards, you typically need to subtract 1 from the message's
* timetoken.
*
* @param channels Channels to fetch the message count from.
* @param channelsTimetoken List of timetokens, in order of the channels list.
* Specify a single timetoken to apply it to all channels.
* Otherwise, the list of timetokens must be the same length as the list of channels.
* @param channelsTimetoken List of timetokens representing exclusive boundaries for message counting.
* Each timetoken corresponds to a channel in the same order.
* - **Single timetoken**: Applied to all channels (list with one element)
* - **Multiple timetokens**: Must match the number of channels exactly
* - **Exclusive boundary**: Only messages with timetokens > specified value are counted
* - **Common pattern**: Use `(messageTimetoken - 1)` to count from a specific message onwards
*/
actual fun messageCounts(
channels: List<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ enum class PubNubError(private val code: Int, val message: String) {

SECRET_KEY_MISSING(
114,
"ULS configuration failed. Secret Key not configured",
"Secret Key not configured",
),

JSON_ERROR(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,23 @@ class GroupManagementIntegrationTests : BaseIntegrationTest() {
channelGroup = expectedGroup,
channels = listOf(expectedChannel1, expectedChannel2, expectedChannel3),
).await { result ->
assertFalse(result.isFailure) // TODO is this part of the result? if not then there's nothing to assert on
// assertEquals(1, status.affectedChannelGroups.size)
// assertEquals(3, status.affectedChannels.size)
assertFalse(result.isFailure)
}
}

@Test
fun testDeleteChannelGroup() {
pubnub.addChannelsToChannelGroup(
channelGroup = expectedGroup,
channels = listOf(expectedChannel1, expectedChannel2, expectedChannel3),
).sync()

pubnub.deleteChannelGroup(channelGroup = expectedGroup).sync()

val listAllChannelGroupsResult = pubnub.listAllChannelGroups().sync()
assertFalse(listAllChannelGroupsResult.groups.contains(expectedGroup))
}

private fun addChannelsToGroup() {
pubnub.addChannelsToChannelGroup(
channelGroup = expectedGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,73 @@ import org.junit.jupiter.api.Test
import java.time.Duration

class HistoryIntegrationTest : BaseIntegrationTest() {
@Test
fun canGetMessageCounts() {
val channel01 = randomChannel()
val channel02 = randomChannel()
val firstPublishToChannel01Result = pubnub.publish(channel01, message = "FirstMessageChannel01").sync()
pubnub.publish(channel01, message = "SecondMessage").sync()
val firstPublishToChannel02Result = pubnub.publish(channel02, message = "FirstMessageChannel02").sync()

// Test with multiple timetokens (one per channel)
val messagesCounts = pubnub.messageCounts(
channels = listOf(channel01, channel02),
channelsTimetoken = listOf(
firstPublishToChannel01Result.timetoken - 1, // Count from first message onwards
firstPublishToChannel02Result.timetoken - 1 // Count from first message onwards
)
).sync()
assertEquals(2, messagesCounts.channels[channel01])
assertEquals(1, messagesCounts.channels[channel02])
}

@Test
fun canGetMessageCountsWithSingleTimetoken() {
val channel01 = randomChannel()
val channel02 = randomChannel()
val firstPublishToChannel01Result = pubnub.publish(channel01, message = "FirstMessageChannel01").sync()
pubnub.publish(channel01, message = "SecondMessage").sync()
val firstPublishToChannel02Result = pubnub.publish(channel02, message = "FirstMessageChannel02").sync()

// Test with single timetoken applied to all channels
val messagesCounts = pubnub.messageCounts(
channels = listOf(channel01, channel02),
channelsTimetoken = listOf(firstPublishToChannel01Result.timetoken - 1) // Single timetoken for all channels
).sync()
assertEquals(2, messagesCounts.channels[channel01])
assertEquals(1, messagesCounts.channels[channel02])
}

@Test
fun canGetMessageCountsWithMultipleTimetokens() {
val channel01 = randomChannel()
val channel02 = randomChannel()
val channel03 = randomChannel()

val firstPublishToChannel01Result = pubnub.publish(channel01, message = "FirstMessageChannel01").sync()
pubnub.publish(channel01, message = "SecondMessage").sync()
pubnub.publish(channel01, message = "ThirdMessage").sync()

val firstPublishToChannel02Result = pubnub.publish(channel02, message = "FirstMessageChannel02").sync()
pubnub.publish(channel02, message = "SecondMessage").sync()

val firstPublishToChannel03Result = pubnub.publish(channel03, message = "FirstMessageChannel03").sync()

// Test with multiple timetokens, each tailored to specific channels
val messagesCounts = pubnub.messageCounts(
channels = listOf(channel01, channel02, channel03),
channelsTimetoken = listOf(
firstPublishToChannel01Result.timetoken, // Should count 2 messages (second and third)
firstPublishToChannel02Result.timetoken - 1, // Should count 2 messages (all)
firstPublishToChannel03Result.timetoken - 1 // Should count 1 message (all)
)
).sync()

assertEquals(2, messagesCounts.channels[channel01])
assertEquals(2, messagesCounts.channels[channel02])
assertEquals(1, messagesCounts.channels[channel03])
}

@Test
fun historySingleScenario() {
val channel = randomChannel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.pubnub.api.callbacks.SubscribeCallback
import com.pubnub.api.crypto.CryptoModule
import com.pubnub.api.enums.PNStatusCategory
import com.pubnub.api.models.consumer.PNBoundedPage
import com.pubnub.api.models.consumer.PNPublishResult
import com.pubnub.api.models.consumer.PNStatus
import com.pubnub.api.models.consumer.pubsub.PNMessageResult
import com.pubnub.api.v2.PNConfigurationOverride
Expand Down Expand Up @@ -37,6 +38,7 @@ import org.json.JSONArray
import org.json.JSONObject
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
Expand All @@ -54,6 +56,15 @@ class PublishIntegrationTests : BaseIntegrationTest() {
guestClient = createPubNub {}
}

@Test
fun testFireMessage() {
val expectedChannel = randomChannel()
val fireResult: PNPublishResult =
pubnub.fire(channel = expectedChannel, message = generatePayload(), meta = null).sync()

assertNotNull(fireResult.timetoken)
}

@Test
fun testPublishMessage() {
val expectedChannel = randomChannel()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.pubnub.api.endpoints.access

import com.pubnub.api.PubNubException
import com.pubnub.api.UserId
import com.pubnub.internal.PubNubImpl
import com.pubnub.internal.endpoints.access.RevokeTokenEndpoint
import com.pubnub.internal.managers.RetrofitManager
import com.pubnub.internal.models.server.access_manager.v3.RevokeTokenData
import com.pubnub.internal.models.server.access_manager.v3.RevokeTokenResponse
import com.pubnub.internal.services.AccessManagerService
import com.pubnub.internal.v2.PNConfigurationImpl
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import retrofit2.Call
import retrofit2.Response

class RevokeTokenTest {
private lateinit var pubNub: PubNubImpl

@BeforeEach
internal fun setUp() {
MockKAnnotations.init(this)
val pnConfiguration =
PNConfigurationImpl(
userId = UserId("myUserId"),
subscribeKey = "something",
secretKey = "secretKey"
)
pubNub = spyk(PubNubImpl(configuration = pnConfiguration))
}

@MockK
private lateinit var revokeTokenEndpointMock: RevokeTokenEndpoint

@Test
fun shouldThrowExceptionWhenSecretKeyNotProvided() {
val pnConfiguration =
PNConfigurationImpl(
userId = UserId("myUserId"),
subscribeKey = "something",
)
pubNub = spyk(PubNubImpl(configuration = pnConfiguration))

val token = "test-token"
val exception = assertThrows<PubNubException> {
pubNub.revokeToken(token).sync()
}

assertEquals("Secret Key not configured", exception.errorMessage)
}

@Test
fun shouldThrowExceptionWhenTokenIsBlank() {
val blankToken = ""
val exception = assertThrows<PubNubException> {
pubNub.revokeToken(blankToken).sync()
}

assertEquals("Token missing", exception.errorMessage)
}

@Test
fun can_callRevokeToken() {
val expectedToken = "token_value"
val expectedSubscribeKey = "something"

val retrofitManager = mockk<RetrofitManager>(relaxed = true)
val accessManagerService = mockk<AccessManagerService>(relaxed = true)
val call = mockk<Call<RevokeTokenResponse>>()

every { pubNub.retrofitManager } returns retrofitManager
every { retrofitManager.accessManagerService } returns accessManagerService
every { accessManagerService.revokeToken(any(), any(), any()) } returns call
every { call.execute() } returns Response.success(
RevokeTokenResponse(
200,
RevokeTokenData("message", "token"),
"service"
)
)

// Act
pubNub.revokeToken(expectedToken).sync()

// Assert: verify the call with expected arguments
verify {
accessManagerService.revokeToken(
expectedSubscribeKey,
any(),
any()
)
}
}
}
Loading