Home | History | Annotate | Download | only in features
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "extensions/common/features/complex_feature.h"
      6 
      7 #include "chrome/common/extensions/features/chrome_channel_feature_filter.h"
      8 #include "chrome/common/extensions/features/feature_channel.h"
      9 #include "extensions/common/features/api_feature.h"
     10 #include "extensions/common/features/simple_feature.h"
     11 #include "extensions/common/test_util.h"
     12 #include "extensions/common/value_builder.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 using chrome::VersionInfo;
     16 using extensions::APIFeature;
     17 using extensions::ComplexFeature;
     18 using extensions::DictionaryBuilder;
     19 using extensions::Feature;
     20 using extensions::ListBuilder;
     21 using extensions::Manifest;
     22 using extensions::ScopedCurrentChannel;
     23 using extensions::SimpleFeature;
     24 using extensions::test_util::ParseJsonDictionaryWithSingleQuotes;
     25 
     26 namespace {
     27 
     28 class ExtensionComplexFeatureTest : public testing::Test {
     29  protected:
     30   ExtensionComplexFeatureTest()
     31       : current_channel_(VersionInfo::CHANNEL_UNKNOWN) {}
     32   virtual ~ExtensionComplexFeatureTest() {}
     33 
     34   SimpleFeature* CreateFeature() {
     35     SimpleFeature* feature = new SimpleFeature();
     36     feature->AddFilter(scoped_ptr<extensions::SimpleFeatureFilter>(
     37         new extensions::ChromeChannelFeatureFilter(feature)));
     38     return feature;
     39   }
     40 
     41  private:
     42   ScopedCurrentChannel current_channel_;
     43 };
     44 
     45 TEST_F(ExtensionComplexFeatureTest, MultipleRulesWhitelist) {
     46   const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh");
     47   const std::string kIdBar("barabbbbccccddddeeeeffffgggghhhh");
     48   scoped_ptr<ComplexFeature::FeatureList> features(
     49       new ComplexFeature::FeatureList());
     50 
     51   // Rule: "extension", whitelist "foo".
     52   scoped_ptr<SimpleFeature> simple_feature(CreateFeature());
     53   scoped_ptr<base::DictionaryValue> rule(
     54       DictionaryBuilder()
     55       .Set("whitelist", ListBuilder().Append(kIdFoo))
     56       .Set("extension_types", ListBuilder()
     57           .Append("extension")).Build());
     58   simple_feature->Parse(rule.get());
     59   features->push_back(simple_feature.release());
     60 
     61   // Rule: "legacy_packaged_app", whitelist "bar".
     62   simple_feature.reset(CreateFeature());
     63   rule = DictionaryBuilder()
     64       .Set("whitelist", ListBuilder().Append(kIdBar))
     65       .Set("extension_types", ListBuilder()
     66           .Append("legacy_packaged_app")).Build();
     67   simple_feature->Parse(rule.get());
     68   features->push_back(simple_feature.release());
     69 
     70   scoped_ptr<ComplexFeature> feature(new ComplexFeature(features.Pass()));
     71 
     72   // Test match 1st rule.
     73   EXPECT_EQ(
     74       Feature::IS_AVAILABLE,
     75       feature->IsAvailableToManifest(kIdFoo,
     76                                      Manifest::TYPE_EXTENSION,
     77                                      Manifest::INVALID_LOCATION,
     78                                      Feature::UNSPECIFIED_PLATFORM,
     79                                      Feature::GetCurrentPlatform()).result());
     80 
     81   // Test match 2nd rule.
     82   EXPECT_EQ(
     83       Feature::IS_AVAILABLE,
     84       feature->IsAvailableToManifest(kIdBar,
     85                                      Manifest::TYPE_LEGACY_PACKAGED_APP,
     86                                      Manifest::INVALID_LOCATION,
     87                                      Feature::UNSPECIFIED_PLATFORM,
     88                                      Feature::GetCurrentPlatform()).result());
     89 
     90   // Test whitelist with wrong extension type.
     91   EXPECT_NE(
     92       Feature::IS_AVAILABLE,
     93       feature->IsAvailableToManifest(kIdBar,
     94                                      Manifest::TYPE_EXTENSION,
     95                                      Manifest::INVALID_LOCATION,
     96                                      Feature::UNSPECIFIED_PLATFORM,
     97                                      Feature::GetCurrentPlatform()).result());
     98   EXPECT_NE(
     99       Feature::IS_AVAILABLE,
    100       feature->IsAvailableToManifest(kIdFoo,
    101                                      Manifest::TYPE_LEGACY_PACKAGED_APP,
    102                                      Manifest::INVALID_LOCATION,
    103                                      Feature::UNSPECIFIED_PLATFORM,
    104                                      Feature::GetCurrentPlatform()).result());
    105 }
    106 
    107 TEST_F(ExtensionComplexFeatureTest, MultipleRulesChannels) {
    108   scoped_ptr<ComplexFeature::FeatureList> features(
    109       new ComplexFeature::FeatureList());
    110 
    111   // Rule: "extension", channel trunk.
    112   scoped_ptr<SimpleFeature> simple_feature(CreateFeature());
    113   scoped_ptr<base::DictionaryValue> rule(
    114       DictionaryBuilder()
    115       .Set("channel", "trunk")
    116       .Set("extension_types", ListBuilder().Append("extension")).Build());
    117   simple_feature->Parse(rule.get());
    118   features->push_back(simple_feature.release());
    119 
    120   // Rule: "legacy_packaged_app", channel stable.
    121   simple_feature.reset(CreateFeature());
    122   rule = DictionaryBuilder()
    123       .Set("channel", "stable")
    124       .Set("extension_types", ListBuilder()
    125           .Append("legacy_packaged_app")).Build();
    126   simple_feature->Parse(rule.get());
    127   features->push_back(simple_feature.release());
    128 
    129   scoped_ptr<ComplexFeature> feature(new ComplexFeature(features.Pass()));
    130 
    131   // Test match 1st rule.
    132   {
    133     ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_UNKNOWN);
    134     EXPECT_EQ(
    135         Feature::IS_AVAILABLE,
    136         feature->IsAvailableToManifest("1",
    137                                        Manifest::TYPE_EXTENSION,
    138                                        Manifest::INVALID_LOCATION,
    139                                        Feature::UNSPECIFIED_PLATFORM,
    140                                        Feature::GetCurrentPlatform()).result());
    141   }
    142 
    143   // Test match 2nd rule.
    144   {
    145     ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA);
    146     EXPECT_EQ(
    147         Feature::IS_AVAILABLE,
    148         feature->IsAvailableToManifest("2",
    149                                        Manifest::TYPE_LEGACY_PACKAGED_APP,
    150                                        Manifest::INVALID_LOCATION,
    151                                        Feature::UNSPECIFIED_PLATFORM,
    152                                        Feature::GetCurrentPlatform()).result());
    153   }
    154 
    155   // Test feature not available to extensions above channel unknown.
    156   {
    157     ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA);
    158     EXPECT_NE(
    159         Feature::IS_AVAILABLE,
    160         feature->IsAvailableToManifest("1",
    161                                        Manifest::TYPE_EXTENSION,
    162                                        Manifest::INVALID_LOCATION,
    163                                        Feature::UNSPECIFIED_PLATFORM,
    164                                        Feature::GetCurrentPlatform()).result());
    165   }
    166 }
    167 
    168 // Tests a complex feature with blocked_in_service_worker returns true for
    169 // IsBlockedInServiceWorker().
    170 TEST_F(ExtensionComplexFeatureTest, BlockedInServiceWorker) {
    171   scoped_ptr<ComplexFeature::FeatureList> features(
    172       new ComplexFeature::FeatureList());
    173 
    174   // Two feature rules, both with blocked_in_service_worker: true.
    175   scoped_ptr<SimpleFeature> api_feature(new APIFeature());
    176   api_feature->Parse(ParseJsonDictionaryWithSingleQuotes(
    177                          "{"
    178                          "  'channel': 'trunk',"
    179                          "  'blocked_in_service_worker': true"
    180                          "}").get());
    181   features->push_back(api_feature.release());
    182 
    183   api_feature.reset(new APIFeature());
    184   api_feature->Parse(ParseJsonDictionaryWithSingleQuotes(
    185                          "{"
    186                          "  'channel': 'stable',"
    187                          "  'blocked_in_service_worker': true"
    188                          "}").get());
    189   features->push_back(api_feature.release());
    190 
    191   EXPECT_TRUE(ComplexFeature(features.Pass()).IsBlockedInServiceWorker());
    192 }
    193 
    194 // Tests a complex feature without blocked_in_service_worker returns false for
    195 // IsBlockedInServiceWorker().
    196 TEST_F(ExtensionComplexFeatureTest, NotBlockedInServiceWorker) {
    197   scoped_ptr<ComplexFeature::FeatureList> features(
    198       new ComplexFeature::FeatureList());
    199 
    200   // Two feature rules without blocked_in_service_worker.
    201   scoped_ptr<SimpleFeature> api_feature(new APIFeature());
    202   api_feature->Parse(ParseJsonDictionaryWithSingleQuotes(
    203                          "{"
    204                          "  'channel': 'trunk'"
    205                          "}").get());
    206   features->push_back(api_feature.release());
    207 
    208   api_feature.reset(new APIFeature());
    209   api_feature->Parse(ParseJsonDictionaryWithSingleQuotes(
    210                          "{"
    211                          "  'channel': 'stable'"
    212                          "}").get());
    213   features->push_back(api_feature.release());
    214 
    215   EXPECT_FALSE(ComplexFeature(features.Pass()).IsBlockedInServiceWorker());
    216 }
    217 
    218 }  // namespace
    219