Chromium Code Reviews| Index: chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc |
| diff --git a/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc b/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..df32d22b56c913aa0fa98c210cc5809fb33b69f1 |
| --- /dev/null |
| +++ b/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc |
| @@ -0,0 +1,293 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
|
James Cook
2014/09/11 23:32:31
All the tests in this file are moved unchanged fro
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/common/extensions/features/chrome_channel_feature_filter.h" |
| + |
| +#include <string> |
| + |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/values.h" |
| +#include "chrome/common/chrome_version_info.h" |
| +#include "chrome/common/extensions/features/feature_channel.h" |
| +#include "extensions/common/features/base_feature_provider.h" |
| +#include "extensions/common/features/complex_feature.h" |
| +#include "extensions/common/features/permission_feature.h" |
| +#include "extensions/common/features/simple_feature.h" |
| +#include "extensions/common/value_builder.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +using chrome::VersionInfo; |
| + |
| +namespace extensions { |
| +namespace { |
| + |
| +template <class FeatureClass> |
| +SimpleFeature* CreateFeature() { |
| + SimpleFeature* feature = new FeatureClass(); |
| + feature->AddFilter( |
| + scoped_ptr<SimpleFeatureFilter>(new ChromeChannelFeatureFilter(feature))); |
| + return feature; |
| +} |
| + |
| +Feature::AvailabilityResult IsAvailableInChannel( |
| + const std::string& channel, |
| + VersionInfo::Channel channel_for_testing) { |
| + ScopedCurrentChannel current_channel(channel_for_testing); |
| + |
| + SimpleFeature feature; |
| + feature.AddFilter(scoped_ptr<SimpleFeatureFilter>( |
| + new ChromeChannelFeatureFilter(&feature))); |
| + |
| + base::DictionaryValue feature_value; |
| + feature_value.SetString("channel", channel); |
| + feature.Parse(&feature_value); |
| + |
| + return feature.IsAvailableToManifest("random-extension", |
| + Manifest::TYPE_UNKNOWN, |
| + Manifest::INVALID_LOCATION, |
| + -1, |
| + Feature::GetCurrentPlatform()).result(); |
| +} |
| + |
| +} // namespace |
| + |
| +class ChromeChannelFeatureFilterTest : public testing::Test { |
| + protected: |
| + ChromeChannelFeatureFilterTest() |
| + : current_channel_(VersionInfo::CHANNEL_UNKNOWN) {} |
| + virtual ~ChromeChannelFeatureFilterTest() {} |
| + |
| + private: |
| + ScopedCurrentChannel current_channel_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ChromeChannelFeatureFilterTest); |
| +}; |
| + |
| +// Tests that all combinations of feature channel and Chrome channel correctly |
| +// compute feature availability. |
| +TEST_F(ChromeChannelFeatureFilterTest, SupportedChannel) { |
| + // stable supported. |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("stable", VersionInfo::CHANNEL_UNKNOWN)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("stable", VersionInfo::CHANNEL_CANARY)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("stable", VersionInfo::CHANNEL_DEV)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("stable", VersionInfo::CHANNEL_BETA)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("stable", VersionInfo::CHANNEL_STABLE)); |
| + |
| + // beta supported. |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("beta", VersionInfo::CHANNEL_UNKNOWN)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("beta", VersionInfo::CHANNEL_CANARY)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("beta", VersionInfo::CHANNEL_DEV)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("beta", VersionInfo::CHANNEL_BETA)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("beta", VersionInfo::CHANNEL_STABLE)); |
| + |
| + // dev supported. |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("dev", VersionInfo::CHANNEL_UNKNOWN)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("dev", VersionInfo::CHANNEL_CANARY)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("dev", VersionInfo::CHANNEL_DEV)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("dev", VersionInfo::CHANNEL_BETA)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("dev", VersionInfo::CHANNEL_STABLE)); |
| + |
| + // canary supported. |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("canary", VersionInfo::CHANNEL_UNKNOWN)); |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("canary", VersionInfo::CHANNEL_CANARY)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("canary", VersionInfo::CHANNEL_DEV)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("canary", VersionInfo::CHANNEL_BETA)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("canary", VersionInfo::CHANNEL_STABLE)); |
| + |
| + // trunk supported. |
| + EXPECT_EQ(Feature::IS_AVAILABLE, |
| + IsAvailableInChannel("trunk", VersionInfo::CHANNEL_UNKNOWN)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("trunk", VersionInfo::CHANNEL_CANARY)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("trunk", VersionInfo::CHANNEL_DEV)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("trunk", VersionInfo::CHANNEL_BETA)); |
| + EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| + IsAvailableInChannel("trunk", VersionInfo::CHANNEL_STABLE)); |
| +} |
| + |
| +// Tests the validation of features with channel entries. |
| +TEST_F(ChromeChannelFeatureFilterTest, FeatureValidation) { |
| + scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); |
| + |
| + base::DictionaryValue* feature1 = new base::DictionaryValue(); |
| + feature1->SetString("channel", "trunk"); |
| + value->Set("feature1", feature1); |
| + |
| + base::DictionaryValue* feature2 = new base::DictionaryValue(); |
| + feature2->SetString("channel", "trunk"); |
| + base::ListValue* extension_types = new base::ListValue(); |
| + extension_types->Append(new base::StringValue("extension")); |
| + feature2->Set("extension_types", extension_types); |
| + base::ListValue* contexts = new base::ListValue(); |
| + contexts->Append(new base::StringValue("blessed_extension")); |
| + feature2->Set("contexts", contexts); |
| + value->Set("feature2", feature2); |
| + |
| + scoped_ptr<BaseFeatureProvider> provider( |
| + new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| + |
| + // feature1 won't validate because it lacks an extension type. |
| + EXPECT_FALSE(provider->GetFeature("feature1")); |
| + |
| + // If we add one, it works. |
| + feature1->Set("extension_types", extension_types->DeepCopy()); |
| + provider.reset( |
| + new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| + EXPECT_TRUE(provider->GetFeature("feature1")); |
| + |
| + // Remove the channel, and feature1 won't validate. |
| + feature1->Remove("channel", NULL); |
| + provider.reset( |
| + new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| + EXPECT_FALSE(provider->GetFeature("feature1")); |
| + |
| + // feature2 won't validate because of the presence of "contexts". |
| + EXPECT_FALSE(provider->GetFeature("feature2")); |
| + |
| + // If we remove it, it works. |
| + feature2->Remove("contexts", NULL); |
| + provider.reset( |
| + new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| + EXPECT_TRUE(provider->GetFeature("feature2")); |
| +} |
| + |
| +// Tests simple feature availability across channels. |
| +TEST_F(ChromeChannelFeatureFilterTest, SimpleFeatureAvailability) { |
| + scoped_ptr<base::DictionaryValue> rule( |
| + DictionaryBuilder() |
| + .Set("feature1", |
| + ListBuilder() |
| + .Append(DictionaryBuilder().Set("channel", "beta").Set( |
| + "extension_types", ListBuilder().Append("extension"))) |
| + .Append(DictionaryBuilder().Set("channel", "beta").Set( |
| + "extension_types", |
| + ListBuilder().Append("legacy_packaged_app")))) |
| + .Build()); |
| + |
| + scoped_ptr<BaseFeatureProvider> provider( |
| + new BaseFeatureProvider(*rule, CreateFeature<SimpleFeature>)); |
| + |
| + Feature* feature = provider->GetFeature("feature1"); |
| + EXPECT_TRUE(feature); |
| + |
| + // Make sure both rules are applied correctly. |
| + { |
| + ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA); |
| + EXPECT_EQ( |
| + Feature::IS_AVAILABLE, |
| + feature->IsAvailableToManifest("1", |
| + Manifest::TYPE_EXTENSION, |
| + Manifest::INVALID_LOCATION, |
| + Feature::UNSPECIFIED_PLATFORM).result()); |
| + EXPECT_EQ( |
| + Feature::IS_AVAILABLE, |
| + feature->IsAvailableToManifest("2", |
| + Manifest::TYPE_LEGACY_PACKAGED_APP, |
| + Manifest::INVALID_LOCATION, |
| + Feature::UNSPECIFIED_PLATFORM).result()); |
| + } |
| + { |
| + ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_STABLE); |
| + EXPECT_NE( |
| + Feature::IS_AVAILABLE, |
| + feature->IsAvailableToManifest("1", |
| + Manifest::TYPE_EXTENSION, |
| + Manifest::INVALID_LOCATION, |
| + Feature::UNSPECIFIED_PLATFORM).result()); |
| + EXPECT_NE( |
| + Feature::IS_AVAILABLE, |
| + feature->IsAvailableToManifest("2", |
| + Manifest::TYPE_LEGACY_PACKAGED_APP, |
| + Manifest::INVALID_LOCATION, |
| + Feature::UNSPECIFIED_PLATFORM).result()); |
| + } |
| +} |
| + |
| +// Tests complex feature availability across channels. |
| +TEST_F(ChromeChannelFeatureFilterTest, ComplexFeatureAvailability) { |
| + scoped_ptr<ComplexFeature::FeatureList> features( |
| + new ComplexFeature::FeatureList()); |
| + |
| + // Rule: "extension", channel trunk. |
| + scoped_ptr<SimpleFeature> simple_feature(CreateFeature<SimpleFeature>()); |
| + scoped_ptr<base::DictionaryValue> rule( |
| + DictionaryBuilder() |
| + .Set("channel", "trunk") |
| + .Set("extension_types", ListBuilder().Append("extension")) |
| + .Build()); |
| + simple_feature->Parse(rule.get()); |
| + features->push_back(simple_feature.release()); |
| + |
| + // Rule: "legacy_packaged_app", channel stable. |
| + simple_feature.reset(CreateFeature<SimpleFeature>()); |
| + rule = |
| + DictionaryBuilder() |
| + .Set("channel", "stable") |
| + .Set("extension_types", ListBuilder().Append("legacy_packaged_app")) |
| + .Build(); |
| + simple_feature->Parse(rule.get()); |
| + features->push_back(simple_feature.release()); |
| + |
| + scoped_ptr<ComplexFeature> feature(new ComplexFeature(features.Pass())); |
| + |
| + // Test match 1st rule. |
| + { |
| + ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_UNKNOWN); |
| + EXPECT_EQ( |
| + Feature::IS_AVAILABLE, |
| + feature->IsAvailableToManifest("1", |
| + Manifest::TYPE_EXTENSION, |
| + Manifest::INVALID_LOCATION, |
| + Feature::UNSPECIFIED_PLATFORM, |
| + Feature::GetCurrentPlatform()).result()); |
| + } |
| + |
| + // Test match 2nd rule. |
| + { |
| + ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA); |
| + EXPECT_EQ( |
| + Feature::IS_AVAILABLE, |
| + feature->IsAvailableToManifest("2", |
| + Manifest::TYPE_LEGACY_PACKAGED_APP, |
| + Manifest::INVALID_LOCATION, |
| + Feature::UNSPECIFIED_PLATFORM, |
| + Feature::GetCurrentPlatform()).result()); |
| + } |
| + |
| + // Test feature not available to extensions above channel unknown. |
| + { |
| + ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA); |
| + EXPECT_NE( |
| + Feature::IS_AVAILABLE, |
| + feature->IsAvailableToManifest("1", |
| + Manifest::TYPE_EXTENSION, |
| + Manifest::INVALID_LOCATION, |
| + Feature::UNSPECIFIED_PLATFORM, |
| + Feature::GetCurrentPlatform()).result()); |
| + } |
| +} |
| + |
| +} // namespace extensions |