Skip to content
This repository was archived by the owner on Aug 19, 2019. It is now read-only.

Conversation

@dhrupadb
Copy link
Contributor

No description provided.

@igorpeshansky igorpeshansky changed the title Unittests for MetadataStore and Metadata struct Unit tests for MetadataStore Mar 28, 2018
src/store.h Outdated

private:
friend class MetadataReporter;
friend class MetadataAgentStoreTest;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why MetadataAgentStoreTest and not MetadataStoreTest?

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.


class MetadataAgentStoreTest : public ::testing::Test {
protected:
Configuration *config;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't we make this a unique_ptr? Then you don't have to worry about cleaning it up. Ditto with the store pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

N/A

Configuration *config;
MetadataStore* store;

void SetupStore() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be done in the constructor, can't it? Then they won't even need to be pointers -- just inline objects.

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.

MetadataStore* store;

void SetupStore() {
config = new Configuration(std::istringstream(""));
Copy link
Contributor

Choose a reason for hiding this comment

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

This is equivalent to new Configuration().

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.

time::rfc3339::FromString("2018-03-03T01:23:45.678901234Z"),
time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
json::Parser::FromString("{\"f\":\"hello\"}")
);
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't a container -- just close the parenthesis on the above line. Same everywhere below.

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.

false,
time::rfc3339::FromString("2018-03-03T01:23:45.678901234Z"),
time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
json::Parser::FromString("{\"f\":\"hello\"}")
Copy link
Contributor

Choose a reason for hiding this comment

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

json::object({{"f": json::string("hello")}})

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.

MetadataStore::Metadata m(
"default-version",
false,
time::rfc3339::FromString("2018-03-03T01:23:45.678901234Z"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use std::chrono::system_clock::now()?

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.

m.created_at);
EXPECT_EQ(time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
m.collected_at);
const auto& obj = m.metadata->As<json::Object>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Careful -- the return value isn't a reference. But here auto doesn't buy you anything anyway -- just use const json::Object* obj.

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.

m.collected_at);
EXPECT_EQ("{}", m.metadata->ToString());
EXPECT_FALSE(m.is_deleted);
EXPECT_TRUE(m.ignore);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the only field worth checking. The rest are implementation details.

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.

);
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ("default-version", m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
Copy link
Contributor

Choose a reason for hiding this comment

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

You'll want to check that the clone isn't ignored (EXPECT_FALSE(m_clone.ignore)).

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

Choose a reason for hiding this comment

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

Oops, looks like you already had it and I missed it.

Copy link
Contributor Author

@dhrupadb dhrupadb left a comment

Choose a reason for hiding this comment

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

PTAL

src/store.h Outdated

private:
friend class MetadataReporter;
friend class MetadataAgentStoreTest;
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.

Configuration *config;
MetadataStore* store;

void SetupStore() {
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.

MetadataStore* store;

void SetupStore() {
config = new Configuration(std::istringstream(""));
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.


};

TEST_F(MetadataAgentStoreTest, ResourceIDStore) {
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.


TEST_F(MetadataAgentStoreTest, ResourceNotFoundStore) {
SetupStore();
EXPECT_THROW(store->LookupResource("some_resource_id").type(),
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.

false,
time::rfc3339::FromString("2018-03-03T01:23:45.678901234Z"),
time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
json::Parser::FromString("{\"f\":\"hello\"}")
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.

m.created_at);
EXPECT_EQ(time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
m.collected_at);
const auto& obj = m.metadata->As<json::Object>();
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.

);
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ("default-version", m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
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.

m.collected_at);
EXPECT_EQ("{}", m.metadata->ToString());
EXPECT_FALSE(m.is_deleted);
EXPECT_TRUE(m.ignore);
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.

SetupStore();
MonitoredResource mr("some_resource", {});
std::vector<std::string> resourceId(1, "id");
store->UpdateResource(resourceId, mr);
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.


MetadataStoreTest() : config(), store(config) {}

std::map<MonitoredResource, MetadataStore::Metadata> GetMetadataMap() {
Copy link
Contributor

Choose a reason for hiding this comment

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

[Optional] Mark this function as const.

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.

EXPECT_THROW(store.LookupResource("some_resource_id"), std::out_of_range);
}

TEST_F(MetadataStoreTest, ManyResources) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we could come up with some consistent naming scheme, e.g., OneResource above, MultipleResources here, OneResourceMultipleIds below, then MultipleResourcesMultipleIds, etc...

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.

TEST_F(MetadataStoreTest, ResourceID) {
MonitoredResource mr("some_resource", {});
store.UpdateResource({"id"}, mr);
EXPECT_EQ("some_resource", store.LookupResource("id").type());
Copy link
Contributor

Choose a reason for hiding this comment

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

[Optional] MonitoredResource has an equality operator defined. So you can just compare monitored resources for equality, e.g., EXPECT_EQ(mr, store.LookupResource("id"));.

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.

EXPECT_EQ("some_resource", store.LookupResource("id2").type());
store.UpdateResource({"id-a", "id-b"}, mr);
EXPECT_EQ("some_resource", store.LookupResource("id-a").type());
EXPECT_EQ("some_resource", store.LookupResource("id-b").type());
Copy link
Contributor

Choose a reason for hiding this comment

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

We should check whether "id1" and "id2" still map to the resource. This will document the current behavior, and allow a discussion of whether that's the behavior we want.

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.

EXPECT_TRUE(metadata_map.empty());
}

TEST_F(MetadataStoreTest, EmptyMetadataNonemptyResource) {
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 nice to name tests according to what they test and the expected outcome. How about UpdateResourceDoesNotUpdateMetadata, UpdateMetadataChangesMetadataMap, etc?

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.

store.UpdateMetadata(mr1, std::move(m1));
store.UpdateMetadata(mr2, std::move(m2));
const auto metadata_map_before = GetMetadataMap();
EXPECT_FALSE(metadata_map_before.empty());
Copy link
Contributor

Choose a reason for hiding this comment

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

You can check the exact size instead, here and below.

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.

EXPECT_THROW(metadata_map_after.at(mr2), std::out_of_range);
}

TEST(MetadataTest, ParseMetadata) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Umm, what exactly is this testing? The fact that you can retrieve the fields?
The only thing that's worth testing here, IMO, is that a metadata that wasn't constructed via IGNORED() is not ignored (i.e., EXPECT_FALSE(m.ignore);). I'd even call this test ConstructedMetadataNotIgnored or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just checking that the default constructor works properly. Updated.

time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ("default-version", m_clone.version);
Copy link
Contributor

Choose a reason for hiding this comment

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

How about EXPECT_EQ(m.version, m_clone.version);, etc?

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. for metadata it needs a deep comparison so left it as is.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can just compare the ToString values, i.e., EXPECT_EQ(m.metadata->ToString(), m_clone.metadata->ToString())...

Copy link
Contributor

Choose a reason for hiding this comment

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

Not 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.

Done.


TEST(MetadataTest, TestIgnoredMetadata) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
EXPECT_FALSE(m.is_deleted);
Copy link
Contributor

Choose a reason for hiding this comment

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

How is this relevant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Forgot to delete that. PTAL.

json::object({{"f", json::string("hello")}}));
EXPECT_EQ("default-version", m.version);
EXPECT_FALSE(m.is_deleted);
EXPECT_FALSE(m.ignore);
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's make sure to test this first, and then test the contents.

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

@dhrupadb dhrupadb left a comment

Choose a reason for hiding this comment

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

PTAL


MetadataStoreTest() : config(), store(config) {}

std::map<MonitoredResource, MetadataStore::Metadata> GetMetadataMap() {
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.

TEST_F(MetadataStoreTest, ResourceID) {
MonitoredResource mr("some_resource", {});
store.UpdateResource({"id"}, mr);
EXPECT_EQ("some_resource", store.LookupResource("id").type());
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.

EXPECT_EQ("some_resource", store.LookupResource("id2").type());
store.UpdateResource({"id-a", "id-b"}, mr);
EXPECT_EQ("some_resource", store.LookupResource("id-a").type());
EXPECT_EQ("some_resource", store.LookupResource("id-b").type());
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.

EXPECT_TRUE(metadata_map.empty());
}

TEST_F(MetadataStoreTest, EmptyMetadataNonemptyResource) {
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.

store.UpdateMetadata(mr1, std::move(m1));
store.UpdateMetadata(mr2, std::move(m2));
const auto metadata_map_before = GetMetadataMap();
EXPECT_FALSE(metadata_map_before.empty());
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.

EXPECT_THROW(metadata_map_after.at(mr2), std::out_of_range);
}

TEST(MetadataTest, ParseMetadata) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just checking that the default constructor works properly. Updated.

json::object({{"f", json::string("hello")}}));
EXPECT_EQ("default-version", m.version);
EXPECT_FALSE(m.is_deleted);
EXPECT_FALSE(m.ignore);
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.

time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ("default-version", m_clone.version);
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. for metadata it needs a deep comparison so left it as is.


TEST(MetadataTest, TestIgnoredMetadata) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
EXPECT_FALSE(m.is_deleted);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Forgot to delete that. PTAL.

EXPECT_THROW(store.LookupResource("some_resource_id"), std::out_of_range);
}

TEST_F(MetadataStoreTest, ManyResources) {
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.

EXPECT_EQ(mr, store.LookupResource("id"));
}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe UnknownResourceIdThrowsError?

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

Choose a reason for hiding this comment

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

Not 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.

That's the next test. This was just making sure that an empty store threw an error.

Copy link
Contributor

Choose a reason for hiding this comment

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

The next test actually checks something else. It checks that known keys return data, while unknown keys punt. As opposed to this one, where every key is effectively unknown.
The way it's named now makes it seem like an empty store should always throw an error, where what it's testing is that every lookup will throw an error if the store is empty.
You could call this EmptyStoreLookupThrowsError if you want.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SGTM. updated.

MonitoredResource mr("some_resource", {});
store.UpdateResource({"id"}, mr);
EXPECT_EQ(mr, store.LookupResource("id"));
EXPECT_THROW(store.LookupResource("other_resource"), std::out_of_range);
Copy link
Contributor

Choose a reason for hiding this comment

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

How about switching them around, to ensure that it doesn't keep throwing?

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. You're saying that this guards against multiple throws?

Copy link
Contributor

Choose a reason for hiding this comment

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

It guards against the possibility that once a lookup fails, any subsequent lookup will also throw. Not that this is likely to happen, but unit tests are supposed to be paranoid and guard against corner cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah gotcha. Makes sense.

};

