OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/common/features/simple_feature.h" | 5 #include "extensions/common/features/simple_feature.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 | 10 |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
14 #include "base/test/scoped_command_line.h" | 14 #include "base/test/scoped_command_line.h" |
15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "extensions/common/features/base_feature_provider.h" |
| 17 #include "extensions/common/features/complex_feature.h" |
| 18 #include "extensions/common/features/feature_channel.h" |
| 19 #include "extensions/common/features/permission_feature.h" |
16 #include "extensions/common/manifest.h" | 20 #include "extensions/common/manifest.h" |
17 #include "extensions/common/value_builder.h" | 21 #include "extensions/common/value_builder.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
19 | 23 |
20 namespace extensions { | 24 namespace extensions { |
21 | 25 |
22 namespace { | 26 namespace { |
23 | 27 |
24 struct IsAvailableTestData { | 28 struct IsAvailableTestData { |
25 std::string extension_id; | 29 std::string extension_id; |
26 Manifest::Type extension_type; | 30 Manifest::Type extension_type; |
27 Manifest::Location location; | 31 Manifest::Location location; |
28 Feature::Platform platform; | 32 Feature::Platform platform; |
29 int manifest_version; | 33 int manifest_version; |
30 Feature::AvailabilityResult expected_result; | 34 Feature::AvailabilityResult expected_result; |
31 }; | 35 }; |
32 | 36 |
| 37 template <class FeatureClass> |
| 38 SimpleFeature* CreateFeature() { |
| 39 SimpleFeature* feature = new FeatureClass(); |
| 40 return feature; |
| 41 } |
| 42 |
| 43 Feature::AvailabilityResult IsAvailableInChannel( |
| 44 const std::string& channel, |
| 45 version_info::Channel channel_for_testing) { |
| 46 ScopedCurrentChannel current_channel(channel_for_testing); |
| 47 |
| 48 SimpleFeature feature; |
| 49 |
| 50 base::DictionaryValue feature_value; |
| 51 feature_value.SetString("channel", channel); |
| 52 feature.Parse(&feature_value); |
| 53 |
| 54 return feature |
| 55 .IsAvailableToManifest("random-extension", Manifest::TYPE_UNKNOWN, |
| 56 Manifest::INVALID_LOCATION, -1, |
| 57 Feature::GetCurrentPlatform()) |
| 58 .result(); |
| 59 } |
| 60 |
33 } // namespace | 61 } // namespace |
34 | 62 |
35 class SimpleFeatureTest : public testing::Test { | 63 class SimpleFeatureTest : public testing::Test { |
36 protected: | 64 protected: |
| 65 SimpleFeatureTest() : current_channel_(version_info::Channel::UNKNOWN) {} |
37 bool LocationIsAvailable(SimpleFeature::Location feature_location, | 66 bool LocationIsAvailable(SimpleFeature::Location feature_location, |
38 Manifest::Location manifest_location) { | 67 Manifest::Location manifest_location) { |
39 SimpleFeature feature; | 68 SimpleFeature feature; |
40 feature.set_location(feature_location); | 69 feature.set_location(feature_location); |
41 Feature::AvailabilityResult availability_result = | 70 Feature::AvailabilityResult availability_result = |
42 feature.IsAvailableToManifest(std::string(), | 71 feature.IsAvailableToManifest(std::string(), |
43 Manifest::TYPE_UNKNOWN, | 72 Manifest::TYPE_UNKNOWN, |
44 manifest_location, | 73 manifest_location, |
45 -1, | 74 -1, |
46 Feature::UNSPECIFIED_PLATFORM).result(); | 75 Feature::UNSPECIFIED_PLATFORM).result(); |
47 return availability_result == Feature::IS_AVAILABLE; | 76 return availability_result == Feature::IS_AVAILABLE; |
48 } | 77 } |
| 78 |
| 79 private: |
| 80 ScopedCurrentChannel current_channel_; |
| 81 DISALLOW_COPY_AND_ASSIGN(SimpleFeatureTest); |
49 }; | 82 }; |
50 | 83 |
51 TEST_F(SimpleFeatureTest, IsAvailableNullCase) { | 84 TEST_F(SimpleFeatureTest, IsAvailableNullCase) { |
52 const IsAvailableTestData tests[] = { | 85 const IsAvailableTestData tests[] = { |
53 {"", Manifest::TYPE_UNKNOWN, Manifest::INVALID_LOCATION, | 86 {"", Manifest::TYPE_UNKNOWN, Manifest::INVALID_LOCATION, |
54 Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE}, | 87 Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE}, |
55 {"random-extension", Manifest::TYPE_UNKNOWN, Manifest::INVALID_LOCATION, | 88 {"random-extension", Manifest::TYPE_UNKNOWN, Manifest::INVALID_LOCATION, |
56 Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE}, | 89 Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE}, |
57 {"", Manifest::TYPE_LEGACY_PACKAGED_APP, Manifest::INVALID_LOCATION, | 90 {"", Manifest::TYPE_LEGACY_PACKAGED_APP, Manifest::INVALID_LOCATION, |
58 Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE}, | 91 Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE}, |
(...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 }; | 769 }; |
737 EXPECT_FALSE(SimpleFeature::IsIdInArray("", kIdArray, arraysize(kIdArray))); | 770 EXPECT_FALSE(SimpleFeature::IsIdInArray("", kIdArray, arraysize(kIdArray))); |
738 EXPECT_FALSE(SimpleFeature::IsIdInArray( | 771 EXPECT_FALSE(SimpleFeature::IsIdInArray( |
739 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", kIdArray, arraysize(kIdArray))); | 772 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", kIdArray, arraysize(kIdArray))); |
740 EXPECT_TRUE(SimpleFeature::IsIdInArray( | 773 EXPECT_TRUE(SimpleFeature::IsIdInArray( |
741 "bbbbccccdddddddddeeeeeeffffgghhh", kIdArray, arraysize(kIdArray))); | 774 "bbbbccccdddddddddeeeeeeffffgghhh", kIdArray, arraysize(kIdArray))); |
742 EXPECT_TRUE(SimpleFeature::IsIdInArray( | 775 EXPECT_TRUE(SimpleFeature::IsIdInArray( |
743 "aaaabbbbccccddddeeeeffffgggghhhh", kIdArray, arraysize(kIdArray))); | 776 "aaaabbbbccccddddeeeeffffgggghhhh", kIdArray, arraysize(kIdArray))); |
744 } | 777 } |
745 | 778 |
| 779 // Tests that all combinations of feature channel and Chrome channel correctly |
| 780 // compute feature availability. |
| 781 TEST_F(SimpleFeatureTest, SupportedChannel) { |
| 782 // stable supported. |
| 783 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 784 IsAvailableInChannel("stable", version_info::Channel::UNKNOWN)); |
| 785 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 786 IsAvailableInChannel("stable", version_info::Channel::CANARY)); |
| 787 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 788 IsAvailableInChannel("stable", version_info::Channel::DEV)); |
| 789 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 790 IsAvailableInChannel("stable", version_info::Channel::BETA)); |
| 791 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 792 IsAvailableInChannel("stable", version_info::Channel::STABLE)); |
| 793 |
| 794 // beta supported. |
| 795 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 796 IsAvailableInChannel("beta", version_info::Channel::UNKNOWN)); |
| 797 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 798 IsAvailableInChannel("beta", version_info::Channel::CANARY)); |
| 799 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 800 IsAvailableInChannel("beta", version_info::Channel::DEV)); |
| 801 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 802 IsAvailableInChannel("beta", version_info::Channel::BETA)); |
| 803 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 804 IsAvailableInChannel("beta", version_info::Channel::STABLE)); |
| 805 |
| 806 // dev supported. |
| 807 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 808 IsAvailableInChannel("dev", version_info::Channel::UNKNOWN)); |
| 809 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 810 IsAvailableInChannel("dev", version_info::Channel::CANARY)); |
| 811 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 812 IsAvailableInChannel("dev", version_info::Channel::DEV)); |
| 813 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 814 IsAvailableInChannel("dev", version_info::Channel::BETA)); |
| 815 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 816 IsAvailableInChannel("dev", version_info::Channel::STABLE)); |
| 817 |
| 818 // canary supported. |
| 819 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 820 IsAvailableInChannel("canary", version_info::Channel::UNKNOWN)); |
| 821 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 822 IsAvailableInChannel("canary", version_info::Channel::CANARY)); |
| 823 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 824 IsAvailableInChannel("canary", version_info::Channel::DEV)); |
| 825 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 826 IsAvailableInChannel("canary", version_info::Channel::BETA)); |
| 827 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 828 IsAvailableInChannel("canary", version_info::Channel::STABLE)); |
| 829 |
| 830 // trunk supported. |
| 831 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 832 IsAvailableInChannel("trunk", version_info::Channel::UNKNOWN)); |
| 833 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 834 IsAvailableInChannel("trunk", version_info::Channel::CANARY)); |
| 835 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 836 IsAvailableInChannel("trunk", version_info::Channel::DEV)); |
| 837 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 838 IsAvailableInChannel("trunk", version_info::Channel::BETA)); |
| 839 EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL, |
| 840 IsAvailableInChannel("trunk", version_info::Channel::STABLE)); |
| 841 } |
| 842 |
| 843 // Tests the validation of features with channel entries. |
| 844 TEST_F(SimpleFeatureTest, FeatureValidation) { |
| 845 std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue()); |
| 846 |
| 847 base::DictionaryValue* feature1 = new base::DictionaryValue(); |
| 848 feature1->SetString("channel", "trunk"); |
| 849 value->Set("feature1", feature1); |
| 850 |
| 851 base::DictionaryValue* feature2 = new base::DictionaryValue(); |
| 852 feature2->SetString("channel", "trunk"); |
| 853 base::ListValue* extension_types = new base::ListValue(); |
| 854 extension_types->AppendString("extension"); |
| 855 feature2->Set("extension_types", extension_types); |
| 856 base::ListValue* contexts = new base::ListValue(); |
| 857 contexts->AppendString("blessed_extension"); |
| 858 feature2->Set("contexts", contexts); |
| 859 value->Set("feature2", feature2); |
| 860 |
| 861 std::unique_ptr<BaseFeatureProvider> provider( |
| 862 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| 863 |
| 864 // feature1 won't validate because it lacks an extension type. |
| 865 EXPECT_FALSE(provider->GetFeature("feature1")); |
| 866 |
| 867 // If we add one, it works. |
| 868 feature1->Set("extension_types", extension_types->DeepCopy()); |
| 869 provider.reset( |
| 870 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| 871 EXPECT_TRUE(provider->GetFeature("feature1")); |
| 872 |
| 873 // Remove the channel, and feature1 won't validate. |
| 874 feature1->Remove("channel", NULL); |
| 875 provider.reset( |
| 876 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| 877 EXPECT_FALSE(provider->GetFeature("feature1")); |
| 878 |
| 879 // feature2 won't validate because of the presence of "contexts". |
| 880 EXPECT_FALSE(provider->GetFeature("feature2")); |
| 881 |
| 882 // If we remove it, it works. |
| 883 feature2->Remove("contexts", NULL); |
| 884 provider.reset( |
| 885 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); |
| 886 EXPECT_TRUE(provider->GetFeature("feature2")); |
| 887 } |
| 888 |
| 889 // Tests simple feature availability across channels. |
| 890 TEST_F(SimpleFeatureTest, SimpleFeatureAvailability) { |
| 891 std::unique_ptr<base::DictionaryValue> rule( |
| 892 DictionaryBuilder() |
| 893 .Set("feature1", |
| 894 ListBuilder() |
| 895 .Append(DictionaryBuilder() |
| 896 .Set("channel", "beta") |
| 897 .Set("extension_types", |
| 898 ListBuilder().Append("extension").Build()) |
| 899 .Build()) |
| 900 .Append(DictionaryBuilder() |
| 901 .Set("channel", "beta") |
| 902 .Set("extension_types", |
| 903 ListBuilder() |
| 904 .Append("legacy_packaged_app") |
| 905 .Build()) |
| 906 .Build()) |
| 907 .Build()) |
| 908 .Build()); |
| 909 |
| 910 std::unique_ptr<BaseFeatureProvider> provider( |
| 911 new BaseFeatureProvider(*rule, CreateFeature<SimpleFeature>)); |
| 912 |
| 913 Feature* feature = provider->GetFeature("feature1"); |
| 914 EXPECT_TRUE(feature); |
| 915 |
| 916 // Make sure both rules are applied correctly. |
| 917 { |
| 918 ScopedCurrentChannel current_channel(version_info::Channel::BETA); |
| 919 EXPECT_EQ( |
| 920 Feature::IS_AVAILABLE, |
| 921 feature->IsAvailableToManifest("1", |
| 922 Manifest::TYPE_EXTENSION, |
| 923 Manifest::INVALID_LOCATION, |
| 924 Feature::UNSPECIFIED_PLATFORM).result()); |
| 925 EXPECT_EQ( |
| 926 Feature::IS_AVAILABLE, |
| 927 feature->IsAvailableToManifest("2", |
| 928 Manifest::TYPE_LEGACY_PACKAGED_APP, |
| 929 Manifest::INVALID_LOCATION, |
| 930 Feature::UNSPECIFIED_PLATFORM).result()); |
| 931 } |
| 932 { |
| 933 ScopedCurrentChannel current_channel(version_info::Channel::STABLE); |
| 934 EXPECT_NE( |
| 935 Feature::IS_AVAILABLE, |
| 936 feature->IsAvailableToManifest("1", |
| 937 Manifest::TYPE_EXTENSION, |
| 938 Manifest::INVALID_LOCATION, |
| 939 Feature::UNSPECIFIED_PLATFORM).result()); |
| 940 EXPECT_NE( |
| 941 Feature::IS_AVAILABLE, |
| 942 feature->IsAvailableToManifest("2", |
| 943 Manifest::TYPE_LEGACY_PACKAGED_APP, |
| 944 Manifest::INVALID_LOCATION, |
| 945 Feature::UNSPECIFIED_PLATFORM).result()); |
| 946 } |
| 947 } |
| 948 |
| 949 // Tests complex feature availability across channels. |
| 950 TEST_F(SimpleFeatureTest, ComplexFeatureAvailability) { |
| 951 std::unique_ptr<ComplexFeature::FeatureList> features( |
| 952 new ComplexFeature::FeatureList()); |
| 953 |
| 954 // Rule: "extension", channel trunk. |
| 955 std::unique_ptr<SimpleFeature> simple_feature(CreateFeature<SimpleFeature>()); |
| 956 std::unique_ptr<base::DictionaryValue> rule( |
| 957 DictionaryBuilder() |
| 958 .Set("channel", "trunk") |
| 959 .Set("extension_types", ListBuilder().Append("extension").Build()) |
| 960 .Build()); |
| 961 simple_feature->Parse(rule.get()); |
| 962 features->push_back(std::move(simple_feature)); |
| 963 |
| 964 // Rule: "legacy_packaged_app", channel stable. |
| 965 simple_feature.reset(CreateFeature<SimpleFeature>()); |
| 966 rule = DictionaryBuilder() |
| 967 .Set("channel", "stable") |
| 968 .Set("extension_types", |
| 969 ListBuilder().Append("legacy_packaged_app").Build()) |
| 970 .Build(); |
| 971 simple_feature->Parse(rule.get()); |
| 972 features->push_back(std::move(simple_feature)); |
| 973 |
| 974 std::unique_ptr<ComplexFeature> feature( |
| 975 new ComplexFeature(std::move(features))); |
| 976 |
| 977 // Test match 1st rule. |
| 978 { |
| 979 ScopedCurrentChannel current_channel(version_info::Channel::UNKNOWN); |
| 980 EXPECT_EQ( |
| 981 Feature::IS_AVAILABLE, |
| 982 feature->IsAvailableToManifest("1", |
| 983 Manifest::TYPE_EXTENSION, |
| 984 Manifest::INVALID_LOCATION, |
| 985 Feature::UNSPECIFIED_PLATFORM, |
| 986 Feature::GetCurrentPlatform()).result()); |
| 987 } |
| 988 |
| 989 // Test match 2nd rule. |
| 990 { |
| 991 ScopedCurrentChannel current_channel(version_info::Channel::BETA); |
| 992 EXPECT_EQ( |
| 993 Feature::IS_AVAILABLE, |
| 994 feature->IsAvailableToManifest("2", |
| 995 Manifest::TYPE_LEGACY_PACKAGED_APP, |
| 996 Manifest::INVALID_LOCATION, |
| 997 Feature::UNSPECIFIED_PLATFORM, |
| 998 Feature::GetCurrentPlatform()).result()); |
| 999 } |
| 1000 |
| 1001 // Test feature not available to extensions above channel unknown. |
| 1002 { |
| 1003 ScopedCurrentChannel current_channel(version_info::Channel::BETA); |
| 1004 EXPECT_NE( |
| 1005 Feature::IS_AVAILABLE, |
| 1006 feature->IsAvailableToManifest("1", |
| 1007 Manifest::TYPE_EXTENSION, |
| 1008 Manifest::INVALID_LOCATION, |
| 1009 Feature::UNSPECIFIED_PLATFORM, |
| 1010 Feature::GetCurrentPlatform()).result()); |
| 1011 } |
| 1012 } |
| 1013 |
746 } // namespace extensions | 1014 } // namespace extensions |
OLD | NEW |