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