diff options
10 files changed, 249 insertions, 1 deletions
diff --git a/chrome/browser/extensions/api/gcm/gcm_api.cc b/chrome/browser/extensions/api/gcm/gcm_api.cc index 620aa46..9aa6889 100644 --- a/chrome/browser/extensions/api/gcm/gcm_api.cc +++ b/chrome/browser/extensions/api/gcm/gcm_api.cc @@ -10,9 +10,13 @@ #include "base/sha1.h" #include "base/strings/string_number_conversions.h" +#include "chrome/browser/extensions/extension_system.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/services/gcm/gcm_profile_service.h" #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" +#include "chrome/common/extensions/api/gcm.h" +#include "extensions/browser/event_router.h" #include "extensions/common/extension.h" namespace { @@ -23,13 +27,43 @@ const size_t kGoogDotPrefixLength = arraysize(kGoogDotRestrictedPrefix) - 1; const char kGoogleRestrictedPrefix[] = "google"; const size_t kGooglePrefixLength = arraysize(kGoogleRestrictedPrefix) - 1; +// Error messages. +const char kInvalidParameter[] = + "Function was called with invalid parameters."; +const char kAsyncOperationPending[] = + "Asynchronous operation is pending."; +const char kNetworkError[] = "Network error occured."; +const char kServerError[] = "Server error occured."; +const char kTtlExceeded[] = "Time-to-live exceeded."; +const char kUnknownError[] = "Unknown error occured."; + std::string SHA1HashHexString(const std::string& str) { std::string hash = base::SHA1HashString(str); return base::HexEncode(hash.data(), hash.size()); } const char* GcmResultToError(gcm::GCMClient::Result result) { - // TODO(fgorski): Add proper error translation with the onSendError event. + switch (result) { + case gcm::GCMClient::SUCCESS: + return ""; + case gcm::GCMClient::INVALID_PARAMETER: + return kInvalidParameter; + case gcm::GCMClient::ASYNC_OPERATION_PENDING: + return kAsyncOperationPending; + case gcm::GCMClient::NETWORK_ERROR: + return kNetworkError; + case gcm::GCMClient::SERVER_ERROR: + return kServerError; + case gcm::GCMClient::TTL_EXCEEDED: + return kTtlExceeded; + case gcm::GCMClient::UNKNOWN_ERROR: + return kUnknownError; + default: + NOTREACHED() << "Unexpected value of result cannot be converted: " + << result; + } + + // Never reached, but prevents missing return statement warning. return ""; } @@ -142,4 +176,46 @@ bool GcmSendFunction::ValidateMessageData( return total_size != 0; } +GcmJsEventRouter::GcmJsEventRouter(Profile* profile) : profile_(profile) {} + +GcmJsEventRouter::~GcmJsEventRouter() {} + +void GcmJsEventRouter::OnMessage( + const std::string& app_id, + const gcm::GCMClient::IncomingMessage& message) { + api::gcm::OnMessage::Message message_arg; + message_arg.data.additional_properties = message.data; + + scoped_ptr<Event> event(new Event( + api::gcm::OnMessage::kEventName, + api::gcm::OnMessage::Create(message_arg).Pass(), + profile_)); + ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( + app_id, event.Pass()); +} + +void GcmJsEventRouter::OnMessagesDeleted(const std::string& app_id) { + scoped_ptr<Event> event(new Event( + api::gcm::OnMessagesDeleted::kEventName, + api::gcm::OnMessagesDeleted::Create().Pass(), + profile_)); + ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( + app_id, event.Pass()); +} + +void GcmJsEventRouter::OnSendError(const std::string& app_id, + const std::string& message_id, + gcm::GCMClient::Result result) { + api::gcm::OnSendError::Error error; + error.message_id.reset(new std::string(message_id)); + error.error_message = GcmResultToError(result); + + scoped_ptr<Event> event(new Event( + api::gcm::OnSendError::kEventName, + api::gcm::OnSendError::Create(error).Pass(), + profile_)); + ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( + app_id, event.Pass()); +} + } // namespace extensions diff --git a/chrome/browser/extensions/api/gcm/gcm_api.h b/chrome/browser/extensions/api/gcm/gcm_api.h index 254a23e..dbed949 100644 --- a/chrome/browser/extensions/api/gcm/gcm_api.h +++ b/chrome/browser/extensions/api/gcm/gcm_api.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_GCM_GCM_API_H_ #define CHROME_BROWSER_EXTENSIONS_API_GCM_GCM_API_H_ +#include "chrome/browser/services/gcm/gcm_event_router.h" #include "chrome/common/extensions/api/gcm.h" #include "extensions/browser/extension_function.h" #include "google_apis/gcm/gcm_client.h" @@ -13,6 +14,8 @@ namespace gcm { class GCMProfileService; } // namespace gcm +class Profile; + namespace extensions { class GcmApiFunction : public AsyncExtensionFunction { @@ -78,6 +81,27 @@ class GcmSendFunction : public GcmApiFunction { gcm::GCMClient::OutgoingMessage outgoing_message_; }; +class GcmJsEventRouter : public gcm::GCMEventRouter { + public: + explicit GcmJsEventRouter(Profile* profile); + + virtual ~GcmJsEventRouter(); + + // GCMEventRouter: + virtual void OnMessage( + const std::string& app_id, + const gcm::GCMClient::IncomingMessage& message) OVERRIDE; + virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE; + virtual void OnSendError(const std::string& app_id, + const std::string& message_id, + gcm::GCMClient::Result result) OVERRIDE; + + private: + // The application we route the event to is running in context of the + // |profile_| and the latter outlives the event router. + Profile* profile_; +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_GCM_GCM_API_H_ diff --git a/chrome/browser/extensions/api/gcm/gcm_apitest.cc b/chrome/browser/extensions/api/gcm/gcm_apitest.cc index af37fa0..9435133 100644 --- a/chrome/browser/extensions/api/gcm/gcm_apitest.cc +++ b/chrome/browser/extensions/api/gcm/gcm_apitest.cc @@ -13,6 +13,7 @@ namespace { const char kFunctionsTestExtension[] = "gcm/functions"; +const char kEventsExtension[] = "gcm/events"; } // namespace @@ -141,4 +142,76 @@ IN_PROC_BROWSER_TEST_F(GcmApiTest, MAYBE_SendMessageData) { EXPECT_EQ("value2", iter->second); } +// http://crbug.com/177163 and http://crbug/324982 +#if defined(OS_WIN) && !defined(NDEBUG) +#define MAYBE_OnMessagesDeleted DISABLED_OnMessagesDeleted +#else +#define MAYBE_OnMessagesDeleted OnMessagesDeleted +#endif +IN_PROC_BROWSER_TEST_F(GcmApiTest, MAYBE_OnMessagesDeleted) { + ResultCatcher catcher; + catcher.RestrictToProfile(profile()); + + const extensions::Extension* extension = + LoadTestExtension(kEventsExtension, "on_messages_deleted.html"); + ASSERT_TRUE(extension); + + GcmJsEventRouter router(profile()); + router.OnMessagesDeleted(extension->id()); + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +} + +// http://crbug.com/177163 and http://crbug/324982 +#if defined(OS_WIN) && !defined(NDEBUG) +#define MAYBE_OnMessage DISABLED_OnMessage +#else +#define MAYBE_OnMessage OnMessage +#endif +IN_PROC_BROWSER_TEST_F(GcmApiTest, MAYBE_OnMessage) { + ResultCatcher catcher; + catcher.RestrictToProfile(profile()); + + const extensions::Extension* extension = + LoadTestExtension(kEventsExtension, "on_message.html"); + ASSERT_TRUE(extension); + + GcmJsEventRouter router(profile()); + + gcm::GCMClient::IncomingMessage message; + message.data["property1"] = "value1"; + message.data["property2"] = "value2"; + router.OnMessage(extension->id(), message); + + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +} + +// http://crbug.com/177163 and http://crbug/324982 +#if defined(OS_WIN) && !defined(NDEBUG) +#define MAYBE_OnSendError DISABLED_OnSendError +#else +#define MAYBE_OnSendError OnSendError +#endif +IN_PROC_BROWSER_TEST_F(GcmApiTest, MAYBE_OnSendError) { + ResultCatcher catcher; + catcher.RestrictToProfile(profile()); + + const extensions::Extension* extension = + LoadTestExtension(kEventsExtension, "on_send_error.html"); + ASSERT_TRUE(extension); + + GcmJsEventRouter router(profile()); + router.OnSendError(extension->id(), "error_message_1", + gcm::GCMClient::ASYNC_OPERATION_PENDING); + router.OnSendError(extension->id(), "error_message_2", + gcm::GCMClient::SERVER_ERROR); + router.OnSendError(extension->id(), "error_message_3", + gcm::GCMClient::NETWORK_ERROR); + router.OnSendError(extension->id(), "error_message_4", + gcm::GCMClient::UNKNOWN_ERROR); + router.OnSendError(extension->id(), "error_message_5", + gcm::GCMClient::TTL_EXCEEDED); + + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +} + } // namespace extensions diff --git a/chrome/test/data/extensions/api_test/gcm/events/manifest.json b/chrome/test/data/extensions/api_test/gcm/events/manifest.json new file mode 100644 index 0000000..e7968681 --- /dev/null +++ b/chrome/test/data/extensions/api_test/gcm/events/manifest.json @@ -0,0 +1,7 @@ +{ + "manifest_version": 2, + "name": "Test GCM App", + "version": "1.0", + "description": "Tests GCM API", + "permissions": ["gcm"] +} diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_message.html b/chrome/test/data/extensions/api_test/gcm/events/on_message.html new file mode 100644 index 0000000..48207fa --- /dev/null +++ b/chrome/test/data/extensions/api_test/gcm/events/on_message.html @@ -0,0 +1 @@ +<script src="on_message.js"></script> diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_message.js b/chrome/test/data/extensions/api_test/gcm/events/on_message.js new file mode 100644 index 0000000..7fbfdf2 --- /dev/null +++ b/chrome/test/data/extensions/api_test/gcm/events/on_message.js @@ -0,0 +1,17 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +onload = function() { + chrome.test.runTests([ + function onMessage() { + chrome.test.listenOnce(chrome.gcm.onMessage, function(message) { + chrome.test.assertEq(2, Object.keys(message.data).length); + chrome.test.assertTrue(message.data.hasOwnProperty('property1')); + chrome.test.assertTrue(message.data.hasOwnProperty('property2')); + chrome.test.assertEq('value1', message.data.property1); + chrome.test.assertEq('value2', message.data.property2); + }); + } + ]); +}; diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_messages_deleted.html b/chrome/test/data/extensions/api_test/gcm/events/on_messages_deleted.html new file mode 100644 index 0000000..fa2dfc8 --- /dev/null +++ b/chrome/test/data/extensions/api_test/gcm/events/on_messages_deleted.html @@ -0,0 +1 @@ +<script src="on_messages_deleted.js"></script> diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_messages_deleted.js b/chrome/test/data/extensions/api_test/gcm/events/on_messages_deleted.js new file mode 100644 index 0000000..440042b --- /dev/null +++ b/chrome/test/data/extensions/api_test/gcm/events/on_messages_deleted.js @@ -0,0 +1,13 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +onload = function() { + chrome.test.runTests([ + function messagesDeleted() { + chrome.test.listenOnce(chrome.gcm.onMessagesDeleted, function() { + chrome.test.assertTrue(true); + }); + } + ]); +}; diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_send_error.html b/chrome/test/data/extensions/api_test/gcm/events/on_send_error.html new file mode 100644 index 0000000..6a2ff0c --- /dev/null +++ b/chrome/test/data/extensions/api_test/gcm/events/on_send_error.html @@ -0,0 +1 @@ +<script src="on_send_error.js"></script> diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_send_error.js b/chrome/test/data/extensions/api_test/gcm/events/on_send_error.js new file mode 100644 index 0000000..6200fbd --- /dev/null +++ b/chrome/test/data/extensions/api_test/gcm/events/on_send_error.js @@ -0,0 +1,35 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +onload = function() { + chrome.test.runTests([ + function onSendError() { + var errorMessages = [ + 'Asynchronous operation is pending.', + 'Server error occured.', + 'Network error occured.', + 'Unknown error occured.', + 'Time-to-live exceeded.' + ]; + var messageIds = [ + 'error_message_1', + 'error_message_2', + 'error_message_3', + 'error_message_4', + 'error_message_5' + ]; + var currentError = 0; + var eventHandler = function(error) { + chrome.test.assertEq(errorMessages[currentError], error.errorMessage); + chrome.test.assertEq(messageIds[currentError], error.messageId); + currentError += 1; + if (currentError == messageIds.length) { + chrome.gcm.onSendError.removeListener(eventHandler); + chrome.test.succeed(); + } + }; + chrome.gcm.onSendError.addListener(eventHandler); + } + ]); +}; |