Commit 62c09fce49549eb26ea2f867bee9ad827a77f135
1 parent
3fb907aa
Add first crude test for Hue class and all its prerequisites
Showing
4 changed files
with
682 additions
and
0 deletions
hueplusplus/test/mocks/mock_HttpHandler.h
0 → 100755
| 1 | +/** | |
| 2 | + \file mock_HttpHandler.h | |
| 3 | + Copyright Notice\n | |
| 4 | + Copyright (C) 2017 Jan Rogall - developer\n | |
| 5 | + Copyright (C) 2017 Moritz Wirger - developer\n | |
| 6 | + | |
| 7 | + This program is free software; you can redistribute it and/or modify | |
| 8 | + it under the terms of the GNU General Public License as published by | |
| 9 | + the Free Software Foundation; either version 3 of the License, or | |
| 10 | + (at your option) any later version. | |
| 11 | + This program is distributed in the hope that it will be useful, | |
| 12 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + GNU General Public License for more details. | |
| 15 | + You should have received a copy of the GNU General Public License | |
| 16 | + along with this program; if not, write to the Free Software Foundation, | |
| 17 | + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 18 | +**/ | |
| 19 | + | |
| 20 | +#ifndef _MOCK_HTTPHANDLER_H | |
| 21 | +#define _MOCK_HTTPHANDLER_H | |
| 22 | + | |
| 23 | +#include <string> | |
| 24 | +#include <vector> | |
| 25 | + | |
| 26 | +#include <gmock/gmock.h> | |
| 27 | + | |
| 28 | +#include "../hueplusplus/include/HttpHandler.h" | |
| 29 | +#include "../hueplusplus/include/json/json.h" | |
| 30 | + | |
| 31 | +//! Mock Class | |
| 32 | +class MockHttpHandler : public IHttpHandler | |
| 33 | +{ | |
| 34 | +public: | |
| 35 | + | |
| 36 | + MOCK_CONST_METHOD3( send, std::string(const std::string &msg, const std::string &adr, int port) ); | |
| 37 | + | |
| 38 | + MOCK_CONST_METHOD3( sendGetHTTPBody, std::string(const std::string &msg, const std::string &adr, int port) ); | |
| 39 | + | |
| 40 | + MOCK_CONST_METHOD4( sendMulticast, std::vector<std::string>(const std::string &msg, const std::string &adr, int port, int timeout) ); | |
| 41 | + | |
| 42 | + MOCK_CONST_METHOD6( sendHTTPRequest, std::string(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port) ); | |
| 43 | + | |
| 44 | + MOCK_CONST_METHOD5( GETString, std::string(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) ); | |
| 45 | + | |
| 46 | + MOCK_CONST_METHOD5( POSTString, std::string(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) ); | |
| 47 | + | |
| 48 | + MOCK_CONST_METHOD5( PUTString, std::string(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) ); | |
| 49 | + | |
| 50 | + MOCK_CONST_METHOD5( DELETEString, std::string(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) ); | |
| 51 | + | |
| 52 | + MOCK_CONST_METHOD4( GETJson, Json::Value(std::string uri, const Json::Value& body, const std::string &adr, int port) ); | |
| 53 | + | |
| 54 | + MOCK_CONST_METHOD4( POSTJson, Json::Value(std::string uri, const Json::Value& body, const std::string &adr, int port) ); | |
| 55 | + | |
| 56 | + MOCK_CONST_METHOD4( PUTJson, Json::Value(std::string uri, const Json::Value& body, const std::string &adr, int port) ); | |
| 57 | + | |
| 58 | + MOCK_CONST_METHOD4( DELETEJson, Json::Value(std::string uri, const Json::Value& body, const std::string &adr, int port) ); | |
| 59 | +}; | |
| 60 | + | |
| 61 | +#endif | ... | ... |
hueplusplus/test/test_Hue.cpp
0 → 100755
| 1 | +#include <gtest/gtest.h> | |
| 2 | +#include <gmock/gmock.h> | |
| 3 | + | |
| 4 | +#include "../include/Hue.h" | |
| 5 | +#include "../include/json/json.h" | |
| 6 | +#include "mocks/mock_HttpHandler.h" | |
| 7 | +#include "testhelper.h" | |
| 8 | + | |
| 9 | +#include <iostream> | |
| 10 | +#include <memory> | |
| 11 | +#include <string> | |
| 12 | + | |
| 13 | + | |
| 14 | +class HueFinderTest : public ::testing::Test | |
| 15 | +{ | |
| 16 | +protected: | |
| 17 | + std::shared_ptr<MockHttpHandler> handler; | |
| 18 | +protected: | |
| 19 | + HueFinderTest() | |
| 20 | + { | |
| 21 | + handler = std::make_shared<MockHttpHandler>(); | |
| 22 | + | |
| 23 | + EXPECT_CALL(*handler, sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n", "239.255.255.250", 1900, 5)) | |
| 24 | + .Times(::testing::AtLeast(1)) | |
| 25 | + .WillRepeatedly(::testing::Return(multicast_reply)); | |
| 26 | + | |
| 27 | + EXPECT_CALL(*handler, GETString("/description.xml", "application/xml", "", "192.168.2.1", 80)) | |
| 28 | + .Times(0); | |
| 29 | + | |
| 30 | + EXPECT_CALL(*handler, GETString("/description.xml", "application/xml", "", bridge_ip, 80)) | |
| 31 | + .Times(::testing::AtLeast(1)) | |
| 32 | + .WillRepeatedly(::testing::Return(brige_xml)); | |
| 33 | + } | |
| 34 | + ~HueFinderTest(){}; | |
| 35 | +}; | |
| 36 | + | |
| 37 | +TEST_F(HueFinderTest, FindBridges) | |
| 38 | +{ | |
| 39 | + HueFinder finder(handler); | |
| 40 | + std::vector<HueFinder::HueIdentification> bridges = finder.FindBridges(); | |
| 41 | + | |
| 42 | + HueFinder::HueIdentification bridge_to_comp; | |
| 43 | + bridge_to_comp.ip = bridge_ip; | |
| 44 | + bridge_to_comp.mac = bridge_mac; | |
| 45 | + | |
| 46 | + EXPECT_EQ(bridges.size(), 1) << "HueFinder found more than one Bridge"; | |
| 47 | + EXPECT_EQ(bridges[0].ip, bridge_to_comp.ip) << "HueIdentification ip does not match"; | |
| 48 | + EXPECT_EQ(bridges[0].mac, bridge_to_comp.mac) << "HueIdentification mac does not match"; | |
| 49 | +} | |
| 50 | + | |
| 51 | +TEST_F(HueFinderTest, GetBridge) | |
| 52 | +{ | |
| 53 | + Json::Value request; | |
| 54 | + request["devicetype"] = "HuePlusPlus#User"; | |
| 55 | + | |
| 56 | + Json::Value user_ret_uns; | |
| 57 | + user_ret_uns = Json::Value(Json::arrayValue); | |
| 58 | + user_ret_uns[0] = Json::Value(Json::objectValue); | |
| 59 | + user_ret_uns[0]["error"] = Json::Value(Json::objectValue); | |
| 60 | + user_ret_uns[0]["error"]["type"] = 101; | |
| 61 | + user_ret_uns[0]["error"]["address"] = ""; | |
| 62 | + user_ret_uns[0]["error"]["description"] = "link button not pressed"; | |
| 63 | + | |
| 64 | + EXPECT_CALL(*handler, GETJson("/api", request, bridge_ip, 80)) | |
| 65 | + .Times(::testing::AtLeast(1)) | |
| 66 | + .WillRepeatedly(::testing::Return(user_ret_uns)); | |
| 67 | + | |
| 68 | + HueFinder finder(handler); | |
| 69 | + std::vector<HueFinder::HueIdentification> bridges = finder.FindBridges(); | |
| 70 | + | |
| 71 | + ASSERT_THROW(finder.GetBridge(bridges[0]), std::runtime_error); | |
| 72 | + | |
| 73 | + Json::Value user_ret_suc; | |
| 74 | + user_ret_suc = Json::Value(Json::arrayValue); | |
| 75 | + user_ret_suc[0] = Json::Value(Json::objectValue); | |
| 76 | + user_ret_suc[0]["success"] = Json::Value(Json::objectValue); | |
| 77 | + user_ret_suc[0]["success"]["username"] = bridge_username; | |
| 78 | + | |
| 79 | + EXPECT_CALL(*handler, GETJson("/api", request, bridge_ip, 80)) | |
| 80 | + .Times(1) | |
| 81 | + .WillOnce(::testing::Return(user_ret_suc)); | |
| 82 | + | |
| 83 | + finder = HueFinder(handler); | |
| 84 | + bridges = finder.FindBridges(); | |
| 85 | + | |
| 86 | + Hue test_bridge = finder.GetBridge(bridges[0]); | |
| 87 | + | |
| 88 | + EXPECT_EQ(test_bridge.getBridgeIP(), bridge_ip) << "Bridge IP not matching"; | |
| 89 | + EXPECT_EQ(test_bridge.getUsername(), bridge_username) << "Bridge username not matching"; | |
| 90 | + | |
| 91 | + | |
| 92 | +} | |
| 93 | + | |
| 94 | +TEST_F(HueFinderTest, AddUsername) | |
| 95 | +{ | |
| 96 | + HueFinder finder(handler); | |
| 97 | + std::vector<HueFinder::HueIdentification> bridges = finder.FindBridges(); | |
| 98 | + | |
| 99 | + finder.AddUsername(bridges[0].mac, bridge_username); | |
| 100 | + Hue test_bridge = finder.GetBridge(bridges[0]); | |
| 101 | + | |
| 102 | + EXPECT_EQ(test_bridge.getBridgeIP(), bridge_ip) << "Bridge IP not matching"; | |
| 103 | + EXPECT_EQ(test_bridge.getUsername(), bridge_username) << "Bridge username not matching"; | |
| 104 | +} | |
| 105 | + | |
| 106 | +TEST_F(HueFinderTest, GetAllUsernames) | |
| 107 | +{ | |
| 108 | + HueFinder finder(handler); | |
| 109 | + std::vector<HueFinder::HueIdentification> bridges = finder.FindBridges(); | |
| 110 | + | |
| 111 | + finder.AddUsername(bridges[0].mac, bridge_username); | |
| 112 | + | |
| 113 | + std::map<std::string, std::string> users = finder.GetAllUsernames(); | |
| 114 | + EXPECT_EQ(users[bridge_mac], bridge_username) << "Username of MAC:" << bridge_mac << "not matching"; | |
| 115 | +} | |
| 116 | + | |
| 117 | +TEST(Hue, Constructor) | |
| 118 | +{ | |
| 119 | + std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>(); | |
| 120 | + Hue test_bridge(bridge_ip, bridge_username, handler); | |
| 121 | + | |
| 122 | + EXPECT_EQ(test_bridge.getBridgeIP(), bridge_ip) << "Bridge IP not matching"; | |
| 123 | + EXPECT_EQ(test_bridge.getUsername(), bridge_username) << "Bridge username not matching"; | |
| 124 | +} | |
| 125 | + | |
| 126 | +TEST(Hue, requestUsername) | |
| 127 | +{ | |
| 128 | + std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>(); | |
| 129 | + Json::Value request; | |
| 130 | + request["devicetype"] = "HuePlusPlus#User"; | |
| 131 | + | |
| 132 | + Json::Value user_ret_uns; | |
| 133 | + user_ret_uns = Json::Value(Json::arrayValue); | |
| 134 | + user_ret_uns[0] = Json::Value(Json::objectValue); | |
| 135 | + user_ret_uns[0]["error"] = Json::Value(Json::objectValue); | |
| 136 | + user_ret_uns[0]["error"]["type"] = 101; | |
| 137 | + user_ret_uns[0]["error"]["address"] = ""; | |
| 138 | + user_ret_uns[0]["error"]["description"] = "link button not pressed"; | |
| 139 | + | |
| 140 | + EXPECT_CALL(*handler, GETJson("/api", request, bridge_ip, 80)) | |
| 141 | + .Times(::testing::AtLeast(1)) | |
| 142 | + .WillRepeatedly(::testing::Return(user_ret_uns)); | |
| 143 | + | |
| 144 | + Hue test_bridge(bridge_ip, "", handler); | |
| 145 | + | |
| 146 | + test_bridge.requestUsername(test_bridge.getBridgeIP()); | |
| 147 | + EXPECT_EQ(test_bridge.getUsername(), "") << "Bridge username not matching"; | |
| 148 | + | |
| 149 | + Json::Value user_ret_suc; | |
| 150 | + user_ret_suc = Json::Value(Json::arrayValue); | |
| 151 | + user_ret_suc[0] = Json::Value(Json::objectValue); | |
| 152 | + user_ret_suc[0]["success"] = Json::Value(Json::objectValue); | |
| 153 | + user_ret_suc[0]["success"]["username"] = bridge_username; | |
| 154 | + EXPECT_CALL(*handler, GETJson("/api", request, bridge_ip, 80)) | |
| 155 | + .Times(1) | |
| 156 | + .WillRepeatedly(::testing::Return(user_ret_suc)); | |
| 157 | + | |
| 158 | + test_bridge = Hue(bridge_ip, "", handler); | |
| 159 | + | |
| 160 | + test_bridge.requestUsername(test_bridge.getBridgeIP()); | |
| 161 | + | |
| 162 | + EXPECT_EQ(test_bridge.getBridgeIP(), bridge_ip) << "Bridge IP not matching"; | |
| 163 | + EXPECT_EQ(test_bridge.getUsername(), bridge_username) << "Bridge username not matching"; | |
| 164 | +} | |
| 165 | + | |
| 166 | +TEST(Hue, setIP) | |
| 167 | +{ | |
| 168 | + std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>(); | |
| 169 | + Hue test_bridge(bridge_ip, "", handler); | |
| 170 | + EXPECT_EQ(test_bridge.getBridgeIP(), bridge_ip) << "Bridge IP not matching after initialization"; | |
| 171 | + test_bridge.setIP("192.168.2.112"); | |
| 172 | + EXPECT_EQ(test_bridge.getBridgeIP(), "192.168.2.112") << "Bridge IP not matching after setting it"; | |
| 173 | +} | |
| 174 | + | |
| 175 | +TEST(Hue, getLight) | |
| 176 | +{ | |
| 177 | + std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>(); | |
| 178 | + Json::Value empty_json_obj(Json::objectValue); | |
| 179 | + EXPECT_CALL(*handler, GETJson("/api/"+bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 180 | + .Times(1); | |
| 181 | + | |
| 182 | + Hue test_bridge(bridge_ip, bridge_username, handler); | |
| 183 | + | |
| 184 | + // Test exception | |
| 185 | + ASSERT_THROW(test_bridge.getLight(1), std::runtime_error); | |
| 186 | + | |
| 187 | + Json::Value hue_bridge_state; | |
| 188 | + hue_bridge_state["lights"] = Json::Value(Json::objectValue); | |
| 189 | + hue_bridge_state["lights"]["1"] = Json::Value(Json::objectValue); | |
| 190 | + hue_bridge_state["lights"]["1"]["state"] = Json::Value(Json::objectValue); | |
| 191 | + hue_bridge_state["lights"]["1"]["state"]["on"] = true; | |
| 192 | + hue_bridge_state["lights"]["1"]["state"]["bri"] = 254; | |
| 193 | + hue_bridge_state["lights"]["1"]["state"]["ct"] = 366; | |
| 194 | + hue_bridge_state["lights"]["1"]["state"]["alert"] = "none"; | |
| 195 | + hue_bridge_state["lights"]["1"]["state"]["colormode"] = "ct"; | |
| 196 | + hue_bridge_state["lights"]["1"]["state"]["reachable"] = true; | |
| 197 | + hue_bridge_state["lights"]["1"]["swupdate"] = Json::Value(Json::objectValue); | |
| 198 | + hue_bridge_state["lights"]["1"]["swupdate"]["state"] = "noupdates"; | |
| 199 | + hue_bridge_state["lights"]["1"]["swupdate"]["lastinstall"] = Json::nullValue; | |
| 200 | + hue_bridge_state["lights"]["1"]["type"] = "Color temperature light"; | |
| 201 | + hue_bridge_state["lights"]["1"]["name"] = "Hue ambiance lamp 1"; | |
| 202 | + hue_bridge_state["lights"]["1"]["modelid"] = "LTW001"; | |
| 203 | + hue_bridge_state["lights"]["1"]["manufacturername"] = "Philips"; | |
| 204 | + hue_bridge_state["lights"]["1"]["uniqueid"] = "00:00:00:00:00:00:00:00-00"; | |
| 205 | + hue_bridge_state["lights"]["1"]["swversion"] = "5.50.1.19085"; | |
| 206 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 207 | + .Times(1) | |
| 208 | + .WillOnce(::testing::Return(hue_bridge_state)); | |
| 209 | + | |
| 210 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 211 | + .Times(3) | |
| 212 | + .WillRepeatedly(::testing::Return(hue_bridge_state["lights"]["1"])); | |
| 213 | + | |
| 214 | + // Test when correct data is sent | |
| 215 | + HueLight test_light_1 = test_bridge.getLight(1); | |
| 216 | + EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); | |
| 217 | + EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE); | |
| 218 | + | |
| 219 | + // Test again to check whether light is returned directly -> interesting for code coverage test | |
| 220 | + test_light_1 = test_bridge.getLight(1); | |
| 221 | + EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); | |
| 222 | + EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE); | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + // more coverage stuff | |
| 227 | + hue_bridge_state["lights"]["1"]["modelid"] = "LCT001"; | |
| 228 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 229 | + .Times(1) | |
| 230 | + .WillOnce(::testing::Return(hue_bridge_state)); | |
| 231 | + | |
| 232 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 233 | + .Times(2) | |
| 234 | + .WillRepeatedly(::testing::Return(hue_bridge_state["lights"]["1"])); | |
| 235 | + test_bridge = Hue(bridge_ip, bridge_username, handler); | |
| 236 | + | |
| 237 | + // Test when correct data is sent | |
| 238 | + test_light_1 = test_bridge.getLight(1); | |
| 239 | + EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); | |
| 240 | + EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_B); | |
| 241 | + | |
| 242 | + | |
| 243 | + hue_bridge_state["lights"]["1"]["modelid"] = "LCT010"; | |
| 244 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 245 | + .Times(1) | |
| 246 | + .WillOnce(::testing::Return(hue_bridge_state)); | |
| 247 | + | |
| 248 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 249 | + .Times(2) | |
| 250 | + .WillRepeatedly(::testing::Return(hue_bridge_state["lights"]["1"])); | |
| 251 | + test_bridge = Hue(bridge_ip, bridge_username, handler); | |
| 252 | + | |
| 253 | + // Test when correct data is sent | |
| 254 | + test_light_1 = test_bridge.getLight(1); | |
| 255 | + EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); | |
| 256 | + EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_C); | |
| 257 | + | |
| 258 | + | |
| 259 | + hue_bridge_state["lights"]["1"]["modelid"] = "LST001"; | |
| 260 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 261 | + .Times(1) | |
| 262 | + .WillOnce(::testing::Return(hue_bridge_state)); | |
| 263 | + | |
| 264 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 265 | + .Times(2) | |
| 266 | + .WillRepeatedly(::testing::Return(hue_bridge_state["lights"]["1"])); | |
| 267 | + test_bridge = Hue(bridge_ip, bridge_username, handler); | |
| 268 | + | |
| 269 | + // Test when correct data is sent | |
| 270 | + test_light_1 = test_bridge.getLight(1); | |
| 271 | + EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); | |
| 272 | + EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_A); | |
| 273 | + | |
| 274 | + | |
| 275 | + hue_bridge_state["lights"]["1"]["modelid"] = "LWB004"; | |
| 276 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 277 | + .Times(1) | |
| 278 | + .WillOnce(::testing::Return(hue_bridge_state)); | |
| 279 | + | |
| 280 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 281 | + .Times(2) | |
| 282 | + .WillRepeatedly(::testing::Return(hue_bridge_state["lights"]["1"])); | |
| 283 | + test_bridge = Hue(bridge_ip, bridge_username, handler); | |
| 284 | + | |
| 285 | + // Test when correct data is sent | |
| 286 | + test_light_1 = test_bridge.getLight(1); | |
| 287 | + EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); | |
| 288 | + EXPECT_EQ(test_light_1.getColorType(), ColorType::NONE); | |
| 289 | + | |
| 290 | + | |
| 291 | + hue_bridge_state["lights"]["1"]["modelid"] = "ABC000"; | |
| 292 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 293 | + .Times(1) | |
| 294 | + .WillOnce(::testing::Return(hue_bridge_state)); | |
| 295 | + test_bridge = Hue(bridge_ip, bridge_username, handler); | |
| 296 | + | |
| 297 | + ASSERT_THROW(test_bridge.getLight(1), std::runtime_error); | |
| 298 | + | |
| 299 | +} | |
| 300 | + | |
| 301 | +TEST(Hue, removeLight) | |
| 302 | +{ | |
| 303 | + std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>(); | |
| 304 | + Json::Value empty_json_obj(Json::objectValue); | |
| 305 | + Json::Value hue_bridge_state; | |
| 306 | + hue_bridge_state["lights"] = Json::Value(Json::objectValue); | |
| 307 | + hue_bridge_state["lights"]["1"] = Json::Value(Json::objectValue); | |
| 308 | + hue_bridge_state["lights"]["1"]["state"] = Json::Value(Json::objectValue); | |
| 309 | + hue_bridge_state["lights"]["1"]["state"]["on"] = true; | |
| 310 | + hue_bridge_state["lights"]["1"]["state"]["bri"] = 254; | |
| 311 | + hue_bridge_state["lights"]["1"]["state"]["ct"] = 366; | |
| 312 | + hue_bridge_state["lights"]["1"]["state"]["alert"] = "none"; | |
| 313 | + hue_bridge_state["lights"]["1"]["state"]["colormode"] = "ct"; | |
| 314 | + hue_bridge_state["lights"]["1"]["state"]["reachable"] = true; | |
| 315 | + hue_bridge_state["lights"]["1"]["swupdate"] = Json::Value(Json::objectValue); | |
| 316 | + hue_bridge_state["lights"]["1"]["swupdate"]["state"] = "noupdates"; | |
| 317 | + hue_bridge_state["lights"]["1"]["swupdate"]["lastinstall"] = Json::nullValue; | |
| 318 | + hue_bridge_state["lights"]["1"]["type"] = "Color temperature light"; | |
| 319 | + hue_bridge_state["lights"]["1"]["name"] = "Hue ambiance lamp 1"; | |
| 320 | + hue_bridge_state["lights"]["1"]["modelid"] = "LTW001"; | |
| 321 | + hue_bridge_state["lights"]["1"]["manufacturername"] = "Philips"; | |
| 322 | + hue_bridge_state["lights"]["1"]["uniqueid"] = "00:00:00:00:00:00:00:00-00"; | |
| 323 | + hue_bridge_state["lights"]["1"]["swversion"] = "5.50.1.19085"; | |
| 324 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 325 | + .Times(1) | |
| 326 | + .WillOnce(::testing::Return(hue_bridge_state)); | |
| 327 | + | |
| 328 | + Hue test_bridge(bridge_ip, bridge_username, handler); | |
| 329 | + | |
| 330 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 331 | + .Times(1) | |
| 332 | + .WillRepeatedly(::testing::Return(hue_bridge_state["lights"]["1"])); | |
| 333 | + | |
| 334 | + Json::Value return_answer; | |
| 335 | + return_answer = Json::Value(Json::arrayValue); | |
| 336 | + return_answer[0] = Json::Value(Json::objectValue); | |
| 337 | + return_answer[0]["success"] = "/lights/1 deleted"; | |
| 338 | + EXPECT_CALL(*handler, DELETEJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 339 | + .Times(2) | |
| 340 | + .WillOnce(::testing::Return(return_answer)); | |
| 341 | + | |
| 342 | + // Test when correct data is sent | |
| 343 | + HueLight test_light_1 = test_bridge.getLight(1); | |
| 344 | + | |
| 345 | + EXPECT_EQ(test_bridge.removeLight(1), true); | |
| 346 | + | |
| 347 | + EXPECT_EQ(test_bridge.removeLight(1), false); | |
| 348 | +} | |
| 349 | + | |
| 350 | +TEST(Hue, getAllLights) | |
| 351 | +{ | |
| 352 | + std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>(); | |
| 353 | + Json::Value empty_json_obj(Json::objectValue); | |
| 354 | + Json::Value hue_bridge_state; | |
| 355 | + hue_bridge_state["lights"] = Json::Value(Json::objectValue); | |
| 356 | + hue_bridge_state["lights"]["1"] = Json::Value(Json::objectValue); | |
| 357 | + hue_bridge_state["lights"]["1"]["state"] = Json::Value(Json::objectValue); | |
| 358 | + hue_bridge_state["lights"]["1"]["state"]["on"] = true; | |
| 359 | + hue_bridge_state["lights"]["1"]["state"]["bri"] = 254; | |
| 360 | + hue_bridge_state["lights"]["1"]["state"]["ct"] = 366; | |
| 361 | + hue_bridge_state["lights"]["1"]["state"]["alert"] = "none"; | |
| 362 | + hue_bridge_state["lights"]["1"]["state"]["colormode"] = "ct"; | |
| 363 | + hue_bridge_state["lights"]["1"]["state"]["reachable"] = true; | |
| 364 | + hue_bridge_state["lights"]["1"]["swupdate"] = Json::Value(Json::objectValue); | |
| 365 | + hue_bridge_state["lights"]["1"]["swupdate"]["state"] = "noupdates"; | |
| 366 | + hue_bridge_state["lights"]["1"]["swupdate"]["lastinstall"] = Json::nullValue; | |
| 367 | + hue_bridge_state["lights"]["1"]["type"] = "Color temperature light"; | |
| 368 | + hue_bridge_state["lights"]["1"]["name"] = "Hue ambiance lamp 1"; | |
| 369 | + hue_bridge_state["lights"]["1"]["modelid"] = "LTW001"; | |
| 370 | + hue_bridge_state["lights"]["1"]["manufacturername"] = "Philips"; | |
| 371 | + hue_bridge_state["lights"]["1"]["uniqueid"] = "00:00:00:00:00:00:00:00-00"; | |
| 372 | + hue_bridge_state["lights"]["1"]["swversion"] = "5.50.1.19085"; | |
| 373 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username, empty_json_obj, bridge_ip, 80)) | |
| 374 | + .Times(2) | |
| 375 | + .WillRepeatedly(::testing::Return(hue_bridge_state)); | |
| 376 | + | |
| 377 | + EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", empty_json_obj, bridge_ip, 80)) | |
| 378 | + .Times(2) | |
| 379 | + .WillRepeatedly(::testing::Return(hue_bridge_state["lights"]["1"])); | |
| 380 | + | |
| 381 | + Hue test_bridge(bridge_ip, bridge_username, handler); | |
| 382 | + | |
| 383 | + std::vector<std::reference_wrapper<HueLight>> test_lights = test_bridge.getAllLights(); | |
| 384 | + EXPECT_EQ(test_lights[0].get().getName(), "Hue ambiance lamp 1"); | |
| 385 | + EXPECT_EQ(test_lights[0].get().getColorType(), ColorType::TEMPERATURE); | |
| 386 | +} | |
| 387 | + | |
| 388 | +TEST(Hue, refreshState) | |
| 389 | +{ | |
| 390 | + std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>(); | |
| 391 | + Hue test_bridge(bridge_ip, "", handler); // NULL as username leads to segfault | |
| 392 | + | |
| 393 | + std::vector<std::reference_wrapper<HueLight>> test_lights = test_bridge.getAllLights(); | |
| 394 | + EXPECT_EQ(test_lights.size(), 0); | |
| 395 | +} | ... | ... |
hueplusplus/test/test_Main.cpp
0 → 100755
hueplusplus/test/testhelper.h
0 → 100755
| 1 | + | |
| 2 | +const std::string bridge_ip = "192.168.2.116"; //!< IP-Address of the fake hue bridge in dotted decimal notation like "192.168.2.1" | |
| 3 | +const std::string bridge_username = "83b7780291a6ceffbe0bd049104df"; //!< Username that is ussed to access the fake hue bridge | |
| 4 | +const std::string bridge_id = "111111FFFE11E111"; | |
| 5 | +const std::string bridge_uuid = "1f111f11-da11-11e1-1b11-11111111e111"; | |
| 6 | +const std::string bridge_mac = "11111111e111"; | |
| 7 | + | |
| 8 | +const std::string brige_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" | |
| 9 | + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">" | |
| 10 | + "<specVersion>" | |
| 11 | + "<major>1</major>" | |
| 12 | + "<minor>0</minor>" | |
| 13 | + "</specVersion>" | |
| 14 | + "<URLBase>http://192.168.2.116:80/</URLBase>" | |
| 15 | + "<device>" | |
| 16 | + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>" | |
| 17 | + "<friendlyName>Philips hue (192.168.2.116)</friendlyName>" | |
| 18 | + "<manufacturer>Royal Philips Electronics</manufacturer>" | |
| 19 | + "<manufacturerURL>http://www.philips.com</manufacturerURL>" | |
| 20 | + "<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>" | |
| 21 | + "<modelName>Philips hue bridge 2015</modelName>" | |
| 22 | + "<modelNumber>BSB002</modelNumber>" | |
| 23 | + "<modelURL>http://www.meethue.com</modelURL>" | |
| 24 | + "<serialNumber>11111111e111</serialNumber>" | |
| 25 | + "<UDN>uuid:1f111f11-da11-11e1-1b11-11111111e111</UDN>" | |
| 26 | + "<presentationURL>index.html</presentationURL>" | |
| 27 | + "<iconList>" | |
| 28 | + "<icon>" | |
| 29 | + "<mimetype>image/png</mimetype>" | |
| 30 | + "<height>48</height>" | |
| 31 | + "<width>48</width>" | |
| 32 | + "<depth>24</depth>" | |
| 33 | + "<url>hue_logo_0.png</url>" | |
| 34 | + "</icon>" | |
| 35 | + "</iconList>" | |
| 36 | + "</device>" | |
| 37 | + "</root>"; | |
| 38 | + | |
| 39 | +const std::vector<std::string> multicast_reply = { | |
| 40 | + "HTTP/1.1 200 OK\r\n" | |
| 41 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 42 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 43 | + "EXT:\r\n" | |
| 44 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 45 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 46 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 47 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 48 | + "X-User-Agent: redsonic\r\n" | |
| 49 | + "ST: upnp:rootdevice\r\n" | |
| 50 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::upnp:rootdevice", | |
| 51 | + | |
| 52 | + "HTTP/1.1 200 OK\r\n" | |
| 53 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 54 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 55 | + "EXT:\r\n" | |
| 56 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 57 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 58 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 59 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 60 | + "X-User-Agent: redsonic\r\n" | |
| 61 | + "ST: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00\r\n" | |
| 62 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00", | |
| 63 | + | |
| 64 | + "HTTP/1.1 200 OK\r\n" | |
| 65 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 66 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 67 | + "EXT:\r\n" | |
| 68 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 69 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 70 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 71 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 72 | + "X-User-Agent: redsonic\r\n" | |
| 73 | + "ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n" | |
| 74 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:device:InternetGatewayDevice:1", | |
| 75 | + | |
| 76 | + "HTTP/1.1 200 OK\r\n" | |
| 77 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 78 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 79 | + "EXT:\r\n" | |
| 80 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 81 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 82 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 83 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 84 | + "X-User-Agent: redsonic\r\n" | |
| 85 | + "ST: urn:schemas-upnp-org:service:Layer3Forwarding:1\r\n" | |
| 86 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:service:Layer3Forwarding:1", | |
| 87 | + | |
| 88 | + "HTTP/1.1 200 OK\r\n" | |
| 89 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 90 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 91 | + "EXT:\r\n" | |
| 92 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 93 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 94 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 95 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 96 | + "X-User-Agent: redsonic\r\n" | |
| 97 | + "ST: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00\r\n" | |
| 98 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00", | |
| 99 | + | |
| 100 | + "HTTP/1.1 200 OK\r\n" | |
| 101 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 102 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 103 | + "EXT:\r\n" | |
| 104 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 105 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 106 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 107 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 108 | + "X-User-Agent: redsonic\r\n" | |
| 109 | + "ST: urn:schemas-upnp-org:device:WANDevice:1\r\n" | |
| 110 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:device:WANDevice:1", | |
| 111 | + | |
| 112 | + "HTTP/1.1 200 OK\r\n" | |
| 113 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 114 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 115 | + "EXT:\r\n" | |
| 116 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 117 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 118 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 119 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 120 | + "X-User-Agent: redsonic\r\n" | |
| 121 | + "ST: urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\r\n" | |
| 122 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1", | |
| 123 | + | |
| 124 | + "HTTP/1.1 200 OK\r\n" | |
| 125 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 126 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 127 | + "EXT:\r\n" | |
| 128 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 129 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 130 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 131 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 132 | + "X-User-Agent: redsonic\r\n" | |
| 133 | + "ST: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00\r\n" | |
| 134 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00", | |
| 135 | + | |
| 136 | + "HTTP/1.1 200 OK\r\n" | |
| 137 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 138 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 139 | + "EXT:\r\n" | |
| 140 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 141 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 142 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 143 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 144 | + "X-User-Agent: redsonic\r\n" | |
| 145 | + "ST: urn:schemas-upnp-org:device:WANConnectionDevice:1\r\n" | |
| 146 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:device:WANConnectionDevice:1", | |
| 147 | + | |
| 148 | + "HTTP/1.1 200 OK\r\n" | |
| 149 | + "CACHE-CONTROL: max-age=300\r\n" | |
| 150 | + "DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n" | |
| 151 | + "EXT:\r\n" | |
| 152 | + "LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n" | |
| 153 | + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" | |
| 154 | + "01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n" | |
| 155 | + "SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n" | |
| 156 | + "X-User-Agent: redsonic\r\n" | |
| 157 | + "ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n" | |
| 158 | + "USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:service:WANIPConnection:1", | |
| 159 | + | |
| 160 | + "HTTP/1.1 200 OK\r\n" | |
| 161 | + "HOST: 239.255.255.250:1900\r\n" | |
| 162 | + "EXT:\r\n" | |
| 163 | + "CACHE-CONTROL: max-age=100\r\n" | |
| 164 | + "LOCATION: http://192.168.2.116:80/description.xml\r\n" | |
| 165 | + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n" | |
| 166 | + "hue-bridgeid: 111111FFFE11E111\r\n" | |
| 167 | + "ST: upnp:rootdevice\r\n" | |
| 168 | + "USN: uuid:1f111f11-da11-11e1-1b11-11111111e111::upnp:rootdevice", | |
| 169 | + | |
| 170 | + "HTTP/1.1 200 OK\r\n" | |
| 171 | + "HOST: 239.255.255.250:1900\r\n" | |
| 172 | + "EXT:\r\n" | |
| 173 | + "CACHE-CONTROL: max-age=100\r\n" | |
| 174 | + "LOCATION: http://192.168.2.116:80/description.xml\r\n" | |
| 175 | + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n" | |
| 176 | + "hue-bridgeid: 111111FFFE11E111\r\n" | |
| 177 | + "ST: uuid:1f111f11-da11-11e1-1b11-11111111e111\r\n" | |
| 178 | + "USN: uuid:1f111f11-da11-11e1-1b11-11111111e111", | |
| 179 | + | |
| 180 | + "HTTP/1.1 200 OK\r\n" | |
| 181 | + "HOST: 239.255.255.250:1900\r\n" | |
| 182 | + "EXT:\r\n" | |
| 183 | + "CACHE-CONTROL: max-age=100\r\n" | |
| 184 | + "LOCATION: http://192.168.2.116:80/description.xml\r\n" | |
| 185 | + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n" | |
| 186 | + "hue-bridgeid: 111111FFFE11E111\r\n" | |
| 187 | + "ST: urn:schemas-upnp-org:device:basic:1\r\n" | |
| 188 | + "USN: uuid:1f111f11-da11-11e1-1b11-11111111e111", | |
| 189 | + | |
| 190 | + "HTTP/1.1 200 OK\r\n" | |
| 191 | + "HOST: 239.255.255.250:1900\r\n" | |
| 192 | + "EXT:\r\n" | |
| 193 | + "CACHE-CONTROL: max-age=100\r\n" | |
| 194 | + "LOCATION: http://192.168.2.116:80/description.xml\r\n" | |
| 195 | + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n" | |
| 196 | + "hue-bridgeid: 111111FFFE11E111\r\n" | |
| 197 | + "ST: upnp:rootdevice\r\n" | |
| 198 | + "USN: uuid:1f111f11-da11-11e1-1b11-11111111e111::upnp:rootdevice", | |
| 199 | + | |
| 200 | + "HTTP/1.1 200 OK\r\n" | |
| 201 | + "HOST: 239.255.255.250:1900\r\n" | |
| 202 | + "EXT:\r\n" | |
| 203 | + "CACHE-CONTROL: max-age=100\r\n" | |
| 204 | + "LOCATION: http://192.168.2.116:80/description.xml\r\n" | |
| 205 | + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n" | |
| 206 | + "hue-bridgeid: 111111FFFE11E111\r\n" | |
| 207 | + "ST: uuid:1f111f11-da11-11e1-1b11-11111111e111\r\n" | |
| 208 | + "USN: uuid:1f111f11-da11-11e1-1b11-11111111e111", | |
| 209 | + | |
| 210 | + "HTTP/1.1 200 OK\r\n" | |
| 211 | + "HOST: 239.255.255.250:1900\r\n" | |
| 212 | + "EXT:\r\n" | |
| 213 | + "CACHE-CONTROL: max-age=100\r\n" | |
| 214 | + "LOCATION: http://192.168.2.116:80/description.xml\r\n" | |
| 215 | + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n" | |
| 216 | + "hue-bridgeid: 111111FFFE11E111\r\n" | |
| 217 | + "ST: urn:schemas-upnp-org:device:basic:1\r\n" | |
| 218 | + "USN: uuid:1f111f11-da11-11e1-1b11-11111111e111" | |
| 219 | +}; | ... | ... |