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