Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add list caches API #35

Merged
merged 4 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -7,6 +7,7 @@ import org.junit.runner.RunWith
import software.momento.kotlin.sdk.exceptions.NotFoundException
import software.momento.kotlin.sdk.responses.cache.control.CacheCreateResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheDeleteResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheListResponse
import java.util.*
import kotlin.test.Test

Expand Down Expand Up @@ -44,4 +45,21 @@ class CacheClientControlTest: BaseAndroidTestClass() {
assert((deleteResponse as CacheDeleteResponse.Error).cause is NotFoundException)
}
}

@Test
fun listCacheHappyPath() = runTest {
pratik151192 marked this conversation as resolved.
Show resolved Hide resolved
val cacheName = "kotlin-android-create-delete-${UUID.randomUUID()}"
var createResponse = cacheClient.createCache(cacheName)
assert(createResponse is CacheCreateResponse.Success)

var listCachesResponse = cacheClient.listCaches()
assert(listCachesResponse is CacheListResponse.Success)

val caches = (listCachesResponse as CacheListResponse.Success).caches
val cacheNames = caches.map { it.name }
assert(cacheNames.contains(cacheName))

var deleteResponse = cacheClient.deleteCache(cacheName)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do this in a finally block? The cache won't be deleted if there is a transient error with list caches.

assert(deleteResponse is CacheDeleteResponse.Success)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package software.momento.kotlin.sdk.internal

import grpc.control_client._CreateCacheRequest
import grpc.control_client._DeleteCacheRequest
import grpc.control_client._ListCachesRequest
import io.grpc.Metadata
import software.momento.kotlin.sdk.auth.CredentialProvider
import software.momento.kotlin.sdk.config.Configuration
import software.momento.kotlin.sdk.exceptions.CacheServiceExceptionMapper
import software.momento.kotlin.sdk.exceptions.MomentoErrorCode
import software.momento.kotlin.sdk.responses.cache.control.CacheCreateResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheDeleteResponse
import software.momento.kotlin.sdk.internal.utils.ValidationUtils
import software.momento.kotlin.sdk.responses.cache.control.CacheInfo
import software.momento.kotlin.sdk.responses.cache.control.CacheListResponse

internal actual class InternalControlClient actual constructor(
credentialProvider: CredentialProvider,
Expand Down Expand Up @@ -72,6 +76,29 @@ internal actual class InternalControlClient actual constructor(
})
}

internal actual suspend fun listCaches(): CacheListResponse {
return runCatching {}.fold(onSuccess = {
sendListCaches()
}, onFailure = { e ->
CacheListResponse.Error(CacheServiceExceptionMapper.convert(e))
})
}

private suspend fun sendListCaches(): CacheListResponse {
val request = _ListCachesRequest.newBuilder().setNextToken("").build()
val metadata = Metadata()

return runCatching {
this.stubsManager.stub.listCaches(request, metadata)
}.fold(onSuccess = { listCacheResponse ->
CacheListResponse.Success(
listCacheResponse.cacheList.map { CacheInfo(it.cacheName) }
)
}, onFailure = { e ->
CacheListResponse.Error(CacheServiceExceptionMapper.convert(e, metadata))
})
}

override fun close() {
stubsManager.close()
}
Expand Down
10 changes: 10 additions & 0 deletions src/commonMain/kotlin/software/momento/kotlin/sdk/CacheClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import software.momento.kotlin.sdk.responses.cache.GetResponse
import software.momento.kotlin.sdk.responses.cache.SetResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheCreateResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheDeleteResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheListResponse
import kotlin.time.Duration

/**
Expand Down Expand Up @@ -51,6 +52,15 @@ public class CacheClient(
return controlClient.deleteCache(cacheName)
}

/**
* Asynchronously lists all the caches in the account.
*
* @return The result of the cache list: [CacheListResponse.Success] or [CacheListResponse.Error].
*/
public suspend fun listCaches(): CacheListResponse {
return controlClient.listCaches()
}

