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