TEST_F(MetadataStoreTest, ResourceWithOneIdStoredCorrectly) {
MonitoredResource mr("some_resource", {});
Copy link
Contributor

Choose a reason for hiding this comment

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

The first value is type, so how about using "type" instead of "some_resource"? Also below.

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.

}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
EXPECT_THROW(store.LookupResource("some_resource_id"), std::out_of_range);
Copy link
Contributor

Choose a reason for hiding this comment

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

s/"some_resource_id"/"unknown_id"/

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

Choose a reason for hiding this comment

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

Let's use either missing_id or unknown_id consistently throughout.

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.

MonitoredResource mr("some_resource", {});
store.UpdateResource({"id"}, mr);
EXPECT_EQ(mr, store.LookupResource("id"));
EXPECT_THROW(store.LookupResource("other_resource"), std::out_of_range);
Copy link
Contributor

Choose a reason for hiding this comment

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

s/"other_resource"/"unknown_id"/

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.

MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ(m.version, m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
EXPECT_FALSE(m_clone.ignore);
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's check this first.

Copy link
Contributor Author

@dhrupadb dhrupadb Mar 29, 2018

Choose a reason for hiding this comment

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

Done.

json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ(m.version, m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not EXPECT_EQ(m.is_deleted, m_clone.is_deleted)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This means the type could change though. Are we ok with that?

Copy link
Contributor

Choose a reason for hiding this comment

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

Huh? Doesn't the construction test check that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. But in case the implementation changes we want to explicitly check the field.

TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_TRUE(m_clone.ignore);
Copy link
Contributor

Choose a reason for hiding this comment

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

[Optional] EXPECT_EQ(m.ignore, m_clone.ignore). But may not be worth it with just one value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same comment as above.

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't the construction test already check that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. But in case the implementation changes we want to explicitly check the field.

void PurgeDeletedEntries() {
store.PurgeDeletedEntries();
}

Copy link
Contributor

Choose a reason for hiding this comment

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

No need for a blank line 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.

Done.


class MetadataStoreTest : public ::testing::Test {
protected:
Configuration config;
Copy link
Contributor

Choose a reason for hiding this comment

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

Data members follow function members (style guide).

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

@dhrupadb dhrupadb left a comment

Choose a reason for hiding this comment

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

PTAL


class MetadataStoreTest : public ::testing::Test {
protected:
Configuration config;
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.

void PurgeDeletedEntries() {
store.PurgeDeletedEntries();
}

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.


};

TEST_F(MetadataStoreTest, ResourceWithOneIdStoredCorrectly) {
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.

};

TEST_F(MetadataStoreTest, ResourceWithOneIdStoredCorrectly) {
MonitoredResource mr("some_resource", {});
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.

EXPECT_EQ(mr, store.LookupResource("id"));
}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
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.

EXPECT_THROW(metadata_map_after.at(mr2), std::out_of_range);
}

TEST(MetadataTest, MetadataParsedCorrectly) {
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.

EXPECT_EQ("hello", obj->Get<json::String>("f"));
}

TEST(MetadataTest, MetadataClonedCorrectly) {
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.

json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ(m.version, m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This means the type could change though. Are we ok with that?

MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ(m.version, m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
EXPECT_FALSE(m_clone.ignore);
Copy link
Contributor Author

@dhrupadb dhrupadb Mar 29, 2018

Choose a reason for hiding this comment

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

Done.

TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_TRUE(m_clone.ignore);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same comment as above.

EXPECT_EQ(mr, store.LookupResource("id"));
}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not done?

MonitoredResource mr("some_resource", {});
store.UpdateResource({"id"}, mr);
EXPECT_EQ(mr, store.LookupResource("id"));
EXPECT_THROW(store.LookupResource("other_resource"), std::out_of_range);
Copy link
Contributor

Choose a reason for hiding this comment

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

It guards against the possibility that once a lookup fails, any subsequent lookup will also throw. Not that this is likely to happen, but unit tests are supposed to be paranoid and guard against corner cases.

}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
EXPECT_THROW(store.LookupResource("some_resource_id"), std::out_of_range);
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's use either missing_id or unknown_id consistently throughout.


TEST_F(MetadataStoreTest, ResourceNotFoundThrowsError) {
MonitoredResource mr("some_resource", {});
TEST_F(MetadataStoreTest, UnknownResourceIdThrowsError) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah. See above. Let's name this one ResourceLookupFailsIndependently or something?

Copy link
Contributor

Choose a reason for hiding this comment

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

This test actually conflates a few things, so let's decouple them. First, let's also add a separate test to just store a resource and return it successfully (KnownResourceIdFindsResource). Then, I'd name this test ResourceLookupFailuresAreIndependent, because it tests the interaction between lookup failures and lookup successes.

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. The first test ResourceWithOneIdCorrectlyStored is the same as KnownResourceIdFindsResource.

json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ(m.version, m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
Copy link
Contributor

Choose a reason for hiding this comment

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

Huh? Doesn't the construction test check that?

time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ("default-version", m_clone.version);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not done.

m.created_at);
EXPECT_EQ(time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
m.collected_at);
const json::Object* obj = m.metadata->As<json::Object>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Replicating the comment from an earlier thread:
You can just compare the ToString values, i.e., EXPECT_EQ(m.metadata->ToString(), m_clone.metadata->ToString())...

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.

TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_TRUE(m_clone.ignore);
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't the construction test already check that?

Copy link
Contributor Author

@dhrupadb dhrupadb left a comment

Choose a reason for hiding this comment

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

PTAL

EXPECT_EQ(mr, store.LookupResource("id"));
}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
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's the next test. This was just making sure that an empty store threw an error.

m.created_at);
EXPECT_EQ(time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
m.collected_at);
const json::Object* obj = m.metadata->As<json::Object>();
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.

}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
EXPECT_THROW(store.LookupResource("some_resource_id"), std::out_of_range);
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.

MonitoredResource mr("some_resource", {});
store.UpdateResource({"id"}, mr);
EXPECT_EQ(mr, store.LookupResource("id"));
EXPECT_THROW(store.LookupResource("other_resource"), std::out_of_range);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah gotcha. Makes sense.

json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ(m.version, m_clone.version);
EXPECT_FALSE(m_clone.is_deleted);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. But in case the implementation changes we want to explicitly check the field.

TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_TRUE(m_clone.ignore);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. But in case the implementation changes we want to explicitly check the field.

time::rfc3339::FromString("2018-03-03T01:32:45.678901234Z"),
json::object({{"f", json::string("hello")}}));
MetadataStore::Metadata m_clone = m.Clone();
EXPECT_EQ("default-version", m_clone.version);
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.

