blob: 3f854fea8b2a00f867cb81abd635752083c91ac8 [file] [log] [blame]
// 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_manager.h"
#include <cstdlib> // for abs().
#include <vector>
#include <base/bind.h>
#include <base/values.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <weave/provider/test/mock_config_store.h>
#include "src/commands/schema_constants.h"
#include "src/commands/unittest_utils.h"
#include "src/states/error_codes.h"
#include "src/states/mock_state_change_queue_interface.h"
namespace weave {
using testing::_;
using testing::Return;
using test::CreateDictionaryValue;
namespace {
const char kBaseDefinition[] = R"({
"base": {
"manufacturer":"string",
"serialNumber":"string"
},
"device": {
"state_property":"string"
}
})";
std::unique_ptr<base::DictionaryValue> GetTestSchema() {
return CreateDictionaryValue(kBaseDefinition);
}
const char kBaseDefaults[] = R"({
"base": {
"manufacturer":"Test Factory",
"serialNumber":"Test Model"
}
})";
std::unique_ptr<base::DictionaryValue> GetTestValues() {
return CreateDictionaryValue(kBaseDefaults);
}
} // anonymous namespace
class StateManagerTest : public ::testing::Test {
public:
void SetUp() override {
// Initial expectations.
EXPECT_CALL(mock_state_change_queue_, IsEmpty()).Times(0);
EXPECT_CALL(mock_state_change_queue_, NotifyPropertiesUpdated(_, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_state_change_queue_, GetAndClearRecordedStateChanges())
.Times(0);
mgr_.reset(new StateManager(&mock_state_change_queue_));
EXPECT_CALL(*this, OnStateChanged()).Times(2);
mgr_->AddChangedCallback(
base::Bind(&StateManagerTest::OnStateChanged, base::Unretained(this)));
LoadStateDefinition(GetTestSchema().get(), nullptr);
ASSERT_TRUE(mgr_->SetProperties(*GetTestValues().get(), nullptr));
}
void TearDown() override { mgr_.reset(); }
void LoadStateDefinition(const base::DictionaryValue* json,
ErrorPtr* error) {
ASSERT_TRUE(mgr_->LoadStateDefinition(*json, error));
}
bool SetPropertyValue(const std::string& name,
const base::Value& value,
ErrorPtr* error) {
return mgr_->SetPropertyValue(name, value, timestamp_, error);
}
MOCK_CONST_METHOD0(OnStateChanged, void());
base::Time timestamp_{base::Time::Now()};
std::unique_ptr<StateManager> mgr_;
testing::StrictMock<MockStateChangeQueueInterface> mock_state_change_queue_;
};
TEST(StateManager, Empty) {
testing::StrictMock<MockStateChangeQueueInterface> mock_state_change_queue;
StateManager manager(&mock_state_change_queue);
}
TEST_F(StateManagerTest, Initialized) {
auto expected = R"({
'base': {
'manufacturer': 'Test Factory',
'serialNumber': 'Test Model'
},
'device': {
'state_property': ''
}
})";
EXPECT_JSON_EQ(expected, *mgr_->GetState());
}
TEST_F(StateManagerTest, LoadStateDefinition) {
auto dict = CreateDictionaryValue(R"({
'power': {
'battery_level':'integer'
}
})");
LoadStateDefinition(dict.get(), nullptr);
auto expected = R"({
'base': {
'manufacturer': 'Test Factory',
'serialNumber': 'Test Model'
},
'power': {
'battery_level': 0
},
'device': {
'state_property': ''
}
})";
EXPECT_JSON_EQ(expected, *mgr_->GetState());
}
TEST_F(StateManagerTest, Startup) {
StateManager manager(&mock_state_change_queue_);
auto state_definition = R"({
"base": {
"firmwareVersion": "string",
"localDiscoveryEnabled": "boolean",
"localAnonymousAccessMaxRole": [ "none", "viewer", "user" ],
"localPairingEnabled": "boolean"
},
"power": {"battery_level":"integer"}
})";
ASSERT_TRUE(manager.LoadStateDefinitionFromJson(state_definition, nullptr));
auto state_values = R"({
"base": {
"firmwareVersion": "unknown",
"localDiscoveryEnabled": false,
"localAnonymousAccessMaxRole": "none",
"localPairingEnabled": false
},
"power": {"battery_level":44}
})";
ASSERT_TRUE(manager.SetPropertiesFromJson(state_values, nullptr));
auto expected = R"({
'base': {
'firmwareVersion': 'unknown',
'localAnonymousAccessMaxRole': 'none',
'localDiscoveryEnabled': false,
'localPairingEnabled': false
},
'power': {
'battery_level': 44
}
})";
EXPECT_JSON_EQ(expected, *manager.GetState());
}
TEST_F(StateManagerTest, SetPropertyValue) {
ValueMap expected_prop_set{
{"device.state_property", test::make_string_prop_value("Test Value")},
};
EXPECT_CALL(mock_state_change_queue_,
NotifyPropertiesUpdated(timestamp_, expected_prop_set))
.WillOnce(Return(true));
ASSERT_TRUE(SetPropertyValue("device.state_property",
base::StringValue{"Test Value"}, nullptr));
auto expected = R"({
'base': {
'manufacturer': 'Test Factory',
'serialNumber': 'Test Model'
},
'device': {
'state_property': 'Test Value'
}
})";
EXPECT_JSON_EQ(expected, *mgr_->GetState());
}
TEST_F(StateManagerTest, SetPropertyValue_Error_NoName) {
ErrorPtr error;
ASSERT_FALSE(SetPropertyValue("", base::FundamentalValue{0}, &error));
EXPECT_EQ(errors::state::kDomain, error->GetDomain());
EXPECT_EQ(errors::state::kPropertyNameMissing, error->GetCode());
}
TEST_F(StateManagerTest, SetPropertyValue_Error_NoPackage) {
ErrorPtr error;
ASSERT_FALSE(
SetPropertyValue("state_property", base::FundamentalValue{0}, &error));
EXPECT_EQ(errors::state::kDomain, error->GetDomain());
EXPECT_EQ(errors::state::kPackageNameMissing, error->GetCode());
}
TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownPackage) {
ErrorPtr error;
ASSERT_FALSE(
SetPropertyValue("power.level", base::FundamentalValue{0}, &error));
EXPECT_EQ(errors::state::kDomain, error->GetDomain());
EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
}
TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownProperty) {
ErrorPtr error;
ASSERT_FALSE(
SetPropertyValue("base.level", base::FundamentalValue{0}, &error));
EXPECT_EQ(errors::state::kDomain, error->GetDomain());
EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
}
TEST_F(StateManagerTest, GetAndClearRecordedStateChanges) {
EXPECT_CALL(mock_state_change_queue_, NotifyPropertiesUpdated(timestamp_, _))
.WillOnce(Return(true));
ASSERT_TRUE(SetPropertyValue("device.state_property",
base::StringValue{"Test Value"}, nullptr));
std::vector<StateChange> expected_val;
expected_val.emplace_back(
timestamp_, ValueMap{{"device.state_property",
test::make_string_prop_value("Test Value")}});
EXPECT_CALL(mock_state_change_queue_, GetAndClearRecordedStateChanges())
.WillOnce(Return(expected_val));
EXPECT_CALL(mock_state_change_queue_, GetLastStateChangeId())
.WillOnce(Return(0));
auto changes = mgr_->GetAndClearRecordedStateChanges();
ASSERT_EQ(1, changes.second.size());
EXPECT_EQ(expected_val.back().timestamp, changes.second.back().timestamp);
EXPECT_EQ(expected_val.back().changed_properties,
changes.second.back().changed_properties);
}
TEST_F(StateManagerTest, SetProperties) {
ValueMap expected_prop_set{
{"base.manufacturer", test::make_string_prop_value("No Name")},
};
EXPECT_CALL(mock_state_change_queue_,
NotifyPropertiesUpdated(_, expected_prop_set))
.WillOnce(Return(true));
EXPECT_CALL(*this, OnStateChanged()).Times(1);
ASSERT_TRUE(mgr_->SetProperties(
*CreateDictionaryValue("{'base':{'manufacturer':'No Name'}}"), nullptr));
auto expected = R"({
'base': {
'manufacturer': 'No Name',
'serialNumber': 'Test Model'
},
'device': {
'state_property': ''
}
})";
EXPECT_JSON_EQ(expected, *mgr_->GetState());
}
TEST_F(StateManagerTest, GetProperty) {
EXPECT_JSON_EQ("'Test Model'", *mgr_->GetProperty("base.serialNumber"));
EXPECT_JSON_EQ("''", *mgr_->GetProperty("device.state_property"));
EXPECT_EQ(nullptr, mgr_->GetProperty("device.unknown"));
EXPECT_EQ(nullptr, mgr_->GetProperty("unknown.state_property"));
}
} // namespace weave