Refactor NetworkStatsFactoryTest
This patch changes the way of mocking samples in the tests, and
enabling use bpf stats flag, testing through the code path
that is not running in the production code does not make any
sense.
This change also copied methods from NetworkStatsFactory
as we want to continue parsing the golden files to test the
464xlat adjustment which historically has been prone to errors.
And deleting tests that does not execrise NetworkStatsFactory
code or rely on monotonic accumulative readings from native
layer, which is not happening today.
Bug: 234315786
Test: atest FrameworksNetTests CtsNetTestCases \
ConnectivityCoverageTests
Change-Id: I5cab2b78651f1da628705c191e42857c8b59d826
This commit is contained in:
@@ -33,23 +33,27 @@ import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.TrafficStats;
|
||||
import android.net.UnderlyingNetworkInfo;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.frameworks.tests.net.R;
|
||||
import com.android.internal.util.ProcFileReader;
|
||||
import com.android.server.BpfNetMaps;
|
||||
import com.android.testutils.DevSdkIgnoreRule;
|
||||
import com.android.testutils.DevSdkIgnoreRunner;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
import libcore.io.Streams;
|
||||
import libcore.testing.io.TestIoUtils;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -60,10 +64,8 @@ import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
|
||||
/** Tests for {@link NetworkStatsFactory}. */
|
||||
@RunWith(DevSdkIgnoreRunner.class)
|
||||
@@ -75,6 +77,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
private File mTestProc;
|
||||
private NetworkStatsFactory mFactory;
|
||||
@Mock private Context mContext;
|
||||
@Mock private NetworkStatsFactory.Dependencies mDeps;
|
||||
@Mock private BpfNetMaps mBpfNetMaps;
|
||||
|
||||
@Before
|
||||
@@ -86,7 +89,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// applications. So in order to have a test support native library, the native code
|
||||
// related to networkStatsFactory is compiled to a minimal native library and loaded here.
|
||||
System.loadLibrary("networkstatsfactorytestjni");
|
||||
mFactory = new NetworkStatsFactory(mContext, mTestProc, false, mBpfNetMaps);
|
||||
doReturn(mBpfNetMaps).when(mDeps).createBpfNetMaps(any());
|
||||
mFactory = new NetworkStatsFactory(mContext, mTestProc, true, mDeps);
|
||||
mFactory.updateUnderlyingNetworkInfos(new UnderlyingNetworkInfo[0]);
|
||||
}
|
||||
|
||||
@@ -97,7 +101,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
|
||||
@Test
|
||||
public void testNetworkStatsDetail() throws Exception {
|
||||
final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
|
||||
final NetworkStats stats = factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_typical);
|
||||
|
||||
assertEquals(70, stats.size());
|
||||
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 18621L, 2898L);
|
||||
@@ -122,8 +126,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// over VPN.
|
||||
//
|
||||
// VPN UID rewrites packets read from TUN back to TUN, plus some of its own traffic
|
||||
|
||||
final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_rewrite_through_self);
|
||||
final NetworkStats tunStats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_rewrite_through_self);
|
||||
|
||||
assertValues(tunStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
|
||||
DEFAULT_NETWORK_ALL, 2000L, 200L, 1000L, 100L, 0);
|
||||
@@ -164,7 +168,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// UID_RED: 2000 bytes, 200 packets
|
||||
// UID_BLUE: 1000 bytes, 100 packets
|
||||
// UID_VPN: 6300 bytes, 0 packets
|
||||
final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_with_clat);
|
||||
final NetworkStats tunStats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_with_clat);
|
||||
|
||||
assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_RED, 2000L, 200L, 1000, 100L);
|
||||
assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
|
||||
@@ -188,7 +193,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
|
||||
// Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
|
||||
// attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
|
||||
final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying);
|
||||
final NetworkStats tunStats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_one_underlying);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
|
||||
@@ -217,7 +223,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// Of 8800 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
|
||||
// attributed to UID_BLUE, and 5800 bytes attributed to UID_VPN.
|
||||
final NetworkStats tunStats =
|
||||
parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_own_traffic);
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_one_underlying_own_traffic);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
|
||||
@@ -239,7 +245,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
|
||||
// with nothing attributed to UID_VPN for both rx/tx traffic.
|
||||
final NetworkStats tunStats =
|
||||
parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_compression);
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_one_underlying_compression);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 250L, 25L, 250L, 25L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_BLUE, 750L, 75L, 750L, 75L);
|
||||
@@ -263,7 +269,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// - 500 bytes rx/tx each over WiFi/Cell attributed to both UID_RED and UID_BLUE.
|
||||
// - 1200 bytes rx/tx each over WiFi/Cell for VPN_UID.
|
||||
final NetworkStats tunStats =
|
||||
parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_duplication);
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_two_underlying_duplication);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 500L, 50L, 500L, 50L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_BLUE, 500L, 50L, 500L, 50L);
|
||||
@@ -303,7 +309,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// Of 3850 bytes received over Cell, expect 3000 bytes attributed to UID_RED, 500 bytes
|
||||
// attributed to UID_BLUE, and 350 bytes attributed to UID_VPN.
|
||||
final NetworkStats tunStats =
|
||||
parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_two_vpn);
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_one_underlying_two_vpn);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
|
||||
@@ -333,7 +339,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
//
|
||||
// For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for tx traffic.
|
||||
// And, 30 bytes over WiFi and 20 bytes over Cell for rx traffic.
|
||||
final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split);
|
||||
final NetworkStats tunStats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_two_underlying_split);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 300L, 30L, 600L, 60L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_VPN, 30L, 0L, 60L, 0L);
|
||||
@@ -357,7 +364,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// rx/tx.
|
||||
// UID_VPN gets nothing attributed to it (avoiding negative stats).
|
||||
final NetworkStats tunStats =
|
||||
parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split_compression);
|
||||
factoryReadNetworkStatsDetail(
|
||||
R.raw.xt_qtaguid_vpn_two_underlying_split_compression);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 600L, 60L, 600L, 60L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
|
||||
@@ -378,7 +386,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
|
||||
// VPN sent/received 1100 bytes (100 packets) over Cell.
|
||||
// Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
|
||||
final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_incorrect_iface);
|
||||
final NetworkStats tunStats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_vpn_incorrect_iface);
|
||||
|
||||
assertValues(tunStats, TEST_IFACE, UID_RED, 0L, 0L, 0L, 0L);
|
||||
assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
|
||||
@@ -403,36 +412,15 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
|
||||
@Test
|
||||
public void testNetworkStatsWithSet() throws Exception {
|
||||
final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
|
||||
final NetworkStats stats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_typical);
|
||||
|
||||
assertEquals(70, stats.size());
|
||||
assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L,
|
||||
676L);
|
||||
assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkStatsSingle() throws Exception {
|
||||
stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all"));
|
||||
|
||||
final NetworkStats stats = mFactory.readNetworkStatsSummaryDev();
|
||||
assertEquals(6, stats.size());
|
||||
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 2112L, 24L, 700L, 10L);
|
||||
assertStatsEntry(stats, "test1", UID_ALL, SET_ALL, TAG_NONE, 6L, 8L, 10L, 12L);
|
||||
assertStatsEntry(stats, "test2", UID_ALL, SET_ALL, TAG_NONE, 1L, 2L, 3L, 4L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkStatsXt() throws Exception {
|
||||
stageFile(R.raw.xt_qtaguid_iface_fmt_typical, file("net/xt_qtaguid/iface_stat_fmt"));
|
||||
|
||||
final NetworkStats stats = mFactory.readNetworkStatsSummaryXt();
|
||||
assertEquals(3, stats.size());
|
||||
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L);
|
||||
assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L,
|
||||
2468L);
|
||||
assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleClatAccountingSimple() throws Exception {
|
||||
mFactory.noteStackedIface("v4-wlan0", "wlan0");
|
||||
@@ -441,7 +429,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
// - 213 received 464xlat packets of size 200 bytes
|
||||
// - 41 sent 464xlat packets of size 100 bytes
|
||||
// - no other traffic on base interface for root uid.
|
||||
NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_simple);
|
||||
final NetworkStats stats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_with_clat_simple);
|
||||
assertEquals(3, stats.size());
|
||||
|
||||
assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 46860L, 4920L);
|
||||
@@ -452,7 +441,8 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
public void testDoubleClatAccounting() throws Exception {
|
||||
mFactory.noteStackedIface("v4-wlan0", "wlan0");
|
||||
|
||||
NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat);
|
||||
final NetworkStats stats =
|
||||
factoryReadNetworkStatsDetail(R.raw.xt_qtaguid_with_clat);
|
||||
assertEquals(42, stats.size());
|
||||
|
||||
assertStatsEntry(stats, "v4-wlan0", 0, SET_DEFAULT, 0x0, 356L, 276L);
|
||||
@@ -473,65 +463,78 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
|
||||
assertNoStatsEntry(stats, "wlan0", 1029, SET_DEFAULT, 0x0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleClatAccounting100MBDownload() throws Exception {
|
||||
// Downloading 100mb from an ipv4 only destination in a foreground activity
|
||||
|
||||
long appRxBytesBefore = 328684029L;
|
||||
long appRxBytesAfter = 439237478L;
|
||||
assertEquals("App traffic should be ~100MB", 110553449, appRxBytesAfter - appRxBytesBefore);
|
||||
|
||||
long rootRxBytes = 330187296L;
|
||||
|
||||
mFactory.noteStackedIface("v4-wlan0", "wlan0");
|
||||
NetworkStats stats;
|
||||
|
||||
// Stats snapshot before the download
|
||||
stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_before);
|
||||
assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesBefore, 5199872L);
|
||||
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L);
|
||||
|
||||
// Stats snapshot after the download
|
||||
stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after);
|
||||
assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
|
||||
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a {@link Resources#openRawResource(int)} into {@link File} for
|
||||
* testing purposes.
|
||||
*/
|
||||
private void stageFile(int rawId, File file) throws Exception {
|
||||
new File(file.getParent()).mkdirs();
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
private NetworkStats parseNetworkStatsFromGoldenSample(int resourceId, int initialSize,
|
||||
boolean consumeHeader, boolean checkActive, boolean isUidData) throws IOException {
|
||||
final NetworkStats stats =
|
||||
new NetworkStats(SystemClock.elapsedRealtime(), initialSize);
|
||||
final NetworkStats.Entry entry = new NetworkStats.Entry();
|
||||
ProcFileReader reader = null;
|
||||
int idx = 1;
|
||||
int lastIdx = 1;
|
||||
try {
|
||||
in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
|
||||
out = new FileOutputStream(file);
|
||||
Streams.copy(in, out);
|
||||
reader = new ProcFileReader(InstrumentationRegistry.getContext().getResources()
|
||||
.openRawResource(resourceId));
|
||||
|
||||
if (consumeHeader) {
|
||||
reader.finishLine();
|
||||
}
|
||||
|
||||
while (reader.hasMoreData()) {
|
||||
if (isUidData) {
|
||||
idx = reader.nextInt();
|
||||
if (idx != lastIdx + 1) {
|
||||
throw new ProtocolException(
|
||||
"inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
|
||||
}
|
||||
lastIdx = idx;
|
||||
}
|
||||
|
||||
entry.iface = reader.nextString();
|
||||
// Read the uid based information from file. Otherwise, assign with target value.
|
||||
entry.tag = isUidData ? kernelToTag(reader.nextString()) : TAG_NONE;
|
||||
entry.uid = isUidData ? reader.nextInt() : UID_ALL;
|
||||
entry.set = isUidData ? reader.nextInt() : SET_ALL;
|
||||
|
||||
// For fetching active numbers. Dev specific
|
||||
final boolean active = checkActive ? reader.nextInt() != 0 : false;
|
||||
|
||||
// Always include snapshot values
|
||||
entry.rxBytes = reader.nextLong();
|
||||
entry.rxPackets = reader.nextLong();
|
||||
entry.txBytes = reader.nextLong();
|
||||
entry.txPackets = reader.nextLong();
|
||||
|
||||
// Fold in active numbers, but only when active
|
||||
if (active) {
|
||||
entry.rxBytes += reader.nextLong();
|
||||
entry.rxPackets += reader.nextLong();
|
||||
entry.txBytes += reader.nextLong();
|
||||
entry.txPackets += reader.nextLong();
|
||||
}
|
||||
|
||||
stats.insertEntry(entry);
|
||||
reader.finishLine();
|
||||
}
|
||||
} catch (NullPointerException | NumberFormatException e) {
|
||||
final String errMsg = isUidData
|
||||
? "problem parsing idx " + idx : "problem parsing stats";
|
||||
final ProtocolException pe = new ProtocolException(errMsg);
|
||||
pe.initCause(e);
|
||||
throw pe;
|
||||
} finally {
|
||||
IoUtils.closeQuietly(in);
|
||||
IoUtils.closeQuietly(out);
|
||||
IoUtils.closeQuietly(reader);
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
private void stageLong(long value, File file) throws Exception {
|
||||
new File(file.getParent()).mkdirs();
|
||||
FileWriter out = null;
|
||||
try {
|
||||
out = new FileWriter(file);
|
||||
out.write(Long.toString(value));
|
||||
} finally {
|
||||
IoUtils.closeQuietly(out);
|
||||
}
|
||||
}
|
||||
|
||||
private File file(String path) throws Exception {
|
||||
return new File(mTestProc, path);
|
||||
}
|
||||
|
||||
private NetworkStats parseDetailedStats(int resourceId) throws Exception {
|
||||
stageFile(resourceId, file("net/xt_qtaguid/stats"));
|
||||
private NetworkStats factoryReadNetworkStatsDetail(int resourceId) throws Exception {
|
||||
// Choose a general detail stats sample size from the experiences to prevent from
|
||||
// frequently allocating buckets.
|
||||
final NetworkStats statsFromResource = parseNetworkStatsFromGoldenSample(resourceId,
|
||||
24 /* initialSize */, true /* consumeHeader */, false /* checkActive */,
|
||||
true /* isUidData */);
|
||||
doReturn(statsFromResource).when(mDeps).getNetworkStatsDetail(any(), anyInt(), any(),
|
||||
anyInt(), anyBoolean());
|
||||
return mFactory.readNetworkStatsDetail();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user