EXPECT_EQ(mr, store.LookupResource("id"));
}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The next test actually checks something else. It checks that known keys return data, while unknown keys punt. As opposed to this one, where every key is effectively unknown.
The way it's named now makes it seem like an empty store should always throw an error, where what it's testing is that every lookup will throw an error if the store is empty.
You could call this EmptyStoreLookupThrowsError if you want.


TEST_F(MetadataStoreTest, ResourceNotFoundThrowsError) {
MonitoredResource mr("some_resource", {});
TEST_F(MetadataStoreTest, UnknownResourceIdThrowsError) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This test actually conflates a few things, so let's decouple them. First, let's also add a separate test to just store a resource and return it successfully (KnownResourceIdFindsResource). Then, I'd name this test ResourceLookupFailuresAreIndependent, because it tests the interaction between lookup failures and lookup successes.

Copy link
Contributor Author

@dhrupadb dhrupadb left a comment

Choose a reason for hiding this comment

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

PTAL

EXPECT_EQ(mr, store.LookupResource("id"));
}

TEST_F(MetadataStoreTest, EmptyStoreThrowsError) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

SGTM. updated.

Copy link
Contributor

@igorpeshansky igorpeshansky left a comment

Choose a reason for hiding this comment

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

LGTM :shipit:

store.PurgeDeletedEntries();
}

Configuration config;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we actually need a local copy of the config? I'm only seeing it being used in the constructor.

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. Good catch.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, we do need a local copy of the config, to make sure it gets properly cleaned up. The store does not own the config reference, so the new code leaks. In the previous version, the MetadataStoreTest object owned the Configuration object, and cleanup happened automatically. Can we please revert this change?

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.

TEST_F(MetadataStoreTest, MultipleUpdateMetadataChangesMetadataMap) {
MonitoredResource mr1("type1", {});
MonitoredResource mr2("type2", {});
MetadataStore::Metadata m1(
Copy link
Contributor

Choose a reason for hiding this comment

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

Observation, I got really confused when reading the comparisons, as I didn't pick up on mr1 and m1. Would it be worth using metadata1 and metadata2 to keep it incredibly obvious? I know it's not "consistent", but it would have helped when glancing through quickly.

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

Choose a reason for hiding this comment

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

@bmoyles0117 you're right about the confusion, but I actually prefer m over metadata, because metadata.metadata reads really weird. Can we instead address it by renaming mr to resource? Sorry, @dhrupadb...

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.


TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
Copy link
Contributor

@bmoyles0117 bmoyles0117 Mar 29, 2018

Choose a reason for hiding this comment

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

It might seem like overkill, but it would be nice to add EXPECT_TRUE(m.ignore);, as I believe m.Clone() could potentially mutate the object, and thus copy from there and have both be false. If it's not possible that the value could be mutated, ignore :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So I was on the same train but @igorpeshansky 's point is that we should test that "cloning" an IGNORED metadata type works. As a result if .ignore before and after is the same the test worked, independent of the actual value. As is it is impossible to mutate the type of the ignore field because it can only be set via the default constructor.

Copy link
Contributor

Choose a reason for hiding this comment

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

@dhrupadb, weren't you testing m_clone.ignore? Bryan suggests testing m.ignore. However, Clone() is declared const, so it shouldn't mutate any publicly visible state.

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. Added a check for m.

Copy link
Contributor

Choose a reason for hiding this comment

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

No point in checking m, really, unless you don't trust const.
One thing that would help is changing the implementation of Clone() to use IGNORED() directly rather than the empty constructor/initializer list (effectively inlining the IGNORED() implementation). I've taken the liberty of pushing that change into your branch, hope that's ok.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep LGTM. Thanks!

Copy link
Contributor Author

@dhrupadb dhrupadb left a comment

Choose a reason for hiding this comment

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

PTAL


TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So I was on the same train but @igorpeshansky 's point is that we should test that "cloning" an IGNORED metadata type works. As a result if .ignore before and after is the same the test worked, independent of the actual value. As is it is impossible to mutate the type of the ignore field because it can only be set via the default constructor.

TEST_F(MetadataStoreTest, MultipleUpdateMetadataChangesMetadataMap) {
MonitoredResource mr1("type1", {});
MonitoredResource mr2("type2", {});
MetadataStore::Metadata m1(
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.

store.PurgeDeletedEntries();
}

Configuration config;
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. Good catch.

Copy link
Contributor

@bmoyles0117 bmoyles0117 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@bmoyles0117 bmoyles0117 left a comment

Choose a reason for hiding this comment

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

LGTM


TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
Copy link
Contributor

Choose a reason for hiding this comment

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

@dhrupadb, weren't you testing m_clone.ignore? Bryan suggests testing m.ignore. However, Clone() is declared const, so it shouldn't mutate any publicly visible state.

TEST_F(MetadataStoreTest, MultipleUpdateMetadataChangesMetadataMap) {
MonitoredResource mr1("type1", {});
MonitoredResource mr2("type2", {});
MetadataStore::Metadata m1(
Copy link
Contributor

Choose a reason for hiding this comment

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

@bmoyles0117 you're right about the confusion, but I actually prefer m over metadata, because metadata.metadata reads really weird. Can we instead address it by renaming mr to resource? Sorry, @dhrupadb...

store.PurgeDeletedEntries();
}

Configuration config;
Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, we do need a local copy of the config, to make sure it gets properly cleaned up. The store does not own the config reference, so the new code leaks. In the previous version, the MetadataStoreTest object owned the Configuration object, and cleanup happened automatically. Can we please revert this change?

@dhrupadb dhrupadb force-pushed the dhrupadb-metadata-store-unittests branch from 78587f2 to 1d173e5 Compare March 29, 2018 23:46
Copy link
Contributor Author

@dhrupadb dhrupadb left a comment

Choose a reason for hiding this comment

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

PTAL

store.PurgeDeletedEntries();
}

Configuration config;
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.

TEST_F(MetadataStoreTest, MultipleUpdateMetadataChangesMetadataMap) {
MonitoredResource mr1("type1", {});
MonitoredResource mr2("type2", {});
MetadataStore::Metadata m1(
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.


TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
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. Added a check for m.

Copy link
Contributor

@igorpeshansky igorpeshansky left a comment

Choose a reason for hiding this comment

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

LGTM :shipit:


TEST(MetadataTest, IgnoredMetadataCorrectlyCloned) {
MetadataStore::Metadata m = MetadataStore::Metadata::IGNORED();
MetadataStore::Metadata m_clone = m.Clone();
Copy link
Contributor

Choose a reason for hiding this comment

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

No point in checking m, really, unless you don't trust const.
One thing that would help is changing the implementation of Clone() to use IGNORED() directly rather than the empty constructor/initializer list (effectively inlining the IGNORED() implementation). I've taken the liberty of pushing that change into your branch, hope that's ok.

Copy link
Contributor

@bmoyles0117 bmoyles0117 left a comment

Choose a reason for hiding this comment

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

LGTM

@igorpeshansky igorpeshansky merged commit b17a704 into master Mar 30, 2018
@igorpeshansky igorpeshansky deleted the dhrupadb-metadata-store-unittests branch March 30, 2018 06:23
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants