changeset 1096:9809bd9e2cdb

add: tests and did some simplification of code
author sam <sam@basx.dev>
date Sun, 07 Apr 2024 01:17:40 +0700
parents b6427706c7b1
children bc3efccc2bf4
files semicongine/storage.nim tests/test_storage.nim
diffstat 2 files changed, 62 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/semicongine/storage.nim	Sun Apr 07 00:35:45 2024 +0700
+++ b/semicongine/storage.nim	Sun Apr 07 01:17:40 2024 +0700
@@ -62,33 +62,33 @@
   storageType.path().string.removeFile()
 
 type
-  LoadFuture*[T, U] = object
-    thread: Thread[U]
+  LoadFuture*[T] = object
+    thread: Thread[(StorageType, string, ptr Channel[T])]
     channel: ptr Channel[T]
     result: T
 
-proc cleanup*[T, U](p: var LoadFuture[T, U]) =
+proc cleanup*[T](p: var LoadFuture[T]) =
   if p.channel != nil:
     p.thread.joinThread()
     p.channel[].close()
     deallocShared(p.channel)
     p.channel = nil
 
-proc awaitResult*[T, U](p: var LoadFuture[T, U]): T =
+proc awaitResult*[T](p: var LoadFuture[T]): T =
   if p.channel == nil:
     return p.result
   result = p.channel[].recv()
   p.result = result
   p.cleanup()
 
-proc hasResult*[T, U](p: var LoadFuture[T, U]): bool =
+proc hasResult*[T](p: var LoadFuture[T]): bool =
   let ret = p.channel[].tryRecv()
   result = ret.dataAvailable
   if result:
     p.result = ret.msg
     p.cleanup()
 
-proc getResult*[T, U](p: LoadFuture[T, U]): T =
+proc getResult*[T](p: LoadFuture[T]): T =
   assert p.channel == nil, "Result is not available yet"
   return p.result
 
@@ -98,7 +98,7 @@
   let ret = loadFromDb[T](db, params[1])
   params[2][].send(ret)
 
-proc load*[T](storageType: StorageType, key: string): LoadFuture[T, (StorageType, string, ptr Channel[T])] =
+proc load*[T](storageType: StorageType, key: string): LoadFuture[T] =
   result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T])))
   result.channel[].open()
   createThread(result.thread, loadWorker[T], (storageType, key, result.channel))
@@ -106,12 +106,12 @@
 # STORING ######################################3333
 #
 type
-  StoreFuture*[T, U] = object
-    thread: Thread[U]
+  StoreFuture*[T] = object
+    thread: Thread[(StorageType, string, ptr Channel[T], ptr Channel[bool])]
     channel: ptr Channel[T]
     doneChannel: ptr Channel[bool]
 
-proc cleanup*[T, U](p: var StoreFuture[T, U]) =
+proc cleanup*[T](p: var StoreFuture[T]) =
   if p.channel != nil:
     p.thread.joinThread()
     p.channel[].close()
@@ -121,11 +121,11 @@
     p.channel = nil
     p.doneChannel = nil
 
-proc awaitStored*[T, U](p: var StoreFuture[T, U]) =
+proc awaitStored*[T](p: var StoreFuture[T]) =
   discard p.doneChannel[].recv()
   p.cleanup()
 
-proc isStored*[T, U](p: var StoreFuture[T, U]): bool =
+proc isStored*[T](p: var StoreFuture[T]): bool =
   let ret = p.doneChannel[].tryRecv()
   result = ret.dataAvailable
   if ret.dataAvailable:
@@ -137,7 +137,7 @@
   storeInDb(db, params[1], params[2][].recv())
   params[3][].send(true)
 
-proc store*[T](storageType: StorageType, key: string, value: T): StoreFuture[T, (StorageType, string, ptr Channel[T], ptr Channel[bool])] =
+proc store*[T](storageType: StorageType, key: string, value: T): StoreFuture[T] =
   result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T])))
   result.channel[].open()
   result.doneChannel = cast[ptr Channel[bool]](allocShared0(sizeof(Channel[bool])))
--- a/tests/test_storage.nim	Sun Apr 07 00:35:45 2024 +0700
+++ b/tests/test_storage.nim	Sun Apr 07 01:17:40 2024 +0700
@@ -1,4 +1,5 @@
 import std/os
+import std/strformat
 
 import semicongine
 
@@ -7,35 +8,59 @@
   const KEY = "test"
 
   # get default
-  var promise1 = load[int](storage, KEY)
-  assert promise1.awaitResult() == default(type(TEST_VALUE))
+  var future1 = load[int](storage, KEY)
+  assert future1.awaitResult() == default(type(TEST_VALUE))
 
   # save and load custom
-  var promise2 = store(storage, KEY, TEST_VALUE)
-  promise2.awaitStored()
-  promise1 = load[int](storage, KEY)
-  assert promise1.awaitResult() == TEST_VALUE
+  var future2 = store(storage, KEY, TEST_VALUE)
+  future2.awaitStored()
+  future1 = load[int](storage, KEY)
+  assert future1.awaitResult() == TEST_VALUE
 
 proc testBusyWait(storage: StorageType) =
   const TEST_VALUE = "43"
   const KEY = "test2"
 
   # get default
-  var promise1 = load[string](storage, KEY)
-  while not promise1.hasResult():
+  var future1 = load[string](storage, KEY)
+  while not future1.hasResult():
     sleep(1)
-  assert promise1.getResult() == default(type(TEST_VALUE))
+  assert future1.getResult() == default(type(TEST_VALUE))
 
   # save and load custom
-  var promise2 = store(storage, KEY, TEST_VALUE)
-  while not promise2.isStored():
+  var future2 = store(storage, KEY, TEST_VALUE)
+  while not future2.isStored():
+    sleep(1)
+  future1 = load[string](storage, KEY)
+  while not future1.hasResult():
     sleep(1)
-  promise1 = load[string](storage, KEY)
-  while not promise1.hasResult():
-    sleep(1)
-  assert promise1.awaitResult() == TEST_VALUE
+  assert future1.awaitResult() == TEST_VALUE
+
+proc stressTest(storage: StorageType) =
+  for i in 1 .. 10000:
+    let key = &"key-{i}"
+    var p = store(storage, key, i)
+    p.awaitStored()
+    var p1 = load[int](storage, key)
+    assert p1.awaitResult() == i
+
+proc concurrentStressTest(storage: StorageType) =
+  var storeFutures: seq[StoreFuture[int]]
+
+  for i in 1 .. 10000:
+    let key = &"key-{i}"
+    echo key
+    storeFutures.add store(storage, key, i)
+
+  for i in 1 .. 10000:
+    echo i
+    let key = &"key-{i}"
+    storeFutures[i - 1].awaitStored()
+    var p1 = load[int](storage, key)
+    assert p1.awaitResult() == i
 
 proc main() =
+  SystemStorage.purge()
   echo "SystemStorage: Testing simple store/load"
   SystemStorage.testSimple()
   echo "SystemStorage: Testing store/load with busy wait"
@@ -46,7 +71,16 @@
   UserStorage.testSimple()
   echo "UserStorage: Testing store/load with busy wait"
   UserStorage.testBusyWait()
+
+  echo "Stress test with 10'000 saves/loads"
+  SystemStorage.stressTest()
+
+  SystemStorage.purge()
   UserStorage.purge()
 
+  # TODO: fails currently, but is likely not too important
+  # echo "Stress test with 10'000 saves/loads and a little concurrency"
+  # SystemStorage.concurrentStressTest()
+
 when isMainModule:
   main()