ConfigurableTestSourceFactory.cpp (5791B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "Microsoft/ConfigurableTestSourceFactory.h" 5 6 #include <json/json.h> 7 8 using namespace std::string_literals; 9 using namespace std::string_view_literals; 10 11 namespace AppInstaller::Repository::Microsoft 12 { 13 namespace 14 { 15 // The configuration defined for a source. 16 // This can be added to as new scenarios are needed for testing. 17 struct TestSourceConfiguration 18 { 19 TestSourceConfiguration(const std::string& config) 20 { 21 Json::Value root; 22 Json::CharReaderBuilder builder; 23 const std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); 24 25 std::string error; 26 27 if (reader->parse(config.c_str(), config.c_str() + config.size(), &root, &error)) 28 { 29 // TODO: If this becomes more dynamic, refactor the UserSettings code to make it easier to leverage here 30 ParseHR(root, ".OpenHR", OpenHR); 31 ParseHR(root, ".SearchHR", SearchHR); 32 } 33 else 34 { 35 AICLI_LOG(Repo, Error, << "Error parsing test source config: " << error); 36 THROW_HR_MSG(E_INVALIDARG, "%hs", error.c_str()); 37 } 38 } 39 40 // The HR to throw on Factory::Create (if FAILED) 41 HRESULT OpenHR = S_OK; 42 43 // The HR to throw on Source::Search (if FAILED) 44 HRESULT SearchHR = S_OK; 45 46 private: 47 static void ParseHR(const Json::Value& root, const std::string& path, HRESULT& hr) 48 { 49 const Json::Path jsonPath(path); 50 Json::Value node = jsonPath.resolve(root); 51 if (!node.isNull()) 52 { 53 if (node.isIntegral()) 54 { 55 hr = node.asInt(); 56 } 57 else if (node.isString()) 58 { 59 hr = static_cast<HRESULT>(std::strtoll(node.asString().c_str(), nullptr, 0)); 60 } 61 } 62 } 63 }; 64 65 // The configurable source itself. 66 struct ConfigurableTestSource : public ISource 67 { 68 static constexpr ISourceType SourceType = ISourceType::ConfigurableTestSource; 69 70 ConfigurableTestSource(const SourceDetails& details, const TestSourceConfiguration& config) : 71 m_details(details), m_config(config) {} 72 73 const SourceDetails& GetDetails() const override { return m_details; } 74 75 const std::string& GetIdentifier() const override { return m_details.Identifier; } 76 77 SearchResult Search(const SearchRequest&) const override 78 { 79 THROW_IF_FAILED(m_config.SearchHR); 80 return {}; 81 } 82 83 void* CastTo(ISourceType type) override 84 { 85 if (type == SourceType) 86 { 87 return this; 88 } 89 90 return nullptr; 91 } 92 93 private: 94 SourceDetails m_details; 95 TestSourceConfiguration m_config; 96 }; 97 98 struct ConfigurableTestSourceReference : public ISourceReference 99 { 100 ConfigurableTestSourceReference(const SourceDetails& details) : m_details(details) 101 { 102 m_details.Identifier = "*ConfigurableTestSource"; 103 } 104 105 std::string GetIdentifier() override { return m_details.Identifier; } 106 107 SourceDetails& GetDetails() override { return m_details; }; 108 109 bool SetCustomHeader(std::optional<std::string>) override { return true; } 110 111 std::shared_ptr<ISource> Open(IProgressCallback&) override 112 { 113 // enables `source add` with FAILED(OpenHR) 114 TestSourceConfiguration config{ m_details.Arg }; 115 THROW_IF_FAILED(config.OpenHR); 116 return std::make_shared<ConfigurableTestSource>(m_details, config); 117 } 118 119 private: 120 SourceDetails m_details; 121 }; 122 123 // The actual factory implementation. 124 struct ConfigurableTestSourceFactoryImpl : public ISourceFactory 125 { 126 std::string_view TypeName() const override final 127 { 128 return ConfigurableTestSourceFactory::Type(); 129 } 130 131 std::shared_ptr<ISourceReference> Create(const SourceDetails& details) override final 132 { 133 return std::make_shared<ConfigurableTestSourceReference>(details); 134 } 135 136 bool Add(SourceDetails& details, IProgressCallback&) override final 137 { 138 // Attempt to parse the configuration so that we can fail at the appropriate point 139 TestSourceConfiguration config{ details.Arg }; 140 return true; 141 } 142 143 bool Update(const SourceDetails&, IProgressCallback&) override final 144 { 145 return true; 146 } 147 148 bool BackgroundUpdate(const SourceDetails&, IProgressCallback&) override final 149 { 150 return true; 151 } 152 153 bool Remove(const SourceDetails&, IProgressCallback&) override final 154 { 155 return true; 156 } 157 }; 158 } 159 160 std::unique_ptr<ISourceFactory> ConfigurableTestSourceFactory::Create() 161 { 162 return std::make_unique<ConfigurableTestSourceFactoryImpl>(); 163 } 164 }