Commit bc52722a6d2a0b1ec82ebdfb67e91790c6138ecd

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent ec625114

Add documentation and tests for BridgeConfig.

include/hueplusplus/BridgeConfig.h
@@ -27,6 +27,7 @@ @@ -27,6 +27,7 @@
27 27
28 namespace hueplusplus 28 namespace hueplusplus
29 { 29 {
  30 +//! \brief API version consisting of major, minor and patch version
30 struct Version 31 struct Version
31 { 32 {
32 int major; 33 int major;
@@ -34,31 +35,62 @@ struct Version @@ -34,31 +35,62 @@ struct Version
34 int patch; 35 int patch;
35 }; 36 };
36 37
  38 +//! \brief User that is whitelisted for Hue API usage
37 struct WhitelistedUser 39 struct WhitelistedUser
38 { 40 {
  41 + //! \brief API username of the user
39 std::string key; 42 std::string key;
  43 + //! \brief Name provided on user creation
40 std::string name; 44 std::string name;
  45 + //! \brief Last time the user was used
41 time::AbsoluteTime lastUsed; 46 time::AbsoluteTime lastUsed;
  47 + //! \brief Time the user was created
42 time::AbsoluteTime created; 48 time::AbsoluteTime created;
43 }; 49 };
44 50
  51 +//! \brief General bridge configuration properties.
45 class BridgeConfig 52 class BridgeConfig
46 { 53 {
47 public: 54 public:
  55 + //! \brief Construct BridgeConfig
48 BridgeConfig(std::shared_ptr<APICache> baseCache, std::chrono::steady_clock::duration refreshDuration); 56 BridgeConfig(std::shared_ptr<APICache> baseCache, std::chrono::steady_clock::duration refreshDuration);
49 57
  58 +
  59 + //! \brief Refreshes internal cached state.
  60 + //! \throws std::system_error when system or socket operations fail
  61 + //! \throws HueException when response contained no body
  62 + //! \throws HueAPIResponseException when response contains an error
  63 + //! \throws nlohmann::json::parse_error when response could not be parsed
50 void refresh(); 64 void refresh();
51 65
  66 + //! \brief Get the list of whitelisted users
  67 + //! \returns All users authorized for API access
52 std::vector<WhitelistedUser> getWhitelistedUsers() const; 68 std::vector<WhitelistedUser> getWhitelistedUsers() const;
  69 + //! \brief Remove user from the whitelist
  70 + //! \param userKey The API username of the user to remove
  71 + //! \throws std::system_error when system or socket operations fail
  72 + //! \throws HueException when response contained no body
  73 + //! \throws HueAPIResponseException when response contains an error
  74 + //! \throws nlohmann::json::parse_error when response could not be parsed
53 void removeUser(const std::string& userKey); 75 void removeUser(const std::string& userKey);
54 76
  77 + //! \brief Get link button state
  78 + //! \returns true when link button was pressed in the last 30 seconds.
  79 + //!
  80 + //! Indicates whether new users can be added currently.
55 bool getLinkButton() const; 81 bool getLinkButton() const;
  82 + //! \brief Set the link button state to pressed
56 void pressLinkButton(); 83 void pressLinkButton();
57 84
  85 + //! \brief Add the closest lamp to the network
58 void touchLink(); 86 void touchLink();
59 87
  88 + //! \brief Get bridge MAC address
60 std::string getMACAddress() const; 89 std::string getMACAddress() const;
  90 + //! \brief Get current (of last refresh) UTC time of the bridge
61 time::AbsoluteTime getUTCTime() const; 91 time::AbsoluteTime getUTCTime() const;
  92 + //! \brief Get configured timezone for the bridge
  93 + //! \note For times not in UTC, the timezone of the program and the bridge are assumed to be identical.
62 std::string getTimezone() const; 94 std::string getTimezone() const;
63 95
64 protected: 96 protected:
include/hueplusplus/Hue.h
@@ -156,6 +156,10 @@ public: @@ -156,6 +156,10 @@ public:
156 //! Should only be called rarely, as a full refresh is costly and usually not necessary. 156 //! Should only be called rarely, as a full refresh is costly and usually not necessary.
157 //! Instead refresh only the parts you are interested in or rely on periodic refreshes 157 //! Instead refresh only the parts you are interested in or rely on periodic refreshes
158 //! that happen automatically when calling non-const methods. 158 //! that happen automatically when calling non-const methods.
  159 + //! \throws std::system_error when system or socket operations fail
  160 + //! \throws HueException when response contained no body
  161 + //! \throws HueAPIResponseException when response contains an error
  162 + //! \throws nlohmann::json::parse_error when response could not be parsed
159 void refresh(); 163 void refresh();
160 164
161 //! \brief Function to get the ip address of the hue bridge 165 //! \brief Function to get the ip address of the hue bridge
src/Hue.cpp
@@ -282,5 +282,6 @@ void Hue::setHttpHandler(std::shared_ptr&lt;const IHttpHandler&gt; handler) @@ -282,5 +282,6 @@ void Hue::setHttpHandler(std::shared_ptr&lt;const IHttpHandler&gt; handler)
282 scheduleList = CreateableResourceList<Schedule, int, CreateSchedule>(stateCache, "schedules", refreshDuration); 282 scheduleList = CreateableResourceList<Schedule, int, CreateSchedule>(stateCache, "schedules", refreshDuration);
283 sceneList = CreateableResourceList<Scene, std::string, CreateScene>(stateCache, "scenes", refreshDuration); 283 sceneList = CreateableResourceList<Scene, std::string, CreateScene>(stateCache, "scenes", refreshDuration);
284 bridgeConfig = BridgeConfig(stateCache, refreshDuration); 284 bridgeConfig = BridgeConfig(stateCache, refreshDuration);
  285 + stateCache->refresh();
285 } 286 }
286 } // namespace hueplusplus 287 } // namespace hueplusplus
test/CMakeLists.txt
@@ -48,7 +48,7 @@ set(TEST_SOURCES @@ -48,7 +48,7 @@ set(TEST_SOURCES
48 test_SimpleColorHueStrategy.cpp 48 test_SimpleColorHueStrategy.cpp
49 test_SimpleColorTemperatureStrategy.cpp 49 test_SimpleColorTemperatureStrategy.cpp
50 test_StateTransaction.cpp 50 test_StateTransaction.cpp
51 - test_TimePattern.cpp "test_ColorUnits.cpp") 51 + test_TimePattern.cpp "test_ColorUnits.cpp" "test_BridgeConfig.cpp")
52 52
53 set(HuePlusPlus_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include") 53 set(HuePlusPlus_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include")
54 54
test/test_BridgeConfig.cpp 0 โ†’ 100644
  1 +/**
  2 + \file test_BridgeConfig.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include <hueplusplus/BridgeConfig.h>
  23 +
  24 +#include <gtest/gtest.h>
  25 +
  26 +#include "testhelper.h"
  27 +
  28 +#include "mocks/mock_HttpHandler.h"
  29 +
  30 +using namespace hueplusplus;
  31 +using namespace testing;
  32 +
  33 +TEST(BridgeConfig, refresh)
  34 +{
  35 + auto handler = std::make_shared<MockHttpHandler>();
  36 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  37 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  38 + EXPECT_CALL(
  39 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  40 + .WillOnce(Return(nlohmann::json::object()));
  41 + baseCache->refresh();
  42 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  43 +
  44 + EXPECT_CALL(*handler,
  45 + GETJson("/api/" + getBridgeUsername() + "/config", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  46 + .WillOnce(Return(nlohmann::json::object()));
  47 + config.refresh();
  48 +}
  49 +
  50 +TEST(BridgeConfig, getWhitelistedUsers)
  51 +{
  52 + const nlohmann::json state {{"config",
  53 + {{"whitelist",
  54 + {{"abcd",
  55 + {{"name", "User A"}, {"last use date", "2020-04-01T10:00:04"},
  56 + {"create date", "2020-01-01T12:00:00"}}},
  57 + {"cdef",
  58 + {{"name", "User B"}, {"last use date", "2020-03-05T14:00:00"},
  59 + {"create date", "2020-02-01T02:03:40"}}}}}}}};
  60 + auto handler = std::make_shared<MockHttpHandler>();
  61 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  62 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  63 + EXPECT_CALL(
  64 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  65 + .WillOnce(Return(state));
  66 + baseCache->refresh();
  67 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  68 +
  69 + std::vector<WhitelistedUser> users = config.getWhitelistedUsers();
  70 + EXPECT_THAT(users,
  71 + UnorderedElementsAre(Truly([](const WhitelistedUser& u) { return u.key == "abcd" && u.name == "User A"; }),
  72 + Truly([](const WhitelistedUser& u) { return u.key == "cdef" && u.name == "User B"; })));
  73 +}
  74 +
  75 +TEST(BridgeConfig, removeUser)
  76 +{
  77 + auto handler = std::make_shared<MockHttpHandler>();
  78 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  79 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  80 + EXPECT_CALL(
  81 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  82 + .WillOnce(Return(nlohmann::json::object()));
  83 + baseCache->refresh();
  84 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  85 +
  86 + const std::string userKey = "abcd";
  87 + EXPECT_CALL(*handler,
  88 + DELETEJson("/api/" + getBridgeUsername() + "/config/whitelist/" + userKey, nlohmann::json::object(),
  89 + getBridgeIp(), getBridgePort()))
  90 + .WillOnce(Return(nlohmann::json {"/config/whitelist/" + userKey + " deleted"}));
  91 + config.removeUser(userKey);
  92 +}
  93 +
  94 +TEST(BridgeConfig, getLinkButton)
  95 +{
  96 + const nlohmann::json state {{"config", {{"linkbutton", true}}}};
  97 + auto handler = std::make_shared<MockHttpHandler>();
  98 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  99 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  100 + EXPECT_CALL(
  101 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  102 + .WillOnce(Return(state));
  103 + baseCache->refresh();
  104 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  105 +
  106 + EXPECT_TRUE(config.getLinkButton());
  107 + EXPECT_CALL(*handler,
  108 + GETJson("/api/" + getBridgeUsername() + "/config", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  109 + .WillOnce(Return(nlohmann::json {{"linkbutton", false}}));
  110 + config.refresh();
  111 + EXPECT_FALSE(config.getLinkButton());
  112 +}
  113 +
  114 +TEST(BridgeConfig, pressLinkButton)
  115 +{
  116 + auto handler = std::make_shared<MockHttpHandler>();
  117 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  118 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  119 + EXPECT_CALL(
  120 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  121 + .WillOnce(Return(nlohmann::json::object()));
  122 + baseCache->refresh();
  123 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  124 +
  125 + EXPECT_CALL(*handler,
  126 + PUTJson("/api/" + getBridgeUsername() + "/config", nlohmann::json {{"linkbutton", true}}, getBridgeIp(),
  127 + getBridgePort()))
  128 + .WillOnce(Return(nlohmann::json {{{"success", {{"/config/linkbutton", true}}}}}));
  129 + config.pressLinkButton();
  130 +}
  131 +
  132 +TEST(BridgeConfig, touchLink)
  133 +{
  134 + auto handler = std::make_shared<MockHttpHandler>();
  135 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  136 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  137 + EXPECT_CALL(
  138 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  139 + .WillOnce(Return(nlohmann::json::object()));
  140 + baseCache->refresh();
  141 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  142 +
  143 + EXPECT_CALL(*handler,
  144 + PUTJson("/api/" + getBridgeUsername() + "/config", nlohmann::json {{"touchlink", true}}, getBridgeIp(),
  145 + getBridgePort()))
  146 + .WillOnce(Return(nlohmann::json {{{"success", {{"/config/touchlink", true}}}}}));
  147 + config.touchLink();
  148 +}
  149 +
  150 +TEST(BridgeConfig, getMACAddress)
  151 +{
  152 + const nlohmann::json state {{"config", {{"mac", getBridgeMac()}}}};
  153 + auto handler = std::make_shared<MockHttpHandler>();
  154 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  155 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  156 + EXPECT_CALL(
  157 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  158 + .WillOnce(Return(state));
  159 + baseCache->refresh();
  160 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  161 +
  162 + EXPECT_EQ(getBridgeMac(), config.getMACAddress());
  163 +}
  164 +
  165 +TEST(BridgeConfig, getUTCTime)
  166 +{
  167 + const std::string utc = "2020-06-01T10:00:00";
  168 + const nlohmann::json state {{"config", {{"UTC", utc}}}};
  169 + auto handler = std::make_shared<MockHttpHandler>();
  170 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  171 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  172 + EXPECT_CALL(
  173 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  174 + .WillOnce(Return(state));
  175 + baseCache->refresh();
  176 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  177 +
  178 + EXPECT_EQ(time::AbsoluteTime::parseUTC(utc).getBaseTime(), config.getUTCTime().getBaseTime());
  179 +}
  180 +
  181 +TEST(BridgeConfig, getTimezone)
  182 +{
  183 + const std::string timezone = "ab";
  184 + const nlohmann::json state {{"config", {{"timezone", timezone}}}};
  185 + auto handler = std::make_shared<MockHttpHandler>();
  186 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  187 + auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max());
  188 + EXPECT_CALL(
  189 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  190 + .WillOnce(Return(state));
  191 + baseCache->refresh();
  192 + BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
  193 +
  194 + EXPECT_EQ(timezone, config.getTimezone());
  195 +}
test/test_Hue.cpp
@@ -208,20 +208,16 @@ TEST(Hue, requestUsername) @@ -208,20 +208,16 @@ TEST(Hue, requestUsername)
208 208
209 Hue test_bridge(getBridgeIp(), getBridgePort(), "", handler); 209 Hue test_bridge(getBridgeIp(), getBridgePort(), "", handler);
210 210
211 - std::string username = test_bridge.requestUsername();  
212 -  
213 - EXPECT_EQ(username, test_bridge.getUsername()) << "Returned username not matching";  
214 - EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";  
215 - EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";  
216 -  
217 - // Verify that username is correctly set in api requests  
218 - nlohmann::json hue_bridge_state {{"lights", {}}}; 211 + nlohmann::json hue_bridge_state{ {"lights", {}} };
219 EXPECT_CALL( 212 EXPECT_CALL(
220 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) 213 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
221 .Times(1) 214 .Times(1)
222 .WillOnce(Return(hue_bridge_state)); 215 .WillOnce(Return(hue_bridge_state));
  216 + std::string username = test_bridge.requestUsername();
223 217
224 - test_bridge.lights().getAll(); 218 + EXPECT_EQ(username, test_bridge.getUsername()) << "Returned username not matching";
  219 + EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";
  220 + EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
225 } 221 }
226 } 222 }
227 223