Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a JSON extract test that extracts row data #1066

Merged
merged 13 commits into from
Nov 17, 2021

Conversation

waynelwarren
Copy link
Contributor

This is a different test file than test_gaia_db_extract.cpp because it uses one of the test DDL files, which is required in order to insert rows with direct access.

The test exercises the gaia_db_extract function in new ways with a variety of parameters.

The CMakeLists.txt file was updated according to a pattern found in other tests.

This has test already founds bugs, which have been fixed in the gaia_db_extract.cpp file.

auto field_name = field_object.name();
switch (value.type)
{
case reflection::String:
row[field_name] = value.hold.string_value;
// Null is possible.
row[field_name] = value.hold.string_value == nullptr ? s_null_string : value.hold.string_value;
Copy link
Contributor

Choose a reason for hiding this comment

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

Enclose the expression in parentheses - i.e.:

row[field_name] = (value.hold.string_value == nullptr) ? s_null_string : value.hold.string_value;

I'm surprised that clang didn't ask for this.

@@ -192,14 +196,15 @@ static bool add_field_value(json_t& row, const gaia_field_t& field_object, const
static string dump_rows(string database, string table, uint64_t start_after, uint32_t row_limit)
{
bool terminate = false;
bool top_level_included = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Start the boolean names with a verb. This should be include_top_level instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

Or it sounds like has_included_top_level is actually the better form.

// Try this with a number of permutations.
test_with_different_sizes(100, 3);

// It is important to run this with > 1024 rows.
Copy link
Contributor

@LaurentiuCristofor LaurentiuCristofor Nov 6, 2021

Choose a reason for hiding this comment

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

You could define a min constant, set it to 1024 and pass values based on it to the tests.

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 think I did what you suggested on all comments (so far).

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually if you're referring to the strange iterator behavior you observed, you want the constant db_server_t::c_stream_batch_size. That's private for now though.

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW I just duplicated that constant in production/db/core/tests/test_db_client.cpp:

// duplicated from production/db/core/inc/db_server.hpp
constexpr size_t c_stream_batch_size = 1 << 10;

Not sure if duplication or loss of encapsulation is the lesser evil here.

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'm not sure why this test should be aware of such a constant. The discovery of the issue had nothing to do with internal knowledge.

@senderista
Copy link
Contributor

senderista commented Nov 9, 2021

Just a nit: I think there's a bit of confusion re: the meaning of *PRIVATE_INCLUDES vs. *PUBLIC_INCLUDES. The intention was to specify whether this target's include directories are inherited by other targets depending on this target via target_link_libraries() (the PUBLIC keyword forces inheritance). It doesn't have anything to do with whether the include directories are in a location that we consider "public" (i.e. part of the SDK) or "private" (i.e. internal). For an executable, no other targets will ever depend on this target, so the PUBLIC/PRIVATE include dir distinction is unnecessary (everything can be PRIVATE).

@@ -158,7 +158,8 @@ static bool add_field_value(json_t& row, const gaia_field_t& field_object, const
switch (value.type)
{
case reflection::String:
row[field_name] = value.hold.string_value;
// Null is possible.
row[field_name] = (value.hold.string_value == nullptr) ? c_empty_string : value.hold.string_value;

Choose a reason for hiding this comment

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

did clang-tidy ask for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, but Laurentiu thought that it should.

// Utility function that creates one named employee row.
employee_t create_employee(const char* name)
{
auto w = employee_writer();

Choose a reason for hiding this comment

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

w should be employee_w according to standards.

Copy link
Contributor

Choose a reason for hiding this comment

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

And I'd change e->employee below as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay @LaurentiuCristofor , did that too.

{
begin_transaction();

#ifdef GAIAPLAT_1673

Choose a reason for hiding this comment

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

this probably should have a comment talking about why

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a comment.

return e;
}

void test_with_different_sizes(uint32_t number_rows_inserted, uint32_t block_size)

Choose a reason for hiding this comment

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

test methods should have comments that very clearly document what it is testing and what the expected result is.

without this information, I cannot figure out what this test is for.

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 have commented all of the test functions, including the new TEST_F().

};

// Store rows, convert them to JSON, scan through them as multiple blocks.
TEST_F(row_extract_test, read_blocks)

Choose a reason for hiding this comment

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

if this is the actual test, why is it calling a function/method that has a name starting with test_?

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 simply named the function after what it does. the Actual test has a number of sub-tests.

@waynelwarren
Copy link
Contributor Author

I just added an entirely new test here - it does the full cycle of insert_row(), extract as JSON string, parse from JSON string, compare JSON values to original database values. If you can, @JackAtGaia and @LaurentiuCristofor , I would appreciate your review.

Copy link
Contributor

@LaurentiuCristofor LaurentiuCristofor left a comment

Choose a reason for hiding this comment

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

Left some minor comments, LGTM otherwise.

// Create a bunch of employee rows.
for (uint32_t i = 0; i < number_rows_inserted; i++)
{
string empl_name = "Mr. " + std::to_string(i);
Copy link
Contributor

Choose a reason for hiding this comment

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

empl_name could just be reduced to name here.

uint64_t row_id = c_start_at_first;
int32_t row_count = 0;
int32_t block_count = 0;
for (;;)
Copy link
Contributor

Choose a reason for hiding this comment

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

It's more typical to use while (true) for such loops.

++row_count;
}
}
if (block_size > 0)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd add a line to separate this if from the previous loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Easy enough, I have made the changes. See them in the next commit.

In a previous life, for (;;) was a common convention. I think both forms are clear.

@waynelwarren waynelwarren merged commit ae328d9 into master Nov 17, 2021
@waynelwarren waynelwarren deleted the wayne/add-json-extract-test branch November 17, 2021 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants