1 /**
2  * @file unit-capi-metadata.cc
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  * @section DESCRIPTION
29  *
30  * Tests the C API for array metadata.
31  */
32 
33 #include "test/src/helpers.h"
34 #include "test/src/vfs_helpers.h"
35 #include "tiledb/sm/c_api/tiledb.h"
36 #include "tiledb/sm/c_api/tiledb_struct_def.h"
37 #include "tiledb/sm/enums/encryption_type.h"
38 #include "tiledb/sm/global_state/unit_test_config.h"
39 
40 #ifdef _WIN32
41 #include "tiledb/sm/filesystem/win.h"
42 #else
43 #include "tiledb/sm/filesystem/posix.h"
44 #endif
45 
46 #include <catch.hpp>
47 #include <chrono>
48 #include <iostream>
49 #include <thread>
50 
51 using namespace tiledb::sm;
52 using namespace tiledb::test;
53 
54 /* ********************************* */
55 /*         STRUCT DEFINITION         */
56 /* ********************************* */
57 
58 struct CMetadataFx {
59   tiledb_ctx_t* ctx_;
60   tiledb_vfs_t* vfs_;
61   const std::vector<std::unique_ptr<SupportedFs>> fs_vec_;
62   std::string temp_dir_;
63   std::string array_name_;
64   const char* ARRAY_NAME = "test_metadata";
65   tiledb_array_t* array_ = nullptr;
66   const char* key_ = "0123456789abcdeF0123456789abcdeF";
67   const uint32_t key_len_ =
68       (uint32_t)strlen("0123456789abcdeF0123456789abcdeF");
69   const tiledb_encryption_type_t enc_type_ = TILEDB_AES_256_GCM;
70 
71   void create_default_array_1d();
72   void create_default_array_1d_with_key();
73 
74   // Used to get the number of directories or files of another directory
75   struct get_num_struct {
76     int num;
77   };
78 
79   static int get_meta_num(const char* path, void* data);
80 
81   CMetadataFx();
82   ~CMetadataFx();
83 };
84 
CMetadataFx()85 CMetadataFx::CMetadataFx()
86     : fs_vec_(vfs_test_get_fs_vec()) {
87   // Initialize vfs test
88   REQUIRE(vfs_test_init(fs_vec_, &ctx_, &vfs_).ok());
89 
90 // Create temporary directory based on the supported filesystem
91 #ifdef _WIN32
92   SupportedFsLocal windows_fs;
93   temp_dir_ = windows_fs.file_prefix() + windows_fs.temp_dir();
94 #else
95   SupportedFsLocal posix_fs;
96   temp_dir_ = posix_fs.file_prefix() + posix_fs.temp_dir();
97 #endif
98 
99   create_dir(temp_dir_, ctx_, vfs_);
100 
101   array_name_ = temp_dir_ + ARRAY_NAME;
102   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array_);
103   CHECK(rc == TILEDB_OK);
104 }
105 
~CMetadataFx()106 CMetadataFx::~CMetadataFx() {
107   tiledb_array_free(&array_);
108   remove_dir(temp_dir_, ctx_, vfs_);
109   tiledb_ctx_free(&ctx_);
110   tiledb_vfs_free(&vfs_);
111 }
112 
get_meta_num(const char * path,void * data)113 int CMetadataFx::get_meta_num(const char* path, void* data) {
114   (void)path;
115   auto data_struct = (CMetadataFx::get_num_struct*)data;
116   ++data_struct->num;
117 
118   return 1;
119 }
120 
create_default_array_1d()121 void CMetadataFx::create_default_array_1d() {
122   uint64_t domain[] = {1, 10};
123   uint64_t tile_extent = 5;
124   create_array(
125       ctx_,
126       array_name_,
127       TILEDB_DENSE,
128       {"d"},
129       {TILEDB_UINT64},
130       {domain},
131       {&tile_extent},
132       {"a", "b", "c"},
133       {TILEDB_INT32, TILEDB_CHAR, TILEDB_FLOAT32},
134       {1, TILEDB_VAR_NUM, 2},
135       {tiledb::test::Compressor(TILEDB_FILTER_NONE, -1),
136        tiledb::test::Compressor(TILEDB_FILTER_ZSTD, -1),
137        tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1)},
138       TILEDB_ROW_MAJOR,
139       TILEDB_ROW_MAJOR,
140       2);
141 }
142 
create_default_array_1d_with_key()143 void CMetadataFx::create_default_array_1d_with_key() {
144   uint64_t domain[] = {1, 10};
145   uint64_t tile_extent = 5;
146   create_array(
147       ctx_,
148       array_name_,
149       enc_type_,
150       key_,
151       key_len_,
152       TILEDB_DENSE,
153       {"d"},
154       {TILEDB_UINT64},
155       {domain},
156       {&tile_extent},
157       {"a", "b", "c"},
158       {TILEDB_INT32, TILEDB_CHAR, TILEDB_FLOAT32},
159       {1, TILEDB_VAR_NUM, 2},
160       {tiledb::test::Compressor(TILEDB_FILTER_NONE, -1),
161        tiledb::test::Compressor(TILEDB_FILTER_ZSTD, -1),
162        tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1)},
163       TILEDB_ROW_MAJOR,
164       TILEDB_ROW_MAJOR,
165       2);
166 }
167 
168 /* ********************************* */
169 /*                TESTS              */
170 /* ********************************* */
171 
172 TEST_CASE_METHOD(
173     CMetadataFx, "C API: Metadata, basic errors", "[capi][metadata][errors]") {
174   // Create default array
175   create_default_array_1d();
176 
177   // Create array
178   tiledb_array_t* array;
179   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
180   REQUIRE(rc == TILEDB_OK);
181 
182   // Put metadata on an array that is not opened
183   int v = 5;
184   rc = tiledb_array_put_metadata(ctx_, array, "key", TILEDB_INT32, 1, &v);
185   CHECK(rc == TILEDB_ERR);
186 
187   // Write metadata on an array opened in READ mode
188   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
189   REQUIRE(rc == TILEDB_OK);
190   rc = tiledb_array_put_metadata(ctx_, array, "key", TILEDB_INT32, 1, &v);
191   CHECK(rc == TILEDB_ERR);
192 
193   // Close array
194   rc = tiledb_array_close(ctx_, array);
195   REQUIRE(rc == TILEDB_OK);
196 
197   // Reopen array in WRITE mode
198   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
199   REQUIRE(rc == TILEDB_OK);
200 
201   // Write null key
202   rc = tiledb_array_put_metadata(ctx_, array, NULL, TILEDB_INT32, 1, &v);
203   CHECK(rc == TILEDB_ERR);
204 
205   // Write value type ANY
206   rc = tiledb_array_put_metadata(ctx_, array, "key", TILEDB_ANY, 1, &v);
207   CHECK(rc == TILEDB_ERR);
208 
209   // Write a correct item
210   rc = tiledb_array_put_metadata(ctx_, array, "key", TILEDB_INT32, 1, &v);
211   CHECK(rc == TILEDB_OK);
212 
213   // Close array
214   rc = tiledb_array_close(ctx_, array);
215   REQUIRE(rc == TILEDB_OK);
216 
217   // Open with key
218   tiledb_config_t* config;
219   tiledb_error_t* error = nullptr;
220   rc = tiledb_config_alloc(&config, &error);
221   REQUIRE(rc == TILEDB_OK);
222   REQUIRE(error == nullptr);
223   std::string encryption_type_string =
224       encryption_type_str((tiledb::sm::EncryptionType)enc_type_);
225   rc = tiledb_config_set(
226       config, "sm.encryption_type", encryption_type_string.c_str(), &error);
227   REQUIRE(rc == TILEDB_OK);
228   REQUIRE(error == nullptr);
229   rc = tiledb_config_set(config, "sm.encryption_key", key_, &error);
230   REQUIRE(rc == TILEDB_OK);
231   REQUIRE(error == nullptr);
232   tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(
233       key_len_);
234   rc = tiledb_array_set_config(ctx_, array, config);
235   REQUIRE(rc == TILEDB_OK);
236   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
237   CHECK(rc == TILEDB_ERR);
238 
239   // Clean up
240   tiledb_array_free(&array);
241   tiledb_config_free(&config);
242 }
243 
244 TEST_CASE_METHOD(
245     CMetadataFx, "C API: Metadata, write/read", "[capi][metadata][read]") {
246   // Create default array
247   create_default_array_1d();
248 
249   // Create and open array in write mode
250   tiledb_array_t* array;
251   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
252   REQUIRE(rc == TILEDB_OK);
253   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
254   REQUIRE(rc == TILEDB_OK);
255 
256   // Write items
257   int32_t v = 5;
258   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v);
259   CHECK(rc == TILEDB_OK);
260   float f[] = {1.1f, 1.2f};
261   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f);
262   CHECK(rc == TILEDB_OK);
263 
264   // Close array
265   rc = tiledb_array_close(ctx_, array);
266   REQUIRE(rc == TILEDB_OK);
267   tiledb_array_free(&array);
268 
269   // Open the array in read mode
270   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
271   REQUIRE(rc == TILEDB_OK);
272   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
273   REQUIRE(rc == TILEDB_OK);
274 
275   // Read
276   const void* v_r;
277   tiledb_datatype_t v_type;
278   uint32_t v_num;
279   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
280   CHECK(rc == TILEDB_OK);
281   CHECK(v_type == TILEDB_INT32);
282   CHECK(v_num == 1);
283   CHECK(*((const int32_t*)v_r) == 5);
284 
285   rc = tiledb_array_get_metadata(ctx_, array, "bb", &v_type, &v_num, &v_r);
286   CHECK(rc == TILEDB_OK);
287   CHECK(v_type == TILEDB_FLOAT32);
288   CHECK(v_num == 2);
289   CHECK(((const float*)v_r)[0] == 1.1f);
290   CHECK(((const float*)v_r)[1] == 1.2f);
291 
292   rc = tiledb_array_get_metadata(ctx_, array, "foo", &v_type, &v_num, &v_r);
293   CHECK(rc == TILEDB_OK);
294   CHECK(v_r == nullptr);
295 
296   uint64_t num = 0;
297   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
298   CHECK(rc == TILEDB_OK);
299   CHECK(num == 2);
300 
301   const char* key;
302   uint32_t key_len;
303   rc = tiledb_array_get_metadata_from_index(
304       ctx_, array, 10, &key, &key_len, &v_type, &v_num, &v_r);
305   CHECK(rc == TILEDB_ERR);
306 
307   rc = tiledb_array_get_metadata_from_index(
308       ctx_, array, 1, &key, &key_len, &v_type, &v_num, &v_r);
309   CHECK(rc == TILEDB_OK);
310   CHECK(v_type == TILEDB_FLOAT32);
311   CHECK(v_num == 2);
312   CHECK(((const float*)v_r)[0] == 1.1f);
313   CHECK(((const float*)v_r)[1] == 1.2f);
314   CHECK(key_len == strlen("bb"));
315   CHECK(!strncmp(key, "bb", strlen("bb")));
316 
317   // Check has_key
318   int32_t has_key = 0;
319   rc = tiledb_array_has_metadata_key(ctx_, array, "bb", &v_type, &has_key);
320   CHECK(rc == TILEDB_OK);
321   CHECK(v_type == TILEDB_FLOAT32);
322   CHECK(has_key == 1);
323 
324   // Check not has_key
325   v_type = (tiledb_datatype_t)std::numeric_limits<int32_t>::max();
326   rc = tiledb_array_has_metadata_key(
327       ctx_, array, "non-existent-key", &v_type, &has_key);
328   CHECK(rc == TILEDB_OK);
329   // The API does not touch v_type when no key is found.
330   CHECK((int32_t)v_type == std::numeric_limits<int32_t>::max());
331   CHECK(has_key == 0);
332 
333   // Close array
334   rc = tiledb_array_close(ctx_, array);
335   REQUIRE(rc == TILEDB_OK);
336   tiledb_array_free(&array);
337 }
338 
339 TEST_CASE_METHOD(
340     CMetadataFx, "C API: Metadata, UTF-8", "[capi][metadata][utf-8]") {
341   // Create default array
342   create_default_array_1d();
343 
344   // Create and open array in write mode
345   tiledb_array_t* array;
346   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
347   REQUIRE(rc == TILEDB_OK);
348   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
349   REQUIRE(rc == TILEDB_OK);
350 
351   // Write UTF-8 (≥ holds 3 bytes)
352   int32_t v = 5;
353   rc = tiledb_array_put_metadata(ctx_, array, "≥", TILEDB_INT32, 1, &v);
354   CHECK(rc == TILEDB_OK);
355 
356   // Close array
357   rc = tiledb_array_close(ctx_, array);
358   REQUIRE(rc == TILEDB_OK);
359   tiledb_array_free(&array);
360 
361   // Open the array in read mode
362   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
363   REQUIRE(rc == TILEDB_OK);
364   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
365   REQUIRE(rc == TILEDB_OK);
366 
367   // Read
368   const void* v_r;
369   tiledb_datatype_t v_type;
370   uint32_t v_num;
371   rc = tiledb_array_get_metadata(ctx_, array, "≥", &v_type, &v_num, &v_r);
372   CHECK(rc == TILEDB_OK);
373   CHECK(v_type == TILEDB_INT32);
374   CHECK(v_num == 1);
375   CHECK(*((const int32_t*)v_r) == 5);
376 
377   const char* key;
378   uint32_t key_len;
379   rc = tiledb_array_get_metadata_from_index(
380       ctx_, array, 0, &key, &key_len, &v_type, &v_num, &v_r);
381   CHECK(rc == TILEDB_OK);
382   CHECK(v_type == TILEDB_INT32);
383   CHECK(v_num == 1);
384   CHECK(*((const int32_t*)v_r) == 5);
385   CHECK(key_len == strlen("≥"));
386   CHECK(!strncmp(key, "≥", strlen("≥")));
387 
388   // Close array
389   rc = tiledb_array_close(ctx_, array);
390   REQUIRE(rc == TILEDB_OK);
391   tiledb_array_free(&array);
392 }
393 
394 TEST_CASE_METHOD(
395     CMetadataFx, "C API: Metadata, delete", "[capi][metadata][delete]") {
396   // Create default array
397   create_default_array_1d();
398 
399   // Create and open array in write mode
400   tiledb_array_t* array;
401   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
402   REQUIRE(rc == TILEDB_OK);
403   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
404   REQUIRE(rc == TILEDB_OK);
405 
406   // Write items
407   int32_t v = 5;
408   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v);
409   CHECK(rc == TILEDB_OK);
410   float f[] = {1.1f, 1.2f};
411   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f);
412   CHECK(rc == TILEDB_OK);
413 
414   // Close array
415   rc = tiledb_array_close(ctx_, array);
416   REQUIRE(rc == TILEDB_OK);
417   tiledb_array_free(&array);
418 
419   // Prevent array metadata filename/timestamp conflicts
420   std::this_thread::sleep_for(std::chrono::milliseconds(1));
421 
422   // Delete an item that exists and one that does not exist
423   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
424   REQUIRE(rc == TILEDB_OK);
425   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
426   REQUIRE(rc == TILEDB_OK);
427   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
428   CHECK(rc == TILEDB_OK);
429   rc = tiledb_array_delete_metadata(ctx_, array, "foo");
430   CHECK(rc == TILEDB_OK);
431   rc = tiledb_array_close(ctx_, array);
432   REQUIRE(rc == TILEDB_OK);
433   tiledb_array_free(&array);
434 
435   // Open the array in read mode
436   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
437   REQUIRE(rc == TILEDB_OK);
438   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
439   REQUIRE(rc == TILEDB_OK);
440 
441   // Read
442   const void* v_r;
443   tiledb_datatype_t v_type;
444   uint32_t v_num;
445   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
446   CHECK(rc == TILEDB_OK);
447   CHECK(v_r == nullptr);
448 
449   rc = tiledb_array_get_metadata(ctx_, array, "bb", &v_type, &v_num, &v_r);
450   CHECK(rc == TILEDB_OK);
451   CHECK(v_type == TILEDB_FLOAT32);
452   CHECK(v_num == 2);
453   CHECK(((const float*)v_r)[0] == 1.1f);
454   CHECK(((const float*)v_r)[1] == 1.2f);
455 
456   rc = tiledb_array_get_metadata(ctx_, array, "foo", &v_type, &v_num, &v_r);
457   CHECK(rc == TILEDB_OK);
458   CHECK(v_r == nullptr);
459 
460   uint64_t num = 0;
461   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
462   CHECK(rc == TILEDB_OK);
463   CHECK(num == 1);
464 
465   const char* key;
466   uint32_t key_len;
467   rc = tiledb_array_get_metadata_from_index(
468       ctx_, array, 0, &key, &key_len, &v_type, &v_num, &v_r);
469   CHECK(rc == TILEDB_OK);
470   CHECK(v_type == TILEDB_FLOAT32);
471   CHECK(v_num == 2);
472   CHECK(((const float*)v_r)[0] == 1.1f);
473   CHECK(((const float*)v_r)[1] == 1.2f);
474   CHECK(key_len == strlen("bb"));
475   CHECK(!strncmp(key, "bb", strlen("bb")));
476 
477   // Close array
478   rc = tiledb_array_close(ctx_, array);
479   REQUIRE(rc == TILEDB_OK);
480   tiledb_array_free(&array);
481 }
482 
483 TEST_CASE_METHOD(
484     CMetadataFx,
485     "C API: Metadata, multiple metadata and consolidate",
486     "[capi][metadata][multiple][consolidation]") {
487   // Create default array
488   create_default_array_1d();
489 
490   // Create and open array in write mode
491   tiledb_array_t* array;
492   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
493   REQUIRE(rc == TILEDB_OK);
494   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 1);
495   REQUIRE(rc == TILEDB_OK);
496   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
497   REQUIRE(rc == TILEDB_OK);
498 
499   // Write items
500   int32_t v = 5;
501   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v);
502   CHECK(rc == TILEDB_OK);
503   float f[] = {1.1f, 1.2f};
504   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f);
505   CHECK(rc == TILEDB_OK);
506 
507   // Close array
508   rc = tiledb_array_close(ctx_, array);
509   REQUIRE(rc == TILEDB_OK);
510   tiledb_array_free(&array);
511 
512   // Update
513   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
514   REQUIRE(rc == TILEDB_OK);
515   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 2);
516   REQUIRE(rc == TILEDB_OK);
517   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
518   REQUIRE(rc == TILEDB_OK);
519   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
520   CHECK(rc == TILEDB_OK);
521   v = 10;
522   rc = tiledb_array_put_metadata(ctx_, array, "cccc", TILEDB_INT32, 1, &v);
523   CHECK(rc == TILEDB_OK);
524   rc = tiledb_array_close(ctx_, array);
525   REQUIRE(rc == TILEDB_OK);
526   tiledb_array_free(&array);
527 
528   // Open the array in read mode
529   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
530   REQUIRE(rc == TILEDB_OK);
531   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
532   REQUIRE(rc == TILEDB_OK);
533 
534   // Read
535   const void* v_r;
536   tiledb_datatype_t v_type;
537   uint32_t v_num;
538   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
539   CHECK(rc == TILEDB_OK);
540   CHECK(v_r == nullptr);
541 
542   rc = tiledb_array_get_metadata(ctx_, array, "bb", &v_type, &v_num, &v_r);
543   CHECK(rc == TILEDB_OK);
544   CHECK(v_type == TILEDB_FLOAT32);
545   CHECK(v_num == 2);
546   CHECK(((const float*)v_r)[0] == 1.1f);
547   CHECK(((const float*)v_r)[1] == 1.2f);
548 
549   rc = tiledb_array_get_metadata(ctx_, array, "cccc", &v_type, &v_num, &v_r);
550   CHECK(rc == TILEDB_OK);
551   CHECK(v_type == TILEDB_INT32);
552   CHECK(v_num == 1);
553   CHECK(*((const int32_t*)v_r) == 10);
554 
555   uint64_t num = 0;
556   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
557   CHECK(rc == TILEDB_OK);
558   CHECK(num == 2);
559 
560   const char* key;
561   uint32_t key_len;
562   rc = tiledb_array_get_metadata_from_index(
563       ctx_, array, 0, &key, &key_len, &v_type, &v_num, &v_r);
564   CHECK(rc == TILEDB_OK);
565   CHECK(v_type == TILEDB_FLOAT32);
566   CHECK(v_num == 2);
567   CHECK(((const float*)v_r)[0] == 1.1f);
568   CHECK(((const float*)v_r)[1] == 1.2f);
569   CHECK(key_len == strlen("bb"));
570   CHECK(!strncmp(key, "bb", strlen("bb")));
571 
572   // Close array
573   rc = tiledb_array_close(ctx_, array);
574   REQUIRE(rc == TILEDB_OK);
575   tiledb_array_free(&array);
576 
577   // Consolidate
578   SECTION("tiledb_array_consolidate") {
579     // Configuration for consolidating array metadata
580     tiledb_config_t* config = nullptr;
581     tiledb_error_t* error = nullptr;
582     REQUIRE(tiledb_config_alloc(&config, &error) == TILEDB_OK);
583     REQUIRE(error == nullptr);
584     int rc = tiledb_config_set(
585         config, "sm.consolidation.mode", "array_meta", &error);
586     REQUIRE(rc == TILEDB_OK);
587     REQUIRE(error == nullptr);
588     rc = tiledb_array_consolidate(ctx_, array_name_.c_str(), config);
589     CHECK(rc == TILEDB_OK);
590     tiledb_config_free(&config);
591   }
592 
593   // Check number of metadata files
594   get_num_struct data = {0};
595   auto meta_folder =
596       array_name_ + "/" + tiledb::sm::constants::array_metadata_folder_name;
597   rc = tiledb_vfs_ls(ctx_, vfs_, meta_folder.c_str(), &get_meta_num, &data);
598   CHECK(rc == TILEDB_OK);
599   CHECK(data.num == 4);
600 
601   // Read at timestamp 1
602   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
603   REQUIRE(rc == TILEDB_OK);
604   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 1);
605   REQUIRE(rc == TILEDB_OK);
606   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
607   REQUIRE(rc == TILEDB_OK);
608   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
609   CHECK(rc == TILEDB_OK);
610   CHECK(v_type == TILEDB_INT32);
611   CHECK(*(const int32_t*)v_r == 5);
612   CHECK(v_num == 1);
613   rc = tiledb_array_close(ctx_, array);
614   REQUIRE(rc == TILEDB_OK);
615   tiledb_array_free(&array);
616 
617   // Vacuum
618   tiledb_config_t* config_v = nullptr;
619   tiledb_error_t* error_v = nullptr;
620   REQUIRE(tiledb_config_alloc(&config_v, &error_v) == TILEDB_OK);
621   REQUIRE(error_v == nullptr);
622   rc = tiledb_config_set(config_v, "sm.vacuum.mode", "array_meta", &error_v);
623   REQUIRE(rc == TILEDB_OK);
624   REQUIRE(error_v == nullptr);
625   rc = tiledb_array_vacuum(ctx_, array_name_.c_str(), config_v);
626   CHECK(rc == TILEDB_OK);
627   tiledb_config_free(&config_v);
628 
629   // Check number of metadata files
630   data = {0};
631   rc = tiledb_vfs_ls(ctx_, vfs_, meta_folder.c_str(), &get_meta_num, &data);
632   CHECK(rc == TILEDB_OK);
633   CHECK(data.num == 1);
634 
635   // Open the array in read mode
636   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
637   REQUIRE(rc == TILEDB_OK);
638   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
639   REQUIRE(rc == TILEDB_OK);
640 
641   num = 0;
642   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
643   CHECK(rc == TILEDB_OK);
644   CHECK(num == 2);
645 
646   // Close array
647   rc = tiledb_array_close(ctx_, array);
648   REQUIRE(rc == TILEDB_OK);
649   tiledb_array_free(&array);
650 
651   // Write once more
652   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
653   REQUIRE(rc == TILEDB_OK);
654   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
655   REQUIRE(rc == TILEDB_OK);
656 
657   // Write items
658   v = 50;
659   rc = tiledb_array_put_metadata(ctx_, array, "d", TILEDB_INT32, 1, &v);
660   CHECK(rc == TILEDB_OK);
661 
662   // Close array
663   rc = tiledb_array_close(ctx_, array);
664   REQUIRE(rc == TILEDB_OK);
665   tiledb_array_free(&array);
666 
667   // Consolidate again
668   tiledb_config_t* config = nullptr;
669   tiledb_error_t* error = nullptr;
670   REQUIRE(tiledb_config_alloc(&config, &error) == TILEDB_OK);
671   REQUIRE(error == nullptr);
672   rc = tiledb_config_set(config, "sm.consolidation.mode", "array_meta", &error);
673   REQUIRE(rc == TILEDB_OK);
674   REQUIRE(error == nullptr);
675   rc = tiledb_array_consolidate(ctx_, array_name_.c_str(), config);
676   CHECK(rc == TILEDB_OK);
677   tiledb_config_free(&config);
678   tiledb_array_free(&array);
679 
680   // Open the array in read mode
681   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
682   REQUIRE(rc == TILEDB_OK);
683   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
684   REQUIRE(rc == TILEDB_OK);
685 
686   num = 0;
687   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
688   CHECK(rc == TILEDB_OK);
689   CHECK(num == 3);
690 
691   rc = tiledb_array_get_metadata(ctx_, array, "cccc", &v_type, &v_num, &v_r);
692   CHECK(rc == TILEDB_OK);
693   CHECK(v_type == TILEDB_INT32);
694   CHECK(v_num == 1);
695   CHECK(*((const int32_t*)v_r) == 10);
696 
697   rc = tiledb_array_get_metadata(ctx_, array, "d", &v_type, &v_num, &v_r);
698   CHECK(rc == TILEDB_OK);
699   CHECK(v_type == TILEDB_INT32);
700   CHECK(v_num == 1);
701   CHECK(*((const int32_t*)v_r) == 50);
702 
703   // Close array
704   rc = tiledb_array_close(ctx_, array);
705   REQUIRE(rc == TILEDB_OK);
706   tiledb_array_free(&array);
707 }
708 
709 TEST_CASE_METHOD(
710     CMetadataFx, "C API: Metadata, open at", "[capi][metadata][open-at]") {
711   // Create default array
712   create_default_array_1d();
713 
714   // Create and open array in write mode
715   tiledb_array_t* array;
716   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
717   REQUIRE(rc == TILEDB_OK);
718   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 1);
719   REQUIRE(rc == TILEDB_OK);
720   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
721   REQUIRE(rc == TILEDB_OK);
722 
723   // Write items
724   int32_t v = 5;
725   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v);
726   CHECK(rc == TILEDB_OK);
727   float f[] = {1.1f, 1.2f};
728   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f);
729   CHECK(rc == TILEDB_OK);
730 
731   // Close array
732   rc = tiledb_array_close(ctx_, array);
733   REQUIRE(rc == TILEDB_OK);
734   tiledb_array_free(&array);
735 
736   // Update
737   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
738   REQUIRE(rc == TILEDB_OK);
739   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 2);
740   REQUIRE(rc == TILEDB_OK);
741   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
742   REQUIRE(rc == TILEDB_OK);
743   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
744   CHECK(rc == TILEDB_OK);
745   rc = tiledb_array_close(ctx_, array);
746   REQUIRE(rc == TILEDB_OK);
747   tiledb_array_free(&array);
748 
749   // Open the array in read mode at a timestamp
750   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
751   REQUIRE(rc == TILEDB_OK);
752   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 1);
753   REQUIRE(rc == TILEDB_OK);
754   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
755   REQUIRE(rc == TILEDB_OK);
756 
757   // Read
758   const void* v_r;
759   tiledb_datatype_t v_type;
760   uint32_t v_num;
761   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
762   CHECK(rc == TILEDB_OK);
763   CHECK(v_type == TILEDB_INT32);
764   CHECK(v_num == 1);
765   CHECK(*((const int32_t*)v_r) == 5);
766 
767   uint64_t num = 0;
768   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
769   CHECK(rc == TILEDB_OK);
770   CHECK(num == 2);
771 
772   // Close array
773   rc = tiledb_array_close(ctx_, array);
774   REQUIRE(rc == TILEDB_OK);
775   tiledb_array_free(&array);
776 }
777 
778 TEST_CASE_METHOD(
779     CMetadataFx, "C API: Metadata, reopen", "[capi][metadata][reopen]") {
780   // Create default array
781   create_default_array_1d();
782 
783   // Create and open array in write mode
784   tiledb_array_t* array;
785   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
786   REQUIRE(rc == TILEDB_OK);
787   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 1);
788   REQUIRE(rc == TILEDB_OK);
789   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
790   REQUIRE(rc == TILEDB_OK);
791 
792   // Write items
793   int32_t v = 5;
794   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v);
795   CHECK(rc == TILEDB_OK);
796   float f[] = {1.1f, 1.2f};
797   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f);
798   CHECK(rc == TILEDB_OK);
799 
800   // Close array
801   rc = tiledb_array_close(ctx_, array);
802   REQUIRE(rc == TILEDB_OK);
803   tiledb_array_free(&array);
804 
805   // Update
806   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
807   REQUIRE(rc == TILEDB_OK);
808   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 2);
809   REQUIRE(rc == TILEDB_OK);
810   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
811   REQUIRE(rc == TILEDB_OK);
812   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
813   CHECK(rc == TILEDB_OK);
814   rc = tiledb_array_close(ctx_, array);
815   REQUIRE(rc == TILEDB_OK);
816   tiledb_array_free(&array);
817 
818   // Open the array in read mode at a timestamp
819   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
820   REQUIRE(rc == TILEDB_OK);
821   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 1);
822   REQUIRE(rc == TILEDB_OK);
823   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
824   REQUIRE(rc == TILEDB_OK);
825 
826   // Read
827   const void* v_r;
828   tiledb_datatype_t v_type;
829   uint32_t v_num;
830   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
831   CHECK(rc == TILEDB_OK);
832   CHECK(v_type == TILEDB_INT32);
833   CHECK(v_num == 1);
834   CHECK(*((const int32_t*)v_r) == 5);
835 
836   uint64_t num = 0;
837   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
838   CHECK(rc == TILEDB_OK);
839   CHECK(num == 2);
840 
841   // Reopen
842   rc = tiledb_array_set_open_timestamp_end(
843       ctx_, array, tiledb::sm::utils::time::timestamp_now_ms());
844   REQUIRE(rc == TILEDB_OK);
845   rc = tiledb_array_reopen(ctx_, array);
846   CHECK(rc == TILEDB_OK);
847 
848   // Read
849   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
850   CHECK(rc == TILEDB_OK);
851   CHECK(v_r == nullptr);
852 
853   num = 0;
854   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
855   CHECK(rc == TILEDB_OK);
856   CHECK(num == 1);
857 
858   // Close array
859   rc = tiledb_array_close(ctx_, array);
860   REQUIRE(rc == TILEDB_OK);
861   tiledb_array_free(&array);
862 }
863 
864 TEST_CASE_METHOD(
865     CMetadataFx,
866     "C API: Metadata, timestamp_end",
867     "[capi][metadata][timestamp-end]") {
868   // Create default array
869   create_default_array_1d();
870 
871   // Create and open array in write mode
872   tiledb_array_t* array;
873   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
874   REQUIRE(rc == TILEDB_OK);
875   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 1);
876   REQUIRE(rc == TILEDB_OK);
877   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
878   REQUIRE(rc == TILEDB_OK);
879 
880   // Write items
881   int32_t v1 = 4;
882   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v1);
883   CHECK(rc == TILEDB_OK);
884   float f1[] = {1.0f, 1.2f};
885   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f1);
886   CHECK(rc == TILEDB_OK);
887 
888   // Close array
889   rc = tiledb_array_close(ctx_, array);
890   REQUIRE(rc == TILEDB_OK);
891   tiledb_array_free(&array);
892 
893   // Update
894   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
895   REQUIRE(rc == TILEDB_OK);
896   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 2);
897   REQUIRE(rc == TILEDB_OK);
898   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
899   REQUIRE(rc == TILEDB_OK);
900   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
901   CHECK(rc == TILEDB_OK);
902   rc = tiledb_array_close(ctx_, array);
903   REQUIRE(rc == TILEDB_OK);
904   tiledb_array_free(&array);
905 
906   // Create and open array in write mode
907   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
908   REQUIRE(rc == TILEDB_OK);
909   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 3);
910   REQUIRE(rc == TILEDB_OK);
911   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
912   REQUIRE(rc == TILEDB_OK);
913 
914   // Write items
915   int32_t v2 = 5;
916   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v2);
917   CHECK(rc == TILEDB_OK);
918   float f2[] = {1.1f, 1.2f};
919   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f2);
920   CHECK(rc == TILEDB_OK);
921 
922   // Close array
923   rc = tiledb_array_close(ctx_, array);
924   REQUIRE(rc == TILEDB_OK);
925   tiledb_array_free(&array);
926 
927   // Update
928   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
929   REQUIRE(rc == TILEDB_OK);
930   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 4);
931   REQUIRE(rc == TILEDB_OK);
932   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
933   REQUIRE(rc == TILEDB_OK);
934   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
935   CHECK(rc == TILEDB_OK);
936   rc = tiledb_array_close(ctx_, array);
937   REQUIRE(rc == TILEDB_OK);
938   tiledb_array_free(&array);
939 
940   // Create and open array in write mode
941   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
942   REQUIRE(rc == TILEDB_OK);
943   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 5);
944   REQUIRE(rc == TILEDB_OK);
945   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
946   REQUIRE(rc == TILEDB_OK);
947 
948   // Write items
949   int32_t v3 = 6;
950   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v3);
951   CHECK(rc == TILEDB_OK);
952   float f3[] = {1.2f, 1.3f};
953   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f3);
954   CHECK(rc == TILEDB_OK);
955 
956   // Close array
957   rc = tiledb_array_close(ctx_, array);
958   REQUIRE(rc == TILEDB_OK);
959   tiledb_array_free(&array);
960 
961   // Update
962   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
963   REQUIRE(rc == TILEDB_OK);
964   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 6);
965   REQUIRE(rc == TILEDB_OK);
966   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
967   REQUIRE(rc == TILEDB_OK);
968   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
969   CHECK(rc == TILEDB_OK);
970   rc = tiledb_array_close(ctx_, array);
971   REQUIRE(rc == TILEDB_OK);
972   tiledb_array_free(&array);
973 
974   // Open the array in read mode between timestamp1 and timestamp2
975   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
976   rc = tiledb_array_set_open_timestamp_start(ctx_, array, 2);
977   REQUIRE(rc == TILEDB_OK);
978   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 3);
979   REQUIRE(rc == TILEDB_OK);
980   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
981   REQUIRE(rc == TILEDB_OK);
982 
983   // Read - ensure that the data is only that written between
984   // timestamp1 and timestamp2
985   const void* v_r;
986   tiledb_datatype_t v_type;
987   uint32_t v_num;
988   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
989   CHECK(rc == TILEDB_OK);
990   CHECK(v_type == TILEDB_INT32);
991   CHECK(v_num == 1);
992   CHECK(*((const int32_t*)v_r) == 5);
993 
994   uint64_t num = 0;
995   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
996   CHECK(rc == TILEDB_OK);
997   CHECK(num == 2);
998 
999   // Close array
1000   rc = tiledb_array_close(ctx_, array);
1001   REQUIRE(rc == TILEDB_OK);
1002   tiledb_array_free(&array);
1003 }
1004 
1005 TEST_CASE_METHOD(
1006     CMetadataFx,
1007     "C API: Metadata, encryption",
1008     "[capi][metadata][encryption]") {
1009   // Create default array
1010   create_default_array_1d_with_key();
1011 
1012   // Create and open array in write mode
1013   tiledb_array_t* array;
1014   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1015   REQUIRE(rc == TILEDB_OK);
1016   tiledb_config_t* config;
1017   tiledb_error_t* error = nullptr;
1018   rc = tiledb_config_alloc(&config, &error);
1019   REQUIRE(rc == TILEDB_OK);
1020   REQUIRE(error == nullptr);
1021   std::string encryption_type_string =
1022       encryption_type_str((tiledb::sm::EncryptionType)enc_type_);
1023   rc = tiledb_config_set(
1024       config, "sm.encryption_type", encryption_type_string.c_str(), &error);
1025   REQUIRE(rc == TILEDB_OK);
1026   REQUIRE(error == nullptr);
1027   rc = tiledb_config_set(config, "sm.encryption_key", key_, &error);
1028   REQUIRE(rc == TILEDB_OK);
1029   REQUIRE(error == nullptr);
1030   rc = tiledb_array_set_config(ctx_, array, config);
1031   REQUIRE(rc == TILEDB_OK);
1032   tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(
1033       key_len_);
1034   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1035   REQUIRE(rc == TILEDB_OK);
1036 
1037   // Write items
1038   int32_t v = 5;
1039   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v);
1040   CHECK(rc == TILEDB_OK);
1041   float f[] = {1.1f, 1.2f};
1042   rc = tiledb_array_put_metadata(ctx_, array, "bb", TILEDB_FLOAT32, 2, f);
1043   CHECK(rc == TILEDB_OK);
1044 
1045   // Close array
1046   rc = tiledb_array_close(ctx_, array);
1047   REQUIRE(rc == TILEDB_OK);
1048   tiledb_array_free(&array);
1049 
1050   // Prevent array metadata filename/timestamp conflicts
1051   std::this_thread::sleep_for(std::chrono::milliseconds(1));
1052 
1053   // Update
1054   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1055   REQUIRE(rc == TILEDB_OK);
1056   rc = tiledb_array_set_config(ctx_, array, config);
1057   REQUIRE(rc == TILEDB_OK);
1058   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1059   REQUIRE(rc == TILEDB_OK);
1060   rc = tiledb_array_delete_metadata(ctx_, array, "aaa");
1061   CHECK(rc == TILEDB_OK);
1062   v = 10;
1063   rc = tiledb_array_put_metadata(ctx_, array, "cccc", TILEDB_INT32, 1, &v);
1064   CHECK(rc == TILEDB_OK);
1065   rc = tiledb_array_close(ctx_, array);
1066   REQUIRE(rc == TILEDB_OK);
1067   tiledb_array_free(&array);
1068 
1069   // Open the array in read mode
1070   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1071   REQUIRE(rc == TILEDB_OK);
1072   rc = tiledb_array_set_config(ctx_, array, config);
1073   REQUIRE(rc == TILEDB_OK);
1074   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1075   REQUIRE(rc == TILEDB_OK);
1076 
1077   // Read
1078   const void* v_r;
1079   tiledb_datatype_t v_type;
1080   uint32_t v_num;
1081   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
1082   CHECK(rc == TILEDB_OK);
1083   CHECK(v_r == nullptr);
1084 
1085   rc = tiledb_array_get_metadata(ctx_, array, "bb", &v_type, &v_num, &v_r);
1086   CHECK(rc == TILEDB_OK);
1087   CHECK(v_type == TILEDB_FLOAT32);
1088   CHECK(v_num == 2);
1089   CHECK(((const float*)v_r)[0] == 1.1f);
1090   CHECK(((const float*)v_r)[1] == 1.2f);
1091 
1092   rc = tiledb_array_get_metadata(ctx_, array, "cccc", &v_type, &v_num, &v_r);
1093   CHECK(rc == TILEDB_OK);
1094   CHECK(v_type == TILEDB_INT32);
1095   CHECK(v_num == 1);
1096   CHECK(*((const int32_t*)v_r) == 10);
1097 
1098   uint64_t num = 0;
1099   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
1100   CHECK(rc == TILEDB_OK);
1101   CHECK(num == 2);
1102 
1103   const char* key;
1104   uint32_t key_len;
1105   rc = tiledb_array_get_metadata_from_index(
1106       ctx_, array, 0, &key, &key_len, &v_type, &v_num, &v_r);
1107   CHECK(rc == TILEDB_OK);
1108   CHECK(v_type == TILEDB_FLOAT32);
1109   CHECK(v_num == 2);
1110   CHECK(((const float*)v_r)[0] == 1.1f);
1111   CHECK(((const float*)v_r)[1] == 1.2f);
1112   CHECK(key_len == strlen("bb"));
1113   CHECK(!strncmp(key, "bb", strlen("bb")));
1114 
1115   // Close array
1116   rc = tiledb_array_close(ctx_, array);
1117   REQUIRE(rc == TILEDB_OK);
1118   tiledb_array_free(&array);
1119 
1120   // Consolidate without key - error
1121   REQUIRE(tiledb_config_alloc(&config, &error) == TILEDB_OK);
1122   REQUIRE(error == nullptr);
1123   rc = tiledb_config_set(config, "sm.consolidation.mode", "array_meta", &error);
1124   REQUIRE(rc == TILEDB_OK);
1125   REQUIRE(error == nullptr);
1126   rc = tiledb_array_consolidate(ctx_, array_name_.c_str(), config);
1127   CHECK(rc == TILEDB_ERR);
1128   tiledb_config_free(&config);
1129 
1130   // Consolidate with key - ok
1131   REQUIRE(tiledb_config_alloc(&config, &error) == TILEDB_OK);
1132   REQUIRE(error == nullptr);
1133   rc = tiledb_config_set(config, "sm.consolidation.mode", "array_meta", &error);
1134   REQUIRE(rc == TILEDB_OK);
1135   REQUIRE(error == nullptr);
1136   encryption_type_string =
1137       encryption_type_str((tiledb::sm::EncryptionType)enc_type_);
1138   rc = tiledb_config_set(
1139       config, "sm.encryption_type", encryption_type_string.c_str(), &error);
1140   REQUIRE(error == nullptr);
1141   rc = tiledb_config_set(config, "sm.encryption_key", key_, &error);
1142   REQUIRE(rc == TILEDB_OK);
1143   REQUIRE(error == nullptr);
1144   rc = tiledb_array_consolidate(ctx_, array_name_.c_str(), config);
1145   CHECK(rc == TILEDB_OK);
1146   tiledb_config_free(&config);
1147   tiledb_array_free(&array);
1148 
1149   // Open the array in read mode
1150   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1151   REQUIRE(rc == TILEDB_OK);
1152   REQUIRE(tiledb_config_alloc(&config, &error) == TILEDB_OK);
1153   REQUIRE(error == nullptr);
1154   encryption_type_string =
1155       encryption_type_str((tiledb::sm::EncryptionType)enc_type_);
1156   rc = tiledb_config_set(
1157       config, "sm.encryption_type", encryption_type_string.c_str(), &error);
1158   REQUIRE(rc == TILEDB_OK);
1159   REQUIRE(error == nullptr);
1160   rc = tiledb_config_set(config, "sm.encryption_key", key_, &error);
1161   REQUIRE(rc == TILEDB_OK);
1162   REQUIRE(error == nullptr);
1163   rc = tiledb_array_set_config(ctx_, array, config);
1164   REQUIRE(rc == TILEDB_OK);
1165   tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(
1166       key_len_);
1167   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1168   REQUIRE(rc == TILEDB_OK);
1169 
1170   num = 0;
1171   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
1172   CHECK(rc == TILEDB_OK);
1173   CHECK(num == 2);
1174 
1175   // Close array
1176   rc = tiledb_array_close(ctx_, array);
1177   REQUIRE(rc == TILEDB_OK);
1178   tiledb_array_free(&array);
1179 
1180   // Write once more
1181   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1182   REQUIRE(rc == TILEDB_OK);
1183   rc = tiledb_array_set_config(ctx_, array, config);
1184   REQUIRE(rc == TILEDB_OK);
1185   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1186   REQUIRE(rc == TILEDB_OK);
1187 
1188   // Write items
1189   v = 50;
1190   rc = tiledb_array_put_metadata(ctx_, array, "d", TILEDB_INT32, 1, &v);
1191   CHECK(rc == TILEDB_OK);
1192 
1193   // Close array
1194   rc = tiledb_array_close(ctx_, array);
1195   REQUIRE(rc == TILEDB_OK);
1196   tiledb_array_free(&array);
1197 
1198   // Consolidate again
1199   rc = tiledb_config_set(config, "sm.consolidation.mode", "array_meta", &error);
1200   REQUIRE(rc == TILEDB_OK);
1201   REQUIRE(error == nullptr);
1202   encryption_type_string =
1203       encryption_type_str((tiledb::sm::EncryptionType)enc_type_);
1204   rc = tiledb_config_set(
1205       config, "sm.encryption_type", encryption_type_string.c_str(), &error);
1206   REQUIRE(error == nullptr);
1207   rc = tiledb_config_set(config, "sm.encryption_key", key_, &error);
1208   REQUIRE(rc == TILEDB_OK);
1209   REQUIRE(error == nullptr);
1210 
1211   rc = tiledb_array_consolidate(ctx_, array_name_.c_str(), config);
1212   CHECK(rc == TILEDB_OK);
1213   tiledb_array_free(&array);
1214 
1215   // Open the array in read mode
1216   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1217   REQUIRE(rc == TILEDB_OK);
1218   rc = tiledb_array_set_config(ctx_, array, config);
1219   REQUIRE(rc == TILEDB_OK);
1220   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1221   REQUIRE(rc == TILEDB_OK);
1222 
1223   num = 0;
1224   rc = tiledb_array_get_metadata_num(ctx_, array, &num);
1225   CHECK(rc == TILEDB_OK);
1226   CHECK(num == 3);
1227 
1228   rc = tiledb_array_get_metadata(ctx_, array, "cccc", &v_type, &v_num, &v_r);
1229   CHECK(rc == TILEDB_OK);
1230   CHECK(v_type == TILEDB_INT32);
1231   CHECK(v_num == 1);
1232   CHECK(*((const int32_t*)v_r) == 10);
1233 
1234   rc = tiledb_array_get_metadata(ctx_, array, "d", &v_type, &v_num, &v_r);
1235   CHECK(rc == TILEDB_OK);
1236   CHECK(v_type == TILEDB_INT32);
1237   CHECK(v_num == 1);
1238   CHECK(*((const int32_t*)v_r) == 50);
1239 
1240   // Close array
1241   rc = tiledb_array_close(ctx_, array);
1242   REQUIRE(rc == TILEDB_OK);
1243   tiledb_array_free(&array);
1244   tiledb_config_free(&config);
1245 }
1246 
1247 TEST_CASE_METHOD(
1248     CMetadataFx, "C API: Metadata, overwrite", "[capi][metadata][overwrite]") {
1249   // Create default array
1250   create_default_array_1d();
1251 
1252   // Open array
1253   tiledb_array_t* array;
1254   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1255   CHECK(rc == TILEDB_OK);
1256   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1257   CHECK(rc == TILEDB_OK);
1258 
1259   // Write and overwrite
1260   int32_t v = 5;
1261   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v);
1262   CHECK(rc == TILEDB_OK);
1263   int32_t v2 = 10;
1264   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v2);
1265   CHECK(rc == TILEDB_OK);
1266 
1267   // Close array
1268   rc = tiledb_array_close(ctx_, array);
1269   CHECK(rc == TILEDB_OK);
1270 
1271   // Read back
1272   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1273   CHECK(rc == TILEDB_OK);
1274   const void* vback_ptr = NULL;
1275   tiledb_datatype_t vtype;
1276   uint32_t vnum = 0;
1277   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &vtype, &vnum, &vback_ptr);
1278   CHECK(rc == TILEDB_OK);
1279   CHECK(vtype == TILEDB_INT32);
1280   CHECK(vnum == 1);
1281   CHECK(*((int32_t*)vback_ptr) == 10);
1282   rc = tiledb_array_close(ctx_, array);
1283   CHECK(rc == TILEDB_OK);
1284   tiledb_array_free(&array);
1285 
1286   // Prevent array metadata filename/timestamp conflicts
1287   std::this_thread::sleep_for(std::chrono::milliseconds(1));
1288 
1289   // Overwrite again
1290   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1291   CHECK(rc == TILEDB_OK);
1292   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1293   CHECK(rc == TILEDB_OK);
1294   int32_t v3 = 20;
1295   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_INT32, 1, &v3);
1296   CHECK(rc == TILEDB_OK);
1297   rc = tiledb_array_close(ctx_, array);
1298   CHECK(rc == TILEDB_OK);
1299 
1300   // Read back
1301   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1302   CHECK(rc == TILEDB_OK);
1303   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &vtype, &vnum, &vback_ptr);
1304   CHECK(rc == TILEDB_OK);
1305   CHECK(vtype == TILEDB_INT32);
1306   CHECK(vnum == 1);
1307   CHECK(*((int32_t*)vback_ptr) == 20);
1308   rc = tiledb_array_close(ctx_, array);
1309   CHECK(rc == TILEDB_OK);
1310 
1311   tiledb_array_free(&array);
1312 }
1313 
1314 TEST_CASE_METHOD(
1315     CMetadataFx,
1316     "C API: Metadata, write/read zero-valued",
1317     "[capi][metadata][read][zero-valued]") {
1318   // Create default array
1319   create_default_array_1d();
1320 
1321   // Create and open array in write mode
1322   tiledb_array_t* array;
1323   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1324   REQUIRE(rc == TILEDB_OK);
1325   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1326   REQUIRE(rc == TILEDB_OK);
1327 
1328   // Write items
1329   rc = tiledb_array_put_metadata(ctx_, array, "aaa", TILEDB_CHAR, 0, nullptr);
1330   REQUIRE(rc == TILEDB_OK);
1331   rc = tiledb_array_put_metadata(ctx_, array, "b", TILEDB_INT32, 1, nullptr);
1332   REQUIRE(rc == TILEDB_OK);
1333 
1334   // Close array
1335   rc = tiledb_array_close(ctx_, array);
1336   REQUIRE(rc == TILEDB_OK);
1337   tiledb_array_free(&array);
1338 
1339   // Open the array in read mode
1340   rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array);
1341   REQUIRE(rc == TILEDB_OK);
1342   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1343   REQUIRE(rc == TILEDB_OK);
1344 
1345   // Read
1346   const void* v_r;
1347   tiledb_datatype_t v_type;
1348   uint32_t v_num;
1349   rc = tiledb_array_get_metadata(ctx_, array, "aaa", &v_type, &v_num, &v_r);
1350   CHECK(rc == TILEDB_OK);
1351   CHECK(v_type == TILEDB_CHAR);
1352   CHECK(v_num == 1);
1353   CHECK(v_r == nullptr);
1354   rc = tiledb_array_get_metadata(ctx_, array, "b", &v_type, &v_num, &v_r);
1355   CHECK(rc == TILEDB_OK);
1356   CHECK(v_type == TILEDB_INT32);
1357   CHECK(v_num == 1);
1358   CHECK(v_r == nullptr);
1359 
1360   // Close array
1361   rc = tiledb_array_close(ctx_, array);
1362   REQUIRE(rc == TILEDB_OK);
1363   tiledb_array_free(&array);
1364 }
1365