/**
* Asynchronously sets the value in cache with a given Time To Live (TTL) seconds.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import software.momento.kotlin.sdk.auth.CredentialProvider
import software.momento.kotlin.sdk.config.Configuration
import software.momento.kotlin.sdk.responses.cache.control.CacheCreateResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheDeleteResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheListResponse

internal expect class InternalControlClient(credentialProvider: CredentialProvider, configuration: Configuration) :
InternalClient {

internal suspend fun createCache(cacheName: String): CacheCreateResponse

internal suspend fun deleteCache(cacheName: String): CacheDeleteResponse

internal suspend fun listCaches(): CacheListResponse
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package software.momento.kotlin.sdk.responses.cache.control

/** Information about a cache.
* @param name the cache name
* */
public data class CacheInfo(public val name: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package software.momento.kotlin.sdk.responses.cache.control

import software.momento.kotlin.sdk.exceptions.SdkException

/** Response for a list caches operation. */
public sealed interface CacheListResponse {

/** A successful list caches operation. Contains the discovered caches. */
public data class Success(val caches: List<CacheInfo>) : CacheListResponse

/**
* A failed list caches operation. The response itself is an exception, so it can be directly
* thrown, or the cause of the error can be retrieved with [.getCause]. The message is a
* copy of the message of the cause.
*/
public class Error(cause: SdkException) : SdkException(cause), CacheListResponse

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package software.momento.kotlin.sdk.internal

import grpc.control_client._CreateCacheRequest
import grpc.control_client._DeleteCacheRequest
import grpc.control_client._ListCachesRequest
import io.grpc.Metadata
import software.momento.kotlin.sdk.auth.CredentialProvider
import software.momento.kotlin.sdk.config.Configuration
import software.momento.kotlin.sdk.exceptions.CacheServiceExceptionMapper
import software.momento.kotlin.sdk.exceptions.MomentoErrorCode
import software.momento.kotlin.sdk.responses.cache.control.CacheCreateResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheDeleteResponse
import software.momento.kotlin.sdk.internal.utils.ValidationUtils
import software.momento.kotlin.sdk.responses.cache.control.CacheInfo
import software.momento.kotlin.sdk.responses.cache.control.CacheListResponse

internal actual class InternalControlClient actual constructor(
credentialProvider: CredentialProvider, configuration: Configuration
Expand Down Expand Up @@ -56,6 +60,29 @@ internal actual class InternalControlClient actual constructor(
})
}

internal actual suspend fun listCaches(): CacheListResponse {
return runCatching {}.fold(onSuccess = {
sendListCaches()
}, onFailure = { e ->
CacheListResponse.Error(CacheServiceExceptionMapper.convert(e))
})
}

private suspend fun sendListCaches(): CacheListResponse {
val request = _ListCachesRequest.newBuilder().setNextToken("").build()
val metadata = Metadata()

return runCatching {
this.stubsManager.stub.listCaches(request, metadata)
}.fold(onSuccess = { listCacheResponse ->
CacheListResponse.Success(
listCacheResponse.cacheList.map { CacheInfo(it.cacheName) }
)
}, onFailure = { e ->
CacheListResponse.Error(CacheServiceExceptionMapper.convert(e, metadata))
})
}

private suspend fun sendDeleteCache(
cacheName: String
): CacheDeleteResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import kotlinx.coroutines.test.runTest
import software.momento.kotlin.sdk.exceptions.NotFoundException
import software.momento.kotlin.sdk.responses.cache.control.CacheCreateResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheDeleteResponse
import software.momento.kotlin.sdk.responses.cache.control.CacheListResponse
import java.util.*
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class CacheClientControlTest: BaseJvmTestClass() {

Expand Down Expand Up @@ -39,4 +42,23 @@ class CacheClientControlTest: BaseJvmTestClass() {
assert((deleteResponse as CacheDeleteResponse.Error).cause is NotFoundException)
}
}

@Test
fun listCacheHappyPath() = runTest {
val cacheName = "kotlin-jvm-create-delete-${UUID.randomUUID()}"
pratik151192 marked this conversation as resolved.
Show resolved Hide resolved
var createResponse = cacheClient.createCache(cacheName)
assert(createResponse is CacheCreateResponse.Success)

var listCachesResponse = cacheClient.listCaches()
assert(listCachesResponse is CacheListResponse.Success)

val caches = (listCachesResponse as CacheListResponse.Success).caches
assertTrue(caches.size > 1, "There should be exactly 2 caches in the response")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the assertion is correct, but we don't know that there will be only two caches.


val cacheNames = caches.map { it.name }
assertTrue(cacheName in cacheNames, "$cacheName should be one of the cache names")

var deleteResponse = cacheClient.deleteCache(cacheName)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in a finally as well.

assert(deleteResponse is CacheDeleteResponse.Success)
}
}
Loading