Skip to content

Commit

Permalink
Add a test for write access failures. (#4496)
Browse files Browse the repository at this point in the history
[SC-35061](https://app.shortcut.com/tiledb-inc/story/35061/add-tests-for-write-access-failures)

See also
#4052 (review).

The test runs on non-Windows only.

---
TYPE: NO_HISTORY
  • Loading branch information
teo-tsirpanis committed Nov 7, 2023
1 parent 6533869 commit 5efd7f5
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 0 deletions.
100 changes: 100 additions & 0 deletions test/src/unit-capi-query.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <test/support/tdb_catch.h>
#include "test/support/src/helpers.h"
#include "test/support/src/vfs_helpers.h"
#include "tiledb/platform/platform.h"
#ifdef _WIN32
#include "tiledb/sm/filesystem/win.h"
#else
Expand Down Expand Up @@ -704,3 +705,102 @@ TEST_CASE_METHOD(
tiledb_array_free(&rarray);
remove_temp_dir(temp_dir);
}

TEST_CASE_METHOD(
QueryFx,
"C API: Test query write failure",
"[capi][query][write-failure]") {
// DenyWriteAccess is not supported on Windows.
if constexpr (tiledb::platform::is_os_windows)
return;
SupportedFsLocal local_fs;
std::string temp_dir = local_fs.temp_dir();
std::string array_name = temp_dir + "write_failure";
create_temp_dir(temp_dir);

tiledb_layout_t layout =
GENERATE(TILEDB_ROW_MAJOR, TILEDB_UNORDERED, TILEDB_GLOBAL_ORDER);
tiledb_array_type_t array_type =
layout == TILEDB_UNORDERED ? TILEDB_SPARSE : TILEDB_DENSE;

tiledb_ctx_t* ctx;
int rc;
{
tiledb_array_schema_t* schema;
tiledb_domain_t* domain;
tiledb_dimension_t* dim;
tiledb_attribute_t* attr;

rc = tiledb_ctx_alloc(nullptr, &ctx);
REQUIRE(rc == TILEDB_OK);

rc = tiledb_array_schema_alloc(ctx, array_type, &schema);
REQUIRE(rc == TILEDB_OK);

rc = tiledb_domain_alloc(ctx, &domain);
REQUIRE(rc == TILEDB_OK);

int bounds[] = {0, 4};
int extent = 1;
rc = tiledb_dimension_alloc(ctx, "d1", TILEDB_INT32, bounds, &extent, &dim);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_domain_add_dimension(ctx, domain, dim);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_array_schema_set_domain(ctx, schema, domain);
REQUIRE(rc == TILEDB_OK);

rc = tiledb_attribute_alloc(ctx, "attr1", TILEDB_INT32, &attr);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_array_schema_add_attribute(ctx, schema, attr);
REQUIRE(rc == TILEDB_OK);

rc = tiledb_array_create(ctx, array_name.c_str(), schema);
REQUIRE(rc == TILEDB_OK);

tiledb_attribute_free(&attr);
tiledb_dimension_free(&dim);
tiledb_domain_free(&domain);
tiledb_array_schema_free(&schema);
}

{
DenyWriteAccess dwa{array_name + "/__fragments"};

tiledb_array_t* array;
tiledb_query_t* query;
rc = tiledb_array_alloc(ctx, array_name.c_str(), &array);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_array_open(ctx, array, TILEDB_WRITE);
REQUIRE(rc == TILEDB_OK);

rc = tiledb_query_alloc(ctx, array, TILEDB_WRITE, &query);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_query_set_layout(ctx, query, layout);
REQUIRE(rc == TILEDB_OK);
int data[] = {0, 1, 2, 3, 4};
uint64_t data_size = sizeof(data);
rc = tiledb_query_set_data_buffer(ctx, query, "attr1", data, &data_size);
REQUIRE(rc == TILEDB_OK);
if (array_type == TILEDB_SPARSE) {
rc = tiledb_query_set_data_buffer(ctx, query, "d1", data, &data_size);
REQUIRE(rc == TILEDB_OK);
}

rc = tiledb_query_submit(ctx, query);
REQUIRE(rc != TILEDB_OK);

tiledb_error_t* err;
rc = tiledb_ctx_get_last_error(ctx, &err);
REQUIRE(rc == TILEDB_OK);
const char* msg;
rc = tiledb_error_message(err, &msg);
REQUIRE(rc == TILEDB_OK);
REQUIRE(
std::string(msg).find("Cannot create directory") != std::string::npos);

tiledb_error_free(&err);
tiledb_query_free(&query);
tiledb_array_free(&array);
}
tiledb_ctx_free(&ctx);
}
36 changes: 36 additions & 0 deletions test/support/src/vfs_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#ifndef TILEDB_VFS_HELPERS_H
#define TILEDB_VFS_HELPERS_H

#include <filesystem>
#include "test/support/src/helpers.h"
#include "test/support/tdb_catch.h"

Expand Down Expand Up @@ -683,6 +684,41 @@ struct TemporaryDirectoryFixture {
const std::vector<std::unique_ptr<SupportedFs>> supported_filesystems_;
};

/**
* Denies write access to a local filesystem path.
*
* Not supported on Windows. The permissions function there sets the
* readonly bit on the path, which is not supported on directories.
*
* To support it on Windows we would have to add and remove Access Control
* Lists, which is a nontrivial thing to do.
*/
class DenyWriteAccess {
public:
DenyWriteAccess() = delete;

DenyWriteAccess(const std::string& path)
: path_(path)
, previous_perms_(std::filesystem::status(path).permissions()) {
std::filesystem::permissions(
path_,
std::filesystem::perms::owner_write,
std::filesystem::perm_options::remove);
}

~DenyWriteAccess() {
std::filesystem::permissions(
path_, previous_perms_, std::filesystem::perm_options::replace);
}

private:
/** The path. */
const std::string path_;

/** The previous permissions of the path. */
const std::filesystem::perms previous_perms_;
};

} // End of namespace test
} // End of namespace tiledb

Expand Down

0 comments on commit 5efd7f5

Please sign in to comment.