Commit 64bf38de authored by tbarzic's avatar tbarzic Committed by Commit bot

Introduce session type parameter to extension features

This adds session type to extension features grammar. The session
type refers to the type of user active in the session in which
an extension is running. The parameter will enable making a feature
available depending on type of the session in which the extension/app
is running.

Feature session types are declared as list of individual session types
in which a feature is available (undefined list means no restrictions).
Currently, values supported for session type are as follows:
* 'kiosk' - kiosk app session
* 'regular' -  non-kiosk user session
The list of supported values is expected to be expanded in future.

Depends on https://codereview.chromium.org/2241203003/ for plumbing
of current session type to feature availability checks

BUG=606417

Review-Url: https://codereview.chromium.org/2255613003
Cr-Commit-Position: refs/heads/master@{#418938}
parent e292bdc2
...@@ -253,6 +253,18 @@ available on. ...@@ -253,6 +253,18 @@ available on.
The accepted values are lists of strings from `chromeos`, `mac`, `linux`, and The accepted values are lists of strings from `chromeos`, `mac`, `linux`, and
`win`. `win`.
### session\_types
The `session_types` property specifies in which types of sessions a feature
should be available. The session type describes the type of user that is
logged in the current session. Session types to which feature can be restricted
are only supported on Chrome OS - features restricted to set of session types
will be disabled on other platforms. Also, note that all currently supported
session types imply that a user is logged into the session (i.e. features that
use 'session_types' property will be disabled when a user is not logged in).
The accepted values are lists of strings from `regular` and `kiosk`.
### whitelist ### whitelist
The `whitelist` property specifies a list of ID hashes for extensions that The `whitelist` property specifies a list of ID hashes for extensions that
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "chrome/common/extensions/extension_features_unittest.h" #include "chrome/common/extensions/extension_features_unittest.h"
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h" #include "extensions/common/extension_builder.h"
#include "extensions/common/features/feature_session_type.h"
#include "extensions/common/features/simple_feature.h" #include "extensions/common/features/simple_feature.h"
#include "extensions/common/manifest.h" #include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_constants.h"
...@@ -38,6 +39,15 @@ const char* const kTestFeatures[] = { ...@@ -38,6 +39,15 @@ const char* const kTestFeatures[] = {
"test6", "test7", "parent1", "parent2", "parent3", "test6", "test7", "parent1", "parent2", "parent3",
}; };
const char* const kSessionTypeTestFeatures[] = {
"test1", "kiosk_only", "non_kiosk", "multiple_session_types"};
struct FeatureSessionTypesTestData {
std::string api_name;
bool expect_available;
FeatureSessionType current_session_type;
};
class TestExtensionAPI : public ExtensionAPI { class TestExtensionAPI : public ExtensionAPI {
public: public:
TestExtensionAPI() {} TestExtensionAPI() {}
...@@ -281,6 +291,41 @@ TEST(ExtensionAPITest, IsAnyFeatureAvailableToContext) { ...@@ -281,6 +291,41 @@ TEST(ExtensionAPITest, IsAnyFeatureAvailableToContext) {
} }
} }
TEST(ExtensionAPITest, SessionTypeFeature) {
const std::vector<FeatureSessionTypesTestData> kTestData(
{{"kiosk_only", true, FeatureSessionType::KIOSK},
{"kiosk_only", false, FeatureSessionType::REGULAR},
{"kiosk_only", false, FeatureSessionType::UNKNOWN},
{"non_kiosk", false, FeatureSessionType::KIOSK},
{"non_kiosk", true, FeatureSessionType::REGULAR},
{"non_kiosk", false, FeatureSessionType::UNKNOWN},
{"multiple_session_types", true, FeatureSessionType::KIOSK},
{"multiple_session_types", true, FeatureSessionType::REGULAR},
{"multiple_session_types", false, FeatureSessionType::UNKNOWN},
{"test1", true, FeatureSessionType::KIOSK},
{"test1", true, FeatureSessionType::REGULAR},
{"test1", true, FeatureSessionType::UNKNOWN}});
UnittestFeatureProvider api_feature_provider;
for (const auto& test : kTestData) {
TestExtensionAPI api;
api.RegisterDependencyProvider("api", &api_feature_provider);
for (const auto& key : kSessionTypeTestFeatures)
api.add_fake_schema(key);
ExtensionAPI::OverrideSharedInstanceForTest scope(&api);
std::unique_ptr<base::AutoReset<FeatureSessionType>> current_session(
ScopedCurrentFeatureSessionType(test.current_session_type));
EXPECT_EQ(test.expect_available,
api.IsAvailable(test.api_name, nullptr,
Feature::BLESSED_EXTENSION_CONTEXT, GURL())
.is_available())
<< "Test case (" << test.api_name << ", "
<< static_cast<int>(test.current_session_type) << ").";
}
}
TEST(ExtensionAPITest, LazyGetSchema) { TEST(ExtensionAPITest, LazyGetSchema) {
std::unique_ptr<ExtensionAPI> apis( std::unique_ptr<ExtensionAPI> apis(
ExtensionAPI::CreateWithDefaultConfiguration()); ExtensionAPI::CreateWithDefaultConfiguration());
......
...@@ -91,5 +91,20 @@ ...@@ -91,5 +91,20 @@
"contexts": ["content_script", "blessed_extension", "unblessed_extension"] "contexts": ["content_script", "blessed_extension", "unblessed_extension"]
}, },
"parent3.noparent.child": { "parent3.noparent.child": {
},
"kiosk_only": {
"channel": "stable",
"contexts": ["content_script", "blessed_extension", "unblessed_extension"],
"session_types": ["kiosk"]
},
"non_kiosk": {
"channel": "stable",
"contexts": ["content_script", "blessed_extension", "unblessed_extension"],
"session_types": ["regular"]
},
"multiple_session_types": {
"channel": "stable",
"contexts": ["content_script", "blessed_extension", "unblessed_extension"],
"session_types": ["kiosk", "regular"]
} }
} }
...@@ -61,6 +61,7 @@ class Feature { ...@@ -61,6 +61,7 @@ class Feature {
INVALID_PLATFORM, INVALID_PLATFORM,
INVALID_MIN_MANIFEST_VERSION, INVALID_MIN_MANIFEST_VERSION,
INVALID_MAX_MANIFEST_VERSION, INVALID_MAX_MANIFEST_VERSION,
INVALID_SESSION_TYPE,
NOT_PRESENT, NOT_PRESENT,
UNSUPPORTED_CHANNEL, UNSUPPORTED_CHANNEL,
FOUND_IN_BLACKLIST, FOUND_IN_BLACKLIST,
......
...@@ -126,6 +126,20 @@ std::string GetDisplayName(version_info::Channel channel) { ...@@ -126,6 +126,20 @@ std::string GetDisplayName(version_info::Channel channel) {
return ""; return "";
} }
std::string GetDisplayName(FeatureSessionType session_type) {
switch (session_type) {
case FeatureSessionType::INITIAL:
return "user-less";
case FeatureSessionType::UNKNOWN:
return "unknown";
case FeatureSessionType::KIOSK:
return "kiosk app";
case FeatureSessionType::REGULAR:
return "regular user";
}
return "";
}
// Gets a human-readable list of the display names (pluralized, comma separated // Gets a human-readable list of the display names (pluralized, comma separated
// with the "and" in the correct place) for each of |enum_types|. // with the "and" in the correct place) for each of |enum_types|.
template <typename EnumType> template <typename EnumType>
...@@ -245,6 +259,12 @@ Feature::Availability SimpleFeature::IsAvailableToManifest( ...@@ -245,6 +259,12 @@ Feature::Availability SimpleFeature::IsAvailableToManifest(
if (channel_ && *channel_ < GetCurrentChannel()) if (channel_ && *channel_ < GetCurrentChannel())
return CreateAvailability(UNSUPPORTED_CHANNEL, *channel_); return CreateAvailability(UNSUPPORTED_CHANNEL, *channel_);
FeatureSessionType session = GetCurrentFeatureSessionType();
if (!session_types_.empty() &&
!base::ContainsValue(session_types_, session)) {
return CreateAvailability(INVALID_SESSION_TYPE, session);
}
return CheckDependencies(base::Bind(&IsAvailableToManifestForBind, return CheckDependencies(base::Bind(&IsAvailableToManifestForBind,
extension_id, extension_id,
type, type,
...@@ -255,7 +275,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest( ...@@ -255,7 +275,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest(
Feature::Availability SimpleFeature::IsAvailableToContext( Feature::Availability SimpleFeature::IsAvailableToContext(
const Extension* extension, const Extension* extension,
SimpleFeature::Context context, Feature::Context context,
const GURL& url, const GURL& url,
SimpleFeature::Platform platform) const { SimpleFeature::Platform platform) const {
if (extension) { if (extension) {
...@@ -283,10 +303,16 @@ Feature::Availability SimpleFeature::IsAvailableToContext( ...@@ -283,10 +303,16 @@ Feature::Availability SimpleFeature::IsAvailableToContext(
return CreateAvailability(INVALID_URL, url); return CreateAvailability(INVALID_URL, url);
} }
FeatureSessionType session = GetCurrentFeatureSessionType();
if (!session_types_.empty() &&
!base::ContainsValue(session_types_, session)) {
return CreateAvailability(INVALID_SESSION_TYPE, session);
}
// TODO(kalman): Assert that if the context was a webpage or WebUI context // TODO(kalman): Assert that if the context was a webpage or WebUI context
// then at some point a "matches" restriction was checked. // then at some point a "matches" restriction was checked.
return CheckDependencies(base::Bind( return CheckDependencies(base::Bind(&IsAvailableToContextForBind, extension,
&IsAvailableToContextForBind, extension, context, url, platform)); context, url, platform));
} }
std::string SimpleFeature::GetAvailabilityMessage( std::string SimpleFeature::GetAvailabilityMessage(
...@@ -294,7 +320,8 @@ std::string SimpleFeature::GetAvailabilityMessage( ...@@ -294,7 +320,8 @@ std::string SimpleFeature::GetAvailabilityMessage(
Manifest::Type type, Manifest::Type type,
const GURL& url, const GURL& url,
Context context, Context context,
version_info::Channel channel) const { version_info::Channel channel,
FeatureSessionType session_type) const {
switch (result) { switch (result) {
case IS_AVAILABLE: case IS_AVAILABLE:
return std::string(); return std::string();
...@@ -338,6 +365,14 @@ std::string SimpleFeature::GetAvailabilityMessage( ...@@ -338,6 +365,14 @@ std::string SimpleFeature::GetAvailabilityMessage(
"'%s' requires manifest version of %d or lower.", "'%s' requires manifest version of %d or lower.",
name().c_str(), name().c_str(),
max_manifest_version_); max_manifest_version_);
case INVALID_SESSION_TYPE:
return base::StringPrintf(
"'%s' is only allowed to run in %s sessions, but this is %s session.",
name().c_str(),
ListDisplayNames(std::vector<FeatureSessionType>(
session_types_.begin(), session_types_.end()))
.c_str(),
GetDisplayName(session_type).c_str());
case NOT_PRESENT: case NOT_PRESENT:
return base::StringPrintf( return base::StringPrintf(
"'%s' requires a different Feature that is not present.", "'%s' requires a different Feature that is not present.",
...@@ -360,25 +395,26 @@ std::string SimpleFeature::GetAvailabilityMessage( ...@@ -360,25 +395,26 @@ std::string SimpleFeature::GetAvailabilityMessage(
Feature::Availability SimpleFeature::CreateAvailability( Feature::Availability SimpleFeature::CreateAvailability(
AvailabilityResult result) const { AvailabilityResult result) const {
return Availability( return Availability(
result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), result, GetAvailabilityMessage(
UNSPECIFIED_CONTEXT, result, Manifest::TYPE_UNKNOWN, GURL(), UNSPECIFIED_CONTEXT,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN, FeatureSessionType::UNKNOWN));
} }
Feature::Availability SimpleFeature::CreateAvailability( Feature::Availability SimpleFeature::CreateAvailability(
AvailabilityResult result, Manifest::Type type) const { AvailabilityResult result, Manifest::Type type) const {
return Availability( return Availability(
result, GetAvailabilityMessage(result, type, GURL(), UNSPECIFIED_CONTEXT, result, GetAvailabilityMessage(result, type, GURL(), UNSPECIFIED_CONTEXT,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN,
FeatureSessionType::UNKNOWN));
} }
Feature::Availability SimpleFeature::CreateAvailability( Feature::Availability SimpleFeature::CreateAvailability(
AvailabilityResult result, AvailabilityResult result,
const GURL& url) const { const GURL& url) const {
return Availability( return Availability(
result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, url, result, GetAvailabilityMessage(
UNSPECIFIED_CONTEXT, result, Manifest::TYPE_UNKNOWN, url, UNSPECIFIED_CONTEXT,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN, FeatureSessionType::UNKNOWN));
} }
Feature::Availability SimpleFeature::CreateAvailability( Feature::Availability SimpleFeature::CreateAvailability(
...@@ -386,7 +422,8 @@ Feature::Availability SimpleFeature::CreateAvailability( ...@@ -386,7 +422,8 @@ Feature::Availability SimpleFeature::CreateAvailability(
Context context) const { Context context) const {
return Availability( return Availability(
result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(),
context, version_info::Channel::UNKNOWN)); context, version_info::Channel::UNKNOWN,
FeatureSessionType::UNKNOWN));
} }
Feature::Availability SimpleFeature::CreateAvailability( Feature::Availability SimpleFeature::CreateAvailability(
...@@ -394,7 +431,17 @@ Feature::Availability SimpleFeature::CreateAvailability( ...@@ -394,7 +431,17 @@ Feature::Availability SimpleFeature::CreateAvailability(
version_info::Channel channel) const { version_info::Channel channel) const {
return Availability( return Availability(
result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(),
UNSPECIFIED_CONTEXT, channel)); UNSPECIFIED_CONTEXT, channel,
FeatureSessionType::UNKNOWN));
}
Feature::Availability SimpleFeature::CreateAvailability(
AvailabilityResult result,
FeatureSessionType session_type) const {
return Availability(
result, GetAvailabilityMessage(
result, Manifest::TYPE_UNKNOWN, GURL(), UNSPECIFIED_CONTEXT,
version_info::Channel::UNKNOWN, session_type));
} }
bool SimpleFeature::IsInternal() const { bool SimpleFeature::IsInternal() const {
...@@ -498,6 +545,11 @@ void SimpleFeature::set_extension_types( ...@@ -498,6 +545,11 @@ void SimpleFeature::set_extension_types(
extension_types_ = types; extension_types_ = types;
} }
void SimpleFeature::set_session_types(
std::initializer_list<FeatureSessionType> types) {
session_types_ = types;
}
void SimpleFeature::set_matches( void SimpleFeature::set_matches(
std::initializer_list<const char* const> matches) { std::initializer_list<const char* const> matches) {
matches_.ClearPatterns(); matches_.ClearPatterns();
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "components/version_info/version_info.h" #include "components/version_info/version_info.h"
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "extensions/common/features/feature.h" #include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_session_type.h"
#include "extensions/common/manifest.h" #include "extensions/common/manifest.h"
namespace extensions { namespace extensions {
...@@ -106,6 +107,7 @@ class SimpleFeature : public Feature { ...@@ -106,6 +107,7 @@ class SimpleFeature : public Feature {
void set_contexts(std::initializer_list<Context> contexts); void set_contexts(std::initializer_list<Context> contexts);
void set_dependencies(std::initializer_list<const char* const> dependencies); void set_dependencies(std::initializer_list<const char* const> dependencies);
void set_extension_types(std::initializer_list<Manifest::Type> types); void set_extension_types(std::initializer_list<Manifest::Type> types);
void set_session_types(std::initializer_list<FeatureSessionType> types);
void set_internal(bool is_internal) { is_internal_ = is_internal; } void set_internal(bool is_internal) { is_internal_ = is_internal; }
void set_location(Location location) { location_ = location; } void set_location(Location location) { location_ = location; }
// set_matches() is an exception to pass-by-value since we construct an // set_matches() is an exception to pass-by-value since we construct an
...@@ -149,7 +151,8 @@ class SimpleFeature : public Feature { ...@@ -149,7 +151,8 @@ class SimpleFeature : public Feature {
Manifest::Type type, Manifest::Type type,
const GURL& url, const GURL& url,
Context context, Context context,
version_info::Channel channel) const; version_info::Channel channel,
FeatureSessionType session_type) const;
// Handy utilities which construct the correct availability message. // Handy utilities which construct the correct availability message.
Availability CreateAvailability(AvailabilityResult result) const; Availability CreateAvailability(AvailabilityResult result) const;
...@@ -161,6 +164,8 @@ class SimpleFeature : public Feature { ...@@ -161,6 +164,8 @@ class SimpleFeature : public Feature {
Context context) const; Context context) const;
Availability CreateAvailability(AvailabilityResult result, Availability CreateAvailability(AvailabilityResult result,
version_info::Channel channel) const; version_info::Channel channel) const;
Availability CreateAvailability(AvailabilityResult result,
FeatureSessionType session_type) const;
private: private:
friend struct FeatureComparator; friend struct FeatureComparator;
...@@ -174,6 +179,7 @@ class SimpleFeature : public Feature { ...@@ -174,6 +179,7 @@ class SimpleFeature : public Feature {
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, CommandLineSwitch); FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, CommandLineSwitch);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ComplexFeatureAvailability); FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ComplexFeatureAvailability);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Context); FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Context);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, SessionType);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, FeatureValidation); FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, FeatureValidation);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, HashedIdBlacklist); FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, HashedIdBlacklist);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, HashedIdWhitelist); FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, HashedIdWhitelist);
...@@ -213,6 +219,7 @@ class SimpleFeature : public Feature { ...@@ -213,6 +219,7 @@ class SimpleFeature : public Feature {
std::vector<std::string> whitelist_; std::vector<std::string> whitelist_;
std::vector<std::string> dependencies_; std::vector<std::string> dependencies_;
std::vector<Manifest::Type> extension_types_; std::vector<Manifest::Type> extension_types_;
std::vector<FeatureSessionType> session_types_;
std::vector<Context> contexts_; std::vector<Context> contexts_;
std::vector<Platform> platforms_; std::vector<Platform> platforms_;
URLPatternSet matches_; URLPatternSet matches_;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <string> #include <string>
#include <vector>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/macros.h" #include "base/macros.h"
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
#include "extensions/common/features/api_feature.h" #include "extensions/common/features/api_feature.h"
#include "extensions/common/features/complex_feature.h" #include "extensions/common/features/complex_feature.h"
#include "extensions/common/features/feature_channel.h" #include "extensions/common/features/feature_channel.h"
#include "extensions/common/features/feature_session_type.h"
#include "extensions/common/features/permission_feature.h" #include "extensions/common/features/permission_feature.h"
#include "extensions/common/manifest.h" #include "extensions/common/manifest.h"
#include "extensions/common/value_builder.h" #include "extensions/common/value_builder.h"
...@@ -36,6 +38,13 @@ struct IsAvailableTestData { ...@@ -36,6 +38,13 @@ struct IsAvailableTestData {
Feature::AvailabilityResult expected_result; Feature::AvailabilityResult expected_result;
}; };
struct FeatureSessionTypeTestData {
std::string desc;
Feature::AvailabilityResult expected_availability;
FeatureSessionType current_session_type;
std::initializer_list<FeatureSessionType> feature_session_types;
};
template <class FeatureClass> template <class FeatureClass>
SimpleFeature* CreateFeature() { SimpleFeature* CreateFeature() {
return new FeatureClass(); return new FeatureClass();
...@@ -398,6 +407,104 @@ TEST_F(SimpleFeatureTest, Context) { ...@@ -398,6 +407,104 @@ TEST_F(SimpleFeatureTest, Context) {
feature.set_max_manifest_version(25); feature.set_max_manifest_version(25);
} }
TEST_F(SimpleFeatureTest, SessionType) {
base::DictionaryValue manifest;
manifest.SetString("name", "test");
manifest.SetString("version", "1");
manifest.SetInteger("manifest_version", 2);
manifest.SetString("app.launch.local_path", "foo.html");
std::string error;
scoped_refptr<const Extension> extension(
Extension::Create(base::FilePath(), Manifest::INTERNAL, manifest,
Extension::NO_FLAGS, &error));
EXPECT_EQ("", error);
ASSERT_TRUE(extension.get());
const FeatureSessionTypeTestData kTestData[] = {
{"kiosk_feature in kiosk session",
Feature::IS_AVAILABLE,
FeatureSessionType::KIOSK,
{FeatureSessionType::KIOSK}},
{"kiosk feature in regular session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::REGULAR,
{FeatureSessionType::KIOSK}},
{"kiosk feature in unknown session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::UNKNOWN,
{FeatureSessionType::KIOSK}},
{"kiosk feature in initial session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::INITIAL,
{FeatureSessionType::KIOSK}},
{"non kiosk feature in kiosk session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::KIOSK,
{FeatureSessionType::REGULAR}},
{"non kiosk feature in regular session",
Feature::IS_AVAILABLE,
FeatureSessionType::REGULAR,
{FeatureSessionType::REGULAR}},
{"non kiosk feature in unknown session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::UNKNOWN,
{FeatureSessionType::REGULAR}},
{"non kiosk feature in initial session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::INITIAL,
{FeatureSessionType::REGULAR}},
{"session agnostic feature in kiosk session",
Feature::IS_AVAILABLE,
FeatureSessionType::KIOSK,
{}},
{"session agnostic feature in regular session",
Feature::IS_AVAILABLE,
FeatureSessionType::REGULAR,
{}},
{"session agnostic feature in unknown session",
Feature::IS_AVAILABLE,
FeatureSessionType::UNKNOWN,
{}},
{"feature with multiple session types",
Feature::IS_AVAILABLE,
FeatureSessionType::REGULAR,
{FeatureSessionType::REGULAR, FeatureSessionType::KIOSK}},
{"feature with multiple session types in unknown session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::UNKNOWN,
{FeatureSessionType::REGULAR, FeatureSessionType::KIOSK}},
{"feature with multiple session types in initial session",
Feature::INVALID_SESSION_TYPE,
FeatureSessionType::INITIAL,
{FeatureSessionType::REGULAR, FeatureSessionType::KIOSK}}};
for (size_t i = 0; i < arraysize(kTestData); ++i) {
std::unique_ptr<base::AutoReset<FeatureSessionType>> current_session(
ScopedCurrentFeatureSessionType(kTestData[i].current_session_type));
SimpleFeature feature;
feature.set_session_types(kTestData[i].feature_session_types);
EXPECT_EQ(kTestData[i].expected_availability,
feature
.IsAvailableToContext(extension.get(),
Feature::BLESSED_EXTENSION_CONTEXT,
Feature::CHROMEOS_PLATFORM)
.result())
<< "Failed test '" << kTestData[i].desc << "'.";
EXPECT_EQ(
kTestData[i].expected_availability,
feature
.IsAvailableToManifest(extension->id(), Manifest::TYPE_UNKNOWN,
Manifest::INVALID_LOCATION, -1,
Feature::CHROMEOS_PLATFORM)
.result())
<< "Failed test '" << kTestData[i].desc << "'.";
}
}
TEST_F(SimpleFeatureTest, Location) { TEST_F(SimpleFeatureTest, Location) {
// Component extensions can access any location. // Component extensions can access any location.
EXPECT_TRUE(LocationIsAvailable(SimpleFeature::COMPONENT_LOCATION, EXPECT_TRUE(LocationIsAvailable(SimpleFeature::COMPONENT_LOCATION,
......
...@@ -189,6 +189,14 @@ FEATURE_GRAMMAR = ( ...@@ -189,6 +189,14 @@ FEATURE_GRAMMAR = (
} }
} }
}, },
'session_types': {
list: {
'enum_map': {
'regular': 'FeatureSessionType::REGULAR',
'kiosk': 'FeatureSessionType::KIOSK',
}
}
},
'whitelist': { 'whitelist': {
list: {'subtype': unicode} list: {'subtype': unicode}
}, },
......
...@@ -46,6 +46,7 @@ class FeatureCompilerTest(unittest.TestCase): ...@@ -46,6 +46,7 @@ class FeatureCompilerTest(unittest.TestCase):
'max_manifest_version': 1, 'max_manifest_version': 1,
'noparent': True, 'noparent': True,
'platforms': ['mac', 'win'], 'platforms': ['mac', 'win'],
'session_types': ['kiosk', 'regular'],
'whitelist': ['zzz', 'yyy'] 'whitelist': ['zzz', 'yyy']
}) })
self.assertFalse(f.errors) self.assertFalse(f.errors)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment