1module Test.Scylladb.Main where
5import Data.Array as Array
6import Data.Either (Either(..))
7import Data.Maybe (Maybe(..))
9import Effect.Aff (Aff, bracket, delay, launchAff_, throwError, try)
10import Effect.Class (liftEffect)
11import Effect.Console (log)
12import Effect.Exception (error)
13import Data.Time.Duration (Milliseconds(..))
14import Test.Spec (Spec, around, describe, it)
15import Test.Spec.Assertions (shouldEqual, shouldSatisfy)
16import Test.Spec.Reporter.Console (consoleReporter)
17import Test.Spec.Runner (runSpec)
18import Yoga.Test.Docker as Docker
19import Yoga.ScyllaDB.ScyllaDB as Scylla
20import Yoga.ScyllaDB.Schema.Test as SchemaTest
23testContactPoint :: Scylla.ContactPoint
24testContactPoint = Scylla.ContactPoint "127.0.0.1"
26testDatacenter :: Scylla.Datacenter
27testDatacenter = Scylla.Datacenter "datacenter1"
29testKeyspace :: Scylla.Keyspace
30testKeyspace = Scylla.Keyspace "test_ks"
33testPort = 9043 -- Test port from docker-compose.test.yml
35-- Helper to create and manage ScyllaDB connection
36withScylla :: (Scylla.Client -> Aff Unit) -> Aff Unit
38 client <- liftEffect $ Scylla.createClient
39 { contactPoints: [ testContactPoint ]
40 , localDataCenter: testDatacenter
41 , protocolOptions: { port: testPort, maxSchemaAgreementWaitSeconds: 10 }
43 _ <- Scylla.connect client
45 -- Wait for cluster to be ready
46 delay (Milliseconds 1000.0)
48 -- Clean up test keyspace before each test
49 _ <- try $ Scylla.dropKeyspace testKeyspace client
53 _ <- Scylla.shutdown client
56-- Helper to check if value is Left
57isLeft :: forall a b. Either a b -> Boolean
61-- Helper to set up test keyspace
62setupKeyspace :: Scylla.Client -> Aff Unit
63setupKeyspace client = do
64 _ <- Scylla.createKeyspace testKeyspace (Scylla.ReplicationFactor 1) client
65 _ <- Scylla.useKeyspace testKeyspace client
68-- Helper to set up users table
69setupUsersTable :: Scylla.Client -> Aff Unit
70setupUsersTable client = do
74 CREATE TABLE test_ks.users (
89 describe "Yoga.ScyllaDB Integration Tests" do
91 -- Connection Management Tests
93 describe "Connection Management" do
94 it "connects to ScyllaDB successfully" \client -> do
95 healthy <- Scylla.ping client
96 healthy `shouldEqual` true
98 it "retrieves cluster hosts" \client -> do
99 hosts <- liftEffect $ Scylla.getHosts client
100 (Array.length hosts) `shouldSatisfy` (\l -> l > 0)
102 describe "Connection Errors" do
103 it "handles connection failures" do
105 client <- liftEffect $ Scylla.createClient
106 { contactPoints: [ Scylla.ContactPoint "invalid-host-9999" ]
107 , localDataCenter: testDatacenter
108 , protocolOptions: { port: 9999, maxSchemaAgreementWaitSeconds: 10 }
110 Scylla.connect client
111 result `shouldSatisfy` isLeft
113 -- Keyspace Operations Tests
115 describe "Keyspace Operations" do
116 it "creates and drops keyspaces" \client -> do
117 _ <- Scylla.createKeyspace testKeyspace (Scylla.ReplicationFactor 1) client
118 _ <- Scylla.dropKeyspace testKeyspace client
121 it "uses keyspace" \client -> do
123 result <- Scylla.useKeyspace testKeyspace client
124 result.rowLength `shouldEqual` 0
126 it "retrieves keyspace metadata" \client -> do
128 meta <- liftEffect $ Scylla.getKeyspace testKeyspace client
131 Nothing -> throwError (error "Expected to find keyspace metadata")
133 -- Table Operations Tests
135 describe "Table Operations" do
136 it "creates tables with various column types" \client -> do
138 result <- Scylla.execute
141 CREATE TABLE test_ks.users (
153 result.rowLength `shouldEqual` 0
155 it "inserts and queries data" \client -> do
157 setupUsersTable client
159 userId <- liftEffect Scylla.uuid
160 _ <- Scylla.execute (Scylla.CQL "INSERT INTO test_ks.users (id, name, age) VALUES (?, ?, ?)")
161 [ Scylla.toCQLValue userId, Scylla.toCQLValue "Alice", Scylla.toCQLValue 30 ]
164 result <- Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.users WHERE id = ?")
165 [ Scylla.toCQLValue userId ]
167 result.rowLength `shouldEqual` 1
169 it "updates data" \client -> do
171 setupUsersTable client
173 userId <- liftEffect Scylla.uuid
174 _ <- Scylla.execute (Scylla.CQL "INSERT INTO test_ks.users (id, name, email) VALUES (?, ?, ?)")
175 [ Scylla.toCQLValue userId, Scylla.toCQLValue "Bob", Scylla.toCQLValue "bob@example.com" ]
178 _ <- Scylla.execute (Scylla.CQL "UPDATE test_ks.users SET email = ? WHERE id = ?")
179 [ Scylla.toCQLValue "bob.new@example.com", Scylla.toCQLValue userId ]
182 result <- Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.users WHERE id = ?")
183 [ Scylla.toCQLValue userId ]
185 result.rowLength `shouldEqual` 1
187 it "deletes data" \client -> do
189 setupUsersTable client
191 userId <- liftEffect Scylla.uuid
192 _ <- Scylla.execute (Scylla.CQL "INSERT INTO test_ks.users (id, name) VALUES (?, ?)")
193 [ Scylla.toCQLValue userId, Scylla.toCQLValue "Charlie" ]
196 _ <- Scylla.execute (Scylla.CQL "DELETE FROM test_ks.users WHERE id = ?")
197 [ Scylla.toCQLValue userId ]
200 result <- Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.users WHERE id = ?")
201 [ Scylla.toCQLValue userId ]
203 result.rowLength `shouldEqual` 0
205 -- Consistency Level Tests
207 describe "Consistency Levels" do
208 it "executes with ONE consistency level" \client -> do
210 result <- Scylla.executeWithOptions
211 (Scylla.CQL "SELECT * FROM system.local")
213 { consistency: Scylla.One }
215 result.rowLength `shouldSatisfy` (\l -> l > 0)
217 it "executes with QUORUM consistency level" \client -> do
219 result <- Scylla.executeWithOptions
220 (Scylla.CQL "SELECT * FROM system.local")
222 { consistency: Scylla.Quorum }
224 result.rowLength `shouldSatisfy` (\l -> l > 0)
226 it "executes with LOCAL_ONE consistency level" \client -> do
228 result <- Scylla.executeWithOptions
229 (Scylla.CQL "SELECT * FROM system.local")
231 { consistency: Scylla.LocalOne }
233 result.rowLength `shouldSatisfy` (\l -> l > 0)
235 -- Prepared Statement Tests
237 describe "Prepared Statements" do
238 it "prepares and executes statements" \client -> do
240 setupUsersTable client
242 prepared <- Scylla.prepare
243 (Scylla.CQL "INSERT INTO test_ks.users (id, name) VALUES (?, ?)")
246 userId <- liftEffect Scylla.uuid
247 result <- Scylla.executePrepared prepared
248 [ Scylla.toCQLValue userId, Scylla.toCQLValue "Diana" ]
250 result.rowLength `shouldEqual` 0
252 it "reuses prepared statements for multiple inserts" \client -> do
254 setupUsersTable client
256 prepared <- Scylla.prepare
257 (Scylla.CQL "INSERT INTO test_ks.users (id, name) VALUES (?, ?)")
260 userId1 <- liftEffect Scylla.uuid
261 userId2 <- liftEffect Scylla.uuid
262 userId3 <- liftEffect Scylla.uuid
264 _ <- Scylla.executePrepared prepared [ Scylla.toCQLValue userId1, Scylla.toCQLValue "Eve" ] client
265 _ <- Scylla.executePrepared prepared [ Scylla.toCQLValue userId2, Scylla.toCQLValue "Frank" ] client
266 _ <- Scylla.executePrepared prepared [ Scylla.toCQLValue userId3, Scylla.toCQLValue "Grace" ] client
268 result <- Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.users") [] client
269 result.rowLength `shouldEqual` 3
271 -- Batch Operations Tests
273 describe "Batch Operations" do
274 it "executes batch inserts" \client -> do
276 setupUsersTable client
278 userId1 <- liftEffect Scylla.uuid
279 userId2 <- liftEffect Scylla.uuid
283 [ { query: Scylla.CQL "INSERT INTO test_ks.users (id, name) VALUES (?, ?)"
284 , params: [ Scylla.toCQLValue userId1, Scylla.toCQLValue "Henry" ]
286 , { query: Scylla.CQL "INSERT INTO test_ks.users (id, name) VALUES (?, ?)"
287 , params: [ Scylla.toCQLValue userId2, Scylla.toCQLValue "Iris" ]
291 _ <- Scylla.batch batchQueries client
293 result <- Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.users") [] client
294 result.rowLength `shouldEqual` 2
296 it "executes batch with consistency options" \client -> do
298 setupUsersTable client
300 userId <- liftEffect Scylla.uuid
304 [ { query: Scylla.CQL "INSERT INTO test_ks.users (id, name) VALUES (?, ?)"
305 , params: [ Scylla.toCQLValue userId, Scylla.toCQLValue "Jack" ]
309 result <- Scylla.batchWithOptions batchQueries
310 { consistency: Scylla.One, logged: true }
312 result.rowLength `shouldEqual` 0
316 describe "UUID Operations" do
317 it "generates UUIDs" \_ -> do
318 _ <- liftEffect Scylla.uuid
319 _ <- liftEffect Scylla.uuid
320 pure unit -- Just check it doesn't error
322 it "generates time-based UUIDs" \_ -> do
323 _ <- liftEffect Scylla.timeUuid
324 _ <- liftEffect Scylla.timeUuid
325 pure unit -- Just check it doesn't error
327 it "parses UUIDs from strings" \_ -> do
328 -- Valid UUID v4 format
329 maybeUuid <- liftEffect $ Scylla.uuidFromString "550e8400-e29b-41d4-a716-446655440000"
332 Nothing -> throwError (error "Expected to parse valid UUID")
334 it "returns Nothing for invalid UUID strings" \_ -> do
335 maybeUuid <- liftEffect $ Scylla.uuidFromString "not-a-valid-uuid"
338 Just _ -> throwError (error "Expected Nothing for invalid UUID")
342 describe "Data Types" do
343 it "handles various CQL data types" \client -> do
345 setupUsersTable client
347 userId <- liftEffect Scylla.uuid
348 _ <- Scylla.execute (Scylla.CQL "INSERT INTO test_ks.users (id, name, age, active) VALUES (?, ?, ?, ?)")
349 [ Scylla.toCQLValue userId, Scylla.toCQLValue "Kate", Scylla.toCQLValue 25, Scylla.toCQLValue true ]
352 result <- Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.users WHERE id = ?")
353 [ Scylla.toCQLValue userId ]
355 result.rowLength `shouldEqual` 1
357 it "handles null values" \client -> do
359 setupUsersTable client
361 userId <- liftEffect Scylla.uuid
362 _ <- Scylla.execute (Scylla.CQL "INSERT INTO test_ks.users (id, name) VALUES (?, ?)")
363 [ Scylla.toCQLValue userId, Scylla.toCQLValue "Leo" ]
366 result <- Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.users WHERE id = ?")
367 [ Scylla.toCQLValue userId ]
369 result.rowLength `shouldEqual` 1
371 -- Error Handling Tests
373 describe "Error Handling" do
374 it "handles invalid CQL syntax" \client -> do
375 result <- try $ Scylla.execute (Scylla.CQL "INVALID CQL SYNTAX") [] client
378 Right _ -> throwError (error "Expected error for invalid CQL syntax")
380 it "handles missing table errors" \client -> do
382 result <- try $ Scylla.execute (Scylla.CQL "SELECT * FROM test_ks.non_existent_table") [] client
385 Right _ -> throwError (error "Expected error for missing table")
387 it "handles missing keyspace errors" \client -> do
388 result <- try $ Scylla.execute (Scylla.CQL "SELECT * FROM nonexistent_ks.users") [] client
391 Right _ -> throwError (error "Expected error for missing keyspace")
395 -- Schema tests are pure (no Docker needed)
396 runSpec [ consoleReporter ] SchemaTest.spec
398 liftEffect $ log "\n🧪 Starting ScyllaDB Integration Tests (with Docker)\n"
402 liftEffect $ log "⏳ Starting ScyllaDB and waiting for it to be ready (may take 30-60s)..."
403 Docker.startService (Docker.ComposeFile "packages/yoga-scylladb/docker-compose.test.yml") (Docker.Timeout (Milliseconds 60000.0))
404 liftEffect $ log "✅ ScyllaDB is ready!\n"
407 Docker.stopService (Docker.ComposeFile "packages/yoga-scylladb/docker-compose.test.yml")
408 liftEffect $ log "✅ Cleanup complete\n"
410 (\_ -> runSpec [ consoleReporter ] spec)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list