1 /**
2  * @file   unit-capi-array.cc
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB Inc.
9  * @copyright Copyright (c) 2016 MIT and Intel Corporation
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27  * THE SOFTWARE.
28  *
29  * @section DESCRIPTION
30  *
31  * Tests of C API for (dense or sparse) array operations.
32  */
33 
34 #include "catch.hpp"
35 #include "tiledb/sm/c_api/tiledb.h"
36 
37 #include <iostream>
38 
39 #include "catch.hpp"
40 #include "test/src/helpers.h"
41 #include "test/src/vfs_helpers.h"
42 #ifdef _WIN32
43 #include <Windows.h>
44 #include "tiledb/sm/filesystem/win.h"
45 #else
46 #include "tiledb/sm/filesystem/posix.h"
47 #endif
48 #include "tiledb/sm/c_api/tiledb.h"
49 #include "tiledb/sm/enums/encryption_type.h"
50 #include "tiledb/sm/global_state/unit_test_config.h"
51 #include "tiledb/sm/misc/utils.h"
52 
53 #include <chrono>
54 #include <climits>
55 #include <iostream>
56 #include <sstream>
57 #include <thread>
58 
59 using namespace tiledb::test;
60 
61 struct ArrayFx {
62   // TileDB context
63   tiledb_ctx_t* ctx_;
64   tiledb_vfs_t* vfs_;
65 
66   // Vector of supported filesystems
67   const std::vector<std::unique_ptr<SupportedFs>> fs_vec_;
68 
69   // Encryption parameters
70   tiledb_encryption_type_t encryption_type_ = TILEDB_NO_ENCRYPTION;
71   const char* encryption_key_ = nullptr;
72 
73   // Functions
74   ArrayFx();
75   ~ArrayFx();
76   void create_temp_dir(const std::string& path);
77   void remove_temp_dir(const std::string& path);
78   void create_sparse_vector(const std::string& path);
79   void create_sparse_array(const std::string& path);
80   void create_dense_vector(const std::string& path);
81   void create_dense_array(const std::string& path);
82   static std::string random_name(const std::string& prefix);
83   static int get_fragment_timestamps(const char* path, void* data);
84 };
85 
86 static const std::string test_ca_path =
87     std::string(TILEDB_TEST_INPUTS_DIR) + "/test_certs";
88 
89 static const std::string test_ca_file =
90     std::string(TILEDB_TEST_INPUTS_DIR) + "/test_certs/public.crt";
91 
ArrayFx()92 ArrayFx::ArrayFx()
93     : fs_vec_(vfs_test_get_fs_vec()) {
94   // Initialize vfs test
95   REQUIRE(vfs_test_init(fs_vec_, &ctx_, &vfs_).ok());
96 }
97 
~ArrayFx()98 ArrayFx::~ArrayFx() {
99   // Close vfs test
100   REQUIRE(vfs_test_close(fs_vec_, ctx_, vfs_).ok());
101   tiledb_vfs_free(&vfs_);
102   tiledb_ctx_free(&ctx_);
103 }
104 
create_temp_dir(const std::string & path)105 void ArrayFx::create_temp_dir(const std::string& path) {
106   remove_temp_dir(path);
107   REQUIRE(tiledb_vfs_create_dir(ctx_, vfs_, path.c_str()) == TILEDB_OK);
108 }
109 
remove_temp_dir(const std::string & path)110 void ArrayFx::remove_temp_dir(const std::string& path) {
111   int is_dir = 0;
112   REQUIRE(tiledb_vfs_is_dir(ctx_, vfs_, path.c_str(), &is_dir) == TILEDB_OK);
113   if (is_dir)
114     REQUIRE(tiledb_vfs_remove_dir(ctx_, vfs_, path.c_str()) == TILEDB_OK);
115 }
116 
random_name(const std::string & prefix)117 std::string ArrayFx::random_name(const std::string& prefix) {
118   std::stringstream ss;
119   ss << prefix << "-" << std::this_thread::get_id() << "-"
120      << TILEDB_TIMESTAMP_NOW_MS;
121   return ss.str();
122 }
123 
get_fragment_timestamps(const char * path,void * data)124 int ArrayFx::get_fragment_timestamps(const char* path, void* data) {
125   auto data_vec = (std::vector<uint64_t>*)data;
126   std::pair<uint64_t, uint64_t> timestamp_range;
127   if (tiledb::sm::utils::parse::ends_with(
128           path, tiledb::sm::constants::ok_file_suffix)) {
129     auto uri = tiledb::sm::URI(path);
130     if (tiledb::sm::utils::parse::get_timestamp_range(uri, &timestamp_range)
131             .ok())
132       data_vec->push_back(timestamp_range.first);
133   }
134 
135   return 1;
136 }
137 
create_sparse_vector(const std::string & path)138 void ArrayFx::create_sparse_vector(const std::string& path) {
139   int rc;
140   int64_t dim_domain[] = {-1, 2};
141   int64_t tile_extent = 2;
142 
143   // Create domain
144   tiledb_domain_t* domain;
145   rc = tiledb_domain_alloc(ctx_, &domain);
146   REQUIRE(rc == TILEDB_OK);
147   tiledb_dimension_t* dim;
148   rc = tiledb_dimension_alloc(
149       ctx_, "d1", TILEDB_INT64, dim_domain, &tile_extent, &dim);
150   REQUIRE(rc == TILEDB_OK);
151   rc = tiledb_domain_add_dimension(ctx_, domain, dim);
152   REQUIRE(rc == TILEDB_OK);
153 
154   // Create attribute
155   tiledb_attribute_t* attr;
156   rc = tiledb_attribute_alloc(ctx_, "a", TILEDB_INT32, &attr);
157   REQUIRE(rc == TILEDB_OK);
158 
159   // Create array schema
160   tiledb_array_schema_t* array_schema;
161   rc = tiledb_array_schema_alloc(ctx_, TILEDB_SPARSE, &array_schema);
162   REQUIRE(rc == TILEDB_OK);
163   rc = tiledb_array_schema_set_cell_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
164   REQUIRE(rc == TILEDB_OK);
165   rc = tiledb_array_schema_set_tile_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
166   REQUIRE(rc == TILEDB_OK);
167   rc = tiledb_array_schema_set_domain(ctx_, array_schema, domain);
168   REQUIRE(rc == TILEDB_OK);
169   rc = tiledb_array_schema_add_attribute(ctx_, array_schema, attr);
170   REQUIRE(rc == TILEDB_OK);
171 
172   rc = tiledb_array_schema_check(ctx_, array_schema);
173   REQUIRE(rc == TILEDB_OK);
174 
175   // Create array
176   rc = tiledb_array_create(ctx_, path.c_str(), array_schema);
177   REQUIRE(rc == TILEDB_OK);
178   tiledb_attribute_free(&attr);
179   tiledb_dimension_free(&dim);
180   tiledb_domain_free(&domain);
181   tiledb_array_schema_free(&array_schema);
182 }
183 
create_sparse_array(const std::string & path)184 void ArrayFx::create_sparse_array(const std::string& path) {
185   int rc;
186   int64_t dim_domain[] = {1, 10, 1, 10};
187   int64_t tile_extent = 2;
188 
189   // Create domain
190   tiledb_domain_t* domain;
191   rc = tiledb_domain_alloc(ctx_, &domain);
192   REQUIRE(rc == TILEDB_OK);
193   tiledb_dimension_t* dim_1;
194   rc = tiledb_dimension_alloc(
195       ctx_, "d1", TILEDB_INT64, dim_domain, &tile_extent, &dim_1);
196   REQUIRE(rc == TILEDB_OK);
197   rc = tiledb_domain_add_dimension(ctx_, domain, dim_1);
198   REQUIRE(rc == TILEDB_OK);
199   tiledb_dimension_t* dim_2;
200   rc = tiledb_dimension_alloc(
201       ctx_, "d2", TILEDB_INT64, &dim_domain[2], &tile_extent, &dim_2);
202   REQUIRE(rc == TILEDB_OK);
203   rc = tiledb_domain_add_dimension(ctx_, domain, dim_2);
204   REQUIRE(rc == TILEDB_OK);
205 
206   // Create attribute
207   tiledb_attribute_t* attr;
208   rc = tiledb_attribute_alloc(ctx_, "a", TILEDB_INT32, &attr);
209   REQUIRE(rc == TILEDB_OK);
210 
211   // Create array schema
212   tiledb_array_schema_t* array_schema;
213   rc = tiledb_array_schema_alloc(ctx_, TILEDB_SPARSE, &array_schema);
214   REQUIRE(rc == TILEDB_OK);
215   rc = tiledb_array_schema_set_cell_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
216   REQUIRE(rc == TILEDB_OK);
217   rc = tiledb_array_schema_set_tile_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
218   REQUIRE(rc == TILEDB_OK);
219   rc = tiledb_array_schema_set_domain(ctx_, array_schema, domain);
220   REQUIRE(rc == TILEDB_OK);
221   rc = tiledb_array_schema_add_attribute(ctx_, array_schema, attr);
222   REQUIRE(rc == TILEDB_OK);
223 
224   rc = tiledb_array_schema_check(ctx_, array_schema);
225   REQUIRE(rc == TILEDB_OK);
226 
227   // Create array
228   rc = tiledb_array_create(ctx_, path.c_str(), array_schema);
229   REQUIRE(rc == TILEDB_OK);
230   tiledb_attribute_free(&attr);
231   tiledb_dimension_free(&dim_1);
232   tiledb_dimension_free(&dim_2);
233   tiledb_domain_free(&domain);
234   tiledb_array_schema_free(&array_schema);
235 }
236 
create_dense_vector(const std::string & path)237 void ArrayFx::create_dense_vector(const std::string& path) {
238   int rc;
239   int64_t dim_domain[] = {1, 10};
240   int64_t tile_extent = 2;
241 
242   // Create domain
243   tiledb_domain_t* domain;
244   rc = tiledb_domain_alloc(ctx_, &domain);
245   REQUIRE(rc == TILEDB_OK);
246   tiledb_dimension_t* dim;
247   rc = tiledb_dimension_alloc(
248       ctx_, "d1", TILEDB_INT64, dim_domain, &tile_extent, &dim);
249   REQUIRE(rc == TILEDB_OK);
250   rc = tiledb_domain_add_dimension(ctx_, domain, dim);
251   REQUIRE(rc == TILEDB_OK);
252 
253   // Create attribute
254   tiledb_attribute_t* attr;
255   rc = tiledb_attribute_alloc(ctx_, "a", TILEDB_INT32, &attr);
256   REQUIRE(rc == TILEDB_OK);
257 
258   // Create array schema
259   tiledb_array_schema_t* array_schema;
260   rc = tiledb_array_schema_alloc(ctx_, TILEDB_DENSE, &array_schema);
261   REQUIRE(rc == TILEDB_OK);
262   rc = tiledb_array_schema_set_cell_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
263   REQUIRE(rc == TILEDB_OK);
264   rc = tiledb_array_schema_set_tile_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
265   REQUIRE(rc == TILEDB_OK);
266   rc = tiledb_array_schema_set_domain(ctx_, array_schema, domain);
267   REQUIRE(rc == TILEDB_OK);
268   rc = tiledb_array_schema_add_attribute(ctx_, array_schema, attr);
269   REQUIRE(rc == TILEDB_OK);
270 
271   rc = tiledb_array_schema_check(ctx_, array_schema);
272   REQUIRE(rc == TILEDB_OK);
273 
274   // Create array
275   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
276     tiledb_ctx_free(&ctx_);
277     tiledb_vfs_free(&vfs_);
278     tiledb_config_t* cfg;
279     tiledb_error_t* err = nullptr;
280     rc = tiledb_config_alloc(&cfg, &err);
281     REQUIRE(rc == TILEDB_OK);
282     REQUIRE(err == nullptr);
283     std::string encryption_type_string =
284         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
285     rc = tiledb_config_set(
286         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
287     REQUIRE(err == nullptr);
288     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
289     REQUIRE(rc == TILEDB_OK);
290     REQUIRE(err == nullptr);
291     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.reset();
292     REQUIRE(vfs_test_init(fs_vec_, &ctx_, &vfs_, cfg).ok());
293     tiledb_config_free(&cfg);
294   }
295   rc = tiledb_array_create(ctx_, path.c_str(), array_schema);
296   REQUIRE(rc == TILEDB_OK);
297   tiledb_attribute_free(&attr);
298   tiledb_dimension_free(&dim);
299   tiledb_domain_free(&domain);
300   tiledb_array_schema_free(&array_schema);
301 }
302 
create_dense_array(const std::string & path)303 void ArrayFx::create_dense_array(const std::string& path) {
304   int rc;
305   int64_t dim_domain[] = {1, 10, 1, 10};
306   int64_t tile_extent = 2;
307 
308   // Create domain
309   tiledb_domain_t* domain;
310   rc = tiledb_domain_alloc(ctx_, &domain);
311   REQUIRE(rc == TILEDB_OK);
312   tiledb_dimension_t* dim_1;
313   rc = tiledb_dimension_alloc(
314       ctx_, "d1", TILEDB_INT64, dim_domain, &tile_extent, &dim_1);
315   REQUIRE(rc == TILEDB_OK);
316   rc = tiledb_domain_add_dimension(ctx_, domain, dim_1);
317   REQUIRE(rc == TILEDB_OK);
318   tiledb_dimension_t* dim_2;
319   rc = tiledb_dimension_alloc(
320       ctx_, "d2", TILEDB_INT64, &dim_domain[2], &tile_extent, &dim_2);
321   REQUIRE(rc == TILEDB_OK);
322   rc = tiledb_domain_add_dimension(ctx_, domain, dim_2);
323   REQUIRE(rc == TILEDB_OK);
324 
325   // Create attribute
326   tiledb_attribute_t* attr;
327   rc = tiledb_attribute_alloc(ctx_, "a", TILEDB_INT32, &attr);
328   REQUIRE(rc == TILEDB_OK);
329 
330   // Create array schema
331   tiledb_array_schema_t* array_schema;
332   rc = tiledb_array_schema_alloc(ctx_, TILEDB_DENSE, &array_schema);
333   REQUIRE(rc == TILEDB_OK);
334   rc = tiledb_array_schema_set_cell_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
335   REQUIRE(rc == TILEDB_OK);
336   rc = tiledb_array_schema_set_tile_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
337   REQUIRE(rc == TILEDB_OK);
338   rc = tiledb_array_schema_set_domain(ctx_, array_schema, domain);
339   REQUIRE(rc == TILEDB_OK);
340   rc = tiledb_array_schema_add_attribute(ctx_, array_schema, attr);
341   REQUIRE(rc == TILEDB_OK);
342 
343   rc = tiledb_array_schema_check(ctx_, array_schema);
344   REQUIRE(rc == TILEDB_OK);
345 
346   // Create array
347   rc = tiledb_array_create(ctx_, path.c_str(), array_schema);
348   REQUIRE(rc == TILEDB_OK);
349   tiledb_attribute_free(&attr);
350   tiledb_dimension_free(&dim_1);
351   tiledb_dimension_free(&dim_2);
352   tiledb_domain_free(&domain);
353   tiledb_array_schema_free(&array_schema);
354 }
355 
356 TEST_CASE_METHOD(
357     ArrayFx, "C API: Test getting array URI", "[capi][array][array-uri]") {
358   SupportedFsLocal local_fs;
359   std::string array_name =
360       local_fs.file_prefix() + local_fs.temp_dir() + "array_uri";
361   create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
362 
363   // Create array
364   tiledb_array_t* array;
365   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
366   REQUIRE(rc == TILEDB_OK);
367 
368   // Get URI when array is not opened (should not error)
369   const char* uri = nullptr;
370   rc = tiledb_array_get_uri(ctx_, array, &uri);
371   CHECK(rc == TILEDB_OK);
372 
373   // Get URI when array is opened
374   create_sparse_vector(array_name);
375   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
376   REQUIRE(rc == TILEDB_OK);
377   rc = tiledb_array_get_uri(ctx_, array, &uri);
378   CHECK(rc == TILEDB_OK);
379 
380 #ifdef _WIN32
381   char path[MAX_PATH];
382   unsigned length = MAX_PATH;
383   rc = tiledb_uri_to_path(ctx_, uri, path, &length);
384   CHECK(rc == TILEDB_OK);
385   CHECK(!strcmp(path, array_name.c_str()));
386 #else
387   CHECK(!strcmp(uri, array_name.c_str()));
388 #endif
389 
390   // Close array
391   rc = tiledb_array_close(ctx_, array);
392   CHECK(rc == TILEDB_OK);
393 
394   // Clean up
395   tiledb_array_free(&array);
396 
397   remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
398 }
399 
400 TEST_CASE_METHOD(
401     ArrayFx, "C API: Set null URI", "[capi][array][array-null-uri]") {
402   // Create context
403   tiledb_array_t* array;
404   int rc = tiledb_array_alloc(ctx_, nullptr, &array);
405   CHECK(rc == TILEDB_ERR);
406 }
407 
408 TEST_CASE_METHOD(
409     ArrayFx, "C API: Set invalid URI", "[capi][array][array-invalid-uri]") {
410   std::string array_name = "this_is_not_a_valid_array_uri";
411   tiledb_array_t* array;
412   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
413   CHECK(rc == TILEDB_OK);
414   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
415   CHECK(rc == TILEDB_ERR);
416   int is_open;
417   rc = tiledb_array_is_open(ctx_, array, &is_open);
418   REQUIRE(rc == TILEDB_OK);
419   REQUIRE(is_open == 0);
420   tiledb_array_free(&array);
421 }
422 
423 TEST_CASE_METHOD(
424     ArrayFx, "C API: Test array with encryption", "[capi][array][encryption]") {
425   // Create array schema
426   tiledb_array_schema_t* array_schema;
427   int rc = tiledb_array_schema_alloc(ctx_, TILEDB_SPARSE, &array_schema);
428   REQUIRE(rc == TILEDB_OK);
429 
430   // Create dimensions
431   tiledb_dimension_t* d1;
432   const int64_t d1_domain[2] = {0, 99};
433   const int64_t tile_extent[1] = {10};
434   rc = tiledb_dimension_alloc(
435       ctx_, "", TILEDB_INT64, &d1_domain[0], &tile_extent[0], &d1);
436   REQUIRE(rc == TILEDB_OK);
437 
438   // Set domain
439   tiledb_domain_t* domain;
440   rc = tiledb_domain_alloc(ctx_, &domain);
441   REQUIRE(rc == TILEDB_OK);
442   rc = tiledb_domain_add_dimension(ctx_, domain, d1);
443   REQUIRE(rc == TILEDB_OK);
444   rc = tiledb_array_schema_set_domain(ctx_, array_schema, domain);
445   REQUIRE(rc == TILEDB_OK);
446 
447   // Set attribute
448   tiledb_attribute_t* attr1;
449   rc = tiledb_attribute_alloc(ctx_, "foo", TILEDB_INT32, &attr1);
450   REQUIRE(rc == TILEDB_OK);
451   rc = tiledb_attribute_set_cell_val_num(ctx_, attr1, TILEDB_VAR_NUM);
452   REQUIRE(rc == TILEDB_OK);
453   rc = tiledb_array_schema_add_attribute(ctx_, array_schema, attr1);
454   REQUIRE(rc == TILEDB_OK);
455 
456   // Set schema members
457   rc = tiledb_array_schema_set_capacity(ctx_, array_schema, 500);
458   REQUIRE(rc == TILEDB_OK);
459   rc = tiledb_array_schema_set_cell_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
460   REQUIRE(rc == TILEDB_OK);
461   rc = tiledb_array_schema_set_tile_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
462   REQUIRE(rc == TILEDB_OK);
463 
464   // Instantiate local class
465   SupportedFsLocal local_fs;
466 
467   // Check for invalid array schema
468   rc = tiledb_array_schema_check(ctx_, array_schema);
469   REQUIRE(rc == TILEDB_OK);
470 
471   std::string array_name =
472       local_fs.file_prefix() + local_fs.temp_dir() + "encrypyted_array";
473   create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
474 
475   SECTION("- API calls with encrypted schema") {
476     const char key[] = "0123456789abcdeF0123456789abcdeF";
477     uint32_t key_len = (uint32_t)strlen(key);
478 
479     // Check error with invalid key length
480     tiledb_config_t* cfg;
481     tiledb_error_t* err = nullptr;
482     rc = tiledb_config_alloc(&cfg, &err);
483     REQUIRE(rc == TILEDB_OK);
484     REQUIRE(err == nullptr);
485     rc = tiledb_config_set(cfg, "sm.encryption_type", "AES_256_GCM", &err);
486     REQUIRE(err == nullptr);
487     rc = tiledb_config_set(cfg, "sm.encryption_key", key, &err);
488     REQUIRE(rc == TILEDB_OK);
489     REQUIRE(err == nullptr);
490     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(31);
491     tiledb_ctx_t* ctx_invalid_key_len_1;
492     tiledb_vfs_t* vfs_invalid_key_len_1;
493     REQUIRE(vfs_test_init(
494                 fs_vec_, &ctx_invalid_key_len_1, &vfs_invalid_key_len_1, cfg)
495                 .ok());
496     rc = tiledb_array_create(
497         ctx_invalid_key_len_1, array_name.c_str(), array_schema);
498     REQUIRE(rc == TILEDB_ERR);
499     tiledb_ctx_free(&ctx_invalid_key_len_1);
500     tiledb_vfs_free(&vfs_invalid_key_len_1);
501 
502     rc = tiledb_config_set(
503         cfg, "sm.encryption_type", "TILEDB_NO_ENCRYPTION", &err);
504     REQUIRE(err == nullptr);
505     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(
506         key_len);
507     tiledb_ctx_t* ctx_invalid_key_len_2;
508     tiledb_vfs_t* vfs_invalid_key_len_2;
509     REQUIRE(vfs_test_init(
510                 fs_vec_, &ctx_invalid_key_len_2, &vfs_invalid_key_len_2, cfg)
511                 .ok());
512     rc = tiledb_array_create(
513         ctx_invalid_key_len_2, array_name.c_str(), array_schema);
514     REQUIRE(rc == TILEDB_ERR);
515     tiledb_ctx_free(&ctx_invalid_key_len_2);
516     tiledb_vfs_free(&vfs_invalid_key_len_2);
517     // remove the empty array directory
518     remove_temp_dir(array_name);
519 
520     // Create array with proper key
521     rc = tiledb_config_set(cfg, "sm.encryption_type", "AES_256_GCM", &err);
522     REQUIRE(err == nullptr);
523     tiledb_ctx_t* ctx_proper_key;
524     tiledb_vfs_t* vfs_proper_key;
525     REQUIRE(vfs_test_init(fs_vec_, &ctx_proper_key, &vfs_proper_key, cfg).ok());
526     rc = tiledb_array_create(ctx_proper_key, array_name.c_str(), array_schema);
527     REQUIRE(rc == TILEDB_OK);
528     tiledb_ctx_free(&ctx_proper_key);
529     tiledb_vfs_free(&vfs_proper_key);
530 
531     // Clean up
532     tiledb_attribute_free(&attr1);
533     tiledb_dimension_free(&d1);
534     tiledb_domain_free(&domain);
535     tiledb_array_schema_free(&array_schema);
536 
537     // Check getting encryption type
538     tiledb_encryption_type_t enc_type;
539     rc = tiledb_array_encryption_type(ctx_, array_name.c_str(), &enc_type);
540     REQUIRE(rc == TILEDB_OK);
541     REQUIRE(enc_type == TILEDB_AES_256_GCM);
542 
543     // Open array
544     tiledb_array_t* array;
545     rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
546     REQUIRE(rc == TILEDB_OK);
547     // Check error with no key
548     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
549     REQUIRE(rc == TILEDB_ERR);
550     int is_open;
551     rc = tiledb_array_is_open(ctx_, array, &is_open);
552     REQUIRE(rc == TILEDB_OK);
553     REQUIRE(is_open == 0);
554 
555     // Check error with wrong algorithm
556     REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
557     REQUIRE(err == nullptr);
558     rc = tiledb_config_set(cfg, "sm.encryption_type", "NO_ENCRYPTION", &err);
559     REQUIRE(rc == TILEDB_OK);
560     REQUIRE(err == nullptr);
561     rc = tiledb_config_set(cfg, "sm.encryption_key", key, &err);
562     REQUIRE(rc == TILEDB_OK);
563     REQUIRE(err == nullptr);
564     rc = tiledb_array_set_config(ctx_, array, cfg);
565     REQUIRE(rc == TILEDB_OK);
566     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
567     REQUIRE(rc == TILEDB_ERR);
568     rc = tiledb_array_is_open(ctx_, array, &is_open);
569     REQUIRE(rc == TILEDB_OK);
570     REQUIRE(is_open == 0);
571 
572     // Check error with bad key
573     char bad_key[32];
574     rc = tiledb_config_set(cfg, "sm.encryption_type", "AES_256_GCM", &err);
575     REQUIRE(rc == TILEDB_OK);
576     REQUIRE(err == nullptr);
577     rc = tiledb_config_set(cfg, "sm.encryption_key", bad_key, &err);
578     REQUIRE(rc == TILEDB_OK);
579     REQUIRE(err == nullptr);
580     rc = tiledb_array_set_config(ctx_, array, cfg);
581     REQUIRE(rc == TILEDB_OK);
582     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
583     REQUIRE(rc == TILEDB_ERR);
584     rc = tiledb_array_is_open(ctx_, array, &is_open);
585     REQUIRE(rc == TILEDB_OK);
586     REQUIRE(is_open == 0);
587 
588     // Check error with bad key length
589     REQUIRE(
590         tiledb_config_set(cfg, "sm.encryption_key", key, &err) == TILEDB_OK);
591     REQUIRE(err == nullptr);
592     rc = tiledb_array_set_config(ctx_, array, cfg);
593     REQUIRE(rc == TILEDB_OK);
594     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(
595         key_len - 1);
596     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
597     REQUIRE(rc == TILEDB_ERR);
598     rc = tiledb_array_is_open(ctx_, array, &is_open);
599     REQUIRE(rc == TILEDB_OK);
600     REQUIRE(is_open == 0);
601 
602     // Use correct key
603     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(
604         key_len);
605     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
606     REQUIRE(rc == TILEDB_OK);
607     rc = tiledb_array_is_open(ctx_, array, &is_open);
608     REQUIRE(rc == TILEDB_OK);
609     REQUIRE(is_open == 1);
610     tiledb_array_schema_t* read_schema;
611     rc = tiledb_array_get_schema(ctx_, array, &read_schema);
612     REQUIRE(rc == TILEDB_OK);
613     rc = tiledb_config_set(cfg, "sm.encryption_key", bad_key, &err);
614     REQUIRE(rc == TILEDB_OK);
615     REQUIRE(err == nullptr);
616     rc = tiledb_array_set_config(ctx_, array, cfg);
617     REQUIRE(rc == TILEDB_OK);
618 
619     // Opening an already open array without a key should fail
620     tiledb_array_t* array2;
621     rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array2);
622     REQUIRE(rc == TILEDB_OK);
623     rc = tiledb_array_open(ctx_, array2, TILEDB_READ);
624     REQUIRE(rc == TILEDB_ERR);
625 
626     // Opening an array with a bad key should fail
627     rc = tiledb_array_set_config(ctx_, array2, cfg);
628     REQUIRE(rc == TILEDB_OK);
629     rc = tiledb_array_open(ctx_, array2, TILEDB_READ);
630     REQUIRE(rc == TILEDB_ERR);
631 
632     // Check reopening works
633     rc = tiledb_array_reopen(ctx_, array);
634     REQUIRE(rc == TILEDB_OK);
635 
636     // Close arrays
637     rc = tiledb_array_close(ctx_, array2);
638     REQUIRE(rc == TILEDB_OK);
639     rc = tiledb_array_close(ctx_, array);
640     REQUIRE(rc == TILEDB_OK);
641 
642     // Check loading schema requires key
643     tiledb_array_schema_free(&read_schema);
644     rc = tiledb_array_schema_load(ctx_, array_name.c_str(), &read_schema);
645     REQUIRE(rc == TILEDB_ERR);
646     // Check with bad key
647     rc = tiledb_config_set(cfg, "sm.encryption_type", "AES_256_GCM", &err);
648     REQUIRE(err == nullptr);
649     rc = tiledb_config_set(cfg, "sm.encryption_key", bad_key, &err);
650     REQUIRE(rc == TILEDB_OK);
651     REQUIRE(err == nullptr);
652     tiledb_ctx_t* ctx_bad_key;
653     tiledb_vfs_t* vfs_bad_key;
654     REQUIRE(vfs_test_init(fs_vec_, &ctx_bad_key, &vfs_bad_key, cfg).ok());
655     rc =
656         tiledb_array_schema_load(ctx_bad_key, array_name.c_str(), &read_schema);
657     REQUIRE(rc == TILEDB_ERR);
658     tiledb_ctx_free(&ctx_bad_key);
659     tiledb_vfs_free(&vfs_bad_key);
660     // Check with correct key
661     rc = tiledb_config_set(cfg, "sm.encryption_type", "AES_256_GCM", &err);
662     REQUIRE(err == nullptr);
663     rc = tiledb_config_set(cfg, "sm.encryption_key", key, &err);
664     REQUIRE(rc == TILEDB_OK);
665     REQUIRE(err == nullptr);
666     tiledb_ctx_t* ctx_correct_key;
667     tiledb_vfs_t* vfs_correct_key;
668     REQUIRE(
669         vfs_test_init(fs_vec_, &ctx_correct_key, &vfs_correct_key, cfg).ok());
670     rc = tiledb_array_schema_load(
671         ctx_correct_key, array_name.c_str(), &read_schema);
672     REQUIRE(rc == TILEDB_OK);
673     tiledb_ctx_free(&ctx_correct_key);
674     tiledb_vfs_free(&vfs_correct_key);
675 
676     // Check opening after closing still requires a key.
677     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
678     REQUIRE(rc == TILEDB_ERR);
679     rc = tiledb_array_is_open(ctx_, array, &is_open);
680     REQUIRE(rc == TILEDB_OK);
681     REQUIRE(is_open == 0);
682     rc = tiledb_config_set(cfg, "sm.encryption_key", bad_key, &err);
683     REQUIRE(rc == TILEDB_OK);
684     REQUIRE(err == nullptr);
685     rc = tiledb_array_set_config(ctx_, array, cfg);
686     REQUIRE(rc == TILEDB_OK);
687     rc = tiledb_array_set_config(ctx_, array, cfg);
688     REQUIRE(rc == TILEDB_OK);
689     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
690     REQUIRE(rc == TILEDB_ERR);
691     rc = tiledb_array_is_open(ctx_, array, &is_open);
692     REQUIRE(rc == TILEDB_OK);
693     REQUIRE(is_open == 0);
694     rc = tiledb_config_set(cfg, "sm.encryption_key", key, &err);
695     REQUIRE(rc == TILEDB_OK);
696     REQUIRE(err == nullptr);
697     rc = tiledb_array_set_config(ctx_, array, cfg);
698     REQUIRE(rc == TILEDB_OK);
699     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
700     REQUIRE(rc == TILEDB_OK);
701     rc = tiledb_array_is_open(ctx_, array, &is_open);
702     REQUIRE(rc == TILEDB_OK);
703     REQUIRE(is_open == 1);
704     rc = tiledb_array_close(ctx_, array);
705     REQUIRE(rc == TILEDB_OK);
706 
707     // Clean up
708     tiledb_array_schema_free(&read_schema);
709     tiledb_array_free(&array);
710     tiledb_array_free(&array2);
711     tiledb_config_free(&cfg);
712     remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
713   }
714 
715   SECTION("- API calls with unencrypted schema") {
716     // Check for invalid array schema
717     rc = tiledb_array_schema_check(ctx_, array_schema);
718     REQUIRE(rc == TILEDB_OK);
719 
720     // Check create ok with null key
721     tiledb_config_t* cfg;
722     tiledb_error_t* err = nullptr;
723     rc = tiledb_config_alloc(&cfg, &err);
724     REQUIRE(rc == TILEDB_OK);
725     REQUIRE(err == nullptr);
726     tiledb_ctx_t* ctx_null_key;
727     tiledb_vfs_t* vfs_null_key;
728     rc = tiledb_config_set(cfg, "sm.encryption_key", "", &err);
729     REQUIRE(rc == TILEDB_OK);
730     REQUIRE(err == nullptr);
731     REQUIRE(vfs_test_init(fs_vec_, &ctx_null_key, &vfs_null_key, cfg).ok());
732     rc = tiledb_array_create(ctx_, array_name.c_str(), array_schema);
733     REQUIRE(rc == TILEDB_OK);
734     tiledb_ctx_free(&ctx_null_key);
735     tiledb_vfs_free(&vfs_null_key);
736 
737     // Clean up
738     tiledb_attribute_free(&attr1);
739     tiledb_dimension_free(&d1);
740     tiledb_domain_free(&domain);
741     tiledb_array_schema_free(&array_schema);
742 
743     // Check getting encryption type
744     tiledb_encryption_type_t enc_type;
745     rc = tiledb_array_encryption_type(ctx_, array_name.c_str(), &enc_type);
746     REQUIRE(rc == TILEDB_OK);
747     REQUIRE(enc_type == TILEDB_NO_ENCRYPTION);
748 
749     // Open array
750     tiledb_array_t* array;
751     rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
752     REQUIRE(rc == TILEDB_OK);
753     // Check error with key
754     const char key[] = "0123456789abcdeF0123456789abcdeF";
755     rc = tiledb_config_set(cfg, "sm.encryption_type", "AES_256_GCM", &err);
756     REQUIRE(rc == TILEDB_OK);
757     REQUIRE(err == nullptr);
758     rc = tiledb_config_set(cfg, "sm.encryption_key", key, &err);
759     REQUIRE(rc == TILEDB_OK);
760     REQUIRE(err == nullptr);
761     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.reset();
762     rc = tiledb_array_set_config(ctx_, array, cfg);
763     REQUIRE(rc == TILEDB_OK);
764     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
765     REQUIRE(rc == TILEDB_ERR);
766     int is_open;
767     rc = tiledb_array_is_open(ctx_, array, &is_open);
768     REQUIRE(rc == TILEDB_OK);
769     REQUIRE(is_open == 0);
770 
771     // Check ok with null key
772     rc = tiledb_config_set(cfg, "sm.encryption_type", "NO_ENCRYPTION", &err);
773     REQUIRE(rc == TILEDB_OK);
774     REQUIRE(err == nullptr);
775     rc = tiledb_config_set(cfg, "sm.encryption_key", "0", &err);
776     REQUIRE(rc == TILEDB_OK);
777     REQUIRE(err == nullptr);
778     rc = tiledb_array_set_config(ctx_, array, cfg);
779     REQUIRE(rc == TILEDB_OK);
780     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(0);
781     rc = tiledb_array_open(ctx_, array, TILEDB_READ);
782     REQUIRE(rc == TILEDB_OK);
783     rc = tiledb_array_is_open(ctx_, array, &is_open);
784     REQUIRE(rc == TILEDB_OK);
785     REQUIRE(is_open == 1);
786     tiledb_array_schema_t* read_schema;
787     rc = tiledb_array_get_schema(ctx_, array, &read_schema);
788     REQUIRE(rc == TILEDB_OK);
789 
790     rc = tiledb_array_close(ctx_, array);
791     REQUIRE(rc == TILEDB_OK);
792 
793     // Check loading schema with key is error
794     tiledb_array_schema_free(&read_schema);
795     rc = tiledb_config_set(cfg, "sm.encryption_type", "AES_256_GCM", &err);
796     REQUIRE(err == nullptr);
797     rc = tiledb_config_set(cfg, "sm.encryption_key", key, &err);
798     REQUIRE(rc == TILEDB_OK);
799     REQUIRE(err == nullptr);
800     tiledb_ctx_t* ctx_schema;
801     tiledb_vfs_t* vfs_schema;
802     REQUIRE(vfs_test_init(fs_vec_, &ctx_schema, &vfs_schema, cfg).ok());
803     rc = tiledb_array_schema_load(ctx_schema, array_name.c_str(), &read_schema);
804     REQUIRE(rc == TILEDB_ERR);
805     tiledb_ctx_free(&ctx_schema);
806     tiledb_vfs_free(&vfs_schema);
807 
808     // Check ok with nullptr
809     rc = tiledb_config_set(cfg, "sm.encryption_key", "", &err);
810     REQUIRE(rc == TILEDB_OK);
811     REQUIRE(err == nullptr);
812     tiledb_ctx_t* ctx_nullptr;
813     tiledb_vfs_t* vfs_nullptr;
814     REQUIRE(vfs_test_init(fs_vec_, &ctx_nullptr, &vfs_nullptr, cfg).ok());
815     rc = tiledb_array_schema_load(ctx_, array_name.c_str(), &read_schema);
816     REQUIRE(rc == TILEDB_OK);
817     tiledb_ctx_free(&ctx_nullptr);
818     tiledb_vfs_free(&vfs_nullptr);
819 
820     // Clean up
821     tiledb_array_schema_free(&read_schema);
822     tiledb_array_free(&array);
823     tiledb_config_free(&cfg);
824     remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
825   }
826 }
827 
828 TEST_CASE_METHOD(
829     ArrayFx,
830     "C API: Test opening array at timestamp, reads",
831     "[capi][array][open-at][reads]") {
832   // TODO: refactor for each supported FS.
833   std::string temp_dir = fs_vec_[0]->temp_dir();
834 
835   std::string array_name = temp_dir + "array-open-at-reads";
836   SECTION("- without encryption") {
837     encryption_type_ = TILEDB_NO_ENCRYPTION;
838     encryption_key_ = nullptr;
839   }
840 
841   SECTION("- with encryption") {
842     encryption_type_ = TILEDB_AES_256_GCM;
843     encryption_key_ = "0123456789abcdeF0123456789abcdeF";
844   }
845 
846   create_temp_dir(temp_dir);
847 
848   create_dense_vector(array_name);
849 
850   // ---- FIRST WRITE ----
851   // Prepare cell buffers
852   int buffer_a1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
853   uint64_t buffer_a1_size = sizeof(buffer_a1);
854 
855   // Open array
856   tiledb_array_t* array;
857   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
858   CHECK(rc == TILEDB_OK);
859   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
860     tiledb_config_t* cfg;
861     tiledb_error_t* err = nullptr;
862     rc = tiledb_config_alloc(&cfg, &err);
863     CHECK(rc == TILEDB_OK);
864     REQUIRE(err == nullptr);
865     std::string encryption_type_string =
866         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
867     rc = tiledb_config_set(
868         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
869     CHECK(rc == TILEDB_OK);
870     REQUIRE(err == nullptr);
871     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
872     CHECK(rc == TILEDB_OK);
873     REQUIRE(err == nullptr);
874     rc = tiledb_array_set_config(ctx_, array, cfg);
875     CHECK(rc == TILEDB_OK);
876     tiledb_config_free(&cfg);
877     uint32_t key_len = (uint32_t)strlen(encryption_key_);
878     tiledb::sm::UnitTestConfig::instance().array_encryption_key_length.set(
879         key_len);
880   }
881   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
882   CHECK(rc == TILEDB_OK);
883 
884   // Submit query
885   tiledb_query_t* query;
886   rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
887   CHECK(rc == TILEDB_OK);
888   rc = tiledb_query_set_layout(ctx_, query, TILEDB_GLOBAL_ORDER);
889   CHECK(rc == TILEDB_OK);
890   rc = tiledb_query_set_data_buffer(
891       ctx_, query, "a", buffer_a1, &buffer_a1_size);
892   CHECK(rc == TILEDB_OK);
893   rc = tiledb_query_submit(ctx_, query);
894   CHECK(rc == TILEDB_OK);
895   rc = tiledb_query_finalize(ctx_, query);
896   CHECK(rc == TILEDB_OK);
897 
898   // Close array and clean up
899   rc = tiledb_array_close(ctx_, array);
900   CHECK(rc == TILEDB_OK);
901   tiledb_array_free(&array);
902   tiledb_query_free(&query);
903 
904   // ---- UPDATE ----
905   int buffer_upd[] = {50, 60, 70};
906   uint64_t buffer_upd_size = sizeof(buffer_upd);
907   int64_t subarray[] = {5, 7};
908 
909   // Open array
910   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
911   CHECK(rc == TILEDB_OK);
912   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
913     tiledb_config_t* cfg;
914     tiledb_error_t* err = nullptr;
915     rc = tiledb_config_alloc(&cfg, &err);
916     CHECK(rc == TILEDB_OK);
917     REQUIRE(err == nullptr);
918     std::string encryption_type_string =
919         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
920     rc = tiledb_config_set(
921         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
922     CHECK(rc == TILEDB_OK);
923     REQUIRE(err == nullptr);
924     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
925     CHECK(rc == TILEDB_OK);
926     REQUIRE(err == nullptr);
927     rc = tiledb_array_set_config(ctx_, array, cfg);
928     CHECK(rc == TILEDB_OK);
929     tiledb_config_free(&cfg);
930   }
931   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
932   CHECK(rc == TILEDB_OK);
933 
934   // Submit query
935   rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
936   CHECK(rc == TILEDB_OK);
937   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
938   CHECK(rc == TILEDB_OK);
939   rc = tiledb_query_set_subarray(ctx_, query, subarray);
940   CHECK(rc == TILEDB_OK);
941   rc = tiledb_query_set_data_buffer(
942       ctx_, query, "a", buffer_upd, &buffer_upd_size);
943   CHECK(rc == TILEDB_OK);
944   rc = tiledb_query_submit(ctx_, query);
945   CHECK(rc == TILEDB_OK);
946 
947   // Close array and clean up
948   rc = tiledb_array_close(ctx_, array);
949   CHECK(rc == TILEDB_OK);
950   tiledb_array_free(&array);
951   tiledb_query_free(&query);
952 
953   std::vector<uint64_t> fragment_timestamps;
954   rc = tiledb_vfs_ls(
955       ctx_,
956       vfs_,
957       array_name.c_str(),
958       &get_fragment_timestamps,
959       &fragment_timestamps);
960   CHECK(rc == TILEDB_OK);
961 
962   // ---- NORMAL READ ----
963   int buffer_read[10];
964   uint64_t buffer_read_size = sizeof(buffer_read);
965 
966   // Open array
967   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
968   CHECK(rc == TILEDB_OK);
969   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
970     tiledb_config_t* cfg;
971     tiledb_error_t* err = nullptr;
972     rc = tiledb_config_alloc(&cfg, &err);
973     CHECK(rc == TILEDB_OK);
974     REQUIRE(err == nullptr);
975     std::string encryption_type_string =
976         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
977     rc = tiledb_config_set(
978         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
979     CHECK(rc == TILEDB_OK);
980     REQUIRE(err == nullptr);
981     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
982     CHECK(rc == TILEDB_OK);
983     REQUIRE(err == nullptr);
984     rc = tiledb_array_set_config(ctx_, array, cfg);
985     CHECK(rc == TILEDB_OK);
986     tiledb_config_free(&cfg);
987   }
988   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
989   CHECK(rc == TILEDB_OK);
990 
991   // Submit query
992   int64_t subarray_read[] = {1, 10};
993   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
994   CHECK(rc == TILEDB_OK);
995   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
996   CHECK(rc == TILEDB_OK);
997   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
998   CHECK(rc == TILEDB_OK);
999   rc = tiledb_query_set_data_buffer(
1000       ctx_, query, "a", buffer_read, &buffer_read_size);
1001   CHECK(rc == TILEDB_OK);
1002   rc = tiledb_query_submit(ctx_, query);
1003   CHECK(rc == TILEDB_OK);
1004 
1005   // Close array and clean up
1006   rc = tiledb_array_close(ctx_, array);
1007   CHECK(rc == TILEDB_OK);
1008   tiledb_array_free(&array);
1009   tiledb_query_free(&query);
1010 
1011   // Check correctness
1012   int32_t buffer_read_c[] = {1, 2, 3, 4, 50, 60, 70, 8, 9, 10};
1013   CHECK(!std::memcmp(buffer_read, buffer_read_c, sizeof(buffer_read_c)));
1014   CHECK(buffer_read_size == sizeof(buffer_read_c));
1015 
1016   // ---- READ AT ZERO TIMESTAMP ----
1017 
1018   tiledb_config_t* cfg;
1019   tiledb_error_t* err = nullptr;
1020   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1021   CHECK(rc == TILEDB_OK);
1022   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1023   REQUIRE(err == nullptr);
1024   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 0);
1025   REQUIRE(rc == TILEDB_OK);
1026 
1027   // Open array
1028   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1029     std::string encryption_type_string =
1030         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1031     rc = tiledb_config_set(
1032         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1033     CHECK(rc == TILEDB_OK);
1034     REQUIRE(err == nullptr);
1035     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1036     CHECK(rc == TILEDB_OK);
1037     REQUIRE(err == nullptr);
1038     rc = tiledb_array_set_config(ctx_, array, cfg);
1039     CHECK(rc == TILEDB_OK);
1040   }
1041   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1042   CHECK(rc == TILEDB_OK);
1043 
1044   // Check timestamp
1045   uint64_t timestamp_get;
1046   rc = tiledb_array_get_open_timestamp_end(ctx_, array, &timestamp_get);
1047   CHECK(rc == TILEDB_OK);
1048   CHECK(timestamp_get == 0);
1049 
1050   // Submit query
1051   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1052   CHECK(rc == TILEDB_OK);
1053   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1054   CHECK(rc == TILEDB_OK);
1055   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1056   CHECK(rc == TILEDB_OK);
1057   rc = tiledb_query_set_data_buffer(
1058       ctx_, query, "a", buffer_read, &buffer_read_size);
1059   CHECK(rc == TILEDB_OK);
1060   rc = tiledb_query_submit(ctx_, query);
1061   CHECK(rc == TILEDB_OK);
1062 
1063   // Close array and clean up
1064   rc = tiledb_array_close(ctx_, array);
1065   CHECK(rc == TILEDB_OK);
1066   tiledb_array_free(&array);
1067   tiledb_query_free(&query);
1068   tiledb_config_free(&cfg);
1069 
1070   // Check correctness
1071   // Empty array still returns fill values
1072   CHECK(buffer_read_size == 10 * sizeof(int32_t));
1073 
1074   // ---- READ AT TIMESTAMP BEFORE UPDATE ----
1075   buffer_read_size = sizeof(buffer_read);
1076 
1077   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1078   CHECK(rc == TILEDB_OK);
1079   rc = tiledb_array_set_open_timestamp_end(ctx_, array, fragment_timestamps[0]);
1080   REQUIRE(rc == TILEDB_OK);
1081 
1082   // Open array
1083   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1084   REQUIRE(err == nullptr);
1085   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1086     std::string encryption_type_string =
1087         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1088     rc = tiledb_config_set(
1089         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1090     CHECK(rc == TILEDB_OK);
1091     REQUIRE(err == nullptr);
1092     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1093     CHECK(rc == TILEDB_OK);
1094     REQUIRE(err == nullptr);
1095     rc = tiledb_array_set_config(ctx_, array, cfg);
1096     CHECK(rc == TILEDB_OK);
1097   }
1098   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1099   CHECK(rc == TILEDB_OK);
1100 
1101   // Submit query
1102   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1103   CHECK(rc == TILEDB_OK);
1104   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1105   CHECK(rc == TILEDB_OK);
1106   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1107   CHECK(rc == TILEDB_OK);
1108   rc = tiledb_query_set_data_buffer(
1109       ctx_, query, "a", buffer_read, &buffer_read_size);
1110   CHECK(rc == TILEDB_OK);
1111   rc = tiledb_query_submit(ctx_, query);
1112   CHECK(rc == TILEDB_OK);
1113 
1114   // Close array and clean up
1115   rc = tiledb_array_close(ctx_, array);
1116   CHECK(rc == TILEDB_OK);
1117   tiledb_array_free(&array);
1118   tiledb_query_free(&query);
1119   tiledb_config_free(&cfg);
1120 
1121   // Check correctness
1122   int buffer_read_at_c[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1123   CHECK(!std::memcmp(buffer_read, buffer_read_at_c, sizeof(buffer_read_at_c)));
1124   CHECK(buffer_read_size == sizeof(buffer_read_at_c));
1125 
1126   // ---- READ AT LATER TIMESTAMP ----
1127   // Open array
1128   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1129   CHECK(rc == TILEDB_OK);
1130 
1131   rc = tiledb_array_set_open_timestamp_end(ctx_, array, fragment_timestamps[1]);
1132   REQUIRE(rc == TILEDB_OK);
1133 
1134   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1135   REQUIRE(err == nullptr);
1136   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1137     std::string encryption_type_string =
1138         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1139     rc = tiledb_config_set(
1140         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1141     CHECK(rc == TILEDB_OK);
1142     REQUIRE(err == nullptr);
1143     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1144     CHECK(rc == TILEDB_OK);
1145     REQUIRE(err == nullptr);
1146     rc = tiledb_array_set_config(ctx_, array, cfg);
1147     CHECK(rc == TILEDB_OK);
1148   }
1149 
1150   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1151   CHECK(rc == TILEDB_OK);
1152 
1153   // Check timestamp
1154   rc = tiledb_array_get_open_timestamp_end(ctx_, array, &timestamp_get);
1155   CHECK(rc == TILEDB_OK);
1156   CHECK(timestamp_get == fragment_timestamps[1]);
1157 
1158   // Submit query
1159   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1160   CHECK(rc == TILEDB_OK);
1161   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1162   CHECK(rc == TILEDB_OK);
1163   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1164   CHECK(rc == TILEDB_OK);
1165   rc = tiledb_query_set_data_buffer(
1166       ctx_, query, "a", buffer_read, &buffer_read_size);
1167   CHECK(rc == TILEDB_OK);
1168   rc = tiledb_query_submit(ctx_, query);
1169   CHECK(rc == TILEDB_OK);
1170 
1171   // Clean up but don't close the array yet (we will reopen it).
1172   tiledb_query_free(&query);
1173   tiledb_config_free(&cfg);
1174 
1175   // Check correctness
1176   CHECK(!std::memcmp(buffer_read, buffer_read_c, sizeof(buffer_read_c)));
1177   CHECK(buffer_read_size == sizeof(buffer_read_c));
1178 
1179   // ---- REOPEN AT FIRST TIMESTAMP ----
1180   buffer_read_size = sizeof(buffer_read);
1181 
1182   rc = tiledb_array_set_open_timestamp_end(
1183       ctx_, array, fragment_timestamps[1] - 1);
1184   REQUIRE(rc == TILEDB_OK);
1185 
1186   rc = tiledb_array_reopen(ctx_, array);
1187   CHECK(rc == TILEDB_OK);
1188 
1189   // Submit query
1190   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1191   CHECK(rc == TILEDB_OK);
1192   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1193   CHECK(rc == TILEDB_OK);
1194   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1195   CHECK(rc == TILEDB_OK);
1196   rc = tiledb_query_set_data_buffer(
1197       ctx_, query, "a", buffer_read, &buffer_read_size);
1198   CHECK(rc == TILEDB_OK);
1199   rc = tiledb_query_submit(ctx_, query);
1200   CHECK(rc == TILEDB_OK);
1201 
1202   // Clean up but don't close the array yet (we will reopen it).
1203   tiledb_query_free(&query);
1204 
1205   // Check correctness
1206   int buffer_read_reopen_c[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1207   CHECK(!std::memcmp(
1208       buffer_read, buffer_read_reopen_c, sizeof(buffer_read_reopen_c)));
1209   CHECK(buffer_read_size == sizeof(buffer_read_reopen_c));
1210 
1211   // ---- REOPEN STARTING AT FIRST TIMESTAMP ----
1212   buffer_read_size = sizeof(buffer_read);
1213 
1214   // Reopen array
1215   rc = tiledb_array_set_open_timestamp_start(
1216       ctx_, array, fragment_timestamps[0] + 1);
1217   REQUIRE(rc == TILEDB_OK);
1218   rc = tiledb_array_set_open_timestamp_end(ctx_, array, UINT64_MAX);
1219   REQUIRE(rc == TILEDB_OK);
1220   rc = tiledb_array_reopen(ctx_, array);
1221   CHECK(rc == TILEDB_OK);
1222 
1223   // Submit query
1224   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1225   CHECK(rc == TILEDB_OK);
1226   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1227   CHECK(rc == TILEDB_OK);
1228   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1229   CHECK(rc == TILEDB_OK);
1230   rc = tiledb_query_set_data_buffer(
1231       ctx_, query, "a", buffer_read, &buffer_read_size);
1232   CHECK(rc == TILEDB_OK);
1233   rc = tiledb_query_submit(ctx_, query);
1234   CHECK(rc == TILEDB_OK);
1235 
1236   // Close array and clean up
1237   rc = tiledb_array_close(ctx_, array);
1238   CHECK(rc == TILEDB_OK);
1239   tiledb_query_free(&query);
1240   tiledb_array_free(&array);
1241 
1242   // Check correctness
1243   int buffer_read_reopen_start_c[] = {INT_MIN,
1244                                       INT_MIN,
1245                                       INT_MIN,
1246                                       INT_MIN,
1247                                       50,
1248                                       60,
1249                                       70,
1250                                       INT_MIN,
1251                                       INT_MIN,
1252                                       INT_MIN};
1253   CHECK(!std::memcmp(
1254       buffer_read,
1255       buffer_read_reopen_start_c,
1256       sizeof(buffer_read_reopen_start_c)));
1257   CHECK(buffer_read_size == sizeof(buffer_read_reopen_start_c));
1258 
1259   // ---- OPEN STARTING AT FIRST TIMESTAMP ----
1260   buffer_read_size = sizeof(buffer_read);
1261 
1262   // Open array
1263   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1264   CHECK(rc == TILEDB_OK);
1265   rc = tiledb_array_set_open_timestamp_start(
1266       ctx_, array, fragment_timestamps[1]);
1267   REQUIRE(rc == TILEDB_OK);
1268   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1269   REQUIRE(err == nullptr);
1270   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1271     std::string encryption_type_string =
1272         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1273     rc = tiledb_config_set(
1274         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1275     CHECK(rc == TILEDB_OK);
1276     REQUIRE(err == nullptr);
1277     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1278     CHECK(rc == TILEDB_OK);
1279     REQUIRE(err == nullptr);
1280     rc = tiledb_array_set_config(ctx_, array, cfg);
1281     CHECK(rc == TILEDB_OK);
1282   }
1283   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1284   CHECK(rc == TILEDB_OK);
1285 
1286   // Submit query
1287   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1288   CHECK(rc == TILEDB_OK);
1289   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1290   CHECK(rc == TILEDB_OK);
1291   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1292   CHECK(rc == TILEDB_OK);
1293   rc = tiledb_query_set_data_buffer(
1294       ctx_, query, "a", buffer_read, &buffer_read_size);
1295   CHECK(rc == TILEDB_OK);
1296   rc = tiledb_query_submit(ctx_, query);
1297   CHECK(rc == TILEDB_OK);
1298 
1299   // Close array and clean up
1300   rc = tiledb_array_close(ctx_, array);
1301   CHECK(rc == TILEDB_OK);
1302   tiledb_query_free(&query);
1303   tiledb_array_free(&array);
1304   tiledb_config_free(&cfg);
1305 
1306   // Check correctness
1307   // Check correctness
1308   int buffer_read_open_start_c[] = {INT_MIN,
1309                                     INT_MIN,
1310                                     INT_MIN,
1311                                     INT_MIN,
1312                                     50,
1313                                     60,
1314                                     70,
1315                                     INT_MIN,
1316                                     INT_MIN,
1317                                     INT_MIN};
1318   CHECK(!std::memcmp(
1319       buffer_read, buffer_read_open_start_c, sizeof(buffer_read_open_start_c)));
1320   CHECK(buffer_read_size == sizeof(buffer_read_open_start_c));
1321 
1322   // ---- OPEN STARTING AT PAST LAST TIMESTAMP ----
1323   buffer_read_size = sizeof(buffer_read);
1324 
1325   // Open array
1326   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1327   CHECK(rc == TILEDB_OK);
1328   rc = tiledb_array_set_open_timestamp_start(
1329       ctx_, array, fragment_timestamps[1] + 1);
1330   REQUIRE(rc == TILEDB_OK);
1331   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1332   REQUIRE(err == nullptr);
1333   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1334     std::string encryption_type_string =
1335         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1336     rc = tiledb_config_set(
1337         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1338     CHECK(rc == TILEDB_OK);
1339     REQUIRE(err == nullptr);
1340     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1341     CHECK(rc == TILEDB_OK);
1342     REQUIRE(err == nullptr);
1343     rc = tiledb_array_set_config(ctx_, array, cfg);
1344     CHECK(rc == TILEDB_OK);
1345   }
1346   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1347   CHECK(rc == TILEDB_OK);
1348 
1349   // Submit query
1350   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1351   CHECK(rc == TILEDB_OK);
1352   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1353   CHECK(rc == TILEDB_OK);
1354   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1355   CHECK(rc == TILEDB_OK);
1356   rc = tiledb_query_set_data_buffer(
1357       ctx_, query, "a", buffer_read, &buffer_read_size);
1358   CHECK(rc == TILEDB_OK);
1359   rc = tiledb_query_submit(ctx_, query);
1360   CHECK(rc == TILEDB_OK);
1361 
1362   // Close array and clean up
1363   rc = tiledb_array_close(ctx_, array);
1364   CHECK(rc == TILEDB_OK);
1365   tiledb_query_free(&query);
1366   tiledb_array_free(&array);
1367   tiledb_config_free(&cfg);
1368 
1369   // Check correctness
1370   int buffer_read_open_start_now_c[] = {INT_MIN,
1371                                         INT_MIN,
1372                                         INT_MIN,
1373                                         INT_MIN,
1374                                         INT_MIN,
1375                                         INT_MIN,
1376                                         INT_MIN,
1377                                         INT_MIN,
1378                                         INT_MIN,
1379                                         INT_MIN};
1380   CHECK(!std::memcmp(
1381       buffer_read,
1382       buffer_read_open_start_now_c,
1383       sizeof(buffer_read_open_start_now_c)));
1384   CHECK(buffer_read_size == sizeof(buffer_read_open_start_now_c));
1385 
1386   remove_temp_dir(temp_dir);
1387 }
1388 
1389 TEST_CASE_METHOD(
1390     ArrayFx,
1391     "C API: Test opening array at timestamp, writes",
1392     "[capi][array][open-at][writes]") {
1393   // TODO: refactor for each supported FS.
1394   std::string temp_dir = fs_vec_[0]->temp_dir();
1395 
1396   std::string array_name = temp_dir + "array-open-at-writes";
1397   SECTION("- without encryption") {
1398     encryption_type_ = TILEDB_NO_ENCRYPTION;
1399     encryption_key_ = nullptr;
1400   }
1401 
1402   SECTION("- with encryption") {
1403     encryption_type_ = TILEDB_AES_256_GCM;
1404     encryption_key_ = "0123456789abcdeF0123456789abcdeF";
1405   }
1406 
1407   create_temp_dir(temp_dir);
1408 
1409   create_dense_vector(array_name);
1410 
1411   // ---- WRITE ----
1412   // Prepare cell buffers
1413   int buffer_a1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1414   uint64_t buffer_a1_size = sizeof(buffer_a1);
1415 
1416   // Some timestamp, it could be anything
1417   uint64_t timestamp = 1000;
1418 
1419   tiledb_array_t* array;
1420   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1421   CHECK(rc == TILEDB_OK);
1422   tiledb_config_t* cfg = nullptr;
1423   tiledb_error_t* err = nullptr;
1424   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1425   REQUIRE(err == nullptr);
1426 
1427   rc = tiledb_array_set_open_timestamp_end(ctx_, array, timestamp);
1428   REQUIRE(rc == TILEDB_OK);
1429 
1430   // Open array
1431   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1432     std::string encryption_type_string =
1433         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1434     rc = tiledb_config_set(
1435         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1436     CHECK(rc == TILEDB_OK);
1437     REQUIRE(err == nullptr);
1438     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1439     CHECK(rc == TILEDB_OK);
1440     REQUIRE(err == nullptr);
1441     rc = tiledb_array_set_config(ctx_, array, cfg);
1442     CHECK(rc == TILEDB_OK);
1443   }
1444   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1445   CHECK(rc == TILEDB_OK);
1446 
1447   // Submit query
1448   tiledb_query_t* query;
1449   rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
1450   CHECK(rc == TILEDB_OK);
1451   rc = tiledb_query_set_layout(ctx_, query, TILEDB_GLOBAL_ORDER);
1452   CHECK(rc == TILEDB_OK);
1453   rc = tiledb_query_set_data_buffer(
1454       ctx_, query, "a", buffer_a1, &buffer_a1_size);
1455   CHECK(rc == TILEDB_OK);
1456   rc = tiledb_query_submit(ctx_, query);
1457   CHECK(rc == TILEDB_OK);
1458   rc = tiledb_query_finalize(ctx_, query);
1459   CHECK(rc == TILEDB_OK);
1460 
1461   // Get written timestamp
1462   uint64_t timestamp_get;
1463   rc = tiledb_array_get_open_timestamp_end(ctx_, array, &timestamp_get);
1464   CHECK(rc == TILEDB_OK);
1465 
1466   uint64_t t1, t2;
1467   rc = tiledb_query_get_fragment_timestamp_range(ctx_, query, 0, &t1, &t2);
1468   CHECK(rc == TILEDB_OK);
1469   CHECK(timestamp_get == t1);
1470   CHECK(timestamp_get == t2);
1471 
1472   // Close array and clean up
1473   rc = tiledb_array_close(ctx_, array);
1474   CHECK(rc == TILEDB_OK);
1475   tiledb_array_free(&array);
1476   tiledb_query_free(&query);
1477   tiledb_config_free(&cfg);
1478 
1479   // ---- READ AT ZERO TIMESTAMP ----
1480 
1481   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1482   CHECK(rc == TILEDB_OK);
1483   rc = tiledb_array_set_open_timestamp_end(ctx_, array, 0);
1484   REQUIRE(rc == TILEDB_OK);
1485 
1486   // Open array
1487   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1488   REQUIRE(err == nullptr);
1489   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1490     std::string encryption_type_string =
1491         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1492     rc = tiledb_config_set(
1493         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1494     CHECK(rc == TILEDB_OK);
1495     REQUIRE(err == nullptr);
1496     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1497     CHECK(rc == TILEDB_OK);
1498     REQUIRE(err == nullptr);
1499     rc = tiledb_array_set_config(ctx_, array, cfg);
1500     CHECK(rc == TILEDB_OK);
1501   }
1502   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1503   CHECK(rc == TILEDB_OK);
1504 
1505   // Check timestamp
1506   rc = tiledb_array_get_open_timestamp_end(ctx_, array, &timestamp_get);
1507   CHECK(rc == TILEDB_OK);
1508   CHECK(timestamp_get == 0);
1509 
1510   // Submit query
1511   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1512   CHECK(rc == TILEDB_OK);
1513   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1514   CHECK(rc == TILEDB_OK);
1515   int64_t subarray_read[] = {1, 10};
1516   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1517   CHECK(rc == TILEDB_OK);
1518   int buffer_read[10];
1519   uint64_t buffer_read_size = sizeof(buffer_read);
1520   rc = tiledb_query_set_data_buffer(
1521       ctx_, query, "a", buffer_read, &buffer_read_size);
1522   CHECK(rc == TILEDB_OK);
1523   rc = tiledb_query_submit(ctx_, query);
1524   CHECK(rc == TILEDB_OK);
1525 
1526   // Close array and clean up
1527   rc = tiledb_array_close(ctx_, array);
1528   CHECK(rc == TILEDB_OK);
1529   tiledb_array_free(&array);
1530   tiledb_query_free(&query);
1531   tiledb_config_free(&cfg);
1532 
1533   // Check correctness
1534   // Empty array still returns fill values
1535   CHECK(buffer_read_size == 10 * sizeof(int32_t));
1536 
1537   // ---- READ AT THE WRITTEN TIMESTAMP ----
1538   buffer_read_size = sizeof(buffer_read);
1539 
1540   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1541   CHECK(rc == TILEDB_OK);
1542   rc = tiledb_array_set_open_timestamp_end(ctx_, array, timestamp);
1543   REQUIRE(rc == TILEDB_OK);
1544 
1545   // Open array
1546   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1547   REQUIRE(err == nullptr);
1548   if (encryption_type_ != TILEDB_NO_ENCRYPTION) {
1549     std::string encryption_type_string =
1550         encryption_type_str((tiledb::sm::EncryptionType)encryption_type_);
1551     rc = tiledb_config_set(
1552         cfg, "sm.encryption_type", encryption_type_string.c_str(), &err);
1553     CHECK(rc == TILEDB_OK);
1554     REQUIRE(err == nullptr);
1555     rc = tiledb_config_set(cfg, "sm.encryption_key", encryption_key_, &err);
1556     CHECK(rc == TILEDB_OK);
1557     REQUIRE(err == nullptr);
1558     rc = tiledb_array_set_config(ctx_, array, cfg);
1559     CHECK(rc == TILEDB_OK);
1560   }
1561   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1562   CHECK(rc == TILEDB_OK);
1563 
1564   // Submit query
1565   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1566   CHECK(rc == TILEDB_OK);
1567   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1568   CHECK(rc == TILEDB_OK);
1569   rc = tiledb_query_set_subarray(ctx_, query, subarray_read);
1570   CHECK(rc == TILEDB_OK);
1571   rc = tiledb_query_set_data_buffer(
1572       ctx_, query, "a", buffer_read, &buffer_read_size);
1573   CHECK(rc == TILEDB_OK);
1574   rc = tiledb_query_submit(ctx_, query);
1575   CHECK(rc == TILEDB_OK);
1576 
1577   // Close array and clean up
1578   rc = tiledb_array_close(ctx_, array);
1579   CHECK(rc == TILEDB_OK);
1580   tiledb_array_free(&array);
1581   tiledb_query_free(&query);
1582   tiledb_config_free(&cfg);
1583 
1584   // Check correctness
1585   int buffer_read_at_c[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1586   CHECK(!std::memcmp(buffer_read, buffer_read_at_c, sizeof(buffer_read_at_c)));
1587   CHECK(buffer_read_size == sizeof(buffer_read_at_c));
1588 
1589   remove_temp_dir(temp_dir);
1590 }
1591 
1592 TEST_CASE_METHOD(
1593     ArrayFx,
1594     "C API: Check writing coordinates out of bounds",
1595     "[capi][array][array-write-coords-oob]") {
1596   SupportedFsLocal local_fs;
1597   std::string temp_dir = local_fs.file_prefix() + local_fs.temp_dir();
1598   std::string array_name = temp_dir + "array-write-coords-oob";
1599   create_temp_dir(temp_dir);
1600 
1601   int dimension = 0;
1602   int64_t buffer_coords_dim1[3];
1603   int64_t buffer_coords_dim2[3];
1604   int buffer_a1[3];
1605   uint64_t buffer_a1_size, buffer_coords_size;
1606   int rc;
1607   bool check_coords_oob = true;
1608 
1609   // Create TileDB context
1610   tiledb_config_t* cfg = nullptr;
1611   tiledb_error_t* err = nullptr;
1612   tiledb_ctx_t* ctx = nullptr;
1613 
1614   SECTION("- Check out-of-bounds coordinates") {
1615     check_coords_oob = true;
1616     REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1617     REQUIRE(err == nullptr);
1618     rc = tiledb_config_set(cfg, "sm.check_coord_oob", "true", &err);
1619     REQUIRE(rc == TILEDB_OK);
1620     REQUIRE(err == nullptr);
1621 
1622     SECTION("** 1D") {
1623       dimension = 1;
1624       create_sparse_vector(array_name);
1625 
1626       // Prepare cell buffers
1627       buffer_coords_dim1[0] = 1;
1628       buffer_coords_dim1[1] = 2;
1629       buffer_coords_dim1[2] = 30;
1630       buffer_a1[0] = 1;
1631       buffer_a1[1] = 2;
1632       buffer_a1[2] = 3;
1633       buffer_coords_size = 3 * sizeof(int64_t);
1634       buffer_a1_size = 3 * sizeof(int);
1635     }
1636 
1637     SECTION("** 2D") {
1638       dimension = 2;
1639       create_sparse_array(array_name);
1640 
1641       // Prepare cell buffers
1642       buffer_coords_dim1[0] = 1;
1643       buffer_coords_dim1[1] = 2;
1644       buffer_coords_dim1[2] = 3;
1645       buffer_coords_dim2[0] = 1;
1646       buffer_coords_dim2[1] = 30;
1647       buffer_coords_dim2[2] = 3;
1648       buffer_a1[0] = 1;
1649       buffer_a1[1] = 2;
1650       buffer_a1[2] = 3;
1651       buffer_coords_size = 3 * sizeof(int64_t);
1652       buffer_a1_size = 3 * sizeof(int);
1653     }
1654   }
1655 
1656   SECTION("- Do not check out-of-bounds coordinates") {
1657     check_coords_oob = false;
1658     REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1659     REQUIRE(err == nullptr);
1660     rc = tiledb_config_set(cfg, "sm.check_coord_oob", "false", &err);
1661     REQUIRE(rc == TILEDB_OK);
1662     REQUIRE(err == nullptr);
1663 
1664     SECTION("** 1D") {
1665       dimension = 1;
1666       create_sparse_vector(array_name);
1667 
1668       // Prepare cell buffers
1669       buffer_coords_dim1[0] = 1;
1670       buffer_coords_dim1[1] = 2;
1671       buffer_coords_dim1[2] = 30;
1672       buffer_a1[0] = 1;
1673       buffer_a1[1] = 2;
1674       buffer_a1[2] = 3;
1675       buffer_coords_size = 3 * sizeof(int64_t);
1676       buffer_a1_size = 3 * sizeof(int);
1677     }
1678 
1679     SECTION("** 2D") {
1680       dimension = 2;
1681       create_sparse_array(array_name);
1682 
1683       // Prepare cell buffers
1684       buffer_coords_dim1[0] = 1;
1685       buffer_coords_dim1[1] = 2;
1686       buffer_coords_dim1[2] = 3;
1687       buffer_coords_dim2[0] = 1;
1688       buffer_coords_dim2[1] = 30;
1689       buffer_coords_dim2[2] = 3;
1690       buffer_a1[0] = 1;
1691       buffer_a1[1] = 2;
1692       buffer_a1[2] = 3;
1693       buffer_coords_size = 3 * sizeof(int64_t);
1694       buffer_a1_size = 3 * sizeof(int);
1695     }
1696   }
1697 
1698   REQUIRE(tiledb_ctx_alloc(cfg, &ctx) == TILEDB_OK);
1699   REQUIRE(err == nullptr);
1700   tiledb_config_free(&cfg);
1701 
1702   // Open array
1703   tiledb_array_t* array;
1704   rc = tiledb_array_alloc(ctx, array_name.c_str(), &array);
1705   CHECK(rc == TILEDB_OK);
1706   rc = tiledb_array_open(ctx, array, TILEDB_WRITE);
1707   CHECK(rc == TILEDB_OK);
1708 
1709   // Submit query
1710   tiledb_query_t* query;
1711   rc = tiledb_query_alloc(ctx, array, TILEDB_WRITE, &query);
1712   CHECK(rc == TILEDB_OK);
1713   rc = tiledb_query_set_layout(ctx, query, TILEDB_GLOBAL_ORDER);
1714   CHECK(rc == TILEDB_OK);
1715   rc =
1716       tiledb_query_set_data_buffer(ctx, query, "a", buffer_a1, &buffer_a1_size);
1717   CHECK(rc == TILEDB_OK);
1718   rc = tiledb_query_set_data_buffer(
1719       ctx, query, "d1", buffer_coords_dim1, &buffer_coords_size);
1720   CHECK(rc == TILEDB_OK);
1721   if (dimension == 2) {
1722     rc = tiledb_query_set_data_buffer(
1723         ctx, query, "d2", buffer_coords_dim2, &buffer_coords_size);
1724     CHECK(rc == TILEDB_OK);
1725   }
1726   rc = tiledb_query_submit(ctx, query);
1727   if (check_coords_oob)
1728     CHECK(rc == TILEDB_ERR);
1729   else
1730     CHECK(rc == TILEDB_OK);
1731   rc = tiledb_query_finalize(ctx, query);
1732   CHECK(rc == TILEDB_OK);
1733 
1734   // Close array and clean up
1735   rc = tiledb_array_close(ctx, array);
1736   CHECK(rc == TILEDB_OK);
1737   tiledb_array_free(&array);
1738   tiledb_query_free(&query);
1739   tiledb_ctx_free(&ctx);
1740 
1741   remove_temp_dir(temp_dir);
1742 }
1743 
1744 TEST_CASE_METHOD(
1745     ArrayFx, "C API: Test empty array", "[capi][array][array-empty]") {
1746   SupportedFsLocal local_fs;
1747   std::string array_name =
1748       local_fs.file_prefix() + local_fs.temp_dir() + "array_empty";
1749   create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
1750 
1751   create_sparse_vector(array_name);
1752 
1753   // Open array
1754   tiledb_array_t* array;
1755   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1756   REQUIRE(rc == TILEDB_OK);
1757   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1758   REQUIRE(rc == TILEDB_OK);
1759 
1760   // Buffers
1761   int buff_a[10];
1762   uint64_t buff_a_size = sizeof(buff_a);
1763 
1764   // Submit query
1765   tiledb_query_t* query;
1766   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1767   CHECK(rc == TILEDB_OK);
1768   rc = tiledb_query_set_layout(ctx_, query, TILEDB_GLOBAL_ORDER);
1769   CHECK(rc == TILEDB_OK);
1770   rc = tiledb_query_set_data_buffer(ctx_, query, "a", buff_a, &buff_a_size);
1771   CHECK(rc == TILEDB_OK);
1772   rc = tiledb_query_submit(ctx_, query);
1773   CHECK(rc == TILEDB_OK);
1774 
1775   // Check status
1776   tiledb_query_status_t status;
1777   rc = tiledb_query_get_status(ctx_, query, &status);
1778   CHECK(rc == TILEDB_OK);
1779   CHECK(status == TILEDB_COMPLETED);
1780 
1781   // Close array
1782   rc = tiledb_array_close(ctx_, array);
1783   CHECK(rc == TILEDB_OK);
1784 
1785   // No results
1786   CHECK(buff_a_size == 0);
1787 
1788   // Clean up
1789   tiledb_array_free(&array);
1790   tiledb_query_free(&query);
1791 
1792   remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
1793 }
1794 
1795 TEST_CASE_METHOD(
1796     ArrayFx,
1797     "C API: Test array with no filelocks",
1798     "[capi][array][array-no-filelocks]") {
1799   // TODO: refactor for each supported FS.
1800   std::string temp_dir = fs_vec_[0]->temp_dir();
1801 
1802   std::string array_name = temp_dir + "array-no-filelocks";
1803 
1804   // Create new TileDB context with file lock config disabled, rest the same.
1805   tiledb_ctx_free(&ctx_);
1806   tiledb_vfs_free(&vfs_);
1807 
1808   tiledb_config_t* cfg = nullptr;
1809   tiledb_error_t* err = nullptr;
1810   REQUIRE(tiledb_config_alloc(&cfg, &err) == TILEDB_OK);
1811   REQUIRE(err == nullptr);
1812   REQUIRE(
1813       tiledb_config_set(cfg, "vfs.file.enable_filelocks", "false", &err) ==
1814       TILEDB_OK);
1815   REQUIRE(err == nullptr);
1816 
1817   REQUIRE(vfs_test_init(fs_vec_, &ctx_, &vfs_, cfg).ok());
1818 
1819   tiledb_config_free(&cfg);
1820 
1821   create_temp_dir(temp_dir);
1822 
1823   create_dense_vector(array_name);
1824 
1825   // Prepare cell buffers
1826   int buffer_a1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1827   uint64_t buffer_a1_size = sizeof(buffer_a1);
1828 
1829   // Open array
1830   int64_t subarray[] = {1, 10};
1831   tiledb_array_t* array;
1832   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1833   CHECK(rc == TILEDB_OK);
1834   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1835   CHECK(rc == TILEDB_OK);
1836 
1837   // Submit query
1838   tiledb_query_t* query;
1839   rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
1840   CHECK(rc == TILEDB_OK);
1841   rc = tiledb_query_set_layout(ctx_, query, TILEDB_GLOBAL_ORDER);
1842   CHECK(rc == TILEDB_OK);
1843   rc = tiledb_query_set_subarray(ctx_, query, subarray);
1844   CHECK(rc == TILEDB_OK);
1845   rc = tiledb_query_set_data_buffer(
1846       ctx_, query, "a", buffer_a1, &buffer_a1_size);
1847   CHECK(rc == TILEDB_OK);
1848   rc = tiledb_query_submit(ctx_, query);
1849   CHECK(rc == TILEDB_OK);
1850   rc = tiledb_query_finalize(ctx_, query);
1851   CHECK(rc == TILEDB_OK);
1852 
1853   // Close array and clean up
1854   rc = tiledb_array_close(ctx_, array);
1855   CHECK(rc == TILEDB_OK);
1856   tiledb_array_free(&array);
1857   tiledb_query_free(&query);
1858 
1859   int buffer_read[10];
1860   uint64_t buffer_read_size = sizeof(buffer_read);
1861 
1862   // Open array
1863   rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1864   CHECK(rc == TILEDB_OK);
1865   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
1866   CHECK(rc == TILEDB_OK);
1867 
1868   // Submit query
1869   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
1870   CHECK(rc == TILEDB_OK);
1871   rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
1872   CHECK(rc == TILEDB_OK);
1873   rc = tiledb_query_set_subarray(ctx_, query, subarray);
1874   CHECK(rc == TILEDB_OK);
1875   rc = tiledb_query_set_data_buffer(
1876       ctx_, query, "a", buffer_read, &buffer_read_size);
1877   CHECK(rc == TILEDB_OK);
1878   rc = tiledb_query_submit(ctx_, query);
1879   CHECK(rc == TILEDB_OK);
1880 
1881   // Close array and clean up
1882   rc = tiledb_array_close(ctx_, array);
1883   CHECK(rc == TILEDB_OK);
1884   tiledb_array_free(&array);
1885   tiledb_query_free(&query);
1886 
1887   // Check correctness
1888   int buffer_read_c[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1889   CHECK(!std::memcmp(buffer_read, buffer_read_c, sizeof(buffer_read_c)));
1890   CHECK(buffer_read_size == sizeof(buffer_read_c));
1891 
1892   remove_temp_dir(temp_dir);
1893 }
1894 
1895 TEST_CASE_METHOD(
1896     ArrayFx,
1897     "C API: Test query errors, getting subarray info from write queries in "
1898     "sparse arrays",
1899     "[capi][query][error][sparse]") {
1900   SupportedFsLocal local_fs;
1901   std::string array_name =
1902       local_fs.file_prefix() + local_fs.temp_dir() + "query_error_sparse";
1903   create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
1904 
1905   create_sparse_vector(array_name);
1906 
1907   // Open array
1908   tiledb_array_t* array;
1909   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1910   REQUIRE(rc == TILEDB_OK);
1911   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1912   REQUIRE(rc == TILEDB_OK);
1913 
1914   // Prepare query
1915   tiledb_query_t* query;
1916   rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
1917   CHECK(rc == TILEDB_OK);
1918   uint64_t range_num;
1919   rc = tiledb_query_get_range_num(ctx_, query, 0, &range_num);
1920   CHECK(rc == TILEDB_ERR);
1921   const void *start, *end, *stride;
1922   rc = tiledb_query_get_range(ctx_, query, 0, 0, &start, &end, &stride);
1923   CHECK(rc == TILEDB_ERR);
1924   int64_t s = 10;
1925   int64_t e = 20;
1926   rc = tiledb_query_add_range(ctx_, query, 0, &s, &e, nullptr);
1927   CHECK(rc == TILEDB_ERR);
1928   int64_t subarray[] = {-1, 2};
1929   rc = tiledb_query_set_subarray(ctx_, query, subarray);
1930   CHECK(rc == TILEDB_ERR);
1931 
1932   // Close array
1933   rc = tiledb_array_close(ctx_, array);
1934   CHECK(rc == TILEDB_OK);
1935 
1936   // Clean up
1937   tiledb_array_free(&array);
1938   tiledb_query_free(&query);
1939 
1940   remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
1941 }
1942 
1943 TEST_CASE_METHOD(
1944     ArrayFx,
1945     "C API: Test query errors, dense writes",
1946     "[capi][query][error][dense]") {
1947   SupportedFsLocal local_fs;
1948   std::string array_name =
1949       local_fs.file_prefix() + local_fs.temp_dir() + "query_error_dense";
1950   create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
1951 
1952   create_dense_array(array_name);
1953 
1954   // Open array
1955   tiledb_array_t* array;
1956   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
1957   REQUIRE(rc == TILEDB_OK);
1958   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
1959   REQUIRE(rc == TILEDB_OK);
1960 
1961   int32_t a[] = {1, 2, 3, 4};
1962   uint64_t a_size = sizeof(a);
1963 
1964   // Prepare query
1965   tiledb_query_t* query;
1966   rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
1967   CHECK(rc == TILEDB_OK);
1968   rc = tiledb_query_set_data_buffer(ctx_, query, "a", a, &a_size);
1969   CHECK(rc == TILEDB_OK);
1970   uint64_t range_num;
1971   rc = tiledb_query_get_range_num(ctx_, query, 0, &range_num);
1972   CHECK(rc == TILEDB_OK);
1973   CHECK(range_num == 1);  // The default
1974   const void *start, *end, *stride;
1975   rc = tiledb_query_get_range(ctx_, query, 0, 0, &start, &end, &stride);
1976   CHECK(rc == TILEDB_OK);
1977   CHECK(*(const uint64_t*)start == 1);
1978   CHECK(*(const uint64_t*)end == 10);
1979   int64_t s = 1;
1980   int64_t e = 2;
1981   rc = tiledb_query_add_range(ctx_, query, 0, &s, &e, nullptr);
1982   CHECK(rc == TILEDB_OK);
1983 
1984   int64_t subarray[] = {2, 3, 4, 5};
1985   rc = tiledb_query_set_subarray(ctx_, query, subarray);
1986   CHECK(rc == TILEDB_OK);
1987   rc = tiledb_query_add_range(ctx_, query, 0, &s, &e, nullptr);
1988   CHECK(rc == TILEDB_ERR);
1989 
1990   rc = tiledb_query_get_range_num(ctx_, query, 0, &range_num);
1991   CHECK(rc == TILEDB_OK);
1992   CHECK(range_num == 1);
1993   rc = tiledb_query_get_range(ctx_, query, 0, 0, &start, &end, &stride);
1994   CHECK(rc == TILEDB_OK);
1995   CHECK(*(const uint64_t*)start == 2);
1996   CHECK(*(const uint64_t*)end == 3);
1997   rc = tiledb_query_get_range(ctx_, query, 1, 0, &start, &end, &stride);
1998   CHECK(rc == TILEDB_OK);
1999   CHECK(*(const uint64_t*)start == 4);
2000   CHECK(*(const uint64_t*)end == 5);
2001 
2002   rc = tiledb_query_set_layout(ctx_, query, TILEDB_GLOBAL_ORDER);
2003   CHECK(rc == TILEDB_OK);
2004   rc = tiledb_query_submit(ctx_, query);
2005   CHECK(rc == TILEDB_ERR);
2006 
2007   // Close array
2008   rc = tiledb_array_close(ctx_, array);
2009   CHECK(rc == TILEDB_OK);
2010 
2011   // Clean up
2012   tiledb_array_free(&array);
2013   tiledb_query_free(&query);
2014 
2015   remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
2016 }
2017 
2018 TEST_CASE_METHOD(
2019     ArrayFx,
2020     "C API: Test query errors, dense unordered writes",
2021     "[capi][query][error][dense]") {
2022   SupportedFsLocal local_fs;
2023   std::string array_name =
2024       local_fs.file_prefix() + local_fs.temp_dir() + "query_error_dense";
2025   create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
2026 
2027   create_dense_array(array_name);
2028 
2029   // Open array
2030   tiledb_array_t* array;
2031   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
2032   REQUIRE(rc == TILEDB_OK);
2033   rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
2034   REQUIRE(rc == TILEDB_OK);
2035 
2036   // Prepare query
2037   tiledb_query_t* query;
2038   rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
2039   CHECK(rc == TILEDB_OK);
2040 
2041   rc = tiledb_query_set_layout(ctx_, query, TILEDB_UNORDERED);
2042   CHECK(rc == TILEDB_ERR);
2043 
2044   // Close array
2045   rc = tiledb_array_close(ctx_, array);
2046   CHECK(rc == TILEDB_OK);
2047 
2048   // Clean up
2049   tiledb_array_free(&array);
2050   tiledb_query_free(&query);
2051 
2052   remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
2053 }
2054 
2055 TEST_CASE_METHOD(
2056     ArrayFx,
2057     "C API: Test query errors, dense reads in global order",
2058     "[capi][query][error][dense]") {
2059   SupportedFsLocal local_fs;
2060   std::string array_name =
2061       local_fs.file_prefix() + local_fs.temp_dir() + "query_error_dense";
2062   create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
2063 
2064   create_dense_array(array_name);
2065 
2066   // Open array
2067   tiledb_array_t* array;
2068   int rc = tiledb_array_alloc(ctx_, array_name.c_str(), &array);
2069   REQUIRE(rc == TILEDB_OK);
2070   rc = tiledb_array_open(ctx_, array, TILEDB_READ);
2071   REQUIRE(rc == TILEDB_OK);
2072 
2073   int32_t a[4];
2074   uint64_t a_size = sizeof(a);
2075 
2076   // Prepare query
2077   tiledb_query_t* query;
2078   rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
2079   CHECK(rc == TILEDB_OK);
2080   rc = tiledb_query_set_data_buffer(ctx_, query, "a", a, &a_size);
2081   CHECK(rc == TILEDB_OK);
2082 
2083   int64_t subarray[] = {2, 3, 4, 5};
2084   rc = tiledb_query_set_subarray(ctx_, query, subarray);
2085   CHECK(rc == TILEDB_OK);
2086   int64_t s = 1;
2087   int64_t e = 2;
2088   rc = tiledb_query_add_range(ctx_, query, 0, &s, &e, nullptr);
2089   CHECK(rc == TILEDB_OK);
2090 
2091   rc = tiledb_query_set_layout(ctx_, query, TILEDB_GLOBAL_ORDER);
2092   CHECK(rc == TILEDB_OK);
2093   rc = tiledb_query_submit(ctx_, query);
2094   CHECK(rc == TILEDB_ERR);
2095 
2096   // Close array
2097   rc = tiledb_array_close(ctx_, array);
2098   CHECK(rc == TILEDB_OK);
2099 
2100   // Clean up
2101   tiledb_array_free(&array);
2102   tiledb_query_free(&query);
2103 
2104   remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
2105 }