blob: 969cbcd44c50ad95c3cdad49cf54d28eb40acfae [file] [log] [blame]
Lorenzo Colittia93126d2017-08-24 13:28:19 +09001/*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * TetherControllerTest.cpp - unit tests for TetherController.cpp
17 */
18
19#include <string>
20#include <vector>
21
22#include <fcntl.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26
27#include <gtest/gtest.h>
28
29#include <android-base/stringprintf.h>
30#include <android-base/strings.h>
Lorenzo Colitti5192bf72017-09-04 13:30:59 +090031#include <netdutils/StatusOr.h>
Lorenzo Colittia93126d2017-08-24 13:28:19 +090032
33#include "TetherController.h"
34#include "IptablesBaseTest.h"
35
36using android::base::Join;
37using android::base::StringPrintf;
Lorenzo Colitti5192bf72017-09-04 13:30:59 +090038using android::netdutils::StatusOr;
39using TetherStats = android::net::TetherController::TetherStats;
40using TetherStatsList = android::net::TetherController::TetherStatsList;
Lorenzo Colittia93126d2017-08-24 13:28:19 +090041
42namespace android {
43namespace net {
44
45class TetherControllerTest : public IptablesBaseTest {
46public:
47 TetherControllerTest() {
48 TetherController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
49 }
50
51protected:
52 TetherController mTetherCtrl;
53
54 int setDefaults() {
55 return mTetherCtrl.setDefaults();
56 }
57
58 const ExpectedIptablesCommands FLUSH_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +090059 {V4,
60 "*filter\n"
61 ":tetherctrl_FORWARD -\n"
62 "-A tetherctrl_FORWARD -j DROP\n"
63 "COMMIT\n"
64 "*nat\n"
65 ":tetherctrl_nat_POSTROUTING -\n"
66 "COMMIT\n"},
67 {V6,
68 "*filter\n"
69 ":tetherctrl_FORWARD -\n"
70 "COMMIT\n"
71 "*raw\n"
72 ":tetherctrl_raw_PREROUTING -\n"
73 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +090074 };
75
76 const ExpectedIptablesCommands SETUP_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +090077 {V4,
78 "*filter\n"
79 ":tetherctrl_FORWARD -\n"
80 "-A tetherctrl_FORWARD -j DROP\n"
81 "COMMIT\n"
82 "*nat\n"
83 ":tetherctrl_nat_POSTROUTING -\n"
84 "COMMIT\n"},
85 {V6,
86 "*filter\n"
87 ":tetherctrl_FORWARD -\n"
88 "COMMIT\n"
89 "*raw\n"
90 ":tetherctrl_raw_PREROUTING -\n"
91 "COMMIT\n"},
92 {V4,
93 "*mangle\n"
94 "-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN "
95 "-j TCPMSS --clamp-mss-to-pmtu\n"
96 "COMMIT\n"},
97 {V4V6,
98 "*filter\n"
99 ":tetherctrl_counters -\n"
100 "COMMIT\n"},
101 };
102
103 const ExpectedIptablesCommands ALERT_ADD_COMMAND = {
104 {V4V6,
105 "*filter\n"
106 "-I tetherctrl_FORWARD -j bw_global_alert\n"
107 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900108 };
109
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900110 ExpectedIptablesCommands firstIPv4UpstreamCommands(const char *extIf) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900111 std::string v4Cmd = StringPrintf(
112 "*nat\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900113 "-A tetherctrl_nat_POSTROUTING -o %s -j MASQUERADE\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900114 "COMMIT\n", extIf);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900115 return {
116 { V4, v4Cmd },
117 };
118 }
119
120 ExpectedIptablesCommands firstIPv6UpstreamCommands() {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900121 std::string v6Cmd =
Luke Huangae038f82018-11-05 11:17:31 +0900122 "*filter\n"
123 "-A tetherctrl_FORWARD -g tetherctrl_counters\n"
124 "COMMIT\n";
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900125 return {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900126 { V6, v6Cmd },
127 };
128 }
129
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900130 template<typename T>
131 void appendAll(std::vector<T>& cmds, const std::vector<T>& appendCmds) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900132 cmds.insert(cmds.end(), appendCmds.begin(), appendCmds.end());
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900133 }
134
135 ExpectedIptablesCommands startNatCommands(const char *intIf, const char *extIf,
136 bool withCounterChainRules) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900137 std::string rpfilterCmd = StringPrintf(
138 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900139 "-A tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900140 "COMMIT\n", intIf);
141
142 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900143 "*raw",
144 StringPrintf(
145 "-A tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
146 intIf),
147 StringPrintf("-A tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
148 "--helper pptp",
149 intIf),
150 "COMMIT",
151 "*filter",
152 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state"
153 " ESTABLISHED,RELATED -g tetherctrl_counters",
154 extIf, intIf),
155 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
156 intIf, extIf),
157 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
158 extIf),
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900159 };
160
161 std::vector<std::string> v6Cmds = {
162 "*filter",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900163 };
164
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900165 if (withCounterChainRules) {
166 const std::vector<std::string> counterRules = {
167 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", intIf, extIf),
168 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", extIf, intIf),
169 };
170
171 appendAll(v4Cmds, counterRules);
172 appendAll(v6Cmds, counterRules);
173 }
174
175 appendAll(v4Cmds, {
176 "-D tetherctrl_FORWARD -j DROP",
177 "-A tetherctrl_FORWARD -j DROP",
178 "COMMIT\n",
179 });
180
181 v6Cmds.push_back("COMMIT\n");
182
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900183 return {
184 { V6, rpfilterCmd },
185 { V4, Join(v4Cmds, '\n') },
186 { V6, Join(v6Cmds, '\n') },
187 };
188 }
189
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900190 constexpr static const bool WITH_COUNTERS = true;
191 constexpr static const bool NO_COUNTERS = false;
192 constexpr static const bool WITH_IPV6 = true;
193 constexpr static const bool NO_IPV6 = false;
Luke Huangae038f82018-11-05 11:17:31 +0900194 ExpectedIptablesCommands allNewNatCommands(const char* intIf, const char* extIf,
195 bool withCounterChainRules, bool withIPv6Upstream,
196 bool firstEnableNat) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900197 ExpectedIptablesCommands commands;
198 ExpectedIptablesCommands setupFirstIPv4Commands = firstIPv4UpstreamCommands(extIf);
199 ExpectedIptablesCommands startFirstNatCommands = startNatCommands(intIf, extIf,
200 withCounterChainRules);
201
202 appendAll(commands, setupFirstIPv4Commands);
203 if (withIPv6Upstream) {
204 ExpectedIptablesCommands setupFirstIPv6Commands = firstIPv6UpstreamCommands();
205 appendAll(commands, setupFirstIPv6Commands);
206 }
Luke Huangae038f82018-11-05 11:17:31 +0900207 if (firstEnableNat) {
208 appendAll(commands, ALERT_ADD_COMMAND);
209 }
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900210 appendAll(commands, startFirstNatCommands);
211
212 return commands;
213 }
214
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900215 ExpectedIptablesCommands stopNatCommands(const char *intIf, const char *extIf) {
216 std::string rpfilterCmd = StringPrintf(
217 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900218 "-D tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900219 "COMMIT\n", intIf);
220
221 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900222 "*raw",
223 StringPrintf(
224 "-D tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
225 intIf),
226 StringPrintf("-D tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
227 "--helper pptp",
228 intIf),
229 "COMMIT",
230 "*filter",
231 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state"
232 " ESTABLISHED,RELATED -g tetherctrl_counters",
233 extIf, intIf),
234 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
235 intIf, extIf),
236 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
237 extIf),
238 "COMMIT\n",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900239 };
240
241 return {
242 { V6, rpfilterCmd },
243 { V4, Join(v4Cmds, '\n') },
244 };
245
246 }
247};
248
249TEST_F(TetherControllerTest, TestSetupIptablesHooks) {
250 mTetherCtrl.setupIptablesHooks();
251 expectIptablesRestoreCommands(SETUP_COMMANDS);
252}
253
254TEST_F(TetherControllerTest, TestSetDefaults) {
255 setDefaults();
256 expectIptablesRestoreCommands(FLUSH_COMMANDS);
257}
258
259TEST_F(TetherControllerTest, TestAddAndRemoveNat) {
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900260 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900261 ExpectedIptablesCommands firstNat =
262 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900263 mTetherCtrl.enableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900264 expectIptablesRestoreCommands(firstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900265
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900266 // Start second NAT on same upstream. Expect only the counter rules to be created.
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900267 ExpectedIptablesCommands startOtherNatOnSameUpstream = startNatCommands(
268 "usb0", "rmnet0", WITH_COUNTERS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900269 mTetherCtrl.enableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900270 expectIptablesRestoreCommands(startOtherNatOnSameUpstream);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900271
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900272 // Remove the first NAT.
273 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900274 mTetherCtrl.disableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900275 expectIptablesRestoreCommands(stopFirstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900276
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900277 // Remove the last NAT. Expect rules to be cleared.
278 ExpectedIptablesCommands stopLastNat = stopNatCommands("usb0", "rmnet0");
279
280 appendAll(stopLastNat, FLUSH_COMMANDS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900281 mTetherCtrl.disableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900282 expectIptablesRestoreCommands(stopLastNat);
283
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900284 // Re-add a NAT removed previously: tetherctrl_counters chain rules are not re-added
Luke Huangae038f82018-11-05 11:17:31 +0900285 firstNat = allNewNatCommands("wlan0", "rmnet0", NO_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900286 mTetherCtrl.enableNat("wlan0", "rmnet0");
287 expectIptablesRestoreCommands(firstNat);
288
289 // Remove it again. Expect rules to be cleared.
290 stopLastNat = stopNatCommands("wlan0", "rmnet0");
291 appendAll(stopLastNat, FLUSH_COMMANDS);
292 mTetherCtrl.disableNat("wlan0", "rmnet0");
293 expectIptablesRestoreCommands(stopLastNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900294}
295
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900296TEST_F(TetherControllerTest, TestMultipleUpstreams) {
297 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900298 ExpectedIptablesCommands firstNat =
299 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900300 mTetherCtrl.enableNat("wlan0", "rmnet0");
301 expectIptablesRestoreCommands(firstNat);
302
303 // Start second NAT, on new upstream. Expect the upstream and NAT rules to be created for IPv4,
304 // but no counter rules for IPv6.
Luke Huangae038f82018-11-05 11:17:31 +0900305 ExpectedIptablesCommands secondNat =
306 allNewNatCommands("wlan0", "v4-rmnet0", WITH_COUNTERS, NO_IPV6, false);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900307 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
308 expectIptablesRestoreCommands(secondNat);
309
310 // Pretend that the caller has forgotten that it set up the second NAT, and asks us to do so
311 // again. Expect that we take no action.
312 const ExpectedIptablesCommands NONE = {};
313 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
314 expectIptablesRestoreCommands(NONE);
315
316 // Remove the second NAT.
317 ExpectedIptablesCommands stopSecondNat = stopNatCommands("wlan0", "v4-rmnet0");
318 mTetherCtrl.disableNat("wlan0", "v4-rmnet0");
319 expectIptablesRestoreCommands(stopSecondNat);
320
321 // Remove the first NAT. Expect rules to be cleared.
322 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
323 appendAll(stopFirstNat, FLUSH_COMMANDS);
324 mTetherCtrl.disableNat("wlan0", "rmnet0");
325 expectIptablesRestoreCommands(stopFirstNat);
326}
327
Lorenzo Colitti09353392017-08-24 14:20:32 +0900328std::string kTetherCounterHeaders = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900329 "Chain tetherctrl_counters (4 references)",
Lorenzo Colitti09353392017-08-24 14:20:32 +0900330 " pkts bytes target prot opt in out source destination",
331}, '\n');
332
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900333std::string kIPv4TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900334 "Chain tetherctrl_counters (4 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900335 " pkts bytes target prot opt in out source destination",
336 " 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0",
337 " 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0",
338 " 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0",
339 " 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0",
340}, '\n');
341
342std::string kIPv6TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900343 "Chain tetherctrl_counters (2 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900344 " pkts bytes target prot opt in out source destination",
345 " 10000 10000000 RETURN all wlan0 rmnet0 ::/0 ::/0",
346 " 20000 20000000 RETURN all rmnet0 wlan0 ::/0 ::/0",
347}, '\n');
348
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900349void expectTetherStatsEqual(const TetherController::TetherStats& expected,
350 const TetherController::TetherStats& actual) {
351 EXPECT_EQ(expected.intIface, actual.intIface);
352 EXPECT_EQ(expected.extIface, actual.extIface);
353 EXPECT_EQ(expected.rxBytes, actual.rxBytes);
354 EXPECT_EQ(expected.txBytes, actual.txBytes);
355 EXPECT_EQ(expected.rxPackets, actual.rxPackets);
356 EXPECT_EQ(expected.txPackets, actual.txPackets);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900357}
358
359TEST_F(TetherControllerTest, TestGetTetherStats) {
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900360 // Finding no headers is an error.
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900361 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900362 clearIptablesRestoreOutput();
363
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900364 // Finding only v4 or only v6 headers is an error.
365 addIptablesRestoreOutput(kTetherCounterHeaders, "");
366 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
367 clearIptablesRestoreOutput();
368
369 addIptablesRestoreOutput("", kTetherCounterHeaders);
370 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
371 clearIptablesRestoreOutput();
372
373 // Finding headers but no stats is not an error.
374 addIptablesRestoreOutput(kTetherCounterHeaders, kTetherCounterHeaders);
375 StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
376 ASSERT_TRUE(isOk(result));
377 TetherStatsList actual = result.value();
378 ASSERT_EQ(0U, actual.size());
379 clearIptablesRestoreOutput();
380
381
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900382 addIptablesRestoreOutput(kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900383 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900384 clearIptablesRestoreOutput();
385
386 // IPv4 and IPv6 counters are properly added together.
387 addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900388 TetherStats expected0("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
389 TetherStats expected1("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900390 result = mTetherCtrl.getTetherStats();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900391 ASSERT_TRUE(isOk(result));
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900392 actual = result.value();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900393 ASSERT_EQ(2U, actual.size());
394 expectTetherStatsEqual(expected0, result.value()[0]);
395 expectTetherStatsEqual(expected1, result.value()[1]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900396 clearIptablesRestoreOutput();
397
Lorenzo Colitti09353392017-08-24 14:20:32 +0900398 // No stats: error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900399 addIptablesRestoreOutput("", kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900400 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900401 clearIptablesRestoreOutput();
402
403 addIptablesRestoreOutput(kIPv4TetherCounters, "");
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900404 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900405 clearIptablesRestoreOutput();
406
407 // Include only one pair of interfaces and things are fine.
408 std::vector<std::string> counterLines = android::base::Split(kIPv4TetherCounters, "\n");
409 std::vector<std::string> brokenCounterLines = counterLines;
410 counterLines.resize(4);
411 std::string counters = Join(counterLines, "\n") + "\n";
412 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900413 TetherStats expected1_0("wlan0", "rmnet0", 4004, 54, 4746, 52);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900414 result = mTetherCtrl.getTetherStats();
415 ASSERT_TRUE(isOk(result));
416 actual = result.value();
417 ASSERT_EQ(1U, actual.size());
418 expectTetherStatsEqual(expected1_0, actual[0]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900419 clearIptablesRestoreOutput();
420
421 // But if interfaces aren't paired, it's always an error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900422 counterLines.resize(3);
423 counters = Join(counterLines, "\n") + "\n";
424 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900425 result = mTetherCtrl.getTetherStats();
426 ASSERT_FALSE(isOk(result));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900427 clearIptablesRestoreOutput();
428
429 // Token unit test of the fact that we return the stats in the error message which the caller
430 // ignores.
431 std::string expectedError = counters;
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900432 std::string err = result.status().msg();
Lorenzo Colitti9a8a9ff2017-01-31 19:06:59 +0900433 ASSERT_LE(expectedError.size(), err.size());
434 EXPECT_TRUE(std::equal(expectedError.rbegin(), expectedError.rend(), err.rbegin()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900435}
436
437} // namespace net
438} // namespace android