Add mars-nwe FLAIM integration tests
All checks were successful
Source release / source-package (push) Successful in 1m10s
All checks were successful
Source release / source-package (push) Successful in 1m10s
This commit is contained in:
committed by
Mario Fetka
parent
36fcdb3c83
commit
850b37875b
@@ -6,3 +6,7 @@
|
||||
|
||||
add_subdirectory(afp)
|
||||
add_subdirectory(salvage)
|
||||
|
||||
if(ENABLE_DIRECTORY)
|
||||
add_subdirectory(flaim)
|
||||
endif()
|
||||
|
||||
45
tests/flaim/CMakeLists.txt
Normal file
45
tests/flaim/CMakeLists.txt
Normal file
@@ -0,0 +1,45 @@
|
||||
# mars-nwe FLAIM integration tests.
|
||||
#
|
||||
# These tests live in the mars-nwe root test tree instead of the imported FLAIM
|
||||
# submodule because they validate the complete mars-nwe integration contract:
|
||||
# nw-prefixed libraries, nwssl-backed OpenSSL compatibility, MatrixSSL crypto
|
||||
# configuration propagation, and the FLAIM stack used by nwdirectory.
|
||||
|
||||
if(NOT ENABLE_DIRECTORY)
|
||||
message(STATUS "mars-nwe FLAIM tests disabled: ENABLE_DIRECTORY is OFF")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET flaim)
|
||||
message(FATAL_ERROR "mars-nwe FLAIM tests require the flaim target")
|
||||
endif()
|
||||
|
||||
function(mars_nwe_add_flaim_test target source library)
|
||||
add_executable(${target} ${source})
|
||||
target_link_libraries(${target} PRIVATE ${library})
|
||||
set_target_properties(${target} PROPERTIES CXX_STANDARD 98 CXX_STANDARD_REQUIRED YES)
|
||||
endfunction()
|
||||
|
||||
mars_nwe_add_flaim_test(mars_nwe_flaim_api_smoke flaim_api_smoke.cpp flaim)
|
||||
add_test(NAME mars_nwe.flaim.api-create-query-encrypt
|
||||
COMMAND mars_nwe_flaim_api_smoke ${CMAKE_CURRENT_BINARY_DIR}/flaim-api)
|
||||
set_tests_properties(mars_nwe.flaim.api-create-query-encrypt PROPERTIES
|
||||
LABELS "mars_nwe;flaim"
|
||||
ENVIRONMENT "TERM=xterm")
|
||||
|
||||
if(TARGET xflaim)
|
||||
mars_nwe_add_flaim_test(mars_nwe_xflaim_api_smoke xflaim_api_smoke.cpp xflaim)
|
||||
add_test(NAME mars_nwe.xflaim.api-alloc
|
||||
COMMAND mars_nwe_xflaim_api_smoke)
|
||||
set_tests_properties(mars_nwe.xflaim.api-alloc PROPERTIES
|
||||
LABELS "mars_nwe;flaim;xflaim"
|
||||
ENVIRONMENT "TERM=xterm")
|
||||
endif()
|
||||
|
||||
if(TARGET flaimsql)
|
||||
mars_nwe_add_flaim_test(mars_nwe_flaimsql_header_link_smoke flaimsql_header_link_smoke.cpp flaimsql)
|
||||
add_test(NAME mars_nwe.flaimsql.header-link
|
||||
COMMAND mars_nwe_flaimsql_header_link_smoke)
|
||||
set_tests_properties(mars_nwe.flaimsql.header-link PROPERTIES
|
||||
LABELS "mars_nwe;flaim;flaimsql")
|
||||
endif()
|
||||
287
tests/flaim/flaim_api_smoke.cpp
Normal file
287
tests/flaim/flaim_api_smoke.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
#include "flaim.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PERSON_TAG 1
|
||||
#define LAST_NAME_TAG 2
|
||||
#define FIRST_NAME_TAG 3
|
||||
#define SECRET_TAG 4
|
||||
#define AGE_TAG 5
|
||||
#define SECRET_ENCDEF 10
|
||||
|
||||
static const char *kDictionary =
|
||||
"0 @10@ EncDef SecretKey\n"
|
||||
" 1 type aes\n"
|
||||
"0 @1@ field Person\n"
|
||||
" 1 type text\n"
|
||||
"0 @2@ field LastName\n"
|
||||
" 1 type text\n"
|
||||
"0 @3@ field FirstName\n"
|
||||
" 1 type text\n"
|
||||
"0 @4@ field Secret\n"
|
||||
" 1 type text\n"
|
||||
" 1 encdef 10\n"
|
||||
"0 @5@ field Age\n"
|
||||
" 1 type number\n"
|
||||
"0 @100@ index LastFirst_IX\n"
|
||||
" 1 language US\n"
|
||||
" 1 key\n"
|
||||
" 2 field 2\n"
|
||||
" 3 required\n"
|
||||
" 2 field 3\n"
|
||||
" 3 required\n";
|
||||
|
||||
static const char *kSecret = "mars-nwe-flaim-at-rest-secret-value";
|
||||
|
||||
static void fail(const char *what, RCODE rc)
|
||||
{
|
||||
if (rc)
|
||||
{
|
||||
fprintf(stderr, "FAIL: %s: 0x%04x %s\n", what, (unsigned)rc,
|
||||
(const char *)FlmErrorString(rc));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "FAIL: %s\n", what);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void ensure_dir(const char *path)
|
||||
{
|
||||
if (mkdir(path, 0700) != 0 && errno != EEXIST)
|
||||
{
|
||||
perror(path);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void rm_rf(const char *path)
|
||||
{
|
||||
DIR *dir = opendir(path);
|
||||
if (!dir)
|
||||
{
|
||||
unlink(path);
|
||||
return;
|
||||
}
|
||||
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(dir)) != NULL)
|
||||
{
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
char child[4096];
|
||||
snprintf(child, sizeof(child), "%s/%s", path, ent->d_name);
|
||||
rm_rf(child);
|
||||
}
|
||||
closedir(dir);
|
||||
rmdir(path);
|
||||
}
|
||||
|
||||
static int file_contains(const char *path, const char *needle)
|
||||
{
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size_t nlen = strlen(needle);
|
||||
unsigned char buf[8192];
|
||||
size_t overlap = 0;
|
||||
int found = 0;
|
||||
|
||||
while (!found)
|
||||
{
|
||||
size_t got = fread(buf + overlap, 1, sizeof(buf) - overlap, f);
|
||||
if (got == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
size_t total = overlap + got;
|
||||
for (size_t i = 0; i + nlen <= total; ++i)
|
||||
{
|
||||
if (memcmp(buf + i, needle, nlen) == 0)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nlen > 1 && total >= nlen - 1)
|
||||
{
|
||||
overlap = nlen - 1;
|
||||
memmove(buf, buf + total - overlap, overlap);
|
||||
}
|
||||
else
|
||||
{
|
||||
overlap = total;
|
||||
memmove(buf, buf, overlap);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return found;
|
||||
}
|
||||
|
||||
static void assert_secret_not_plaintext(const char *dir)
|
||||
{
|
||||
DIR *d = opendir(dir);
|
||||
if (!d)
|
||||
{
|
||||
perror(dir);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(d)) != NULL)
|
||||
{
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
char path[4096];
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name);
|
||||
struct stat st;
|
||||
if (stat(path, &st) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode))
|
||||
{
|
||||
assert_secret_not_plaintext(path);
|
||||
}
|
||||
else if (S_ISREG(st.st_mode) && file_contains(path, kSecret))
|
||||
{
|
||||
fprintf(stderr, "FAIL: encrypted FLAIM payload appears as plaintext in %s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
static void add_person(HFDB hDb, FLMUINT *drn_out)
|
||||
{
|
||||
FlmRecord *rec = NULL;
|
||||
void *field = NULL;
|
||||
RCODE rc;
|
||||
|
||||
rec = f_new FlmRecord;
|
||||
if (!rec)
|
||||
{
|
||||
fail("alloc FlmRecord", FERR_MEM);
|
||||
}
|
||||
|
||||
if (RC_BAD(rc = rec->insertLast(0, PERSON_TAG, FLM_TEXT_TYPE, NULL))) fail("insert root", rc);
|
||||
if (RC_BAD(rc = rec->insertLast(1, FIRST_NAME_TAG, FLM_TEXT_TYPE, &field))) fail("insert first", rc);
|
||||
if (RC_BAD(rc = rec->setNative(field, "Mars"))) fail("set first", rc);
|
||||
if (RC_BAD(rc = rec->insertLast(1, LAST_NAME_TAG, FLM_TEXT_TYPE, &field))) fail("insert last", rc);
|
||||
if (RC_BAD(rc = rec->setNative(field, "NWE"))) fail("set last", rc);
|
||||
if (RC_BAD(rc = rec->insertLast(1, SECRET_TAG, FLM_TEXT_TYPE, &field))) fail("insert secret", rc);
|
||||
if (RC_BAD(rc = rec->setNative(field, kSecret, SECRET_ENCDEF))) fail("set encrypted secret", rc);
|
||||
if (!rec->isEncryptedField(field)) fail("secret field was not marked encrypted", 0);
|
||||
if (RC_BAD(rc = rec->insertLast(1, AGE_TAG, FLM_NUMBER_TYPE, &field))) fail("insert age", rc);
|
||||
if (RC_BAD(rc = rec->setUINT(field, 28))) fail("set age", rc);
|
||||
|
||||
FLMUINT drn = 0;
|
||||
if (RC_BAD(rc = FlmRecordAdd(hDb, FLM_DATA_CONTAINER, &drn, rec, 0))) fail("FlmRecordAdd", rc);
|
||||
*drn_out = drn;
|
||||
rec->Release();
|
||||
}
|
||||
|
||||
static void verify_person(HFDB hDb, FLMUINT drn)
|
||||
{
|
||||
RCODE rc;
|
||||
FlmRecord *rec = NULL;
|
||||
if (RC_BAD(rc = FlmRecordRetrieve(hDb, FLM_DATA_CONTAINER, drn, FO_EXACT, &rec, NULL)))
|
||||
{
|
||||
fail("FlmRecordRetrieve", rc);
|
||||
}
|
||||
|
||||
char value[128];
|
||||
FLMUINT len = sizeof(value);
|
||||
void *field = rec->find(rec->root(), SECRET_TAG);
|
||||
if (!field) fail("missing secret field", 0);
|
||||
if (RC_BAD(rc = rec->getNative(field, value, &len))) fail("decrypt secret", rc);
|
||||
if (strcmp(value, kSecret) != 0) fail("decrypted secret value mismatch", 0);
|
||||
if (!rec->isEncryptedField(field)) fail("retrieved secret field was not encrypted", 0);
|
||||
|
||||
field = rec->find(rec->root(), AGE_TAG);
|
||||
if (!field) fail("missing age field", 0);
|
||||
FLMUINT age = 0;
|
||||
if (RC_BAD(rc = rec->getUINT(field, &age))) fail("get age", rc);
|
||||
if (age != 28) fail("age value mismatch", 0);
|
||||
|
||||
rec->Release();
|
||||
}
|
||||
|
||||
static void verify_cursor(HFDB hDb)
|
||||
{
|
||||
HFCURSOR cursor = HFCURSOR_NULL;
|
||||
RCODE rc;
|
||||
FLMBYTE value[64];
|
||||
FlmRecord *rec = NULL;
|
||||
|
||||
if (RC_BAD(rc = FlmCursorInit(hDb, FLM_DATA_CONTAINER, &cursor))) fail("FlmCursorInit", rc);
|
||||
if (RC_BAD(rc = FlmCursorAddField(cursor, LAST_NAME_TAG, 0))) fail("cursor last field", rc);
|
||||
if (RC_BAD(rc = FlmCursorAddOp(cursor, FLM_EQ_OP))) fail("cursor last eq", rc);
|
||||
f_sprintf((char *)value, "NWE");
|
||||
if (RC_BAD(rc = FlmCursorAddValue(cursor, FLM_STRING_VAL, value, 0))) fail("cursor last value", rc);
|
||||
if (RC_BAD(rc = FlmCursorAddOp(cursor, FLM_AND_OP))) fail("cursor and", rc);
|
||||
if (RC_BAD(rc = FlmCursorAddField(cursor, FIRST_NAME_TAG, 0))) fail("cursor first field", rc);
|
||||
if (RC_BAD(rc = FlmCursorAddOp(cursor, FLM_EQ_OP))) fail("cursor first eq", rc);
|
||||
f_sprintf((char *)value, "Mars");
|
||||
if (RC_BAD(rc = FlmCursorAddValue(cursor, FLM_STRING_VAL, value, 0))) fail("cursor first value", rc);
|
||||
if (RC_BAD(rc = FlmCursorFirst(cursor, &rec))) fail("FlmCursorFirst", rc);
|
||||
if (rec) rec->Release();
|
||||
FlmCursorFree(&cursor);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "usage: %s WORKDIR\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
rm_rf(argv[1]);
|
||||
ensure_dir(argv[1]);
|
||||
|
||||
char db[4096], data[4096], rfl[4096];
|
||||
snprintf(db, sizeof(db), "%s/classic.db", argv[1]);
|
||||
snprintf(data, sizeof(data), "%s/data", argv[1]);
|
||||
snprintf(rfl, sizeof(rfl), "%s/rfl", argv[1]);
|
||||
ensure_dir(data);
|
||||
ensure_dir(rfl);
|
||||
|
||||
RCODE rc;
|
||||
HFDB hDb = HFDB_NULL;
|
||||
FLMUINT drn = 0;
|
||||
|
||||
if (RC_BAD(rc = FlmStartup())) fail("FlmStartup", rc);
|
||||
if (RC_BAD(rc = FlmDbCreate(db, data, rfl, NULL, kDictionary, NULL, &hDb))) fail("FlmDbCreate", rc);
|
||||
if (RC_BAD(rc = FlmDbTransBegin(hDb, FLM_UPDATE_TRANS, 15))) fail("FlmDbTransBegin", rc);
|
||||
add_person(hDb, &drn);
|
||||
if (RC_BAD(rc = FlmDbTransCommit(hDb))) fail("FlmDbTransCommit", rc);
|
||||
verify_person(hDb, drn);
|
||||
verify_cursor(hDb);
|
||||
FlmDbClose(&hDb);
|
||||
|
||||
if (RC_BAD(rc = FlmDbOpen(db, data, rfl, 0, NULL, &hDb))) fail("FlmDbOpen", rc);
|
||||
verify_person(hDb, drn);
|
||||
FlmDbClose(&hDb);
|
||||
FlmShutdown();
|
||||
|
||||
assert_secret_not_plaintext(argv[1]);
|
||||
printf("mars-nwe FLAIM classic API/encryption smoke passed: %s\n", db);
|
||||
return 0;
|
||||
}
|
||||
18
tests/flaim/flaimsql_header_link_smoke.cpp
Normal file
18
tests/flaim/flaimsql_header_link_smoke.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "flaimsql.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
SQL_STATS stats;
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
stats.eErrorType = SQL_NO_ERROR;
|
||||
if (stats.eErrorType != SQL_NO_ERROR)
|
||||
{
|
||||
fprintf(stderr, "unexpected SQL_STATS value\n");
|
||||
return 1;
|
||||
}
|
||||
printf("mars-nwe FlaimSQL header/link smoke passed\n");
|
||||
return 0;
|
||||
}
|
||||
17
tests/flaim/xflaim_api_smoke.cpp
Normal file
17
tests/flaim/xflaim_api_smoke.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "xflaim.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
IF_DbSystem *dbSystem = NULL;
|
||||
RCODE rc = FlmAllocDbSystem(&dbSystem);
|
||||
if (RC_BAD(rc) || dbSystem == NULL)
|
||||
{
|
||||
fprintf(stderr, "FlmAllocDbSystem failed: 0x%04x\n", (unsigned)rc);
|
||||
return 1;
|
||||
}
|
||||
dbSystem->Release();
|
||||
printf("mars-nwe XFLAIM allocation smoke passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user