PackageTrackingCatalog.cpp (10719B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "TestCommon.h" 5 #include <Microsoft/SQLiteIndexSource.h> 6 #include <winget/ManifestYamlParser.h> 7 #include <winget/PackageTrackingCatalog.h> 8 9 using namespace std::string_literals; 10 using namespace TestCommon; 11 using namespace AppInstaller::Manifest; 12 using namespace AppInstaller::Repository; 13 using namespace AppInstaller::Repository::Microsoft; 14 using namespace AppInstaller::SQLite; 15 using namespace AppInstaller::Utility; 16 17 namespace 18 { 19 static Source SimpleTestSetup(const std::string& filePath, SourceDetails& details, Manifest& manifest, std::string& relativePath) 20 { 21 SQLiteIndex index = SQLiteIndex::CreateNew(filePath, AppInstaller::SQLite::Version::Latest(), SQLiteIndex::CreateOptions::SupportPathless | SQLiteIndex::CreateOptions::DisableDependenciesSupport); 22 23 TestDataFile testManifest("Manifest-Good.yaml"); 24 manifest = YamlParser::CreateFromPath(testManifest); 25 26 relativePath = testManifest.GetPath().filename().u8string(); 27 28 index.AddManifest(manifest, relativePath); 29 30 details.Identifier = "*SimpleTestSetup"; 31 details.Name = "TestName"; 32 details.Type = "TestType"; 33 details.Arg = testManifest.GetPath().parent_path().u8string(); 34 details.Data = ""; 35 36 auto result = std::make_shared<SQLiteIndexSource>(details, std::move(index)); 37 38 PackageTrackingCatalog::RemoveForSource(result->GetIdentifier()); 39 40 return { result }; 41 } 42 43 struct TestCatalog : public PackageTrackingCatalog 44 { 45 using PackageTrackingCatalog::CreateForSource; 46 }; 47 48 PackageTrackingCatalog CreatePackageTrackingCatalogForSource(const Source& source) 49 { 50 return TestCatalog::CreateForSource(source); 51 } 52 } 53 54 TEST_CASE("TrackingCatalog_Create", "[tracking_catalog]") 55 { 56 TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; 57 INFO("Using temporary file named: " << tempFile.GetPath()); 58 59 SourceDetails details; 60 Manifest manifest; 61 std::string relativePath; 62 auto source = SimpleTestSetup(tempFile, details, manifest, relativePath); 63 64 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 65 } 66 67 TEST_CASE("TrackingCatalog_Install", "[tracking_catalog]") 68 { 69 TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; 70 INFO("Using temporary file named: " << tempFile.GetPath()); 71 72 SourceDetails details; 73 Manifest manifest; 74 std::string relativePath; 75 auto source = SimpleTestSetup(tempFile, details, manifest, relativePath); 76 77 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 78 79 SearchRequest request; 80 request.Filters.emplace_back(PackageMatchField::Id, MatchType::Exact, manifest.Id); 81 82 SearchResult resultBefore = catalog.Search(request); 83 REQUIRE(resultBefore.Matches.size() == 0); 84 85 catalog.RecordInstall(manifest, manifest.Installers[0], false); 86 87 SearchResult resultAfter = catalog.Search(request); 88 REQUIRE(resultAfter.Matches.size() == 1); 89 REQUIRE(resultAfter.Matches[0].Package->GetAvailable().size() == 1); 90 91 auto trackingVersion = resultAfter.Matches[0].Package->GetAvailable()[0]->GetLatestVersion(); 92 REQUIRE(trackingVersion); 93 94 auto metadata = trackingVersion->GetMetadata(); 95 REQUIRE(metadata.find(PackageVersionMetadata::TrackingWriteTime) != metadata.end()); 96 } 97 98 TEST_CASE("TrackingCatalog_Reinstall", "[tracking_catalog]") 99 { 100 TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; 101 INFO("Using temporary file named: " << tempFile.GetPath()); 102 103 SourceDetails details; 104 Manifest manifest; 105 std::string relativePath; 106 auto source = SimpleTestSetup(tempFile, details, manifest, relativePath); 107 108 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 109 110 SearchRequest request; 111 request.Filters.emplace_back(PackageMatchField::Id, MatchType::Exact, manifest.Id); 112 113 catalog.RecordInstall(manifest, manifest.Installers[0], false); 114 115 SearchResult resultBefore = catalog.Search(request); 116 REQUIRE(resultBefore.Matches.size() == 1); 117 REQUIRE(resultBefore.Matches[0].Package->GetAvailable().size() == 1); 118 REQUIRE(resultBefore.Matches[0].Package->GetAvailable()[0]->GetLatestVersion()->GetProperty(PackageVersionProperty::Name) == 119 manifest.DefaultLocalization.Get<Localization::PackageName>()); 120 121 // Change name 122 std::string newName = "New Package Name"; 123 manifest.DefaultLocalization.Add<Localization::PackageName>(newName); 124 125 catalog.RecordInstall(manifest, manifest.Installers[0], false); 126 127 SearchResult resultAfter = catalog.Search(request); 128 REQUIRE(resultAfter.Matches.size() == 1); 129 REQUIRE(resultAfter.Matches[0].Package->GetAvailable().size() == 1); 130 REQUIRE(resultAfter.Matches[0].Package->GetAvailable()[0]->GetLatestVersion()->GetProperty(PackageVersionProperty::Name) == 131 newName); 132 } 133 134 TEST_CASE("TrackingCatalog_Upgrade", "[tracking_catalog]") 135 { 136 TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; 137 INFO("Using temporary file named: " << tempFile.GetPath()); 138 139 SourceDetails details; 140 Manifest manifest; 141 std::string relativePath; 142 auto source = SimpleTestSetup(tempFile, details, manifest, relativePath); 143 144 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 145 146 SearchRequest request; 147 request.Filters.emplace_back(PackageMatchField::Id, MatchType::Exact, manifest.Id); 148 149 catalog.RecordInstall(manifest, manifest.Installers[0], false); 150 151 SearchResult resultBefore = catalog.Search(request); 152 REQUIRE(resultBefore.Matches.size() == 1); 153 REQUIRE(resultBefore.Matches[0].Package->GetAvailable().size() == 1); 154 REQUIRE(resultBefore.Matches[0].Package->GetAvailable()[0]->GetLatestVersion()->GetProperty(PackageVersionProperty::Version) == 155 manifest.Version); 156 157 // Change version 158 manifest.Version = "99.1.2.3"; 159 160 catalog.RecordInstall(manifest, manifest.Installers[0], true); 161 162 SearchResult resultAfter = catalog.Search(request); 163 REQUIRE(resultAfter.Matches.size() == 1); 164 REQUIRE(resultAfter.Matches[0].Package->GetAvailable().size() == 1); 165 REQUIRE(resultAfter.Matches[0].Package->GetAvailable()[0]->GetLatestVersion()->GetProperty(PackageVersionProperty::Version) == 166 manifest.Version); 167 } 168 169 TEST_CASE("TrackingCatalog_Uninstall", "[tracking_catalog]") 170 { 171 TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; 172 INFO("Using temporary file named: " << tempFile.GetPath()); 173 174 SourceDetails details; 175 Manifest manifest; 176 std::string relativePath; 177 auto source = SimpleTestSetup(tempFile, details, manifest, relativePath); 178 179 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 180 181 SearchRequest request; 182 request.Filters.emplace_back(PackageMatchField::Id, MatchType::Exact, manifest.Id); 183 184 catalog.RecordInstall(manifest, manifest.Installers[0], false); 185 186 SearchResult resultBefore = catalog.Search(request); 187 REQUIRE(resultBefore.Matches.size() == 1); 188 189 catalog.RecordUninstall(LocIndString{ manifest.Id }); 190 191 SearchResult resultAfter = catalog.Search(request); 192 REQUIRE(resultAfter.Matches.size() == 0); 193 } 194 195 TEST_CASE("TrackingCatalog_Overlapping_ARP_Range", "[tracking_catalog]") 196 { 197 TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; 198 INFO("Using temporary file named: " << tempFile.GetPath()); 199 200 SourceDetails details; 201 Manifest manifest; 202 std::string relativePath; 203 auto source = SimpleTestSetup(tempFile, details, manifest, relativePath); 204 205 REQUIRE(manifest.Installers.size() >= 2); 206 AppsAndFeaturesEntry appEntry{}; 207 appEntry.DisplayVersion = "1.23"; 208 manifest.Installers[0].AppsAndFeaturesEntries.emplace_back(appEntry); 209 appEntry.DisplayVersion = "1.24"; 210 manifest.Installers[1].AppsAndFeaturesEntries.emplace_back(appEntry); 211 212 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 213 214 SearchRequest request; 215 request.Filters.emplace_back(PackageMatchField::Id, MatchType::Exact, manifest.Id); 216 217 catalog.RecordInstall(manifest, manifest.Installers[0], false); 218 219 SearchResult resultBefore = catalog.Search(request); 220 REQUIRE(resultBefore.Matches.size() == 1); 221 REQUIRE(resultBefore.Matches[0].Package->GetAvailable().size() == 1); 222 REQUIRE(resultBefore.Matches[0].Package->GetAvailable()[0]->GetLatestVersion()->GetProperty(PackageVersionProperty::Version) == 223 manifest.Version); 224 225 // Change version 226 manifest.Version = "99.1.2.3"; 227 228 catalog.RecordInstall(manifest, manifest.Installers[0], true); 229 230 SearchResult resultAfter = catalog.Search(request); 231 REQUIRE(resultAfter.Matches.size() == 1); 232 REQUIRE(resultAfter.Matches[0].Package->GetAvailable().size() == 1); 233 REQUIRE(resultAfter.Matches[0].Package->GetAvailable()[0]->GetLatestVersion()->GetProperty(PackageVersionProperty::Version) == 234 manifest.Version); 235 } 236 237 TEST_CASE("TrackingCatalog_Corrupt", "[tracking_catalog]") 238 { 239 TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; 240 INFO("Using temporary file named: " << tempFile.GetPath()); 241 242 SourceDetails details; 243 Manifest manifest; 244 std::string relativePath; 245 auto source = SimpleTestSetup(tempFile, details, manifest, relativePath); 246 247 SearchRequest request; 248 request.Filters.emplace_back(PackageMatchField::Id, MatchType::Exact, manifest.Id); 249 250 std::filesystem::path catalogFile; 251 252 { 253 // Add data to initial database 254 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 255 256 SearchResult resultBefore = catalog.Search(request); 257 REQUIRE(resultBefore.Matches.size() == 0); 258 259 catalog.RecordInstall(manifest, manifest.Installers[0], false); 260 261 SearchResult resultAfter = catalog.Search(request); 262 REQUIRE(resultAfter.Matches.size() == 1); 263 REQUIRE(resultAfter.Matches[0].Package->GetAvailable().size() == 1); 264 265 catalogFile = catalog.GetFilePath(); 266 } 267 268 { 269 std::ofstream file{ catalogFile, std::ios_base::trunc }; 270 file << "Corrupted!"; 271 } 272 273 { 274 // Open database again after "corruption" 275 PackageTrackingCatalog catalog = CreatePackageTrackingCatalogForSource(source); 276 277 // Should not find anything in new database 278 SearchResult resultBefore = catalog.Search(request); 279 REQUIRE(resultBefore.Matches.size() == 0); 280 } 281 }