/ tests / test_writebatch.nim
test_writebatch.nim
  1  # Nim-RocksDB
  2  # Copyright 2024 Status Research & Development GmbH
  3  # Licensed under either of
  4  #
  5  #  * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
  6  #  * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
  7  #
  8  # at your option. This file may not be copied, modified, or distributed except according to those terms.
  9  
 10  {.used.}
 11  
 12  import std/os, tempfile, unittest2, ../rocksdb/[rocksdb, writebatch], ./test_helper
 13  
 14  suite "WriteBatchRef Tests":
 15    const
 16      CF_DEFAULT = "default"
 17      CF_OTHER = "other"
 18  
 19    let
 20      key1 = @[byte(1)]
 21      val1 = @[byte(1)]
 22      key2 = @[byte(2)]
 23      val2 = @[byte(2)]
 24      key3 = @[byte(3)]
 25      val3 = @[byte(3)]
 26  
 27    setup:
 28      let
 29        dbPath = mkdtemp() / "data"
 30        db = initReadWriteDb(dbPath, columnFamilyNames = @[CF_DEFAULT, CF_OTHER])
 31        defaultCfHandle = db.getColFamilyHandle(CF_DEFAULT).get()
 32        otherCfHandle = db.getColFamilyHandle(CF_OTHER).get()
 33  
 34    teardown:
 35      db.close()
 36      removeDir($dbPath)
 37  
 38    test "Test writing batch to the default column family":
 39      let batch = db.openWriteBatch()
 40      defer:
 41        batch.close()
 42      check not batch.isClosed()
 43  
 44      check:
 45        batch.put(key1, val1).isOk()
 46        batch.put(key2, val2).isOk()
 47        batch.put(key3, val3).isOk()
 48        batch.count() == 3
 49  
 50        batch.delete(key2).isOk()
 51        batch.count() == 4
 52        not batch.isClosed()
 53  
 54      let res = db.write(batch)
 55      check:
 56        res.isOk()
 57        db.write(batch).isOk() # test that it's idempotent
 58        db.get(key1).get() == val1
 59        db.keyExists(key2).get() == false
 60        db.get(key3).get() == val3
 61  
 62      batch.clear()
 63      check:
 64        batch.count() == 0
 65        not batch.isClosed()
 66  
 67    test "Test writing batch to column family":
 68      let batch = db.openWriteBatch()
 69      defer:
 70        batch.close()
 71      check not batch.isClosed()
 72  
 73      check:
 74        batch.put(key1, val1, otherCfHandle).isOk()
 75        batch.put(key2, val2, otherCfHandle).isOk()
 76        batch.put(key3, val3, otherCfHandle).isOk()
 77        batch.count() == 3
 78  
 79        batch.delete(key2, otherCfHandle).isOk()
 80        batch.count() == 4
 81        not batch.isClosed()
 82  
 83      let res = db.write(batch)
 84      check:
 85        res.isOk()
 86        db.get(key1, otherCfHandle).get() == val1
 87        db.keyExists(key2, otherCfHandle).get() == false
 88        db.get(key3, otherCfHandle).get() == val3
 89  
 90      batch.clear()
 91      check:
 92        batch.count() == 0
 93        not batch.isClosed()
 94  
 95    test "Test writing to multiple column families in single batch":
 96      let batch = db.openWriteBatch()
 97      defer:
 98        batch.close()
 99      check not batch.isClosed()
100  
101      check:
102        batch.put(key1, val1, defaultCfHandle).isOk()
103        batch.put(key1, val1, otherCfHandle).isOk()
104        batch.put(key2, val2, otherCfHandle).isOk()
105        batch.put(key3, val3, otherCfHandle).isOk()
106        batch.count() == 4
107  
108        batch.delete(key2, otherCfHandle).isOk()
109        batch.count() == 5
110        not batch.isClosed()
111  
112      let res = db.write(batch)
113      check:
114        res.isOk()
115        db.get(key1, defaultCfHandle).get() == val1
116        db.get(key1, otherCfHandle).get() == val1
117        db.keyExists(key2, otherCfHandle).get() == false
118        db.get(key3, otherCfHandle).get() == val3
119  
120      batch.clear()
121      check:
122        batch.count() == 0
123        not batch.isClosed()
124  
125    test "Test writing to multiple column families in multiple batches":
126      let
127        batch1 = db.openWriteBatch()
128        batch2 = db.openWriteBatch()
129      defer:
130        batch1.close()
131        batch2.close()
132  
133      check:
134        not batch1.isClosed()
135        not batch2.isClosed()
136        batch1.put(key1, val1).isOk()
137        batch1.delete(key2, otherCfHandle).isOk()
138        batch1.put(key3, val3, otherCfHandle).isOk()
139        batch2.put(key1, val1, otherCfHandle).isOk()
140        batch2.delete(key1, otherCfHandle).isOk()
141        batch2.put(key3, val3).isOk()
142        batch1.count() == 3
143        batch2.count() == 3
144  
145      let res1 = db.write(batch1)
146      let res2 = db.write(batch2)
147      check:
148        res1.isOk()
149        res2.isOk()
150        db.get(key1).get() == val1
151        db.keyExists(key2).get() == false
152        db.get(key3).get() == val3
153        db.keyExists(key1, otherCfHandle).get() == false
154        db.keyExists(key2, otherCfHandle).get() == false
155        db.get(key3, otherCfHandle).get() == val3
156  
157        # Write batch is unchanged after write
158        batch1.count() == 3
159        batch2.count() == 3
160        not batch1.isClosed()
161        not batch2.isClosed()
162  
163    test "Put, get and delete empty key":
164      let batch = db.openWriteBatch()
165      defer:
166        batch.close()
167  
168      let empty: seq[byte] = @[]
169      check:
170        batch.put(empty, val1).isOk()
171        db.write(batch).isOk()
172        db.get(empty).get() == val1
173        batch.delete(empty).isOk()
174        db.write(batch).isOk()
175        db.get(empty).isErr()
176  
177    test "Test write empty batch":
178      let batch = db.openWriteBatch()
179      defer:
180        batch.close()
181      check not batch.isClosed()
182  
183      check batch.count() == 0
184      let res1 = db.write(batch)
185      check:
186        res1.isOk()
187        batch.count() == 0
188        not batch.isClosed()
189  
190    test "Test close":
191      let batch = db.openWriteBatch()
192  
193      check not batch.isClosed()
194      batch.close()
195      check batch.isClosed()
196      batch.close()
197      check batch.isClosed()
198  
199    test "Test deleteRange":
200      let batch = db.openWriteBatch()
201      defer:
202        batch.close()
203  
204      let
205        keyValue1 = @[1.byte]
206        keyValue2 = @[2.byte]
207        keyValue3 = @[3.byte]
208  
209      check:
210        batch.put(keyValue1, keyValue1).isOk()
211        batch.put(keyValue2, keyValue2).isOk()
212        batch.put(keyValue3, keyValue3).isOk()
213        batch.deleteRange(keyValue1, keyValue3).isOk()
214        batch.count() == 4
215  
216      let res1 = db.write(batch)
217      check:
218        res1.isOk()
219        db.keyExists(keyValue1).get() == false
220        db.keyExists(keyValue2).get() == false
221        db.keyExists(keyValue3).get() == true