winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }