ldb tests: add cmocka tests of kv operation interactions with transactions
authorGary Lockyer <gary@catalyst.net.nz>
Mon, 19 Mar 2018 23:15:12 +0000 (12:15 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 3 May 2018 06:17:45 +0000 (08:17 +0200)
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/ldb/tests/ldb_kv_ops_test.c

index 33575af60114047f2d7a03beb2d953e86bd5f3c8..30ce019fac8d5fe88f2143e64208f49f7b3f8e6a 100644 (file)
@@ -265,6 +265,63 @@ static void test_add_get(void **state)
        talloc_free(tmp_ctx);
 }
 
+/*
+ * Test that attempts to read data without a read transaction fail.
+ */
+static void test_read_outside_transaction(void **state)
+{
+       int ret;
+       struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct test_ctx);
+       struct ltdb_private *ltdb = get_ltdb(test_ctx->ldb);
+       uint8_t key_val[] = "TheKey";
+       struct ldb_val key = {
+               .data   = key_val,
+               .length = sizeof(key_val)
+       };
+
+       uint8_t value[] = "The record contents";
+       struct ldb_val data = {
+               .data    = value,
+               .length = sizeof(value)
+       };
+
+       struct ldb_val read;
+
+       int flags = 0;
+       TALLOC_CTX *tmp_ctx;
+
+       tmp_ctx = talloc_new(test_ctx);
+       assert_non_null(tmp_ctx);
+
+       /*
+        * Begin a transaction
+        */
+       ret = ltdb->kv_ops->begin_write(ltdb);
+       assert_int_equal(ret, 0);
+
+       /*
+        * Write the record
+        */
+       ret = ltdb->kv_ops->store(ltdb, key, data, flags);
+       assert_int_equal(ret, 0);
+
+       /*
+        * Commit the transaction
+        */
+       ret = ltdb->kv_ops->finish_write(ltdb);
+       assert_int_equal(ret, 0);
+
+       /*
+        * And now read it back
+        * Note there is no read transaction active
+        */
+       ret = ltdb->kv_ops->fetch_and_parse(ltdb, key, parse, &read);
+       assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
+
+       talloc_free(tmp_ctx);
+}
+
 /*
  * Test that data can be deleted from the kv store
  */
@@ -727,6 +784,125 @@ static void test_iterate(void **state)
        TALLOC_FREE(tmp_ctx);
 }
 
+struct update_context {
+       struct ldb_context* ldb;
+       int visits[NUM_RECS];
+};
+
+static int update_fn(struct ltdb_private *ltdb,
+                    struct ldb_val key,
+                    struct ldb_val data,
+                    void *ctx) {
+
+       struct ldb_val new_key;
+       struct ldb_module *module = NULL;
+       struct update_context *context =NULL;
+       int ret = LDB_SUCCESS;
+       TALLOC_CTX *tmp_ctx;
+
+       tmp_ctx = talloc_new(ltdb);
+       assert_non_null(tmp_ctx);
+
+       context = talloc_get_type_abort(ctx, struct update_context);
+
+       module = talloc_zero(tmp_ctx, struct ldb_module);
+       module->ldb = context->ldb;
+
+       if (strncmp("key ", (char *) key.data, 4) == 0) {
+               int i = strtol((char *) &key.data[4], NULL, 10);
+               context->visits[i]++;
+               new_key.data = talloc_memdup(tmp_ctx, key.data, key.length);
+               new_key.length  = key.length;
+               new_key.data[0] = 'K';
+
+               ret = ltdb->kv_ops->update_in_iterate(ltdb,
+                                                     key,
+                                                     new_key,
+                                                     data,
+                                                     &module);
+       }
+       TALLOC_FREE(tmp_ctx);
+       return ret;
+}
+
+/*
+ * Test that update_in_iterate behaves as expected.
+ */
+static void test_update_in_iterate(void **state)
+{
+       int ret;
+       struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct test_ctx);
+       struct ltdb_private *ltdb = get_ltdb(test_ctx->ldb);
+       int i;
+       struct update_context *context = NULL;
+
+
+       TALLOC_CTX *tmp_ctx;
+
+       tmp_ctx = talloc_new(test_ctx);
+       assert_non_null(tmp_ctx);
+
+       context = talloc_zero(tmp_ctx, struct update_context);
+       assert_non_null(context);
+       context->ldb = test_ctx->ldb;
+       /*
+        * Begin a transaction
+        */
+       ret = ltdb->kv_ops->begin_write(ltdb);
+       assert_int_equal(ret, 0);
+
+       /*
+        * Write the records
+        */
+       for (i = 0; i < NUM_RECS; i++) {
+               struct ldb_val key;
+               struct ldb_val rec;
+               int flags = 0;
+
+               key.data   = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", i);
+               key.length = strlen((char *)key.data) + 1;
+
+               rec.data   = (uint8_t *) talloc_asprintf(tmp_ctx,
+                                                        "data for record (%04d)",
+                                                        i);
+               rec.length = strlen((char *)rec.data) + 1;
+
+               ret = ltdb->kv_ops->store(ltdb, key, rec, flags);
+               assert_int_equal(ret, 0);
+
+               TALLOC_FREE(key.data);
+               TALLOC_FREE(rec.data);
+       }
+
+       /*
+        * Commit the transaction
+        */
+       ret = ltdb->kv_ops->finish_write(ltdb);
+       assert_int_equal(ret, 0);
+
+       /*
+        * Now iterate over the kv store and ensure that all the
+        * records are visited.
+        */
+
+       /*
+        * Needs to be done inside a transaction
+        */
+       ret = ltdb->kv_ops->begin_write(ltdb);
+       assert_int_equal(ret, 0);
+
+       ret = ltdb->kv_ops->iterate(ltdb, update_fn, context);
+       for (i = 0; i < NUM_RECS; i++) {
+               assert_int_equal(1, context->visits[i]);
+       }
+
+       ret = ltdb->kv_ops->finish_write(ltdb);
+       assert_int_equal(ret, 0);
+
+       TALLOC_FREE(tmp_ctx);
+}
+
 /*
  * Ensure that writes are not visible until the transaction has been
  * committed.
@@ -1366,6 +1542,10 @@ int main(int argc, const char **argv)
                        test_transaction_abort_delete,
                        setup,
                        teardown),
+               cmocka_unit_test_setup_teardown(
+                       test_read_outside_transaction,
+                       setup,
+                       teardown),
                cmocka_unit_test_setup_teardown(
                        test_write_outside_transaction,
                        setup,
@@ -1378,6 +1558,10 @@ int main(int argc, const char **argv)
                        test_iterate,
                        setup,
                        teardown),
+               cmocka_unit_test_setup_teardown(
+                       test_update_in_iterate,
+                       setup,
+                       teardown),
                cmocka_unit_test_setup_teardown(
                        test_write_transaction_isolation,
                        setup,