1
1
package ai .chronon .integrations .aws
2
2
3
- import ai .chronon .online .KVStore .GetRequest
4
- import ai .chronon .online .KVStore .GetResponse
5
- import ai .chronon .online .KVStore .ListRequest
6
- import ai .chronon .online .KVStore .ListValue
7
- import ai .chronon .online .KVStore .PutRequest
3
+ import ai .chronon .online .KVStore ._
8
4
import com .amazonaws .services .dynamodbv2 .local .main .ServerRunner
9
5
import com .amazonaws .services .dynamodbv2 .local .server .DynamoDBProxyServer
10
6
import io .circe .generic .auto ._
7
+ import io .circe .generic .semiauto ._
11
8
import io .circe .parser ._
12
9
import io .circe .syntax ._
13
- import org .scalatest .BeforeAndAfter
10
+ import io .circe .{Decoder , Encoder }
11
+ import org .scalatest .BeforeAndAfterAll
14
12
import org .scalatest .flatspec .AnyFlatSpec
15
- import org .scalatest .matchers .must .Matchers .be
16
13
import org .scalatest .matchers .should .Matchers .convertToAnyShouldWrapper
17
- import software .amazon .awssdk .auth .credentials .AwsBasicCredentials
18
- import software .amazon .awssdk .auth .credentials .StaticCredentialsProvider
14
+ import software .amazon .awssdk .auth .credentials .{AwsBasicCredentials , StaticCredentialsProvider }
19
15
import software .amazon .awssdk .regions .Region
20
16
import software .amazon .awssdk .services .dynamodb .DynamoDbClient
21
17
22
18
import java .net .URI
23
19
import java .nio .charset .StandardCharsets
24
20
import scala .concurrent .Await
25
21
import scala .concurrent .duration .DurationInt
26
- import scala .util .Failure
27
- import scala .util .Success
28
- import scala .util .Try
22
+ import scala .util .{Failure , Success , Try }
29
23
30
- // different types of tables to store
31
- case class Model (modelId : String , modelName : String , online : Boolean )
32
- case class TimeSeries (joinName : String , featureName : String , tileTs : Long , metric : String , summary : Array [Double ])
24
+ object DDBTestUtils {
33
25
34
- class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfter {
26
+ // different types of tables to store
27
+ case class Model (modelId : String , modelName : String , online : Boolean )
28
+ case class TimeSeries (joinName : String , featureName : String , tileTs : Long , metric : String , summary : Array [Double ])
35
29
30
+ }
31
+ class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfterAll {
32
+
33
+ import DDBTestUtils ._
36
34
import DynamoDBKVStoreConstants ._
37
35
36
+ implicit val modelEncoder : Encoder [Model ] = deriveEncoder[Model ]
37
+ implicit val modelDecoder : Decoder [Model ] = deriveDecoder[Model ]
38
+ implicit val tsEncoder : Encoder [TimeSeries ] = deriveEncoder[TimeSeries ]
39
+ implicit val tsDecoder : Decoder [TimeSeries ] = deriveDecoder[TimeSeries ]
40
+
38
41
var server : DynamoDBProxyServer = _
39
42
var client : DynamoDbClient = _
40
43
var kvStoreImpl : DynamoDBKVStoreImpl = _
@@ -55,7 +58,7 @@ class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfter {
55
58
series.asJson.noSpaces.getBytes(StandardCharsets .UTF_8 )
56
59
}
57
60
58
- before {
61
+ override def beforeAll () : Unit = {
59
62
// Start the local DynamoDB instance
60
63
server = ServerRunner .createServerFromCommandLineArgs(Array (" -inMemory" , " -port" , " 8000" ))
61
64
server.start()
@@ -72,9 +75,9 @@ class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfter {
72
75
.build()
73
76
}
74
77
75
- after {
76
- client.close()
77
- server.stop()
78
+ override def afterAll () : Unit = {
79
+ // client.close()
80
+ // server.stop()
78
81
}
79
82
80
83
// Test creation of a table with primary keys only (e.g. model)
@@ -115,20 +118,20 @@ class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfter {
115
118
buildModelPutRequest(model, dataset)
116
119
}
117
120
118
- val putResults = Await .result(kvStore.multiPut(putReqs), 1 .second )
121
+ val putResults = Await .result(kvStore.multiPut(putReqs), 1 .minute )
119
122
putResults.length shouldBe putReqs.length
120
123
putResults.foreach(r => r shouldBe true )
121
124
122
125
// call list - first call is only for 10 elements
123
126
val listReq1 = ListRequest (dataset, Map (listLimit -> 10 ))
124
- val listResults1 = Await .result(kvStore.list(listReq1), 1 .second )
127
+ val listResults1 = Await .result(kvStore.list(listReq1), 1 .minute )
125
128
listResults1.resultProps.contains(continuationKey) shouldBe true
126
129
validateExpectedListResponse(listResults1.values, 10 )
127
130
128
131
// call list - with continuation key
129
132
val listReq2 =
130
133
ListRequest (dataset, Map (listLimit -> 100 , continuationKey -> listResults1.resultProps(continuationKey)))
131
- val listResults2 = Await .result(kvStore.list(listReq2), 1 .second )
134
+ val listResults2 = Await .result(kvStore.list(listReq2), 1 .minute )
132
135
listResults2.resultProps.contains(continuationKey) shouldBe false
133
136
validateExpectedListResponse(listResults2.values, 100 )
134
137
}
@@ -148,17 +151,17 @@ class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfter {
148
151
val putReq2 = buildModelPutRequest(model2, dataset)
149
152
val putReq3 = buildModelPutRequest(model3, dataset)
150
153
151
- val putResults = Await .result(kvStore.multiPut(Seq (putReq1, putReq2, putReq3)), 1 .second )
154
+ val putResults = Await .result(kvStore.multiPut(Seq (putReq1, putReq2, putReq3)), 1 .minute )
152
155
putResults shouldBe Seq (true , true , true )
153
156
154
157
// let's try and read these
155
158
val getReq1 = buildModelGetRequest(model1, dataset)
156
159
val getReq2 = buildModelGetRequest(model2, dataset)
157
160
val getReq3 = buildModelGetRequest(model3, dataset)
158
161
159
- val getResult1 = Await .result(kvStore.multiGet(Seq (getReq1)), 1 .second )
160
- val getResult2 = Await .result(kvStore.multiGet(Seq (getReq2)), 1 .second )
161
- val getResult3 = Await .result(kvStore.multiGet(Seq (getReq3)), 1 .second )
162
+ val getResult1 = Await .result(kvStore.multiGet(Seq (getReq1)), 1 .minute )
163
+ val getResult2 = Await .result(kvStore.multiGet(Seq (getReq2)), 1 .minute )
164
+ val getResult3 = Await .result(kvStore.multiGet(Seq (getReq3)), 1 .minute )
162
165
163
166
validateExpectedModelResponse(model1, getResult1)
164
167
validateExpectedModelResponse(model2, getResult2)
@@ -178,13 +181,13 @@ class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfter {
178
181
179
182
// write to the kv store and confirm the writes were successful
180
183
val putRequests = points.map(p => buildTSPutRequest(p, dataset))
181
- val putResult = Await .result(kvStore.multiPut(putRequests), 1 .second )
184
+ val putResult = Await .result(kvStore.multiPut(putRequests), 1 .minute )
182
185
putResult.length shouldBe tsRange.length
183
186
putResult.foreach(r => r shouldBe true )
184
187
185
188
// query in time range: 10/05/24 00:00 to 10/10
186
189
val getRequest1 = buildTSGetRequest(points.head, dataset, 1728086400000L , 1728518400000L )
187
- val getResult1 = Await .result(kvStore.multiGet(Seq (getRequest1)), 1 .second )
190
+ val getResult1 = Await .result(kvStore.multiGet(Seq (getRequest1)), 1 .minute )
188
191
validateExpectedTimeSeriesResponse(points.head, 1728086400000L , 1728518400000L , getResult1)
189
192
}
190
193
@@ -231,7 +234,7 @@ class DynamoDBKVStoreTest extends AnyFlatSpec with BeforeAndAfter {
231
234
private def validateExpectedListResponse (response : Try [Seq [ListValue ]], maxElements : Int ): Unit = {
232
235
response match {
233
236
case Success (mSeq) =>
234
- mSeq.length should be <= maxElements
237
+ mSeq.length <= maxElements shouldBe true
235
238
mSeq.foreach { modelKV =>
236
239
val jsonStr = new String (modelKV.valueBytes, StandardCharsets .UTF_8 )
237
240
val returnedModel = decode[Model ](jsonStr)
0 commit comments