diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
index 7500b2c1bb..bbbd089e74 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -279,6 +279,7 @@
+
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
index 5d28140d17..4463aea5f5 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -371,6 +371,9 @@
Source Files\Common
+
+ Source Files\Repository
+
diff --git a/src/AppInstallerCLITests/Experiment.cpp b/src/AppInstallerCLITests/Experiment.cpp
new file mode 100644
index 0000000000..b8b5b6e25c
--- /dev/null
+++ b/src/AppInstallerCLITests/Experiment.cpp
@@ -0,0 +1,76 @@
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "TestCommon.h"
+#include "TestSettings.h"
+#include
+#include
+
+using namespace TestCommon;
+using namespace AppInstaller::Settings;
+
+#define SET_POLICY_STATE(_policy_, _state_) \
+ GroupPolicyTestOverride policies; \
+ policies.SetState(_policy_, _state_);
+
+#define SET_USER_SETTINGS(_enabled_, _disabled_) \
+ TestUserSettings settings; \
+ settings.Set({ \
+ {"TestExperimentEnabledByDefault", _enabled_}, \
+ {"TestExperimentDisabledByDefault", _disabled_} \
+ });
+
+#define ASSERT_EXPERIMENTS(_enabled_, _disabled_) \
+ REQUIRE(_enabled_ == Experiment::IsEnabled(Experiment::Key::TestExperimentEnabledByDefault)); \
+ REQUIRE(_disabled_ == Experiment::IsEnabled(Experiment::Key::TestExperimentDisabledByDefault));
+
+TEST_CASE("Experiment_GroupPolicyControl", "[experiment]")
+{
+ SECTION("Not configured")
+ {
+ SET_POLICY_STATE(TogglePolicy::Policy::Experiments, PolicyState::NotConfigured);
+ ASSERT_EXPERIMENTS(true, false);
+ }
+
+ SECTION("Enabled")
+ {
+ SET_POLICY_STATE(TogglePolicy::Policy::Experiments, PolicyState::Enabled);
+ ASSERT_EXPERIMENTS(true, false);
+ }
+
+ SECTION("Disabled")
+ {
+ SET_POLICY_STATE(TogglePolicy::Policy::Experiments, PolicyState::Disabled);
+ ASSERT_EXPERIMENTS(false, false);
+ }
+}
+
+TEST_CASE("Experiment_GroupPolicyDisabled_ReturnFalse", "[experiment]")
+{
+ // If the policy is disabled, then also the user settings should be ignored.
+ SET_POLICY_STATE(TogglePolicy::Policy::Experiments, PolicyState::Disabled);
+ SET_USER_SETTINGS(true, true);
+ ASSERT_EXPERIMENTS(false, false);
+}
+
+TEST_CASE("Experiment_UserSettingsControl", "[experiment]")
+{
+ SECTION("Experiments not configured in user settings")
+ {
+ // Default values are used
+ ASSERT_EXPERIMENTS(true, false);
+ }
+
+ SECTION("Experiments enabled in user settings")
+ {
+ SET_USER_SETTINGS(true, true);
+ ASSERT_EXPERIMENTS(true, true);
+ }
+
+ SECTION("Experiments disabled in user settings")
+ {
+ SET_USER_SETTINGS(false, false);
+ ASSERT_EXPERIMENTS(false, false);
+ }
+}
diff --git a/src/AppInstallerCLITests/GroupPolicy.cpp b/src/AppInstallerCLITests/GroupPolicy.cpp
index 907c55969e..1ad1ead717 100644
--- a/src/AppInstallerCLITests/GroupPolicy.cpp
+++ b/src/AppInstallerCLITests/GroupPolicy.cpp
@@ -402,6 +402,7 @@ TEST_CASE("GroupPolicy_AllEnabled", "[groupPolicy]")
SetRegistryValue(policiesKey.get(), EnableWindowsPackageManagerCommandLineInterfaces, 1);
SetRegistryValue(policiesKey.get(), ConfigurationPolicyValueName, 1);
SetRegistryValue(policiesKey.get(), ProxyCommandLineOptionsPolicyValueName, 1);
+ SetRegistryValue(policiesKey.get(), EnableExperimentsPolicyValueName , 1);
GroupPolicy groupPolicy{ policiesKey.get() };
for (const auto& policy : TogglePolicy::GetAllPolicies())
diff --git a/src/AppInstallerCLITests/TestSettings.h b/src/AppInstallerCLITests/TestSettings.h
index 7da1a728ef..f100a9f0b2 100644
--- a/src/AppInstallerCLITests/TestSettings.h
+++ b/src/AppInstallerCLITests/TestSettings.h
@@ -23,6 +23,7 @@ namespace TestCommon
const std::wstring EnableWindowsPackageManagerCommandLineInterfaces = L"EnableWindowsPackageManagerCommandLineInterfaces";
const std::wstring ConfigurationPolicyValueName = L"EnableWindowsPackageManagerConfiguration";
const std::wstring ProxyCommandLineOptionsPolicyValueName = L"EnableWindowsPackageManagerProxyCommandLineOptions";
+ const std::wstring EnableExperimentsPolicyValueName = L"EnableExperiments";
const std::wstring SourceUpdateIntervalPolicyValueName = L"SourceAutoUpdateInterval";
const std::wstring SourceUpdateIntervalPolicyOldValueName = L"SourceAutoUpdateIntervalInMinutes";
@@ -90,4 +91,4 @@ namespace TestCommon
};
#define REQUIRE_POLICY_EXCEPTION(_expr_, _policy_) REQUIRE_THROWS_MATCHES(_expr_, AppInstaller::Settings::GroupPolicyException, TestCommon::GroupPolicyExceptionMatcher(_policy_))
-}
\ No newline at end of file
+}
diff --git a/src/AppInstallerCommonCore/Experiment.cpp b/src/AppInstallerCommonCore/Experiment.cpp
index b934df5216..0ecb71a707 100644
--- a/src/AppInstallerCommonCore/Experiment.cpp
+++ b/src/AppInstallerCommonCore/Experiment.cpp
@@ -52,6 +52,11 @@ namespace AppInstaller::Settings
bool Experiment::IsEnabled(Key key)
{
std::lock_guard lock(m_mutex);
+
+#ifndef AICLI_DISABLE_TEST_HOOKS
+ m_isEnabledCache.clear();
+#endif
+
if (m_isEnabledCache.find(key) == m_isEnabledCache.end())
{
m_isEnabledCache[key] = IsEnabledInternal(key, User());
@@ -66,7 +71,12 @@ namespace AppInstaller::Settings
{
case Key::CDN:
return Experiment{ "CDN experiment", "CDN", "https://aka.ms/winget-settings", "CDN"};
-
+#ifndef AICLI_DISABLE_TEST_HOOKS
+ case Key::TestExperimentDisabledByDefault:
+ return Experiment{ "Test experiment disabled by default", "TestExperimentDisabledByDefault", "https://aka.ms/winget-settings", "TestExperimentDisabledByDefault" };
+ case Key::TestExperimentEnabledByDefault:
+ return Experiment{ "Test experiment enabled by default", "TestExperimentEnabledByDefault", "https://aka.ms/winget-settings", "TestExperimentEnabledByDefault" };
+#endif
default:
THROW_HR(E_UNEXPECTED);
}
diff --git a/src/AppInstallerCommonCore/Public/winget/Experiment.h b/src/AppInstallerCommonCore/Public/winget/Experiment.h
index ea6ac149ea..42c30d8398 100644
--- a/src/AppInstallerCommonCore/Public/winget/Experiment.h
+++ b/src/AppInstallerCommonCore/Public/winget/Experiment.h
@@ -14,6 +14,11 @@ namespace AppInstaller::Settings
None = 0x0,
CDN = 0x1,
Max,
+
+#ifndef AICLI_DISABLE_TEST_HOOKS
+ TestExperimentDisabledByDefault = 0xFFFFFFFE,
+ TestExperimentEnabledByDefault = 0xFFFFFFFF,
+#endif
};
using Key_t = std::underlying_type_t;
diff --git a/src/Internal/Experiment/Experiment.cpp b/src/Internal/Experiment/Experiment.cpp
index b2a3d166df..dc4316c85b 100644
--- a/src/Internal/Experiment/Experiment.cpp
+++ b/src/Internal/Experiment/Experiment.cpp
@@ -5,8 +5,19 @@
namespace AppInstaller::Experiment
{
- bool IsEnabled(const std::string&)
+ bool IsEnabled(const std::string& key)
{
- return true;
+#ifndef AICLI_DISABLE_TEST_HOOKS
+ if (key == "TestExperimentEnabledByDefault")
+ {
+ return true;
+ }
+
+ if (key == "TestExperimentDisabledByDefault")
+ {
+ return false;
+ }
+#endif
+ return false;
}
}