Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / declarative_webrequest / webrequest_action_unittest.cc
1 // Copyright (c) 2012 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/browser/api/declarative_webrequest/webrequest_action.h"
6
7 #include "base/files/file_path.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/path_service.h"
13 #include "base/test/values_test_util.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "chrome/common/chrome_paths.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "chrome/common/extensions/extension_test_util.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
21 #include "extensions/browser/api/declarative_webrequest/webrequest_condition.h"
22 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
23 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
24 #include "extensions/browser/info_map.h"
25 #include "extensions/common/extension.h"
26 #include "net/base/request_priority.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/url_request/url_request.h"
29 #include "net/url_request/url_request_test_util.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 using base::DictionaryValue;
34 using base::ListValue;
35 using extension_test_util::LoadManifestUnchecked;
36 using testing::HasSubstr;
37
38 namespace extensions {
39
40 namespace {
41
42 const char kUnknownActionType[] = "unknownType";
43
44 scoped_ptr<WebRequestActionSet> CreateSetOfActions(const char* json) {
45   scoped_ptr<base::Value> parsed_value(base::test::ParseJson(json));
46   const base::ListValue* parsed_list;
47   CHECK(parsed_value->GetAsList(&parsed_list));
48
49   WebRequestActionSet::AnyVector actions;
50   for (base::ListValue::const_iterator it = parsed_list->begin();
51        it != parsed_list->end();
52        ++it) {
53     const base::DictionaryValue* dict;
54     CHECK((*it)->GetAsDictionary(&dict));
55     actions.push_back(linked_ptr<base::Value>(dict->DeepCopy()));
56   }
57
58   std::string error;
59   bool bad_message = false;
60
61   scoped_ptr<WebRequestActionSet> action_set(
62       WebRequestActionSet::Create(NULL, NULL, actions, &error, &bad_message));
63   EXPECT_EQ("", error);
64   EXPECT_FALSE(bad_message);
65   CHECK(action_set);
66   return action_set.Pass();
67 }
68
69 }  // namespace
70
71 namespace keys = declarative_webrequest_constants;
72
73 class WebRequestActionWithThreadsTest : public testing::Test {
74  public:
75   WebRequestActionWithThreadsTest()
76       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
77
78  protected:
79   virtual void SetUp() OVERRIDE;
80
81   // Creates a URL request for URL |url_string|, and applies the actions from
82   // |action_set| as if they were triggered by the extension with
83   // |extension_id| during |stage|.
84   bool ActionWorksOnRequest(const char* url_string,
85                             const std::string& extension_id,
86                             const WebRequestActionSet* action_set,
87                             RequestStage stage);
88
89   // Expects a JSON description of an |action| requiring <all_urls> host
90   // permission, and checks that only an extensions with full host permissions
91   // can execute that action at |stage|. Also checks that the action is not
92   // executable for http://clients1.google.com.
93   void CheckActionNeedsAllUrls(const char* action, RequestStage stage);
94
95   net::TestURLRequestContext context_;
96
97   // An extension with *.com host permissions and the DWR permission.
98   scoped_refptr<Extension> extension_;
99   // An extension with host permissions for all URLs and the DWR permission.
100   scoped_refptr<Extension> extension_all_urls_;
101   scoped_refptr<InfoMap> extension_info_map_;
102
103  private:
104   content::TestBrowserThreadBundle thread_bundle_;
105 };
106
107 void WebRequestActionWithThreadsTest::SetUp() {
108   testing::Test::SetUp();
109
110   std::string error;
111   extension_ = LoadManifestUnchecked("permissions",
112                                      "web_request_com_host_permissions.json",
113                                      Manifest::INVALID_LOCATION,
114                                      Extension::NO_FLAGS,
115                                      "ext_id_1",
116                                      &error);
117   ASSERT_TRUE(extension_.get()) << error;
118   extension_all_urls_ =
119       LoadManifestUnchecked("permissions",
120                             "web_request_all_host_permissions.json",
121                             Manifest::INVALID_LOCATION,
122                             Extension::NO_FLAGS,
123                             "ext_id_2",
124                             &error);
125   ASSERT_TRUE(extension_all_urls_.get()) << error;
126   extension_info_map_ = new InfoMap;
127   ASSERT_TRUE(extension_info_map_.get());
128   extension_info_map_->AddExtension(
129       extension_.get(),
130       base::Time::Now(),
131       false /*incognito_enabled*/,
132       false /*notifications_disabled*/);
133   extension_info_map_->AddExtension(extension_all_urls_.get(),
134                                     base::Time::Now(),
135                                     false /*incognito_enabled*/,
136                                     false /*notifications_disabled*/);
137 }
138
139 bool WebRequestActionWithThreadsTest::ActionWorksOnRequest(
140     const char* url_string,
141     const std::string& extension_id,
142     const WebRequestActionSet* action_set,
143     RequestStage stage) {
144   scoped_ptr<net::URLRequest> regular_request(context_.CreateRequest(
145       GURL(url_string), net::DEFAULT_PRIORITY, NULL, NULL));
146   std::list<LinkedPtrEventResponseDelta> deltas;
147   scoped_refptr<net::HttpResponseHeaders> headers(
148       new net::HttpResponseHeaders(""));
149   WebRequestData request_data(regular_request.get(), stage, headers.get());
150   std::set<std::string> ignored_tags;
151   WebRequestAction::ApplyInfo apply_info = { extension_info_map_.get(),
152                                              request_data,
153                                              false /*crosses_incognito*/,
154                                              &deltas, &ignored_tags };
155   action_set->Apply(extension_id, base::Time(), &apply_info);
156   return (1u == deltas.size() || 0u < ignored_tags.size());
157 }
158
159 void WebRequestActionWithThreadsTest::CheckActionNeedsAllUrls(
160     const char* action,
161     RequestStage stage) {
162   scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(action));
163
164   // Although |extension_| has matching *.com host permission, |action|
165   // is intentionally forbidden -- in Declarative WR, host permission
166   // for less than all URLs are ignored (except in SendMessageToExtension).
167   EXPECT_FALSE(ActionWorksOnRequest(
168       "http://test.com", extension_->id(), action_set.get(), stage));
169   // With the "<all_urls>" host permission they are allowed.
170   EXPECT_TRUE(ActionWorksOnRequest(
171       "http://test.com", extension_all_urls_->id(), action_set.get(), stage));
172
173   // The protected URLs should not be touched at all.
174   EXPECT_FALSE(ActionWorksOnRequest(
175       "http://clients1.google.com", extension_->id(), action_set.get(), stage));
176   EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com",
177                                     extension_all_urls_->id(),
178                                     action_set.get(),
179                                     stage));
180 }
181
182 TEST(WebRequestActionTest, CreateAction) {
183   std::string error;
184   bool bad_message = false;
185   scoped_refptr<const WebRequestAction> result;
186
187   // Test wrong data type passed.
188   error.clear();
189   base::ListValue empty_list;
190   result = WebRequestAction::Create(
191       NULL, NULL, empty_list, &error, &bad_message);
192   EXPECT_TRUE(bad_message);
193   EXPECT_FALSE(result.get());
194
195   // Test missing instanceType element.
196   base::DictionaryValue input;
197   error.clear();
198   result = WebRequestAction::Create(NULL, NULL, input, &error, &bad_message);
199   EXPECT_TRUE(bad_message);
200   EXPECT_FALSE(result.get());
201
202   // Test wrong instanceType element.
203   input.SetString(keys::kInstanceTypeKey, kUnknownActionType);
204   error.clear();
205   result = WebRequestAction::Create(NULL, NULL, input, &error, &bad_message);
206   EXPECT_NE("", error);
207   EXPECT_FALSE(result.get());
208
209   // Test success
210   input.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
211   error.clear();
212   result = WebRequestAction::Create(NULL, NULL, input, &error, &bad_message);
213   EXPECT_EQ("", error);
214   EXPECT_FALSE(bad_message);
215   ASSERT_TRUE(result.get());
216   EXPECT_EQ(WebRequestAction::ACTION_CANCEL_REQUEST, result->type());
217 }
218
219 TEST(WebRequestActionTest, CreateActionSet) {
220   std::string error;
221   bool bad_message = false;
222   scoped_ptr<WebRequestActionSet> result;
223
224   WebRequestActionSet::AnyVector input;
225
226   // Test empty input.
227   error.clear();
228   result = WebRequestActionSet::Create(NULL, NULL, input, &error, &bad_message);
229   EXPECT_TRUE(error.empty()) << error;
230   EXPECT_FALSE(bad_message);
231   ASSERT_TRUE(result.get());
232   EXPECT_TRUE(result->actions().empty());
233   EXPECT_EQ(std::numeric_limits<int>::min(), result->GetMinimumPriority());
234
235   base::DictionaryValue correct_action;
236   correct_action.SetString(keys::kInstanceTypeKey, keys::kIgnoreRulesType);
237   correct_action.SetInteger(keys::kLowerPriorityThanKey, 10);
238   base::DictionaryValue incorrect_action;
239   incorrect_action.SetString(keys::kInstanceTypeKey, kUnknownActionType);
240
241   // Test success.
242   input.push_back(linked_ptr<base::Value>(correct_action.DeepCopy()));
243   error.clear();
244   result = WebRequestActionSet::Create(NULL, NULL, input, &error, &bad_message);
245   EXPECT_TRUE(error.empty()) << error;
246   EXPECT_FALSE(bad_message);
247   ASSERT_TRUE(result.get());
248   ASSERT_EQ(1u, result->actions().size());
249   EXPECT_EQ(WebRequestAction::ACTION_IGNORE_RULES,
250             result->actions()[0]->type());
251   EXPECT_EQ(10, result->GetMinimumPriority());
252
253   // Test failure.
254   input.push_back(linked_ptr<base::Value>(incorrect_action.DeepCopy()));
255   error.clear();
256   result = WebRequestActionSet::Create(NULL, NULL, input, &error, &bad_message);
257   EXPECT_NE("", error);
258   EXPECT_FALSE(result.get());
259 }
260
261 // Test capture group syntax conversions of WebRequestRedirectByRegExAction
262 TEST(WebRequestActionTest, PerlToRe2Style) {
263 #define CallPerlToRe2Style WebRequestRedirectByRegExAction::PerlToRe2Style
264   // foo$1bar -> foo\1bar
265   EXPECT_EQ("foo\\1bar", CallPerlToRe2Style("foo$1bar"));
266   // foo\$1bar -> foo$1bar
267   EXPECT_EQ("foo$1bar", CallPerlToRe2Style("foo\\$1bar"));
268   // foo\\$1bar -> foo\\\1bar
269   EXPECT_EQ("foo\\\\\\1bar", CallPerlToRe2Style("foo\\\\$1bar"));
270   // foo\bar -> foobar
271   EXPECT_EQ("foobar", CallPerlToRe2Style("foo\\bar"));
272   // foo$bar -> foo$bar
273   EXPECT_EQ("foo$bar", CallPerlToRe2Style("foo$bar"));
274 #undef CallPerlToRe2Style
275 }
276
277 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirect) {
278   const char kAction[] =
279       "[{"
280       " \"instanceType\": \"declarativeWebRequest.RedirectRequest\","
281       " \"redirectUrl\": \"http://www.foobar.com\""
282       "}]";
283   CheckActionNeedsAllUrls(kAction, ON_BEFORE_REQUEST);
284   CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED);
285 }
286
287 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirectByRegEx) {
288   const char kAction[] =
289       "[{"
290       " \"instanceType\": \"declarativeWebRequest.RedirectByRegEx\","
291       " \"from\": \".*\","
292       " \"to\": \"http://www.foobar.com\""
293       "}]";
294   CheckActionNeedsAllUrls(kAction, ON_BEFORE_REQUEST);
295 }
296
297 TEST_F(WebRequestActionWithThreadsTest, PermissionsToSetRequestHeader) {
298   const char kAction[] =
299       "[{"
300       " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\","
301       " \"name\": \"testname\","
302       " \"value\": \"testvalue\""
303       "}]";
304   CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS);
305 }
306
307 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveRequestHeader) {
308   const char kAction[] =
309       "[{"
310       " \"instanceType\": \"declarativeWebRequest.RemoveRequestHeader\","
311       " \"name\": \"testname\""
312       "}]";
313   CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS);
314 }
315
316 TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddResponseHeader) {
317   const char kAction[] =
318       "[{"
319       " \"instanceType\": \"declarativeWebRequest.AddResponseHeader\","
320       " \"name\": \"testname\","
321       " \"value\": \"testvalue\""
322       "}]";
323   CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED);
324 }
325
326 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveResponseHeader) {
327   const char kAction[] =
328       "[{"
329       " \"instanceType\": \"declarativeWebRequest.RemoveResponseHeader\","
330       " \"name\": \"testname\""
331       "}]";
332   CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED);
333 }
334
335 TEST_F(WebRequestActionWithThreadsTest, PermissionsToSendMessageToExtension) {
336   const char kAction[] =
337       "[{"
338       " \"instanceType\": \"declarativeWebRequest.SendMessageToExtension\","
339       " \"message\": \"testtext\""
340       "}]";
341   scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction));
342
343   // For sending messages, specific host permissions actually matter.
344   EXPECT_TRUE(ActionWorksOnRequest("http://test.com",
345                                    extension_->id(),
346                                    action_set.get(),
347                                    ON_BEFORE_REQUEST));
348   // With the "<all_urls>" host permission they are allowed.
349   EXPECT_TRUE(ActionWorksOnRequest("http://test.com",
350                                    extension_all_urls_->id(),
351                                    action_set.get(),
352                                    ON_BEFORE_REQUEST));
353
354   // The protected URLs should not be touched at all.
355   EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com",
356                                     extension_->id(),
357                                     action_set.get(),
358                                     ON_BEFORE_REQUEST));
359   EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com",
360                                     extension_all_urls_->id(),
361                                     action_set.get(),
362                                     ON_BEFORE_REQUEST));
363 }
364
365 TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddRequestCookie) {
366   const char kAction[] =
367       "[{"
368       " \"instanceType\": \"declarativeWebRequest.AddRequestCookie\","
369       " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
370       "}]";
371   CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS);
372 }
373
374 TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddResponseCookie) {
375   const char kAction[] =
376       "[{"
377       " \"instanceType\": \"declarativeWebRequest.AddResponseCookie\","
378       " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
379       "}]";
380   CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED);
381 }
382
383 TEST_F(WebRequestActionWithThreadsTest, PermissionsToEditRequestCookie) {
384   const char kAction[] =
385       "[{"
386       " \"instanceType\": \"declarativeWebRequest.EditRequestCookie\","
387       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" },"
388       " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }"
389       "}]";
390   CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS);
391 }
392
393 TEST_F(WebRequestActionWithThreadsTest, PermissionsToEditResponseCookie) {
394   const char kAction[] =
395       "[{"
396       " \"instanceType\": \"declarativeWebRequest.EditResponseCookie\","
397       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" },"
398       " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }"
399       "}]";
400   CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED);
401 }
402
403 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveRequestCookie) {
404   const char kAction[] =
405       "[{"
406       " \"instanceType\": \"declarativeWebRequest.RemoveRequestCookie\","
407       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
408       "}]";
409   CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS);
410 }
411
412 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveResponseCookie) {
413   const char kAction[] =
414       "[{"
415       " \"instanceType\": \"declarativeWebRequest.RemoveResponseCookie\","
416       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
417       "}]";
418   CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED);
419 }
420
421 TEST_F(WebRequestActionWithThreadsTest, PermissionsToCancel) {
422   const char kAction[] =
423       "[{"
424       " \"instanceType\": \"declarativeWebRequest.CancelRequest\""
425       "}]";
426   scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction));
427
428   // Cancelling requests works without full host permissions.
429   EXPECT_TRUE(ActionWorksOnRequest("http://test.org",
430                                    extension_->id(),
431                                    action_set.get(),
432                                    ON_BEFORE_REQUEST));
433 }
434
435 TEST_F(WebRequestActionWithThreadsTest,
436        PermissionsToRedirectToTransparentImage) {
437   const char kAction[] =
438       "[{"
439       " \"instanceType\": \"declarativeWebRequest.RedirectToTransparentImage\""
440       "}]";
441   scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction));
442
443   // Redirecting to transparent images works without full host permissions.
444   EXPECT_TRUE(ActionWorksOnRequest("http://test.org",
445                                    extension_->id(),
446                                    action_set.get(),
447                                    ON_BEFORE_REQUEST));
448   EXPECT_TRUE(ActionWorksOnRequest("http://test.org",
449                                    extension_->id(),
450                                    action_set.get(),
451                                    ON_HEADERS_RECEIVED));
452 }
453
454 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirectToEmptyDocument) {
455   const char kAction[] =
456       "[{"
457       " \"instanceType\": \"declarativeWebRequest.RedirectToEmptyDocument\""
458       "}]";
459   scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction));
460
461   // Redirecting to the empty document works without full host permissions.
462   EXPECT_TRUE(ActionWorksOnRequest("http://test.org",
463                                    extension_->id(),
464                                    action_set.get(),
465                                    ON_BEFORE_REQUEST));
466   EXPECT_TRUE(ActionWorksOnRequest("http://test.org",
467                                    extension_->id(),
468                                    action_set.get(),
469                                    ON_HEADERS_RECEIVED));
470 }
471
472 TEST_F(WebRequestActionWithThreadsTest, PermissionsToIgnore) {
473   const char kAction[] =
474       "[{"
475       " \"instanceType\": \"declarativeWebRequest.IgnoreRules\","
476       " \"lowerPriorityThan\": 123,"
477       " \"hasTag\": \"some_tag\""
478       "}]";
479   scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction));
480
481   // Ignoring rules works without full host permissions.
482   EXPECT_TRUE(ActionWorksOnRequest("http://test.org",
483                                    extension_->id(),
484                                    action_set.get(),
485                                    ON_BEFORE_REQUEST));
486 }
487
488 TEST(WebRequestActionTest, GetName) {
489   const char kActions[] =
490       "[{"
491       " \"instanceType\": \"declarativeWebRequest.RedirectRequest\","
492       " \"redirectUrl\": \"http://www.foobar.com\""
493       "},"
494       "{"
495       " \"instanceType\": \"declarativeWebRequest.RedirectByRegEx\","
496       " \"from\": \".*\","
497       " \"to\": \"http://www.foobar.com\""
498       "},"
499       "{"
500       " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\","
501       " \"name\": \"testname\","
502       " \"value\": \"testvalue\""
503       "},"
504       "{"
505       " \"instanceType\": \"declarativeWebRequest.RemoveRequestHeader\","
506       " \"name\": \"testname\""
507       "},"
508       "{"
509       " \"instanceType\": \"declarativeWebRequest.AddResponseHeader\","
510       " \"name\": \"testname\","
511       " \"value\": \"testvalue\""
512       "},"
513       "{"
514       " \"instanceType\": \"declarativeWebRequest.RemoveResponseHeader\","
515       " \"name\": \"testname\""
516       "},"
517       "{"
518       " \"instanceType\": \"declarativeWebRequest.SendMessageToExtension\","
519       " \"message\": \"testtext\""
520       "},"
521       "{"
522       " \"instanceType\": \"declarativeWebRequest.AddRequestCookie\","
523       " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
524       "},"
525       "{"
526       " \"instanceType\": \"declarativeWebRequest.AddResponseCookie\","
527       " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
528       "},"
529       "{"
530       " \"instanceType\": \"declarativeWebRequest.EditRequestCookie\","
531       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" },"
532       " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }"
533       "},"
534       "{"
535       " \"instanceType\": \"declarativeWebRequest.EditResponseCookie\","
536       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" },"
537       " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }"
538       "},"
539       "{"
540       " \"instanceType\": \"declarativeWebRequest.RemoveRequestCookie\","
541       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
542       "},"
543       "{"
544       " \"instanceType\": \"declarativeWebRequest.RemoveResponseCookie\","
545       " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }"
546       "},"
547       "{"
548       " \"instanceType\": \"declarativeWebRequest.CancelRequest\""
549       "},"
550       "{"
551       " \"instanceType\": \"declarativeWebRequest.RedirectToTransparentImage\""
552       "},"
553       "{"
554       " \"instanceType\": \"declarativeWebRequest.RedirectToEmptyDocument\""
555       "},"
556       "{"
557       " \"instanceType\": \"declarativeWebRequest.IgnoreRules\","
558       " \"lowerPriorityThan\": 123,"
559       " \"hasTag\": \"some_tag\""
560       "}]";
561   const char* kExpectedNames[] = {
562     "declarativeWebRequest.RedirectRequest",
563     "declarativeWebRequest.RedirectByRegEx",
564     "declarativeWebRequest.SetRequestHeader",
565     "declarativeWebRequest.RemoveRequestHeader",
566     "declarativeWebRequest.AddResponseHeader",
567     "declarativeWebRequest.RemoveResponseHeader",
568     "declarativeWebRequest.SendMessageToExtension",
569     "declarativeWebRequest.AddRequestCookie",
570     "declarativeWebRequest.AddResponseCookie",
571     "declarativeWebRequest.EditRequestCookie",
572     "declarativeWebRequest.EditResponseCookie",
573     "declarativeWebRequest.RemoveRequestCookie",
574     "declarativeWebRequest.RemoveResponseCookie",
575     "declarativeWebRequest.CancelRequest",
576     "declarativeWebRequest.RedirectToTransparentImage",
577     "declarativeWebRequest.RedirectToEmptyDocument",
578     "declarativeWebRequest.IgnoreRules",
579   };
580   scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kActions));
581   ASSERT_EQ(arraysize(kExpectedNames), action_set->actions().size());
582   size_t index = 0;
583   for (WebRequestActionSet::Actions::const_iterator it =
584            action_set->actions().begin();
585        it != action_set->actions().end();
586        ++it) {
587     EXPECT_EQ(kExpectedNames[index], (*it)->GetName());
588     ++index;
589   }
590 }
591
592 }  // namespace extensions