| // Copyright 2015 The Weave Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/states/state_change_queue.h" | |
| #include <gtest/gtest.h> | |
| #include "src/bind_lambda.h" | |
| #include "src/commands/unittest_utils.h" | |
| namespace weave { | |
| class StateChangeQueueTest : public ::testing::Test { | |
| public: | |
| void SetUp() override { queue_.reset(new StateChangeQueue(100)); } | |
| void TearDown() override { queue_.reset(); } | |
| std::unique_ptr<StateChangeQueue> queue_; | |
| }; | |
| TEST_F(StateChangeQueueTest, Empty) { | |
| EXPECT_TRUE(queue_->IsEmpty()); | |
| EXPECT_EQ(0, queue_->GetLastStateChangeId()); | |
| EXPECT_TRUE(queue_->GetAndClearRecordedStateChanges().empty()); | |
| } | |
| TEST_F(StateChangeQueueTest, UpdateOne) { | |
| StateChange change{base::Time::Now(), | |
| ValueMap{{"prop.name", test::make_int_prop_value(23)}}}; | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated(change.timestamp, | |
| change.changed_properties)); | |
| EXPECT_FALSE(queue_->IsEmpty()); | |
| EXPECT_EQ(1, queue_->GetLastStateChangeId()); | |
| auto changes = queue_->GetAndClearRecordedStateChanges(); | |
| EXPECT_EQ(1, queue_->GetLastStateChangeId()); | |
| ASSERT_EQ(1, changes.size()); | |
| EXPECT_EQ(change.timestamp, changes.front().timestamp); | |
| EXPECT_EQ(change.changed_properties, changes.front().changed_properties); | |
| EXPECT_TRUE(queue_->IsEmpty()); | |
| EXPECT_TRUE(queue_->GetAndClearRecordedStateChanges().empty()); | |
| } | |
| // TODO(vitalybuka): Fix flakiness. | |
| TEST_F(StateChangeQueueTest, DISABLED_UpdateMany) { | |
| StateChange change1{base::Time::Now(), | |
| ValueMap{{"prop.name1", test::make_int_prop_value(23)}}}; | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated(change1.timestamp, | |
| change1.changed_properties)); | |
| StateChange change2{base::Time::Now(), | |
| ValueMap{ | |
| {"prop.name1", test::make_int_prop_value(17)}, | |
| {"prop.name2", test::make_double_prop_value(1.0)}, | |
| {"prop.name3", test::make_bool_prop_value(false)}, | |
| }}; | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated(change2.timestamp, | |
| change2.changed_properties)); | |
| EXPECT_EQ(2, queue_->GetLastStateChangeId()); | |
| EXPECT_FALSE(queue_->IsEmpty()); | |
| auto changes = queue_->GetAndClearRecordedStateChanges(); | |
| ASSERT_EQ(2, changes.size()); | |
| EXPECT_EQ(change1.timestamp, changes[0].timestamp); | |
| EXPECT_EQ(change1.changed_properties, changes[0].changed_properties); | |
| EXPECT_EQ(change2.timestamp, changes[1].timestamp); | |
| EXPECT_EQ(change2.changed_properties, changes[1].changed_properties); | |
| EXPECT_TRUE(queue_->IsEmpty()); | |
| EXPECT_TRUE(queue_->GetAndClearRecordedStateChanges().empty()); | |
| } | |
| TEST_F(StateChangeQueueTest, GroupByTimestamp) { | |
| base::Time timestamp = base::Time::Now(); | |
| base::TimeDelta time_delta = base::TimeDelta::FromMinutes(1); | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| timestamp, ValueMap{{"prop.name1", test::make_int_prop_value(1)}})); | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| timestamp, ValueMap{{"prop.name2", test::make_int_prop_value(2)}})); | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| timestamp, ValueMap{{"prop.name1", test::make_int_prop_value(3)}})); | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| timestamp + time_delta, | |
| ValueMap{{"prop.name1", test::make_int_prop_value(4)}})); | |
| auto changes = queue_->GetAndClearRecordedStateChanges(); | |
| EXPECT_EQ(4, queue_->GetLastStateChangeId()); | |
| ASSERT_EQ(2, changes.size()); | |
| ValueMap expected1{ | |
| {"prop.name1", test::make_int_prop_value(3)}, | |
| {"prop.name2", test::make_int_prop_value(2)}, | |
| }; | |
| ValueMap expected2{ | |
| {"prop.name1", test::make_int_prop_value(4)}, | |
| }; | |
| EXPECT_EQ(timestamp, changes[0].timestamp); | |
| EXPECT_EQ(expected1, changes[0].changed_properties); | |
| EXPECT_EQ(timestamp + time_delta, changes[1].timestamp); | |
| EXPECT_EQ(expected2, changes[1].changed_properties); | |
| } | |
| TEST_F(StateChangeQueueTest, MaxQueueSize) { | |
| queue_.reset(new StateChangeQueue(2)); | |
| base::Time start_time = base::Time::Now(); | |
| base::TimeDelta time_delta1 = base::TimeDelta::FromMinutes(1); | |
| base::TimeDelta time_delta2 = base::TimeDelta::FromMinutes(3); | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| start_time, ValueMap{ | |
| {"prop.name1", test::make_int_prop_value(1)}, | |
| {"prop.name2", test::make_int_prop_value(2)}, | |
| })); | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| start_time + time_delta1, | |
| ValueMap{ | |
| {"prop.name1", test::make_int_prop_value(3)}, | |
| {"prop.name3", test::make_int_prop_value(4)}, | |
| })); | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| start_time + time_delta2, | |
| ValueMap{ | |
| {"prop.name10", test::make_int_prop_value(10)}, | |
| {"prop.name11", test::make_int_prop_value(11)}, | |
| })); | |
| EXPECT_EQ(3, queue_->GetLastStateChangeId()); | |
| auto changes = queue_->GetAndClearRecordedStateChanges(); | |
| ASSERT_EQ(2, changes.size()); | |
| ValueMap expected1{ | |
| {"prop.name1", test::make_int_prop_value(3)}, | |
| {"prop.name2", test::make_int_prop_value(2)}, | |
| {"prop.name3", test::make_int_prop_value(4)}, | |
| }; | |
| EXPECT_EQ(start_time + time_delta1, changes[0].timestamp); | |
| EXPECT_EQ(expected1, changes[0].changed_properties); | |
| ValueMap expected2{ | |
| {"prop.name10", test::make_int_prop_value(10)}, | |
| {"prop.name11", test::make_int_prop_value(11)}, | |
| }; | |
| EXPECT_EQ(start_time + time_delta2, changes[1].timestamp); | |
| EXPECT_EQ(expected2, changes[1].changed_properties); | |
| } | |
| TEST_F(StateChangeQueueTest, ImmediateStateChangeNotification) { | |
| // When queue is empty, registering a new callback will trigger it. | |
| bool called = false; | |
| auto callback = [&called](StateChangeQueueInterface::UpdateID id) { | |
| called = true; | |
| }; | |
| queue_->AddOnStateUpdatedCallback(base::Bind(callback)); | |
| EXPECT_TRUE(called); | |
| } | |
| TEST_F(StateChangeQueueTest, DelayedStateChangeNotification) { | |
| // When queue is not empty, registering a new callback will not trigger it. | |
| ASSERT_TRUE(queue_->NotifyPropertiesUpdated( | |
| base::Time::Now(), ValueMap{ | |
| {"prop.name1", test::make_int_prop_value(1)}, | |
| {"prop.name2", test::make_int_prop_value(2)}, | |
| })); | |
| auto callback = [](StateChangeQueueInterface::UpdateID id) { | |
| FAIL() << "This should not be called"; | |
| }; | |
| queue_->AddOnStateUpdatedCallback(base::Bind(callback)); | |
| } | |
| } // namespace weave |