Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ci/jobs.lib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@


#@ load("sequences.lib.yml",
#@ "sequence_pr_build_test",
#@ "sequence_pr_debug_build_test",
#@ "sequence_pr_clang_format",
#@ "sequence_pr_shell_scripts",
Expand Down
1 change: 1 addition & 0 deletions ci/steps.lib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ config:
INCLUDE_SLOW_TESTS: #@ str(not quick).lower()
RUN_NIGHTLY_TESTS: #@ str(test_nightly).lower()
BUILD_VERBOSE: "1"
VERBOSE: "1"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to make this an environment variable instead of a command-line option?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, a flag would be preferable for ease of typing and for discoverability. I just couldn't figure out how to make it work: the interactions between unit/main.c, config.h, unit/config_parse_test.c, and unit/splinter_test.c were just too messy for me to untangle in the couple hours that I spent on this. I'd welcome some help on that from @gapisback or anyone else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, that would be ideal, but I can see why that would be tricky. Future work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rosenhouse -- I'll need to think this through with you. Am looking at the diffs now and pondered over how to achieve what you want.

Some time ago, I had added this --verbose-progress option that was used initially in functional/splinter_test.c to do some verbose progress reporting while large test workloads run. This arg is parsed and tracked as a bool in test_exec_config->verbose_progress.

With some work we could co-opt this flag to also mean what this VERBOSE=1 env-var wants to do. This boolean field may be the replacement for your newly-added Ctest_verbosity flag.

I'm not entirely sure that this scheme will work to meet all the requirements this change-set is bringing-in. (For instance, the functional tests still seem to spit out messages to stdout even when VERBOSE is not set. I'm a bit confused as to what the expected design is with regards to outputs from tests with this and your previous commit at SHA d2e9e86.)

If there is not a great hurry to replace the new env-var with a command line arg, my suggestion is to let this change set go in as-is. And you & I can talk off-line to see how to smooth things over in future editions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we'll return to this in future work


#! Exercise 'make help' in quick tests mode, to ensure 'help' still works.
#@ if quick:
Expand Down
13 changes: 4 additions & 9 deletions include/splinterdb/platform_linux/public_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,12 @@ typedef int32 bool;
#endif
typedef uint8 bool8;

// By default, platform_default_log() messages are sent to /dev/null
// and platform_error_log() messages go to stderr.
//
// Use platform_set_log_streams() to send the log messages elsewhere.
typedef FILE platform_log_handle;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent idea to remove these from the public api.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

extern platform_log_handle *Platform_default_log_handle;
extern platform_log_handle *Platform_error_log_handle;
typedef FILE platform_log_handle;

// Set the streams where informational and error messages will be printed.
// By default, info messages sent from platform_default_log() go to /dev/null
// and error messages sent from platform_error_log() go to stderr.
//
// These default to /dev/null and stderr, respectively.
// Use platform_set_log_streams() to send those log messages elsewhere.
//
// For example, to send info messages to stdout and errors to stderr, run:
// platform_set_log_streams(stdout, stderr);
Expand Down
3 changes: 3 additions & 0 deletions src/platform_linux/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,15 @@ typedef struct {
extern bool platform_use_hugetlb;
extern bool platform_use_mlock;


/*
* Section 3:
* Shared types/typedefs that rely on platform-specific types/typedefs
* There should not be any generic #includes here, but potentially #includes
* of headers defined in splinterdb cannot be included until now.
*/
extern platform_log_handle *Platform_default_log_handle;
extern platform_log_handle *Platform_error_log_handle;


/*
Expand Down
12 changes: 2 additions & 10 deletions tests/unit/btree_stress_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,23 +234,15 @@ CTEST2(btree_stress, test_random_inserts_concurrent)
if (!iterator_tests(
(cache *)&data->cc, &data->dbtree_cfg, root_addr, nkvs, data->hid))
{
platform_default_log("invalid ranges in original tree\n");
CTEST_ERR("invalid ranges in original tree\n");
}

/* platform_default_log("\n\n\n"); */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure about deleting this dead code and the old lines on L249 onwards below.

Seems like the code author had felt a need that this kind of debugging would be handy if ever this one had to troubleshoot failures in this test's execution.

I'm generally tolerant about such code being left behind, as it does help some future engineer who might have to debug this stuff. (Rob didn't complain, surprisingly ... as he's the author.)

What if we (a) either retain this dead-code in comments or (b) enclose it under if (FALSE) { }? The code is there for troubleshooting and doesn't get in anyone's way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly dislike dead code. I'm going to delete it. No one is speaking up to claim this code as theirs, and I'm guessing it could be added back by someone who's making changes.

/* btree_print_tree((cache *)&cc, &dbtree_cfg, root_addr); */

uint64 packed_root_addr = pack_tests(
(cache *)&data->cc, &data->dbtree_cfg, data->hid, root_addr, nkvs);
if (0 < nkvs && !packed_root_addr) {
ASSERT_TRUE(FALSE, "Pack failed.\n");
}

/* platform_default_log("\n\n\n"); */
/* btree_print_tree((cache *)&cc, &dbtree_cfg,
* packed_root_addr); */
/* platform_default_log("\n\n\n"); */

rc = query_tests((cache *)&data->cc,
&data->dbtree_cfg,
data->hid,
Expand Down Expand Up @@ -493,7 +485,7 @@ pack_tests(cache *cc,
if (!SUCCESS(btree_pack(&req))) {
ASSERT_TRUE(FALSE, "Pack failed! req.num_tuples = %d\n", req.num_tuples);
} else {
platform_default_log("Packed %lu items ", req.num_tuples);
CTEST_LOG_INFO("Packed %lu items ", req.num_tuples);
}

btree_pack_req_deinit(&req, hid);
Expand Down
3 changes: 0 additions & 3 deletions tests/unit/config_parse_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ CTEST_DATA(config_parse)
// Optional setup function for suite, called before every test in suite
CTEST_SETUP(config_parse)
{
Platform_default_log_handle = fopen("/tmp/unit_test.stdout", "a+");
Platform_error_log_handle = fopen("/tmp/unit_test.stderr", "a+");

uint64 heap_capacity = (1024 * MiB);
// Create a heap for io, allocator, cache and splinter
platform_status rc = platform_heap_create(
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/ctest.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,19 @@ struct ctest {
unsigned int magic;
};

// If FALSE (default), then CTEST_LOG_INFO() and CTEST_LOG() will no-op.
extern _Bool Ctest_verbose;

// For immedate logging to stdout
// (contrast with CTEST_LOG which does buffered/delayed logging to stderr)
#define CTEST_LOG_INFO(...) \
do { \
if (Ctest_verbose) { \
fprintf(stdout, __VA_ARGS__); \
fflush(stdout); \
} \
} while (0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor suggestion. It is sufficient if you code this multi-line macro simply as:

if (Ctest_verbosity) { ...} else

Missing ; at end of else will take care of correct usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems dangerous to me.

Suppose someone forgets the ; and writes

CTEST_LOG_INFO("foo")
something_important();

With the do/while implementation of the macro, the compiler will error:

tests/unit/splinterdb_quick_test.c:862:25: fatal error: expected ';' after do/while statement
   CTEST_LOG_INFO("foo")
                        ^
                        ;

But with your proposed if/else implementation, it compiles cleanly, and then something_important() only gets called when VERBOSE is unset.


/*
* Global handles to command-line args are provided so that we can access
* argc/argv indirectly thru these global variables inside setup methods.
Expand Down
48 changes: 39 additions & 9 deletions tests/unit/limitations_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,32 @@ CTEST_DATA(limitations)
* Setup heap memory to be used later to test Splinter configuration.
* splinter_test().
*/
// clang-format off
CTEST_SETUP(limitations)
{
Platform_default_log_handle = fopen("/tmp/unit_test.stdout", "a+");
Platform_error_log_handle = fopen("/tmp/unit_test.stderr", "a+");
// This test exercises error cases, so even when everthing succeeds
// it generates lots of "error" messages.
// By default, that would go to stderr, which would pollute test output.
// Here we ensure those expected error messages are only printed
// when the caller sets the VERBOSE env var to opt-in.
if (Ctest_verbose) {
platform_set_log_streams(stdout, stderr);
CTEST_LOG_INFO("\nVerbose mode on. This test exercises an error case, "
"so on sucess it "
"will print a message that appears to be an error.\n");
} else {
FILE *dev_null = fopen("/dev/null", "w");
ASSERT_NOT_NULL(dev_null);
platform_set_log_streams(dev_null, dev_null);
}

uint64 heap_capacity = (1 * GiB);

// Create a heap for io, allocator, cache and splinter
platform_status rc = platform_heap_create(platform_get_module_id(),
heap_capacity,
&data->hh,
&data->hid);
platform_status rc = platform_heap_create(
platform_get_module_id(), heap_capacity, &data->hh, &data->hid);
platform_assert_status_ok(rc);
}

// clang-format on

/*
* Tear down memory allocated for various sub-systems. Shutdown Splinter.
*/
Expand Down Expand Up @@ -376,6 +384,28 @@ CTEST2(limitations, test_zero_cache_size)
int rc = splinterdb_create(&cfg, &kvsb);
ASSERT_NOT_EQUAL(0, rc);
}
/*
* Check that errors on file-opening are returned, not asserted.
* Previously, a user error, e.g. bad file permissions, would
* just crash the program.
*/
CTEST2(limitations, test_file_error_returns)
{
splinterdb *kvsb;
splinterdb_config cfg;
data_config default_data_cfg;

default_data_config_init(TEST_MAX_KEY_SIZE, &default_data_cfg);
create_default_cfg(&cfg, &default_data_cfg);

cfg.filename = "/dev/null/this-file-cannot-possibly-be-opened";

// this will fail, but shouldn't crash!
int rc = splinterdb_create(&cfg, &kvsb);
ASSERT_NOT_EQUAL(0, rc);
// if we've made it this far, at least the application can report
// the error and recover!
}

/*
* Helper routine to create a valid Splinter configuration using default
Expand Down
35 changes: 35 additions & 0 deletions tests/unit/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ static const char *testcase_name = NULL;

typedef int (*ctest_filter_func)(struct ctest *);

// If false, then CTEST_LOG_INFO() and CTEST_LOG() will no-op.
_Bool Ctest_verbose = FALSE;

/*
* Global handles to command-line args are provided so that we can access
* argc/argv indirectly thru these global variables inside setup methods.
Expand Down Expand Up @@ -88,6 +91,9 @@ ctest_process_args(const int argc,
int
ctest_is_unit_test(const char *argv0);

static bool
ctest_get_verbosity();

static int
suite_all(struct ctest *t);

Expand Down Expand Up @@ -170,6 +176,8 @@ ctest_main(int argc, const char *argv[])
signal(SIGSEGV, sighandler);
#endif

Ctest_verbose = ctest_get_verbosity();

int program_is_unit_test = ctest_is_unit_test(argv[0]);

int print_list = 0; // Are we processing --list arg?
Expand Down Expand Up @@ -340,6 +348,13 @@ ctest_main(int argc, const char *argv[])
num_skip,
(t2 - t1) / 1000);
color_print(color, results);

if (num_fail > 0 && !Ctest_verbose) {
snprintf(results,
sizeof(results),
"(Rerun with env var VERBOSE=1 to see more log messages)");
color_print(color, results);
}
return num_fail;
}

Expand Down Expand Up @@ -384,6 +399,22 @@ ctest_is_unit_test(const char *argv0)
return 0;
}

// Determine the log message verbosity to use for this test run.
// If env var VERBOSE is unset, or is set to "0" or "false", the be quiet.
// Otherwise, be verbose.
static bool
ctest_get_verbosity()
{
char *val = getenv("VERBOSE");
if (val == NULL) {
return 0;
}
if ((strcmp(val, "0") == 0) || (strcmp(val, "false") == 0)) {
return 0;
}
return 1;
}

/*
* ---------------------------------------------------------------------------
* Process the command-line arguments. The main job of this function is to
Expand Down Expand Up @@ -718,6 +749,10 @@ msg_end(void)
void
CTEST_LOG(const char *fmt, ...)
{
if (!Ctest_verbose) {
return;
}

va_list argp;
msg_start(ANSI_BLUE, "LOG");

Expand Down
26 changes: 21 additions & 5 deletions tests/unit/misc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,25 @@ test_vfprintf_usermsg(platform_log_handle *log_handle,
/*
* Global data declaration macro:
*/
CTEST_DATA(misc){};
CTEST_DATA(misc)
{
FILE *log_output;
};

CTEST_SETUP(misc) {}
CTEST_SETUP(misc)
{
// It can be surprising to see errors printed from a successful test run.
// So lets send those messages to /dev/null unless VERBOSE=1.
if (Ctest_verbose) {
data->log_output = stdout;
CTEST_LOG_INFO("\nVerbose mode on. This test exercises error-reporting "
"logic, so on success it will print a message "
"that appears to be an error.\n");
} else {
data->log_output = fopen("/dev/null", "w");
ASSERT_NOT_NULL(data->log_output);
}
}

// Optional teardown function for suite, called after every test in suite
CTEST_TEARDOWN(misc) {}
Expand Down Expand Up @@ -90,7 +106,7 @@ CTEST2(misc, test_assert_basic_msg)
MISC_MSG_WITH_NO_ARGS);

ASSERT_STREQN(expmsg, assert_str, strlen(expmsg));
platform_close_log_stream(&stream, Platform_error_log_handle);
platform_close_log_stream(&stream, data->log_output);
}

/*
Expand Down Expand Up @@ -127,7 +143,7 @@ CTEST2(misc, test_assert_msg_with_args)
arg_name);

ASSERT_STREQN(expmsg, assert_str, strlen(expmsg));
platform_close_log_stream(&stream, Platform_error_log_handle);
platform_close_log_stream(&stream, data->log_output);
}

/*
Expand Down Expand Up @@ -164,7 +180,7 @@ CTEST2(misc, test_ctest_assert_prints_user_msg_with_params)
expmsg,
expmsg_len,
assert_str);
platform_close_log_stream(&stream, Platform_error_log_handle);
platform_close_log_stream(&stream, data->log_output);
}

/* Helper functions follow all test case methods */
Expand Down
Loading