1 /*
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 * BandwidthControllerTest.cpp - unit tests for BandwidthController.cpp
17 */
18
19 #include <string>
20 #include <vector>
21
22 #include <inttypes.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27
28 #include <gtest/gtest.h>
29
30 #include <android-base/strings.h>
31 #include <android-base/stringprintf.h>
32
33 #include <netdutils/MockSyscalls.h>
34 #include "BandwidthController.h"
35 #include "Fwmark.h"
36 #include "IptablesBaseTest.h"
37 #include "bpf/BpfUtils.h"
38 #include "tun_interface.h"
39
40 using ::testing::ByMove;
41 using ::testing::Invoke;
42 using ::testing::Return;
43 using ::testing::StrictMock;
44 using ::testing::Test;
45 using ::testing::_;
46
47 using android::base::Join;
48 using android::base::StringPrintf;
49 using android::bpf::XT_BPF_EGRESS_PROG_PATH;
50 using android::bpf::XT_BPF_INGRESS_PROG_PATH;
51 using android::net::TunInterface;
52 using android::netdutils::status::ok;
53 using android::netdutils::UniqueFile;
54
55 class BandwidthControllerTest : public IptablesBaseTest {
56 protected:
BandwidthControllerTest()57 BandwidthControllerTest() {
58 BandwidthController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
59 }
60 BandwidthController mBw;
61 TunInterface mTun;
62
SetUp()63 void SetUp() {
64 ASSERT_EQ(0, mTun.init());
65 }
66
TearDown()67 void TearDown() {
68 mTun.destroy();
69 }
70
expectSetupCommands(const std::string & expectedClean,std::string expectedAccounting)71 void expectSetupCommands(const std::string& expectedClean, std::string expectedAccounting) {
72 std::string expectedList =
73 "*filter\n"
74 "-S\n"
75 "COMMIT\n";
76
77 std::string expectedFlush =
78 "*filter\n"
79 ":bw_INPUT -\n"
80 ":bw_OUTPUT -\n"
81 ":bw_FORWARD -\n"
82 ":bw_happy_box -\n"
83 ":bw_penalty_box -\n"
84 ":bw_data_saver -\n"
85 ":bw_costly_shared -\n"
86 "COMMIT\n"
87 "*raw\n"
88 ":bw_raw_PREROUTING -\n"
89 "COMMIT\n"
90 "*mangle\n"
91 ":bw_mangle_POSTROUTING -\n"
92 "COMMIT\n";
93
94 ExpectedIptablesCommands expected = {{ V4, expectedList }};
95 if (expectedClean.size()) {
96 expected.push_back({ V4V6, expectedClean });
97 }
98 expected.push_back({ V4V6, expectedFlush });
99 if (expectedAccounting.size()) {
100 expected.push_back({ V4V6, expectedAccounting });
101 }
102
103 expectIptablesRestoreCommands(expected);
104 }
105
106 using IptOp = BandwidthController::IptOp;
107
runIptablesAlertCmd(IptOp a,const char * b,int64_t c)108 int runIptablesAlertCmd(IptOp a, const char *b, int64_t c) {
109 return mBw.runIptablesAlertCmd(a, b, c);
110 }
111
runIptablesAlertFwdCmd(IptOp a,const char * b,int64_t c)112 int runIptablesAlertFwdCmd(IptOp a, const char *b, int64_t c) {
113 return mBw.runIptablesAlertFwdCmd(a, b, c);
114 }
115
setCostlyAlert(const std::string a,int64_t b,int64_t * c)116 int setCostlyAlert(const std::string a, int64_t b, int64_t *c) {
117 return mBw.setCostlyAlert(a, b, c);
118 }
119
removeCostlyAlert(const std::string a,int64_t * b)120 int removeCostlyAlert(const std::string a, int64_t *b) {
121 return mBw.removeCostlyAlert(a, b);
122 }
123
expectUpdateQuota(uint64_t quota)124 void expectUpdateQuota(uint64_t quota) {
125 uintptr_t dummy;
126 FILE* dummyFile = reinterpret_cast<FILE*>(&dummy);
127
128 EXPECT_CALL(mSyscalls, fopen(_, _)).WillOnce(Return(ByMove(UniqueFile(dummyFile))));
129 EXPECT_CALL(mSyscalls, vfprintf(dummyFile, _, _))
130 .WillOnce(Invoke([quota](FILE*, const std::string&, va_list ap) {
131 EXPECT_EQ(quota, va_arg(ap, uint64_t));
132 return 0;
133 }));
134 EXPECT_CALL(mSyscalls, fclose(dummyFile)).WillOnce(Return(ok));
135 }
136
137 StrictMock<android::netdutils::ScopedMockSyscalls> mSyscalls;
138 };
139
TEST_F(BandwidthControllerTest,TestSetupIptablesHooks)140 TEST_F(BandwidthControllerTest, TestSetupIptablesHooks) {
141 // Pretend some bw_costly_shared_<iface> rules already exist...
142 addIptablesRestoreOutput(
143 "-P OUTPUT ACCEPT\n"
144 "-N bw_costly_rmnet_data0\n"
145 "-N bw_costly_shared\n"
146 "-N unrelated\n"
147 "-N bw_costly_rmnet_data7\n");
148
149 // ... and expect that they be flushed and deleted.
150 std::string expectedCleanCmds =
151 "*filter\n"
152 ":bw_costly_rmnet_data0 -\n"
153 "-X bw_costly_rmnet_data0\n"
154 ":bw_costly_rmnet_data7 -\n"
155 "-X bw_costly_rmnet_data7\n"
156 "COMMIT\n";
157
158 mBw.setupIptablesHooks();
159 expectSetupCommands(expectedCleanCmds, "");
160 }
161
TEST_F(BandwidthControllerTest,TestCheckUidBillingMask)162 TEST_F(BandwidthControllerTest, TestCheckUidBillingMask) {
163 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
164
165 // If mask is non-zero, and mask & mask-1 is equal to 0, then the mask is a power of two.
166 bool isPowerOfTwo = uidBillingMask && (uidBillingMask & (uidBillingMask - 1)) == 0;
167
168 // Must be exactly a power of two
169 EXPECT_TRUE(isPowerOfTwo);
170 }
171
TEST_F(BandwidthControllerTest,TestEnableBandwidthControl)172 TEST_F(BandwidthControllerTest, TestEnableBandwidthControl) {
173 // Pretend no bw_costly_shared_<iface> rules already exist...
174 addIptablesRestoreOutput(
175 "-P OUTPUT ACCEPT\n"
176 "-N bw_costly_shared\n"
177 "-N unrelated\n");
178
179 // ... so none are flushed or deleted.
180 std::string expectedClean = "";
181
182 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
183 bool useBpf = BandwidthController::getBpfStatsStatus();
184 std::string expectedAccounting =
185 "*filter\n"
186 "-A bw_INPUT -p esp -j RETURN\n" +
187 StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN\n",
188 uidBillingMask, uidBillingMask) +
189 "-A bw_INPUT -m owner --socket-exists\n" +
190 StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x\n", uidBillingMask) +
191 "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
192 "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
193 "-A bw_OUTPUT -m owner --socket-exists\n"
194 "-A bw_costly_shared --jump bw_penalty_box\n"
195 "-A bw_penalty_box --jump bw_happy_box\n"
196 "-A bw_happy_box --jump bw_data_saver\n"
197 "-A bw_data_saver -j RETURN\n"
198 "-I bw_happy_box -m owner --uid-owner 0-9999 --jump RETURN\n"
199 "COMMIT\n"
200 "*raw\n"
201 "-A bw_raw_PREROUTING -i " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
202 "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
203 "-A bw_raw_PREROUTING -m owner --socket-exists\n";
204 if (useBpf) {
205 expectedAccounting += StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s\n",
206 XT_BPF_INGRESS_PROG_PATH);
207 } else {
208 expectedAccounting += "\n";
209 }
210 expectedAccounting +=
211 "COMMIT\n"
212 "*mangle\n"
213 "-A bw_mangle_POSTROUTING -o " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
214 "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
215 "-A bw_mangle_POSTROUTING -m owner --socket-exists\n" +
216 StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x\n", uidBillingMask);
217 if (useBpf) {
218 expectedAccounting += StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s\n",
219 XT_BPF_EGRESS_PROG_PATH);
220 } else {
221 expectedAccounting += "\n";
222 }
223 expectedAccounting += "COMMIT\n";
224 mBw.enableBandwidthControl(false);
225 expectSetupCommands(expectedClean, expectedAccounting);
226 }
227
TEST_F(BandwidthControllerTest,TestDisableBandwidthControl)228 TEST_F(BandwidthControllerTest, TestDisableBandwidthControl) {
229 // Pretend some bw_costly_shared_<iface> rules already exist...
230 addIptablesRestoreOutput(
231 "-P OUTPUT ACCEPT\n"
232 "-N bw_costly_rmnet_data0\n"
233 "-N bw_costly_shared\n"
234 "-N unrelated\n"
235 "-N bw_costly_rmnet_data7\n");
236
237 // ... and expect that they be flushed.
238 std::string expectedCleanCmds =
239 "*filter\n"
240 ":bw_costly_rmnet_data0 -\n"
241 ":bw_costly_rmnet_data7 -\n"
242 "COMMIT\n";
243
244 mBw.disableBandwidthControl();
245 expectSetupCommands(expectedCleanCmds, "");
246 }
247
TEST_F(BandwidthControllerTest,TestEnableDataSaver)248 TEST_F(BandwidthControllerTest, TestEnableDataSaver) {
249 mBw.enableDataSaver(true);
250 std::string expected4 =
251 "*filter\n"
252 ":bw_data_saver -\n"
253 "-A bw_data_saver --jump REJECT\n"
254 "COMMIT\n";
255 std::string expected6 =
256 "*filter\n"
257 ":bw_data_saver -\n"
258 "-A bw_data_saver -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
259 "-A bw_data_saver -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
260 "-A bw_data_saver -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
261 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
262 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
263 "-A bw_data_saver -p icmpv6 --icmpv6-type redirect -j RETURN\n"
264 "-A bw_data_saver --jump REJECT\n"
265 "COMMIT\n";
266 expectIptablesRestoreCommands({
267 {V4, expected4},
268 {V6, expected6},
269 });
270
271 mBw.enableDataSaver(false);
272 std::string expected = {
273 "*filter\n"
274 ":bw_data_saver -\n"
275 "-A bw_data_saver --jump RETURN\n"
276 "COMMIT\n"
277 };
278 expectIptablesRestoreCommands({
279 {V4, expected},
280 {V6, expected},
281 });
282 }
283
makeInterfaceQuotaCommands(const std::string & iface,int ruleIndex,int64_t quota)284 const std::vector<std::string> makeInterfaceQuotaCommands(const std::string& iface, int ruleIndex,
285 int64_t quota) {
286 const std::string chain = "bw_costly_" + iface;
287 const char* c_chain = chain.c_str();
288 const char* c_iface = iface.c_str();
289 std::vector<std::string> cmds = {
290 "*filter",
291 StringPrintf(":%s -", c_chain),
292 StringPrintf("-A %s -j bw_penalty_box", c_chain),
293 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
294 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
295 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
296 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
297 StringPrintf("-A %s -m quota2 ! --quota %" PRIu64 " --name %s --jump REJECT", c_chain,
298 quota, c_iface),
299 "COMMIT\n",
300 };
301 return {Join(cmds, "\n")};
302 }
303
removeInterfaceQuotaCommands(const std::string & iface)304 const std::vector<std::string> removeInterfaceQuotaCommands(const std::string& iface) {
305 const std::string chain = "bw_costly_" + iface;
306 const char* c_chain = chain.c_str();
307 const char* c_iface = iface.c_str();
308 std::vector<std::string> cmds = {
309 "*filter",
310 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
311 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
312 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
313 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
314 StringPrintf("-F %s", c_chain),
315 StringPrintf("-X %s", c_chain),
316 "COMMIT\n",
317 };
318 return {Join(cmds, "\n")};
319 }
320
TEST_F(BandwidthControllerTest,TestSetInterfaceQuota)321 TEST_F(BandwidthControllerTest, TestSetInterfaceQuota) {
322 constexpr uint64_t kOldQuota = 123456;
323 const std::string iface = mTun.name();
324 std::vector<std::string> expected = makeInterfaceQuotaCommands(iface, 1, kOldQuota);
325
326 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kOldQuota));
327 expectIptablesRestoreCommands(expected);
328
329 constexpr uint64_t kNewQuota = kOldQuota + 1;
330 expected = {};
331 expectUpdateQuota(kNewQuota);
332 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kNewQuota));
333 expectIptablesRestoreCommands(expected);
334
335 expected = removeInterfaceQuotaCommands(iface);
336 EXPECT_EQ(0, mBw.removeInterfaceQuota(iface));
337 expectIptablesRestoreCommands(expected);
338 }
339
makeInterfaceSharedQuotaCommands(const std::string & iface,int ruleIndex,int64_t quota,bool insertQuota)340 const std::vector<std::string> makeInterfaceSharedQuotaCommands(const std::string& iface,
341 int ruleIndex, int64_t quota,
342 bool insertQuota) {
343 const std::string chain = "bw_costly_shared";
344 const char* c_chain = chain.c_str();
345 const char* c_iface = iface.c_str();
346 std::vector<std::string> cmds = {
347 "*filter",
348 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
349 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
350 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
351 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
352 };
353 if (insertQuota) {
354 cmds.push_back(StringPrintf(
355 "-I %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
356 }
357 cmds.push_back("COMMIT\n");
358 return {Join(cmds, "\n")};
359 }
360
removeInterfaceSharedQuotaCommands(const std::string & iface,int64_t quota,bool deleteQuota)361 const std::vector<std::string> removeInterfaceSharedQuotaCommands(const std::string& iface,
362 int64_t quota, bool deleteQuota) {
363 const std::string chain = "bw_costly_shared";
364 const char* c_chain = chain.c_str();
365 const char* c_iface = iface.c_str();
366 std::vector<std::string> cmds = {
367 "*filter",
368 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
369 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
370 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
371 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
372 };
373 if (deleteQuota) {
374 cmds.push_back(StringPrintf(
375 "-D %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
376 }
377 cmds.push_back("COMMIT\n");
378 return {Join(cmds, "\n")};
379 }
380
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaDuplicate)381 TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaDuplicate) {
382 constexpr uint64_t kQuota = 123456;
383 const std::string iface = mTun.name();
384 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, 123456, true);
385 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
386 expectIptablesRestoreCommands(expected);
387
388 expected = {};
389 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
390 expectIptablesRestoreCommands(expected);
391
392 expected = removeInterfaceSharedQuotaCommands(iface, kQuota, true);
393 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
394 expectIptablesRestoreCommands(expected);
395 }
396
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaUpdate)397 TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaUpdate) {
398 constexpr uint64_t kOldQuota = 123456;
399 const std::string iface = mTun.name();
400 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, kOldQuota, true);
401 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kOldQuota));
402 expectIptablesRestoreCommands(expected);
403
404 constexpr uint64_t kNewQuota = kOldQuota + 1;
405 expected = {};
406 expectUpdateQuota(kNewQuota);
407 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kNewQuota));
408 expectIptablesRestoreCommands(expected);
409
410 expected = removeInterfaceSharedQuotaCommands(iface, kNewQuota, true);
411 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
412 expectIptablesRestoreCommands(expected);
413 }
414
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaTwoInterfaces)415 TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaTwoInterfaces) {
416 constexpr uint64_t kQuota = 123456;
417 const std::vector<std::string> ifaces{
418 {"a" + mTun.name()},
419 {"b" + mTun.name()},
420 };
421
422 for (const auto& iface : ifaces) {
423 // Quota rule is only added when the total number of
424 // interfaces transitions from 0 -> 1.
425 bool first = (iface == ifaces[0]);
426 auto expected = makeInterfaceSharedQuotaCommands(iface, 1, kQuota, first);
427 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
428 expectIptablesRestoreCommands(expected);
429 }
430
431 for (const auto& iface : ifaces) {
432 // Quota rule is only removed when the total number of
433 // interfaces transitions from 1 -> 0.
434 bool last = (iface == ifaces[1]);
435 auto expected = removeInterfaceSharedQuotaCommands(iface, kQuota, last);
436 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
437 expectIptablesRestoreCommands(expected);
438 }
439 }
440
TEST_F(BandwidthControllerTest,IptablesAlertCmd)441 TEST_F(BandwidthControllerTest, IptablesAlertCmd) {
442 std::vector<std::string> expected = {
443 "*filter\n"
444 "-I bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
445 "-I bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
446 "COMMIT\n"
447 };
448 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
449 expectIptablesRestoreCommands(expected);
450
451 expected = {
452 "*filter\n"
453 "-D bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
454 "-D bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
455 "COMMIT\n"
456 };
457 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
458 expectIptablesRestoreCommands(expected);
459 }
460
TEST_F(BandwidthControllerTest,IptablesAlertFwdCmd)461 TEST_F(BandwidthControllerTest, IptablesAlertFwdCmd) {
462 std::vector<std::string> expected = {
463 "*filter\n"
464 "-I bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
465 "COMMIT\n"
466 };
467 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
468 expectIptablesRestoreCommands(expected);
469
470 expected = {
471 "*filter\n"
472 "-D bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
473 "COMMIT\n"
474 };
475 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
476 expectIptablesRestoreCommands(expected);
477 }
478
TEST_F(BandwidthControllerTest,CostlyAlert)479 TEST_F(BandwidthControllerTest, CostlyAlert) {
480 const int64_t kQuota = 123456;
481 int64_t alertBytes = 0;
482
483 std::vector<std::string> expected = {
484 "*filter\n"
485 "-A bw_costly_shared -m quota2 ! --quota 123456 --name sharedAlert\n"
486 "COMMIT\n"
487 };
488 EXPECT_EQ(0, setCostlyAlert("shared", kQuota, &alertBytes));
489 EXPECT_EQ(kQuota, alertBytes);
490 expectIptablesRestoreCommands(expected);
491
492 expected = {};
493 expectUpdateQuota(kQuota);
494 EXPECT_EQ(0, setCostlyAlert("shared", kQuota + 1, &alertBytes));
495 EXPECT_EQ(kQuota + 1, alertBytes);
496 expectIptablesRestoreCommands(expected);
497
498 expected = {
499 "*filter\n"
500 "-D bw_costly_shared -m quota2 ! --quota 123457 --name sharedAlert\n"
501 "COMMIT\n"
502 };
503 EXPECT_EQ(0, removeCostlyAlert("shared", &alertBytes));
504 EXPECT_EQ(0, alertBytes);
505 expectIptablesRestoreCommands(expected);
506 }
507
TEST_F(BandwidthControllerTest,ManipulateSpecialApps)508 TEST_F(BandwidthControllerTest, ManipulateSpecialApps) {
509 std::vector<const char *> appUids = { "1000", "1001", "10012" };
510
511 std::vector<std::string> expected = {
512 "*filter\n"
513 "-I bw_happy_box -m owner --uid-owner 1000 --jump RETURN\n"
514 "-I bw_happy_box -m owner --uid-owner 1001 --jump RETURN\n"
515 "-I bw_happy_box -m owner --uid-owner 10012 --jump RETURN\n"
516 "COMMIT\n"
517 };
518 EXPECT_EQ(0, mBw.addNiceApps(appUids.size(), const_cast<char**>(&appUids[0])));
519 expectIptablesRestoreCommands(expected);
520
521 expected = {
522 "*filter\n"
523 "-D bw_penalty_box -m owner --uid-owner 1000 --jump REJECT\n"
524 "-D bw_penalty_box -m owner --uid-owner 1001 --jump REJECT\n"
525 "-D bw_penalty_box -m owner --uid-owner 10012 --jump REJECT\n"
526 "COMMIT\n"
527 };
528 EXPECT_EQ(0, mBw.removeNaughtyApps(appUids.size(), const_cast<char**>(&appUids[0])));
529 expectIptablesRestoreCommands(expected);
530 }
531