SFSClientImplTests.cpp (14793B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 4 #include "../../mock/MockWebServer.h" 5 #include "../../util/SFSExceptionMatcher.h" 6 #include "../../util/TestHelper.h" 7 #include "SFSClientImpl.h" 8 #include "connection/Connection.h" 9 #include "connection/CurlConnectionManager.h" 10 #include "connection/HttpHeader.h" 11 12 #include <catch2/catch_test_macros.hpp> 13 14 #include <set> 15 16 #define TEST(...) TEST_CASE("[Functional][SFSClientImplTests] " __VA_ARGS__) 17 18 using namespace SFS; 19 using namespace SFS::details; 20 using namespace SFS::test; 21 22 namespace 23 { 24 void CheckProduct(const VersionEntity& entity, std::string_view ns, std::string_view name, std::string_view version) 25 { 26 REQUIRE(entity.GetContentType() == ContentType::Generic); 27 REQUIRE(entity.contentId.nameSpace == ns); 28 REQUIRE(entity.contentId.name == name); 29 REQUIRE(entity.contentId.version == version); 30 } 31 32 void CheckAppProduct(const VersionEntity& entity, std::string_view ns, std::string_view name, std::string_view version) 33 { 34 REQUIRE(entity.GetContentType() == ContentType::App); 35 auto appEntity = dynamic_cast<const AppVersionEntity&>(entity); 36 REQUIRE(appEntity.contentId.nameSpace == ns); 37 REQUIRE(appEntity.contentId.name == name); 38 REQUIRE(appEntity.contentId.version == version); 39 REQUIRE_FALSE(appEntity.updateId.empty()); 40 REQUIRE(appEntity.prerequisites.empty()); 41 } 42 43 void CheckProducts(const VersionEntities& entities, 44 std::string_view ns, 45 const std::set<std::pair<std::string, std::string>>& nameVersionPairs) 46 { 47 // json arrays don't guarantee order, and they are the underlying structure, so we need to check using sets 48 std::set<std::pair<std::string, std::string>> uniqueNameVersionPairs; 49 for (const auto& entity : entities) 50 { 51 REQUIRE(entity->contentId.nameSpace == ns); 52 uniqueNameVersionPairs.emplace(entity->contentId.name, entity->contentId.version); 53 } 54 55 for (const auto& nameVersionPair : nameVersionPairs) 56 { 57 REQUIRE(uniqueNameVersionPairs.count(nameVersionPair)); 58 } 59 } 60 61 void CheckDownloadInfo(const FileEntities& files, const std::string& name) 62 { 63 REQUIRE(files.size() == 2); 64 REQUIRE(files[0]->GetContentType() == ContentType::Generic); 65 REQUIRE(files[0]->fileId == (name + ".json")); 66 REQUIRE(files[0]->url == ("http://localhost/1.json")); 67 REQUIRE(files[1]->GetContentType() == ContentType::Generic); 68 REQUIRE(files[1]->fileId == (name + ".bin")); 69 REQUIRE(files[1]->url == ("http://localhost/2.bin")); 70 } 71 72 void CheckAppDownloadInfo(const FileEntities& files, const std::string& name) 73 { 74 REQUIRE(files.size() == 2); 75 REQUIRE(files[0]->GetContentType() == ContentType::App); 76 REQUIRE(files[0]->fileId == (name + ".json")); 77 REQUIRE(files[0]->url == ("http://localhost/1.json")); 78 REQUIRE(files[1]->GetContentType() == ContentType::App); 79 REQUIRE(files[1]->fileId == (name + ".bin")); 80 REQUIRE(files[1]->url == ("http://localhost/2.bin")); 81 } 82 } // namespace 83 84 TEST("Testing class SFSClientImpl()") 85 { 86 test::MockWebServer server; 87 const std::string ns = "testNameSpace"; 88 SFSClientImpl<CurlConnectionManager> sfsClient({"testAccountId", "testInstanceId", ns, LogCallbackToTest}); 89 sfsClient.SetCustomBaseUrl(server.GetBaseUrl()); 90 91 const std::string cv = "aaaaaaaaaaaaaaaa.1"; 92 ConnectionConfig config; 93 config.baseCV = cv; 94 auto connection = sfsClient.MakeConnection(config); 95 server.RegisterExpectedRequestHeader(HttpHeader::UserAgent, GetUserAgentValue()); 96 97 SECTION("Generic products") 98 { 99 server.RegisterProduct("productName", "0.0.0.2"); 100 server.RegisterProduct("productName", "0.0.0.1"); 101 102 SECTION("Testing SFSClientImpl::GetLatestVersion()") 103 { 104 server.RegisterExpectedRequestHeader(HttpHeader::ContentType, "application/json"); 105 std::unique_ptr<VersionEntity> entity; 106 107 SECTION("No attributes") 108 { 109 REQUIRE_NOTHROW(entity = sfsClient.GetLatestVersion({"productName", {}}, *connection)); 110 REQUIRE(entity); 111 CheckProduct(*entity, ns, "productName", "0.0.0.2"); 112 } 113 114 SECTION("With attributes") 115 { 116 const TargetingAttributes attributes{{"attr1", "value"}}; 117 REQUIRE_NOTHROW(entity = sfsClient.GetLatestVersion({"productName", attributes}, *connection)); 118 REQUIRE(entity); 119 CheckProduct(*entity, ns, "productName", "0.0.0.2"); 120 } 121 122 SECTION("Wrong product name") 123 { 124 REQUIRE_THROWS_CODE(entity = sfsClient.GetLatestVersion({"badName", {}}, *connection), HttpNotFound); 125 REQUIRE(!entity); 126 127 const TargetingAttributes attributes{{"attr1", "value"}}; 128 REQUIRE_THROWS_CODE(entity = sfsClient.GetLatestVersion({"badName", attributes}, *connection), 129 HttpNotFound); 130 REQUIRE(!entity); 131 } 132 } 133 134 SECTION("Testing SFSClientImpl::GetLatestVersionBatch()") 135 { 136 server.RegisterExpectedRequestHeader(HttpHeader::ContentType, "application/json"); 137 VersionEntities entities; 138 139 SECTION("No attributes") 140 { 141 REQUIRE_NOTHROW(entities = sfsClient.GetLatestVersionBatch({{"productName", {}}}, *connection)); 142 REQUIRE(!entities.empty()); 143 CheckProduct(*entities[0], ns, "productName", "0.0.0.2"); 144 } 145 146 SECTION("With attributes") 147 { 148 const TargetingAttributes attributes{{"attr1", "value"}}; 149 REQUIRE_NOTHROW(entities = sfsClient.GetLatestVersionBatch({{"productName", attributes}}, *connection)); 150 REQUIRE(!entities.empty()); 151 CheckProduct(*entities[0], ns, "productName", "0.0.0.2"); 152 } 153 154 SECTION("Wrong product name") 155 { 156 REQUIRE_THROWS_CODE(entities = sfsClient.GetLatestVersionBatch({{"badName", {}}}, *connection), 157 HttpNotFound); 158 REQUIRE(entities.empty()); 159 160 const TargetingAttributes attributes{{"attr1", "value"}}; 161 REQUIRE_THROWS_CODE(entities = sfsClient.GetLatestVersionBatch({{"badName", attributes}}, *connection), 162 HttpNotFound); 163 REQUIRE(entities.empty()); 164 } 165 166 SECTION("Multiple unique products") 167 { 168 server.RegisterProduct("productName2", "0.0.0.3"); 169 170 REQUIRE_NOTHROW(entities = sfsClient.GetLatestVersionBatch({{"productName", {}}, {"productName2", {}}}, 171 *connection)); 172 REQUIRE(entities.size() == 2); 173 CheckProducts(entities, ns, {{"productName", "0.0.0.2"}, {"productName2", "0.0.0.3"}}); 174 175 server.RegisterProduct("productName3", "0.0.0.4"); 176 177 REQUIRE_NOTHROW(entities = sfsClient.GetLatestVersionBatch( 178 {{"productName", {}}, {"productName2", {}}, {"productName3", {}}}, 179 *connection)); 180 REQUIRE(entities.size() == 3); 181 CheckProducts(entities, 182 ns, 183 {{"productName", "0.0.0.2"}, {"productName2", "0.0.0.3"}, {"productName3", "0.0.0.4"}}); 184 } 185 186 SECTION("Multiple repeated products") 187 { 188 REQUIRE_NOTHROW(entities = sfsClient.GetLatestVersionBatch({{"productName", {}}, {"productName", {}}}, 189 *connection)); 190 REQUIRE(entities.size() == 1); 191 CheckProduct(*entities[0], ns, "productName", "0.0.0.2"); 192 193 server.RegisterProduct("productName2", "0.0.0.3"); 194 195 REQUIRE_NOTHROW( 196 entities = sfsClient.GetLatestVersionBatch( 197 {{"productName", {}}, {"productName", {}}, {"productName2", {}}, {"productName2", {}}}, 198 *connection)); 199 REQUIRE(entities.size() == 2); 200 CheckProducts(entities, ns, {{"productName", "0.0.0.2"}, {"productName2", "0.0.0.3"}}); 201 } 202 203 SECTION("Multiple wrong products returns 404") 204 { 205 REQUIRE_THROWS_CODE( 206 entities = sfsClient.GetLatestVersionBatch({{"badName", {}}, {"badName2", {}}}, *connection), 207 HttpNotFound); 208 REQUIRE(entities.empty()); 209 } 210 211 SECTION("Multiple products, one wrong returns 200") 212 { 213 REQUIRE_NOTHROW( 214 entities = sfsClient.GetLatestVersionBatch({{"productName", {}}, {"badName", {}}}, *connection)); 215 REQUIRE(entities.size() == 1); 216 CheckProduct(*entities[0], ns, "productName", "0.0.0.2"); 217 } 218 } 219 220 SECTION("Testing SFSClientImpl::GetSpecificVersion()") 221 { 222 std::unique_ptr<VersionEntity> entity; 223 SECTION("Getting 0.0.0.1") 224 { 225 REQUIRE_NOTHROW(entity = sfsClient.GetSpecificVersion("productName", "0.0.0.1", *connection)); 226 REQUIRE(entity); 227 CheckProduct(*entity, ns, "productName", "0.0.0.1"); 228 } 229 230 SECTION("Getting 0.0.0.2") 231 { 232 REQUIRE_NOTHROW(entity = sfsClient.GetSpecificVersion("productName", "0.0.0.2", *connection)); 233 REQUIRE(entity); 234 CheckProduct(*entity, ns, "productName", "0.0.0.2"); 235 } 236 237 SECTION("Wrong product name") 238 { 239 REQUIRE_THROWS_CODE(entity = sfsClient.GetSpecificVersion("badName", "0.0.0.2", *connection), 240 HttpNotFound); 241 REQUIRE(!entity); 242 } 243 244 SECTION("Wrong version") 245 { 246 REQUIRE_THROWS_CODE(entity = sfsClient.GetSpecificVersion("productName", "0.0.0.3", *connection), 247 HttpNotFound); 248 REQUIRE(!entity); 249 } 250 } 251 252 SECTION("Testing SFSClientImpl::GetDownloadInfo()") 253 { 254 server.RegisterExpectedRequestHeader(HttpHeader::ContentType, "application/json"); 255 FileEntities files; 256 257 SECTION("Getting 0.0.0.1") 258 { 259 REQUIRE_NOTHROW(files = sfsClient.GetDownloadInfo("productName", "0.0.0.1", *connection)); 260 REQUIRE(!files.empty()); 261 CheckDownloadInfo(files, "productName"); 262 } 263 264 SECTION("Getting 0.0.0.2") 265 { 266 REQUIRE_NOTHROW(files = sfsClient.GetDownloadInfo("productName", "0.0.0.2", *connection)); 267 REQUIRE(!files.empty()); 268 CheckDownloadInfo(files, "productName"); 269 } 270 271 SECTION("Wrong product name") 272 { 273 REQUIRE_THROWS_CODE(files = sfsClient.GetDownloadInfo("badName", "0.0.0.2", *connection), HttpNotFound); 274 REQUIRE(files.empty()); 275 } 276 277 SECTION("Wrong version") 278 { 279 REQUIRE_THROWS_CODE(files = sfsClient.GetDownloadInfo("productName", "0.0.0.3", *connection), 280 HttpNotFound); 281 REQUIRE(files.empty()); 282 } 283 } 284 } 285 286 SECTION("App products") 287 { 288 server.RegisterAppProduct("productName", "0.0.0.2", {}); 289 server.RegisterAppProduct("productName", "0.0.0.1", {}); 290 291 SECTION("Testing SFSClientImpl::GetLatestVersion()") 292 { 293 server.RegisterExpectedRequestHeader(HttpHeader::ContentType, "application/json"); 294 std::unique_ptr<VersionEntity> entity; 295 296 SECTION("No attributes") 297 { 298 REQUIRE_NOTHROW(entity = sfsClient.GetLatestVersion({"productName", {}}, *connection)); 299 REQUIRE(entity); 300 CheckAppProduct(*entity, ns, "productName", "0.0.0.2"); 301 } 302 303 SECTION("With attributes") 304 { 305 const TargetingAttributes attributes{{"attr1", "value"}}; 306 REQUIRE_NOTHROW(entity = sfsClient.GetLatestVersion({"productName", attributes}, *connection)); 307 REQUIRE(entity); 308 CheckAppProduct(*entity, ns, "productName", "0.0.0.2"); 309 } 310 311 SECTION("Wrong product name") 312 { 313 REQUIRE_THROWS_CODE(entity = sfsClient.GetLatestVersion({"badName", {}}, *connection), HttpNotFound); 314 REQUIRE(!entity); 315 316 const TargetingAttributes attributes{{"attr1", "value"}}; 317 REQUIRE_THROWS_CODE(entity = sfsClient.GetLatestVersion({"badName", attributes}, *connection), 318 HttpNotFound); 319 REQUIRE(!entity); 320 } 321 } 322 323 SECTION("Testing SFSClientImpl::GetDownloadInfo()") 324 { 325 server.RegisterExpectedRequestHeader(HttpHeader::ContentType, "application/json"); 326 FileEntities files; 327 328 SECTION("Getting 0.0.0.1") 329 { 330 REQUIRE_NOTHROW(files = sfsClient.GetDownloadInfo("productName", "0.0.0.1", *connection)); 331 REQUIRE(!files.empty()); 332 CheckAppDownloadInfo(files, "productName"); 333 } 334 335 SECTION("Getting 0.0.0.2") 336 { 337 REQUIRE_NOTHROW(files = sfsClient.GetDownloadInfo("productName", "0.0.0.2", *connection)); 338 REQUIRE(!files.empty()); 339 CheckAppDownloadInfo(files, "productName"); 340 } 341 342 SECTION("Wrong product name") 343 { 344 REQUIRE_THROWS_CODE(files = sfsClient.GetDownloadInfo("badName", "0.0.0.2", *connection), HttpNotFound); 345 REQUIRE(files.empty()); 346 } 347 348 SECTION("Wrong version") 349 { 350 REQUIRE_THROWS_CODE(files = sfsClient.GetDownloadInfo("productName", "0.0.0.3", *connection), 351 HttpNotFound); 352 REQUIRE(files.empty()); 353 } 354 } 355 } 356 357 REQUIRE(server.Stop() == Result::Success); 358 }