Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 5 | #include "src/notification/xmpp_channel.h" |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 6 | |
Vitaly Buka | 10c69ec | 2015-08-12 16:17:16 -0700 | [diff] [blame] | 7 | #include <algorithm> |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 8 | #include <queue> |
| 9 | |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 10 | #include <gtest/gtest.h> |
Vitaly Buka | 727f3e6 | 2015-09-25 17:33:43 -0700 | [diff] [blame] | 11 | #include <weave/provider/test/fake_task_runner.h> |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 12 | #include <weave/provider/test/mock_network.h> |
Alex Vakulenko | 5a7a7da | 2015-09-25 16:10:23 -0700 | [diff] [blame] | 13 | #include <weave/test/fake_stream.h> |
Vitaly Buka | 823fdda | 2015-08-13 00:33:00 -0700 | [diff] [blame] | 14 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 15 | #include "src/bind_lambda.h" |
Vitaly Buka | 6ca868f | 2015-08-13 21:53:05 -0700 | [diff] [blame] | 16 | |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 17 | using testing::_; |
| 18 | using testing::Invoke; |
| 19 | using testing::Return; |
Vitaly Buka | 823fdda | 2015-08-13 00:33:00 -0700 | [diff] [blame] | 20 | using testing::StrictMock; |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 21 | using testing::WithArgs; |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 22 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 23 | namespace weave { |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 24 | |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 25 | namespace { |
| 26 | |
| 27 | constexpr char kAccountName[] = "Account@Name"; |
| 28 | constexpr char kAccessToken[] = "AccessToken"; |
| 29 | |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 30 | constexpr char kStartStreamMessage[] = |
| 31 | "<stream:stream to='clouddevices.gserviceaccount.com' " |
| 32 | "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='*' " |
| 33 | "version='1.0' xmlns='jabber:client'>"; |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 34 | constexpr char kStartStreamResponse[] = |
| 35 | "<stream:stream from=\"clouddevices.gserviceaccount.com\" " |
| 36 | "id=\"0CCF520913ABA04B\" version=\"1.0\" " |
| 37 | "xmlns:stream=\"http://etherx.jabber.org/streams\" " |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 38 | "xmlns=\"jabber:client\">"; |
| 39 | constexpr char kAuthenticationMessage[] = |
| 40 | "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='X-OAUTH2' " |
| 41 | "auth:service='oauth2' auth:allow-non-google-login='true' " |
| 42 | "auth:client-uses-full-bind-result='true' " |
| 43 | "xmlns:auth='http://www.google.com/talk/protocol/auth'>" |
| 44 | "AEFjY291bnRATmFtZQBBY2Nlc3NUb2tlbg==</auth>"; |
| 45 | constexpr char kConnectedResponse[] = |
Alex Vakulenko | 2684b51 | 2015-05-19 13:42:10 -0700 | [diff] [blame] | 46 | "<stream:features><mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" |
| 47 | "<mechanism>X-OAUTH2</mechanism>" |
| 48 | "<mechanism>X-GOOGLE-TOKEN</mechanism></mechanisms></stream:features>"; |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 49 | constexpr char kAuthenticationSucceededResponse[] = |
| 50 | "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>"; |
| 51 | constexpr char kAuthenticationFailedResponse[] = |
| 52 | "<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"><not-authorized/>" |
Alex Vakulenko | 94fe16c | 2015-06-23 12:30:11 -0700 | [diff] [blame] | 53 | "</failure>"; |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 54 | constexpr char kRestartStreamResponse[] = |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 55 | "<stream:features><bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>" |
| 56 | "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>" |
| 57 | "</stream:features>"; |
| 58 | constexpr char kBindResponse[] = |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 59 | "<iq id=\"1\" type=\"result\">" |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 60 | "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">" |
| 61 | "<jid>110cc78f78d7032cc7bf2c6e14c1fa7d@clouddevices.gserviceaccount.com" |
| 62 | "/19853128</jid></bind></iq>"; |
Vitaly Buka | a647c85 | 2015-07-06 14:51:01 -0700 | [diff] [blame] | 63 | constexpr char kSessionResponse[] = "<iq type=\"result\" id=\"2\"/>"; |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 64 | constexpr char kSubscribedResponse[] = |
| 65 | "<iq to=\"" |
| 66 | "110cc78f78d7032cc7bf2c6e14c1fa7d@clouddevices.gserviceaccount.com/" |
| 67 | "19853128\" from=\"" |
| 68 | "110cc78f78d7032cc7bf2c6e14c1fa7d@clouddevices.gserviceaccount.com\" " |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 69 | "id=\"3\" type=\"result\"/>"; |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 70 | constexpr char kBindMessage[] = |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 71 | "<iq id='1' type='set'><bind " |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 72 | "xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>"; |
| 73 | constexpr char kSessionMessage[] = |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 74 | "<iq id='2' type='set'><session " |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 75 | "xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>"; |
| 76 | constexpr char kSubscribeMessage[] = |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 77 | "<iq id='3' type='set' to='Account@Name'>" |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 78 | "<subscribe xmlns='google:push'><item channel='cloud_devices' from=''/>" |
| 79 | "</subscribe></iq>"; |
Vitaly Buka | 10c69ec | 2015-08-12 16:17:16 -0700 | [diff] [blame] | 80 | |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 81 | } // namespace |
| 82 | |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 83 | class FakeXmppChannel : public XmppChannel { |
| 84 | public: |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 85 | explicit FakeXmppChannel(provider::TaskRunner* task_runner, |
| 86 | provider::Network* network) |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 87 | : XmppChannel{kAccountName, kAccessToken, task_runner, network}, |
Alex Vakulenko | 5a7a7da | 2015-09-25 16:10:23 -0700 | [diff] [blame] | 88 | stream_{new test::FakeStream{task_runner_}}, |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 89 | fake_stream_{stream_.get()} {} |
| 90 | |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 91 | void Connect(const base::Callback<void(std::unique_ptr<Stream>, |
| 92 | ErrorPtr error)>& callback) { |
| 93 | callback.Run(std::move(stream_), nullptr); |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 94 | } |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 95 | |
| 96 | XmppState state() const { return state_; } |
| 97 | void set_state(XmppState state) { state_ = state; } |
| 98 | |
Vitaly Buka | 63cc3d2 | 2015-06-23 20:11:36 -0700 | [diff] [blame] | 99 | void SchedulePing(base::TimeDelta interval, |
| 100 | base::TimeDelta timeout) override {} |
Alex Vakulenko | 5cd7997 | 2015-06-01 13:21:18 -0700 | [diff] [blame] | 101 | |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 102 | void ExpectWritePacketString(base::TimeDelta delta, const std::string& data) { |
| 103 | fake_stream_->ExpectWritePacketString(delta, data); |
| 104 | } |
| 105 | |
| 106 | void AddReadPacketString(base::TimeDelta delta, const std::string& data) { |
| 107 | fake_stream_->AddReadPacketString(delta, data); |
| 108 | } |
| 109 | |
Alex Vakulenko | 5a7a7da | 2015-09-25 16:10:23 -0700 | [diff] [blame] | 110 | std::unique_ptr<test::FakeStream> stream_; |
| 111 | test::FakeStream* fake_stream_{nullptr}; |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 112 | }; |
| 113 | |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 114 | class MockNetwork : public provider::test::MockNetwork { |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 115 | public: |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 116 | MockNetwork() { |
Vitaly Buka | 3ab6f6e | 2015-09-24 13:16:16 -0700 | [diff] [blame] | 117 | EXPECT_CALL(*this, AddConnectionChangedCallback(_)) |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 118 | .WillRepeatedly(Return()); |
| 119 | } |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 120 | }; |
| 121 | |
| 122 | class XmppChannelTest : public ::testing::Test { |
| 123 | protected: |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 124 | XmppChannelTest() { |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 125 | EXPECT_CALL(network_, OpenSslSocket("talk.google.com", 5223, _)) |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 126 | .WillOnce( |
| 127 | WithArgs<2>(Invoke(&xmpp_client_, &FakeXmppChannel::Connect))); |
| 128 | } |
| 129 | |
Alex Vakulenko | bf71f70 | 2015-05-18 14:30:56 -0700 | [diff] [blame] | 130 | void StartStream() { |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 131 | xmpp_client_.ExpectWritePacketString({}, kStartStreamMessage); |
| 132 | xmpp_client_.AddReadPacketString({}, kStartStreamResponse); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 133 | xmpp_client_.Start(nullptr); |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 134 | RunUntil(XmppChannel::XmppState::kConnected); |
Alex Vakulenko | bf71f70 | 2015-05-18 14:30:56 -0700 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | void StartWithState(XmppChannel::XmppState state) { |
| 138 | StartStream(); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 139 | xmpp_client_.set_state(state); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 140 | } |
| 141 | |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 142 | void RunUntil(XmppChannel::XmppState st) { |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 143 | for (size_t n = 15; n && xmpp_client_.state() != st; --n) |
Vitaly Buka | 823fdda | 2015-08-13 00:33:00 -0700 | [diff] [blame] | 144 | task_runner_.RunOnce(); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 145 | EXPECT_EQ(st, xmpp_client_.state()); |
Bertrand SIMONNET | d282884 | 2015-08-12 12:18:02 -0700 | [diff] [blame] | 146 | } |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 147 | |
Vitaly Buka | 727f3e6 | 2015-09-25 17:33:43 -0700 | [diff] [blame] | 148 | StrictMock<provider::test::FakeTaskRunner> task_runner_; |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 149 | StrictMock<MockNetwork> network_; |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 150 | FakeXmppChannel xmpp_client_{&task_runner_, &network_}; |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 151 | }; |
| 152 | |
| 153 | TEST_F(XmppChannelTest, StartStream) { |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 154 | EXPECT_EQ(XmppChannel::XmppState::kNotStarted, xmpp_client_.state()); |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 155 | xmpp_client_.ExpectWritePacketString({}, kStartStreamMessage); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 156 | xmpp_client_.Start(nullptr); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 157 | RunUntil(XmppChannel::XmppState::kConnected); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | TEST_F(XmppChannelTest, HandleStartedResponse) { |
Alex Vakulenko | bf71f70 | 2015-05-18 14:30:56 -0700 | [diff] [blame] | 161 | StartStream(); |
Alex Vakulenko | 2684b51 | 2015-05-19 13:42:10 -0700 | [diff] [blame] | 162 | } |
| 163 | |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 164 | TEST_F(XmppChannelTest, HandleConnected) { |
| 165 | StartWithState(XmppChannel::XmppState::kConnected); |
| 166 | xmpp_client_.AddReadPacketString({}, kConnectedResponse); |
| 167 | xmpp_client_.ExpectWritePacketString({}, kAuthenticationMessage); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 168 | RunUntil(XmppChannel::XmppState::kAuthenticationStarted); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | TEST_F(XmppChannelTest, HandleAuthenticationSucceededResponse) { |
| 172 | StartWithState(XmppChannel::XmppState::kAuthenticationStarted); |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 173 | xmpp_client_.AddReadPacketString({}, kAuthenticationSucceededResponse); |
| 174 | xmpp_client_.ExpectWritePacketString({}, kStartStreamMessage); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 175 | RunUntil(XmppChannel::XmppState::kStreamRestartedPostAuthentication); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | TEST_F(XmppChannelTest, HandleAuthenticationFailedResponse) { |
| 179 | StartWithState(XmppChannel::XmppState::kAuthenticationStarted); |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 180 | xmpp_client_.AddReadPacketString({}, kAuthenticationFailedResponse); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 181 | RunUntil(XmppChannel::XmppState::kAuthenticationFailed); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | TEST_F(XmppChannelTest, HandleStreamRestartedResponse) { |
| 185 | StartWithState(XmppChannel::XmppState::kStreamRestartedPostAuthentication); |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 186 | xmpp_client_.AddReadPacketString({}, kRestartStreamResponse); |
| 187 | xmpp_client_.ExpectWritePacketString({}, kBindMessage); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 188 | RunUntil(XmppChannel::XmppState::kBindSent); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 189 | EXPECT_TRUE(xmpp_client_.jid().empty()); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 190 | |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 191 | xmpp_client_.AddReadPacketString({}, kBindResponse); |
| 192 | xmpp_client_.ExpectWritePacketString({}, kSessionMessage); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 193 | RunUntil(XmppChannel::XmppState::kSessionStarted); |
Vitaly Buka | a647c85 | 2015-07-06 14:51:01 -0700 | [diff] [blame] | 194 | EXPECT_EQ( |
| 195 | "110cc78f78d7032cc7bf2c6e14c1fa7d@clouddevices.gserviceaccount.com" |
| 196 | "/19853128", |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 197 | xmpp_client_.jid()); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 198 | |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 199 | xmpp_client_.AddReadPacketString({}, kSessionResponse); |
| 200 | xmpp_client_.ExpectWritePacketString({}, kSubscribeMessage); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 201 | RunUntil(XmppChannel::XmppState::kSubscribeStarted); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 202 | |
Vitaly Buka | a4b3983 | 2015-09-09 02:11:03 -0700 | [diff] [blame] | 203 | xmpp_client_.AddReadPacketString({}, kSubscribedResponse); |
Vitaly Buka | 8b13fa0 | 2015-08-12 13:34:26 -0700 | [diff] [blame] | 204 | RunUntil(XmppChannel::XmppState::kSubscribed); |
Alex Vakulenko | eedf3be | 2015-05-13 17:52:02 -0700 | [diff] [blame] | 205 | } |
| 206 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 207 | } // namespace weave |