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 27  
28 28 namespace hueplusplus
29 29 {
  30 +//! \brief API version consisting of major, minor and patch version
30 31 struct Version
31 32 {
32 33 int major;
... ... @@ -34,31 +35,62 @@ struct Version
34 35 int patch;
35 36 };
36 37  
  38 +//! \brief User that is whitelisted for Hue API usage
37 39 struct WhitelistedUser
38 40 {
  41 + //! \brief API username of the user
39 42 std::string key;
  43 + //! \brief Name provided on user creation
40 44 std::string name;
  45 + //! \brief Last time the user was used
41 46 time::AbsoluteTime lastUsed;
  47 + //! \brief Time the user was created
42 48 time::AbsoluteTime created;
43 49 };
44 50  
  51 +//! \brief General bridge configuration properties.
45 52 class BridgeConfig
46 53 {
47 54 public:
  55 + //! \brief Construct BridgeConfig
48 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 64 void refresh();
51 65  
  66 + //! \brief Get the list of whitelisted users
  67 + //! \returns All users authorized for API access
52 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 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 81 bool getLinkButton() const;
  82 + //! \brief Set the link button state to pressed
56 83 void pressLinkButton();
57 84  
  85 + //! \brief Add the closest lamp to the network
58 86 void touchLink();
59 87  
  88 + //! \brief Get bridge MAC address
60 89 std::string getMACAddress() const;
  90 + //! \brief Get current (of last refresh) UTC time of the bridge
61 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 94 std::string getTimezone() const;
63 95  
64 96 protected:
... ...
include/hueplusplus/Hue.h
... ... @@ -156,6 +156,10 @@ public:
156 156 //! Should only be called rarely, as a full refresh is costly and usually not necessary.
157 157 //! Instead refresh only the parts you are interested in or rely on periodic refreshes
158 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 163 void refresh();
160 164  
161 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 282 scheduleList = CreateableResourceList<Schedule, int, CreateSchedule>(stateCache, "schedules", refreshDuration);
283 283 sceneList = CreateableResourceList<Scene, std::string, CreateScene>(stateCache, "scenes", refreshDuration);
284 284 bridgeConfig = BridgeConfig(stateCache, refreshDuration);
  285 + stateCache->refresh();
285 286 }
286 287 } // namespace hueplusplus
... ...
test/CMakeLists.txt
... ... @@ -48,7 +48,7 @@ set(TEST_SOURCES
48 48 test_SimpleColorHueStrategy.cpp
49 49 test_SimpleColorTemperatureStrategy.cpp
50 50 test_StateTransaction.cpp
51   - test_TimePattern.cpp "test_ColorUnits.cpp")
  51 + test_TimePattern.cpp "test_ColorUnits.cpp" "test_BridgeConfig.cpp")
52 52  
53 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 208  
209 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 212 EXPECT_CALL(
220 213 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
221 214 .Times(1)
222 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  
... ...