Skip to content

Commit

Permalink
Use package tracking data to correlate in CompositeSource (#1671)
Browse files Browse the repository at this point in the history
This change leverages the tracking data that is stored per source to correlate installed packages to available packages.  This will currently provide no additional benefit with the `winget` source, as we aren't doing the work yet to determine the best fit system artifact when none of our current correlation attempts succeed.  It will help the `msstore` source to correlate as that is currently lacking in support to search system references.
  • Loading branch information
JohnMcPMS authored Nov 5, 2021
1 parent 134326d commit 2de86a4
Show file tree
Hide file tree
Showing 18 changed files with 874 additions and 299 deletions.
3 changes: 1 addition & 2 deletions src/AppInstallerCLICore/Workflows/InstallFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "MsiInstallFlow.h"
#include "WorkflowBase.h"
#include "Workflows/DependenciesFlow.h"
#include <winget/PackageTrackingCatalog.h>
#include <AppInstallerDeployment.h>

using namespace winrt::Windows::ApplicationModel::Store::Preview::InstallControl;
Expand Down Expand Up @@ -683,7 +682,7 @@ namespace AppInstaller::CLI::Workflow
return;
}

auto trackingCatalog = PackageTrackingCatalog::CreateForSource(context.Get<Data::PackageVersion>()->GetSource());
auto trackingCatalog = context.Get<Data::PackageVersion>()->GetSource().GetTrackingCatalog();

trackingCatalog.RecordInstall(
context.Get<Data::Manifest>(),
Expand Down
3 changes: 1 addition & 2 deletions src/AppInstallerCLICore/Workflows/UninstallFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "AppInstallerMsixInfo.h"

#include <AppInstallerDeployment.h>
#include <winget/PackageTrackingCatalog.h>

using namespace AppInstaller::CLI::Execution;
using namespace AppInstaller::Manifest;
Expand Down Expand Up @@ -181,7 +180,7 @@ namespace AppInstaller::CLI::Workflow
// Finally record the uninstall for each found value
for (const auto& item : correlatedSources.Items)
{
auto trackingCatalog = PackageTrackingCatalog::CreateForSource(item.FromSource);
auto trackingCatalog = item.FromSource.GetTrackingCatalog();
trackingCatalog.RecordUninstall(item.Identifier);
}
}
Expand Down
198 changes: 184 additions & 14 deletions src/AppInstallerCLITests/CompositeSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
#include "pch.h"
#include "TestCommon.h"
#include "TestSource.h"
#include "TestHooks.h"
#include <CompositeSource.h>
#include <Microsoft/SQLiteIndexSource.h>
#include <PackageTrackingCatalogSourceFactory.h>

using namespace std::string_literals;
using namespace std::string_view_literals;
using namespace TestCommon;
using namespace AppInstaller;
using namespace AppInstaller::Repository;
using namespace AppInstaller::Repository::Microsoft;
using namespace AppInstaller::Utility;

constexpr std::string_view s_Everything_Query = "everything"sv;
Expand All @@ -21,6 +25,13 @@ constexpr std::string_view s_Everything_Query = "everything"sv;
// enable verification of expectations.
struct ComponentTestSource : public TestSource
{
ComponentTestSource() = default;

ComponentTestSource(std::string_view identifier)
{
Details.Identifier = identifier;
}

SearchResult Search(const SearchRequest& request) const override
{
if (request.Query && request.Query.value().Value == s_Everything_Query)
Expand All @@ -41,10 +52,10 @@ struct CompositeTestSetup
{
CompositeTestSetup() : Composite("*Tests")
{
Installed = std::make_shared<ComponentTestSource>();
Available = std::make_shared<ComponentTestSource>();
Composite.SetInstalledSource(Installed);
Composite.AddAvailableSource(Available);
Installed = std::make_shared<ComponentTestSource>("InstalledTestSource1");
Available = std::make_shared<ComponentTestSource>("AvailableTestSource1");
Composite.SetInstalledSource(Source{ Installed });
Composite.AddAvailableSource(Source{ Available });
}

SearchResult Search()
Expand All @@ -59,6 +70,24 @@ struct CompositeTestSetup
CompositeSource Composite;
};

// A helper to create the sources used by the majority of tests in this file.
struct CompositeWithTrackingTestSetup : public CompositeTestSetup
{
CompositeWithTrackingTestSetup() : TrackingFactory([&](const SourceDetails&) { return Tracking; })
{
Tracking = std::make_shared<SQLiteIndexSource>(SourceDetails{}, SQLiteIndex::CreateNew(SQLITE_MEMORY_DB_CONNECTION_TARGET));
TestHook_SetSourceFactoryOverride(std::string{ PackageTrackingCatalogSourceFactory::Type() }, TrackingFactory);
}

~CompositeWithTrackingTestSetup()
{
TestHook_ClearSourceFactoryOverrides();
}

TestSourceFactory TrackingFactory;
std::shared_ptr<SQLiteIndexSource> Tracking;
};

// A helper to make matches.
struct Criteria : public PackageMatchFilter
{
Expand Down Expand Up @@ -95,9 +124,9 @@ struct TestPackageHelper
return *this;
}

TestPackageHelper& WithDefaultName(const std::string& name)
TestPackageHelper& WithDefaultName(std::string_view name)
{
m_manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>(name);
m_manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>(std::string{ name });
return *this;
}

Expand Down Expand Up @@ -130,6 +159,11 @@ struct TestPackageHelper
return m_package;
}

operator const Manifest::Manifest& () const
{
return m_manifest;
}

private:
bool m_isInstalled;
Manifest::Manifest m_manifest;
Expand Down Expand Up @@ -544,7 +578,7 @@ TEST_CASE("CompositeSource_MultipleAvailableSources_MatchFirst", "[CompositeSour

CompositeTestSetup setup;
std::shared_ptr<ComponentTestSource> secondAvailable = std::make_shared<ComponentTestSource>();
setup.Composite.AddAvailableSource(secondAvailable);
setup.Composite.AddAvailableSource(Source{ secondAvailable });

setup.Installed->Everything.Matches.emplace_back(MakeInstalled().WithPFN(pfn), Criteria());

Expand Down Expand Up @@ -582,7 +616,7 @@ TEST_CASE("CompositeSource_MultipleAvailableSources_MatchSecond", "[CompositeSou

CompositeTestSetup setup;
std::shared_ptr<ComponentTestSource> secondAvailable = std::make_shared<ComponentTestSource>();
setup.Composite.AddAvailableSource(secondAvailable);
setup.Composite.AddAvailableSource(Source{ secondAvailable });

setup.Installed->Everything.Matches.emplace_back(MakeInstalled().WithPFN(pfn), Criteria());

Expand Down Expand Up @@ -611,7 +645,7 @@ TEST_CASE("CompositeSource_MultipleAvailableSources_ReverseMatchBoth", "[Composi

CompositeTestSetup setup;
std::shared_ptr<ComponentTestSource> secondAvailable = std::make_shared<ComponentTestSource>();
setup.Composite.AddAvailableSource(secondAvailable);
setup.Composite.AddAvailableSource(Source{ secondAvailable });

setup.Installed->SearchFunction = [&](const SearchRequest& request)
{
Expand Down Expand Up @@ -665,8 +699,8 @@ TEST_CASE("CompositeSource_AvailableSearchFailure", "[CompositeSource]")
AvailableFails->Details.Name = "The one that fails";

CompositeSource Composite("*CompositeSource_AvailableSearchFailure");
Composite.AddAvailableSource(AvailableSucceeds);
Composite.AddAvailableSource(AvailableFails);
Composite.AddAvailableSource(Source{ AvailableSucceeds });
Composite.AddAvailableSource(Source{ AvailableFails });

SearchResult result = Composite.Search({});

Expand Down Expand Up @@ -706,7 +740,7 @@ TEST_CASE("CompositeSource_InstalledToAvailableCorrelationSearchFailure", "[Comp
AvailableFails->SearchFunction = [&](const SearchRequest&) -> SearchResult { THROW_HR(expectedHR); };
AvailableFails->Details.Name = "The one that fails";

setup.Composite.AddAvailableSource(AvailableFails);
setup.Composite.AddAvailableSource(Source{ AvailableFails });

SearchResult result = setup.Search();

Expand Down Expand Up @@ -746,9 +780,9 @@ TEST_CASE("CompositeSource_InstalledAvailableSearchFailure", "[CompositeSource]"
AvailableFails->SearchFunction = [&](const SearchRequest&) -> SearchResult { THROW_HR(expectedHR); };
AvailableFails->Details.Name = "The one that fails";

setup.Composite.AddAvailableSource(AvailableFails);
setup.Composite.AddAvailableSource(Source{ AvailableFails });

setup.Composite.SetInstalledSource(setup.Installed, CompositeSearchBehavior::AvailablePackages);
setup.Composite.SetInstalledSource(Source{ setup.Installed }, CompositeSearchBehavior::AvailablePackages);

SearchRequest request;
request.Query = RequestMatch{ MatchType::Exact, "whatever" };
Expand All @@ -772,3 +806,139 @@ TEST_CASE("CompositeSource_InstalledAvailableSearchFailure", "[CompositeSource]"

REQUIRE(searchFailure == expectedHR);
}

TEST_CASE("CompositeSource_TrackingPackageFound", "[CompositeSource]")
{
std::string availableID = "Available.ID";
std::string pfn = "sortof_apfn";

auto installedPackage = MakeInstalled().WithPFN(pfn);
auto availablePackage = MakeAvailable().WithPFN(pfn).WithId(availableID).WithDefaultName(s_Everything_Query);

CompositeWithTrackingTestSetup setup;
setup.Installed->Everything.Matches.emplace_back(installedPackage, Criteria());
setup.Installed->SearchFunction = [&](const SearchRequest& request)
{
RequireIncludes(request.Inclusions, PackageMatchField::PackageFamilyName, MatchType::Exact, pfn);

SearchResult result;
result.Matches.emplace_back(installedPackage, Criteria());
return result;
};

setup.Available->Everything.Matches.emplace_back(availablePackage, Criteria());
setup.Available->SearchFunction = [&](const SearchRequest& request)
{
if (request.Filters.empty())
{
RequireIncludes(request.Inclusions, PackageMatchField::PackageFamilyName, MatchType::Exact, pfn);
}
else
{
REQUIRE(request.Filters.size() == 1);
RequireIncludes(request.Filters, PackageMatchField::Id, MatchType::CaseInsensitive, availableID);
}

SearchResult result;
result.Matches.emplace_back(availablePackage, Criteria());
return result;
};

setup.Tracking->GetIndex().AddManifest(availablePackage);

SearchResult result = setup.Search();

REQUIRE(result.Matches.size() == 1);
REQUIRE(result.Matches[0].Package);
REQUIRE(result.Matches[0].Package->GetInstalledVersion());
REQUIRE(result.Matches[0].Package->GetInstalledVersion()->GetSource().GetIdentifier() == setup.Available->Details.Identifier);
REQUIRE(result.Matches[0].Package->GetLatestAvailableVersion());
}

TEST_CASE("CompositeSource_TrackingFound_AvailableNot", "[CompositeSource]")
{
std::string availableID = "Available.ID";
std::string pfn = "sortof_apfn";

auto installedPackage = MakeInstalled().WithPFN(pfn);
auto availablePackage = MakeAvailable().WithPFN(pfn).WithId(availableID).WithDefaultName(s_Everything_Query);

CompositeWithTrackingTestSetup setup;
setup.Installed->Everything.Matches.emplace_back(installedPackage, Criteria());
setup.Installed->SearchFunction = [&](const SearchRequest& request)
{
RequireIncludes(request.Inclusions, PackageMatchField::PackageFamilyName, MatchType::Exact, pfn);

SearchResult result;
result.Matches.emplace_back(installedPackage, Criteria());
return result;
};

setup.Tracking->GetIndex().AddManifest(availablePackage);

SearchResult result = setup.Search();

REQUIRE(result.Matches.size() == 1);
REQUIRE(result.Matches[0].Package);
REQUIRE(result.Matches[0].Package->GetInstalledVersion());
REQUIRE(result.Matches[0].Package->GetInstalledVersion()->GetSource().GetIdentifier() == setup.Available->Details.Identifier);
REQUIRE(!result.Matches[0].Package->GetLatestAvailableVersion());
}

TEST_CASE("CompositeSource_TrackingFound_AvailablePath", "[CompositeSource]")
{
std::string availableID = "Available.ID";
std::string pfn = "sortof_apfn";

auto installedPackage = MakeInstalled().WithPFN(pfn);
auto availablePackage = MakeAvailable().WithPFN(pfn).WithId(availableID).WithDefaultName(s_Everything_Query);

CompositeWithTrackingTestSetup setup;
setup.Installed->SearchFunction = [&](const SearchRequest& request)
{
RequireIncludes(request.Inclusions, PackageMatchField::PackageFamilyName, MatchType::Exact, pfn);

SearchResult result;
result.Matches.emplace_back(installedPackage, Criteria());
return result;
};

setup.Available->Everything.Matches.emplace_back(availablePackage, Criteria());
setup.Available->SearchFunction = [&](const SearchRequest& request)
{
REQUIRE(request.Filters.size() == 1);
RequireIncludes(request.Filters, PackageMatchField::Id, MatchType::CaseInsensitive, availableID);

SearchResult result;
result.Matches.emplace_back(availablePackage, Criteria());
return result;
};

setup.Tracking->GetIndex().AddManifest(availablePackage);

SearchResult result = setup.Search();

REQUIRE(result.Matches.size() == 1);
REQUIRE(result.Matches[0].Package);
REQUIRE(result.Matches[0].Package->GetInstalledVersion());
REQUIRE(result.Matches[0].Package->GetInstalledVersion()->GetSource().GetIdentifier() == setup.Available->Details.Identifier);
REQUIRE(result.Matches[0].Package->GetLatestAvailableVersion());
}

TEST_CASE("CompositeSource_TrackingFound_NotInstalled", "[CompositeSource]")
{
std::string availableID = "Available.ID";
std::string pfn = "sortof_apfn";

auto installedPackage = MakeInstalled().WithPFN(pfn);
auto availablePackage = MakeAvailable().WithPFN(pfn).WithId(availableID).WithDefaultName(s_Everything_Query);

CompositeWithTrackingTestSetup setup;
setup.Available->Everything.Matches.emplace_back(availablePackage, Criteria());

setup.Tracking->GetIndex().AddManifest(availablePackage);

SearchResult result = setup.Search();

REQUIRE(result.Matches.empty());
}
Loading

0 comments on commit 2de86a4

Please sign in to comment.