[GCM] Propagating SendError details all the way to the event.
OnSendError allows to specify more message content than simply and error message
and message ID, but it currently is ignored. This patch fixes that problem by
introducing SendErrorDetails structure and updating the whole stack to handle it
properly.
BUG=350026
Review URL: https://codereview.chromium.org/191443002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@256187 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/gcm/gcm_api.cc b/chrome/browser/extensions/api/gcm/gcm_api.cc
index ed3a72e4b..1ad05d2 100644
--- a/chrome/browser/extensions/api/gcm/gcm_api.cc
+++ b/chrome/browser/extensions/api/gcm/gcm_api.cc
@@ -219,12 +219,13 @@
app_id, event.Pass());
}
-void GcmJsEventRouter::OnSendError(const std::string& app_id,
- const std::string& message_id,
- gcm::GCMClient::Result result) {
+void GcmJsEventRouter::OnSendError(
+ const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& send_error_details) {
api::gcm::OnSendError::Error error;
- error.message_id.reset(new std::string(message_id));
- error.error_message = GcmResultToError(result);
+ error.message_id.reset(new std::string(send_error_details.message_id));
+ error.error_message = GcmResultToError(send_error_details.result);
+ error.details.additional_properties = send_error_details.additional_data;
scoped_ptr<Event> event(new Event(
api::gcm::OnSendError::kEventName,
diff --git a/chrome/browser/extensions/api/gcm/gcm_api.h b/chrome/browser/extensions/api/gcm/gcm_api.h
index 71c73d1..320fe72 100644
--- a/chrome/browser/extensions/api/gcm/gcm_api.h
+++ b/chrome/browser/extensions/api/gcm/gcm_api.h
@@ -88,9 +88,9 @@
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;
+ virtual void OnSendError(
+ const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
// EventRouter::Observer:
virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
diff --git a/chrome/browser/extensions/api/gcm/gcm_apitest.cc b/chrome/browser/extensions/api/gcm/gcm_apitest.cc
index 85a70a6..002e210f 100644
--- a/chrome/browser/extensions/api/gcm/gcm_apitest.cc
+++ b/chrome/browser/extensions/api/gcm/gcm_apitest.cc
@@ -17,6 +17,37 @@
const char kEventsExtension[] = "gcm/events";
+gcm::GCMClient::SendErrorDetails CreateErrorDetails(
+ const std::string& message_id,
+ const gcm::GCMClient::Result result,
+ const std::string& total_messages) {
+ gcm::GCMClient::SendErrorDetails error;
+ error.message_id = message_id;
+ error.result = result;
+ error.additional_data["expectedMessageId"] = message_id;
+ switch (result) {
+ case gcm::GCMClient::ASYNC_OPERATION_PENDING:
+ error.additional_data["expectedErrorMessage"] =
+ "Asynchronous operation is pending.";
+ break;
+ case gcm::GCMClient::SERVER_ERROR:
+ error.additional_data["expectedErrorMessage"] = "Server error occurred.";
+ break;
+ case gcm::GCMClient::NETWORK_ERROR:
+ error.additional_data["expectedErrorMessage"] = "Network error occurred.";
+ break;
+ case gcm::GCMClient::TTL_EXCEEDED:
+ error.additional_data["expectedErrorMessage"] = "Time-to-live exceeded.";
+ break;
+ case gcm::GCMClient::UNKNOWN_ERROR:
+ default: // Default case is the same as UNKNOWN_ERROR
+ error.additional_data["expectedErrorMessage"] = "Unknown error occurred.";
+ break;
+ }
+ error.additional_data["totalMessages"] = total_messages;
+ return error;
+}
+
} // namespace
namespace extensions {
@@ -181,17 +212,28 @@
LoadTestExtension(kEventsExtension, "on_send_error.html");
ASSERT_TRUE(extension);
+ std::string total_expected_messages = "5";
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);
+ router.OnSendError(extension->id(),
+ CreateErrorDetails("error_message_1",
+ gcm::GCMClient::ASYNC_OPERATION_PENDING,
+ total_expected_messages));
+ router.OnSendError(extension->id(),
+ CreateErrorDetails("error_message_2",
+ gcm::GCMClient::SERVER_ERROR,
+ total_expected_messages));
+ router.OnSendError(extension->id(),
+ CreateErrorDetails("error_message_3",
+ gcm::GCMClient::NETWORK_ERROR,
+ total_expected_messages));
+ router.OnSendError(extension->id(),
+ CreateErrorDetails("error_message_4",
+ gcm::GCMClient::UNKNOWN_ERROR,
+ total_expected_messages));
+ router.OnSendError(extension->id(),
+ CreateErrorDetails("error_message_5",
+ gcm::GCMClient::TTL_EXCEEDED,
+ total_expected_messages));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
diff --git a/chrome/browser/services/gcm/gcm_client_mock.cc b/chrome/browser/services/gcm/gcm_client_mock.cc
index 6f839aac..678d6bc 100644
--- a/chrome/browser/services/gcm/gcm_client_mock.cc
+++ b/chrome/browser/services/gcm/gcm_client_mock.cc
@@ -92,7 +92,7 @@
base::Bind(&GCMClientMock::SendFinished,
weak_ptr_factory_.GetWeakPtr(),
app_id,
- message.id));
+ message));
}
GCMClient::GCMStatistics GCMClientMock::GetStatistics() const {
@@ -165,17 +165,21 @@
}
void GCMClientMock::SendFinished(const std::string& app_id,
- const std::string& message_id) {
- delegate_->OnSendFinished(app_id, message_id, SUCCESS);
+ const OutgoingMessage& message) {
+ delegate_->OnSendFinished(app_id, message.id, SUCCESS);
// Simulate send error if message id contains a hint.
- if (message_id.find("error") != std::string::npos) {
+ if (message.id.find("error") != std::string::npos) {
+ SendErrorDetails send_error_details;
+ send_error_details.message_id = message.id;
+ send_error_details.result = NETWORK_ERROR;
+ send_error_details.additional_data = message.data;
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&GCMClientMock::MessageSendError,
weak_ptr_factory_.GetWeakPtr(),
app_id,
- message_id),
+ send_error_details),
base::TimeDelta::FromMilliseconds(200));
}
}
@@ -191,10 +195,11 @@
delegate_->OnMessagesDeleted(app_id);
}
-void GCMClientMock::MessageSendError(const std::string& app_id,
- const std::string& message_id) {
+void GCMClientMock::MessageSendError(
+ const std::string& app_id,
+ const GCMClient::SendErrorDetails& send_error_details) {
if (delegate_)
- delegate_->OnMessageSendError(app_id, message_id, NETWORK_ERROR);
+ delegate_->OnMessageSendError(app_id, send_error_details);
}
} // namespace gcm
diff --git a/chrome/browser/services/gcm/gcm_client_mock.h b/chrome/browser/services/gcm/gcm_client_mock.h
index 5c6cf7b..e2d217a 100644
--- a/chrome/browser/services/gcm/gcm_client_mock.h
+++ b/chrome/browser/services/gcm/gcm_client_mock.h
@@ -77,12 +77,12 @@
void CheckinFinished();
void RegisterFinished(const std::string& app_id,
const std::string& registrion_id);
- void SendFinished(const std::string& app_id, const std::string& message_id);
+ void SendFinished(const std::string& app_id, const OutgoingMessage& message);
void MessageReceived(const std::string& app_id,
const IncomingMessage& message);
void MessagesDeleted(const std::string& app_id);
void MessageSendError(const std::string& app_id,
- const std::string& message_id);
+ const SendErrorDetails& send_error_details);
Delegate* delegate_;
Status status_;
diff --git a/chrome/browser/services/gcm/gcm_event_router.h b/chrome/browser/services/gcm/gcm_event_router.h
index 48b109e9..a99e7ad 100644
--- a/chrome/browser/services/gcm/gcm_event_router.h
+++ b/chrome/browser/services/gcm/gcm_event_router.h
@@ -18,9 +18,9 @@
virtual void OnMessage(const std::string& app_id,
const GCMClient::IncomingMessage& message) = 0;
virtual void OnMessagesDeleted(const std::string& app_id) = 0;
- virtual void OnSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) = 0;
+ virtual void OnSendError(
+ const std::string& app_id,
+ const GCMClient::SendErrorDetails& send_error_details) = 0;
};
} // namespace gcm
diff --git a/chrome/browser/services/gcm/gcm_profile_service.cc b/chrome/browser/services/gcm/gcm_profile_service.cc
index 73af428..64e04185 100644
--- a/chrome/browser/services/gcm/gcm_profile_service.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service.cc
@@ -253,9 +253,9 @@
const std::string& app_id,
const GCMClient::IncomingMessage& message) OVERRIDE;
virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
- virtual void OnMessageSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) OVERRIDE;
+ virtual void OnMessageSendError(
+ const std::string& app_id,
+ const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
virtual void OnGCMReady() OVERRIDE;
// Called on IO thread.
@@ -398,8 +398,7 @@
void GCMProfileService::IOWorker::OnMessageSendError(
const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) {
+ const GCMClient::SendErrorDetails& send_error_details) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
content::BrowserThread::PostTask(
@@ -408,8 +407,7 @@
base::Bind(&GCMProfileService::MessageSendError,
service_,
app_id,
- message_id,
- result));
+ send_error_details));
}
void GCMProfileService::IOWorker::OnGCMReady() {
@@ -1026,16 +1024,16 @@
GetEventRouter(app_id)->OnMessagesDeleted(app_id);
}
-void GCMProfileService::MessageSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) {
+void GCMProfileService::MessageSendError(
+ const std::string& app_id,
+ const GCMClient::SendErrorDetails& send_error_details) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Drop the event if signed out.
if (username_.empty())
return;
- GetEventRouter(app_id)->OnSendError(app_id, message_id, result);
+ GetEventRouter(app_id)->OnSendError(app_id, send_error_details);
}
void GCMProfileService::GCMClientReady() {
diff --git a/chrome/browser/services/gcm/gcm_profile_service.h b/chrome/browser/services/gcm/gcm_profile_service.h
index 7158780..741dcfc 100644
--- a/chrome/browser/services/gcm/gcm_profile_service.h
+++ b/chrome/browser/services/gcm/gcm_profile_service.h
@@ -186,8 +186,7 @@
GCMClient::IncomingMessage message);
void MessagesDeleted(const std::string& app_id);
void MessageSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result);
+ const GCMClient::SendErrorDetails& send_error_details);
void GCMClientReady();
// Returns the event router to fire the event for the given app.
diff --git a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
index 92378515..32d35a5 100644
--- a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
@@ -172,10 +172,7 @@
};
explicit FakeGCMEventRouter(Waiter* waiter)
- : waiter_(waiter),
- received_event_(NO_EVENT),
- send_error_result_(GCMClient::SUCCESS) {
- }
+ : waiter_(waiter), received_event_(NO_EVENT) {}
virtual ~FakeGCMEventRouter() {
}
@@ -196,29 +193,37 @@
waiter_->SignalCompleted();
}
- virtual void OnSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) OVERRIDE {
+ virtual void OnSendError(
+ const std::string& app_id,
+ const GCMClient::SendErrorDetails& send_error_details) OVERRIDE {
clear_results();
received_event_ = SEND_ERROR_EVENT;
app_id_ = app_id;
- send_error_message_id_ = message_id;
- send_error_result_ = result;
+ send_error_details_ = send_error_details;
waiter_->SignalCompleted();
}
Event received_event() const { return received_event_; }
const std::string& app_id() const { return app_id_; }
const GCMClient::IncomingMessage& message() const { return message_; }
- const std::string& send_message_id() const { return send_error_message_id_; }
- GCMClient::Result send_result() const { return send_error_result_; }
+ const GCMClient::SendErrorDetails& send_error_details() const {
+ return send_error_details_;
+ }
+ const std::string& send_error_message_id() const {
+ return send_error_details_.message_id;
+ }
+ GCMClient::Result send_error_result() const {
+ return send_error_details_.result;
+ }
+ const GCMClient::MessageData& send_error_data() const {
+ return send_error_details_.additional_data;
+ }
void clear_results() {
received_event_ = NO_EVENT;
app_id_.clear();
message_.data.clear();
- send_error_message_id_.clear();
- send_error_result_ = GCMClient::UNKNOWN_ERROR;
+ send_error_details_ = GCMClient::SendErrorDetails();
}
private:
@@ -226,8 +231,7 @@
Event received_event_;
std::string app_id_;
GCMClient::IncomingMessage message_;
- std::string send_error_message_id_;
- GCMClient::Result send_error_result_;
+ GCMClient::SendErrorDetails send_error_details_;
};
class FakeGCMClientFactory : public GCMClientFactory {
@@ -1076,9 +1080,10 @@
consumer()->gcm_event_router()->received_event());
EXPECT_EQ(kTestingAppId, consumer()->gcm_event_router()->app_id());
EXPECT_EQ(consumer()->send_message_id(),
- consumer()->gcm_event_router()->send_message_id());
+ consumer()->gcm_event_router()->send_error_message_id());
EXPECT_NE(GCMClient::SUCCESS,
- consumer()->gcm_event_router()->send_result());
+ consumer()->gcm_event_router()->send_error_result());
+ EXPECT_EQ(message.data, consumer()->gcm_event_router()->send_error_data());
}
TEST_F(GCMProfileServiceSingleProfileTest, MessageReceived) {
@@ -1488,10 +1493,12 @@
EXPECT_EQ(FakeGCMEventRouter::SEND_ERROR_EVENT,
consumer2()->gcm_event_router()->received_event());
EXPECT_EQ(kTestingAppId, consumer2()->gcm_event_router()->app_id());
- EXPECT_EQ(consumer2()->send_message_id(),
- consumer2()->gcm_event_router()->send_message_id());
+ EXPECT_EQ(out_message4.id,
+ consumer2()->gcm_event_router()->send_error_message_id());
EXPECT_NE(GCMClient::SUCCESS,
- consumer2()->gcm_event_router()->send_result());
+ consumer2()->gcm_event_router()->send_error_result());
+ EXPECT_EQ(out_message4.data,
+ consumer2()->gcm_event_router()->send_error_data());
// Sign in with a different user.
consumer()->SignIn(kTestingUsername3);
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
index 8223142..1afcb288 100644
--- 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
@@ -5,26 +5,24 @@
onload = function() {
chrome.test.runTests([
function onSendError() {
- var errorMessages = [
- 'Asynchronous operation is pending.',
- 'Server error occurred.',
- 'Network error occurred.',
- 'Unknown error occurred.',
- '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 totalMessages = 0;
var eventHandler = function(error) {
- chrome.test.assertEq(errorMessages[currentError], error.errorMessage);
- chrome.test.assertEq(messageIds[currentError], error.messageId);
+ chrome.test.assertEq(3, Object.keys(error.details).length);
+ chrome.test.assertTrue(
+ error.details.hasOwnProperty("expectedMessageId"));
+ chrome.test.assertTrue(
+ error.details.hasOwnProperty("expectedErrorMessage"));
+ chrome.test.assertEq(error.details.expectedMessageId, error.messageId);
+ chrome.test.assertEq(error.details.expectedErrorMessage,
+ error.errorMessage);
currentError += 1;
- if (currentError == messageIds.length) {
+ var tempTotalMessages = +error.details.totalMessages;
+ if (totalMessages == 0)
+ totalMessages = tempTotalMessages;
+ else
+ chrome.test.assertEq(totalMessages, tempTotalMessages);
+ if (currentError == totalMessages) {
chrome.gcm.onSendError.removeListener(eventHandler);
chrome.test.succeed();
}
diff --git a/google_apis/gcm/gcm_client.cc b/google_apis/gcm/gcm_client.cc
index 78b4e08..3bdd699 100644
--- a/google_apis/gcm/gcm_client.cc
+++ b/google_apis/gcm/gcm_client.cc
@@ -19,6 +19,10 @@
GCMClient::IncomingMessage::~IncomingMessage() {
}
+GCMClient::SendErrorDetails::SendErrorDetails() : result(UNKNOWN_ERROR) {}
+
+GCMClient::SendErrorDetails::~SendErrorDetails() {}
+
GCMClient::GCMStatistics::GCMStatistics()
: gcm_client_created(false), connection_client_created(false) {
}
diff --git a/google_apis/gcm/gcm_client.h b/google_apis/gcm/gcm_client.h
index 7bffa4c..0d68712 100644
--- a/google_apis/gcm/gcm_client.h
+++ b/google_apis/gcm/gcm_client.h
@@ -78,6 +78,16 @@
std::string sender_id;
};
+ // Detailed information of the Send Error event.
+ struct GCM_EXPORT SendErrorDetails {
+ SendErrorDetails();
+ ~SendErrorDetails();
+
+ std::string message_id;
+ MessageData additional_data;
+ Result result;
+ };
+
// Internal states and activity statistics of a GCM client.
struct GCM_EXPORT GCMStatistics {
public:
@@ -130,11 +140,10 @@
// Called when a message failed to send to the server.
// |app_id|: application ID.
- // |message_id|: ID of the message being sent.
- // |result|: the type of the error if an error occured, success otherwise.
- virtual void OnMessageSendError(const std::string& app_id,
- const std::string& message_id,
- Result result) = 0;
+ // |send_error_detials|: Details of the send error event, like mesasge ID.
+ virtual void OnMessageSendError(
+ const std::string& app_id,
+ const SendErrorDetails& send_error_details) = 0;
// Called when the GCM becomes ready. To get to this state, GCMClient
// finished loading from the GCM store and retrieved the device check-in
diff --git a/google_apis/gcm/gcm_client_impl.cc b/google_apis/gcm/gcm_client_impl.cc
index af20a5a..0c9d0fa9 100644
--- a/google_apis/gcm/gcm_client_impl.cc
+++ b/google_apis/gcm/gcm_client_impl.cc
@@ -471,17 +471,21 @@
// TTL_EXCEEDED is singled out here, because it can happen long time after the
// message was sent. That is why it comes as |OnMessageSendError| event rather
- // than |OnSendFinished|. All other errors will be raised immediately, through
- // asynchronous callback.
+ // than |OnSendFinished|. SendErrorDetails.additional_data is left empty.
+ // All other errors will be raised immediately, through asynchronous callback.
// It is expected that TTL_EXCEEDED will be issued for a message that was
// previously issued |OnSendFinished| with status SUCCESS.
// For now, we do not report that the message has been sent and acked
// successfully.
// TODO(jianli): Consider adding UMA for this status.
- if (status == MCSClient::TTL_EXCEEDED)
- delegate_->OnMessageSendError(app_id, message_id, GCMClient::TTL_EXCEEDED);
- else if (status != MCSClient::SENT)
+ if (status == MCSClient::TTL_EXCEEDED) {
+ SendErrorDetails send_error_details;
+ send_error_details.message_id = message_id;
+ send_error_details.result = GCMClient::TTL_EXCEEDED;
+ delegate_->OnMessageSendError(app_id, send_error_details);
+ } else if (status != MCSClient::SENT) {
delegate_->OnSendFinished(app_id, message_id, ToGCMClientResult(status));
+ }
}
void GCMClientImpl::OnMCSError() {
@@ -497,31 +501,31 @@
message.GetProtobuf());
DCHECK_EQ(data_message_stanza.device_user_id(), kDefaultUserSerialNumber);
- IncomingMessage incoming_message;
- MessageType message_type = DATA_MESSAGE;
+ // Copying all the data from the stanza to a MessageData object. When present,
+ // keys like kMessageTypeKey or kSendErrorMessageIdKey will be filtered out
+ // later.
+ MessageData message_data;
for (int i = 0; i < data_message_stanza.app_data_size(); ++i) {
std::string key = data_message_stanza.app_data(i).key();
- if (key == kMessageTypeKey)
- message_type = DecodeMessageType(data_message_stanza.app_data(i).value());
- else
- incoming_message.data[key] = data_message_stanza.app_data(i).value();
+ message_data[key] = data_message_stanza.app_data(i).value();
}
+ MessageType message_type = UNKNOWN;
+ MessageData::iterator iter = message_data.find(kMessageTypeKey);
+ if (iter != message_data.end()) {
+ message_type = DecodeMessageType(iter->second);
+ message_data.erase(iter);
+ }
switch (message_type) {
case DATA_MESSAGE:
- incoming_message.sender_id = data_message_stanza.from();
- if (data_message_stanza.has_token())
- incoming_message.collapse_key = data_message_stanza.token();
- delegate_->OnMessageReceived(data_message_stanza.category(),
- incoming_message);
+ HandleIncomingDataMessage(data_message_stanza, message_data);
break;
case DELETED_MESSAGES:
delegate_->OnMessagesDeleted(data_message_stanza.category());
break;
case SEND_ERROR:
- NotifyDelegateOnMessageSendError(
- delegate_, data_message_stanza.category(), incoming_message);
+ HandleIncomingSendError(data_message_stanza, message_data);
break;
case UNKNOWN:
default: // Treat default the same as UNKNOWN.
@@ -531,16 +535,34 @@
}
}
-void GCMClientImpl::NotifyDelegateOnMessageSendError(
- GCMClient::Delegate* delegate,
- const std::string& app_id,
- const IncomingMessage& incoming_message) {
- MessageData::const_iterator iter =
- incoming_message.data.find(kSendErrorMessageIdKey);
- std::string message_id;
- if (iter != incoming_message.data.end())
- message_id = iter->second;
- delegate->OnMessageSendError(app_id, message_id, SERVER_ERROR);
+void GCMClientImpl::HandleIncomingDataMessage(
+ const mcs_proto::DataMessageStanza& data_message_stanza,
+ MessageData& message_data) {
+ IncomingMessage incoming_message;
+ incoming_message.sender_id = data_message_stanza.from();
+ if (data_message_stanza.has_token())
+ incoming_message.collapse_key = data_message_stanza.token();
+ incoming_message.data = message_data;
+ delegate_->OnMessageReceived(data_message_stanza.category(),
+ incoming_message);
+}
+
+void GCMClientImpl::HandleIncomingSendError(
+ const mcs_proto::DataMessageStanza& data_message_stanza,
+ MessageData& message_data) {
+ SendErrorDetails send_error_details;
+ send_error_details.additional_data = message_data;
+ send_error_details.result = SERVER_ERROR;
+
+ MessageData::iterator iter =
+ send_error_details.additional_data.find(kSendErrorMessageIdKey);
+ if (iter != send_error_details.additional_data.end()) {
+ send_error_details.message_id = iter->second;
+ send_error_details.additional_data.erase(iter);
+ }
+
+ delegate_->OnMessageSendError(data_message_stanza.category(),
+ send_error_details);
}
void GCMClientImpl::SetMCSClientForTesting(scoped_ptr<MCSClient> mcs_client) {
diff --git a/google_apis/gcm/gcm_client_impl.h b/google_apis/gcm/gcm_client_impl.h
index f7eafcb..d7f47d0 100644
--- a/google_apis/gcm/gcm_client_impl.h
+++ b/google_apis/gcm/gcm_client_impl.h
@@ -161,16 +161,20 @@
// Completes the GCM store destroy request.
void OnGCMStoreDestroyed(bool success);
- // Handles incoming data message and dispatches it the a relevant user
- // delegate.
+ // Handles incoming data message and dispatches it the delegate of this class.
void HandleIncomingMessage(const gcm::MCSMessage& message);
- // Fires OnMessageSendError event on |delegate|, with specified |app_id| and
- // message ID obtained from |incoming_message| if one is available.
- void NotifyDelegateOnMessageSendError(
- GCMClient::Delegate* delegate,
- const std::string& app_id,
- const IncomingMessage& incoming_message);
+ // Fires OnMessageReceived event on the delegate of this class, based on the
+ // details in |data_message_stanza| and |message_data|.
+ void HandleIncomingDataMessage(
+ const mcs_proto::DataMessageStanza& data_message_stanza,
+ MessageData& message_data);
+
+ // Fires OnMessageSendError event on the delegate of this calss, based on the
+ // details in |data_message_stanza| and |message_data|.
+ void HandleIncomingSendError(
+ const mcs_proto::DataMessageStanza& data_message_stanza,
+ MessageData& message_data);
// For testing purpose only.
// Sets an |mcs_client_| for testing. Takes the ownership of |mcs_client|.
diff --git a/google_apis/gcm/gcm_client_impl_unittest.cc b/google_apis/gcm/gcm_client_impl_unittest.cc
index 2e1d4c9..7320c00 100644
--- a/google_apis/gcm/gcm_client_impl_unittest.cc
+++ b/google_apis/gcm/gcm_client_impl_unittest.cc
@@ -140,9 +140,9 @@
const GCMClient::IncomingMessage& message)
OVERRIDE;
virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
- virtual void OnMessageSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) OVERRIDE;
+ virtual void OnMessageSendError(
+ const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
virtual void OnGCMReady() OVERRIDE;
GCMClientImpl* gcm_client() const { return gcm_client_.get(); }
@@ -160,6 +160,9 @@
const GCMClient::IncomingMessage& last_message() const {
return last_message_;
}
+ const GCMClient::SendErrorDetails& last_error_details() const {
+ return last_error_details_;
+ }
int64 CurrentTime();
@@ -180,6 +183,7 @@
std::string last_message_id_;
GCMClient::Result last_result_;
GCMClient::IncomingMessage last_message_;
+ GCMClient::SendErrorDetails last_error_details_;
scoped_ptr<GCMClientImpl> gcm_client_;
scoped_ptr<FakeConnectionFactory> connection_factory_;
@@ -338,13 +342,12 @@
last_app_id_ = app_id;
}
-void GCMClientImplTest::OnMessageSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) {
+void GCMClientImplTest::OnMessageSendError(
+ const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& send_error_details) {
last_event_ = MESSAGE_SEND_ERROR;
last_app_id_ = app_id;
- last_message_id_ = message_id;
- last_result_ = result;
+ last_error_details_ = send_error_details;
}
int64 GCMClientImplTest::CurrentTime() {
@@ -406,6 +409,7 @@
std::map<std::string, std::string> expected_data;
expected_data["message_type"] = "send_error";
expected_data["google.message_id"] = "007";
+ expected_data["error_details"] = "some details";
MCSMessage message(BuildDownstreamMessage(
"project_id", "app_id", expected_data));
EXPECT_TRUE(message.IsValid());
@@ -413,7 +417,12 @@
EXPECT_EQ(MESSAGE_SEND_ERROR, last_event());
EXPECT_EQ("app_id", last_app_id());
- EXPECT_EQ("007", last_message_id());
+ EXPECT_EQ("007", last_error_details().message_id);
+ EXPECT_EQ(1UL, last_error_details().additional_data.size());
+ GCMClient::MessageData::const_iterator iter =
+ last_error_details().additional_data.find("error_details");
+ EXPECT_TRUE(iter != last_error_details().additional_data.end());
+ EXPECT_EQ("some details", iter->second);
}
TEST_F(GCMClientImplTest, DispatchDownstreamMessgaesDeleted) {