• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 
17 package com.android.server.net
18 
19 import android.util.IndentingPrintWriter
20 import com.android.server.net.NetworkStatsEventLogger.MAX_POLL_REASON
21 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_DUMPSYS
22 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_FORCE_UPDATE
23 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_GLOBAL_ALERT
24 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_NETWORK_STATUS_CHANGED
25 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_OPEN_SESSION
26 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_PERIODIC
27 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED
28 import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REG_CALLBACK
29 import com.android.server.net.NetworkStatsEventLogger.PollEvent
30 import com.android.server.net.NetworkStatsEventLogger.PollEvent.pollReasonNameOf
31 import com.android.testutils.DevSdkIgnoreRunner
32 import java.io.StringWriter
33 import kotlin.test.assertEquals
34 import kotlin.test.assertFailsWith
35 import kotlin.test.assertFalse
36 import kotlin.test.assertTrue
37 import org.junit.Test
38 import org.junit.runner.RunWith
39 
40 const val TEST_PERSIST_FLAG = 0x101
41 
42 @RunWith(DevSdkIgnoreRunner::class)
43 class NetworkStatsEventLoggerTest {
44     val logger = NetworkStatsEventLogger()
45     val stringWriter = TestStringWriter()
46     val pw = IndentingPrintWriter(stringWriter)
47 
48     @Test
testDump_invalidnull49     fun testDump_invalid() {
50         // Verify it won't crash.
51         logger.dump(pw)
52         // Clear output buffer.
53         stringWriter.getOutputAndClear()
54 
55         // Verify log invalid event throws. And nothing output in the dump.
56         val invalidReasons = listOf(-1, MAX_POLL_REASON + 1)
57         invalidReasons.forEach {
58             assertFailsWith<IllegalArgumentException> {
59                 logger.logPollEvent(TEST_PERSIST_FLAG, PollEvent(it))
60             }
61             logger.dumpRecentPollEvents(pw)
62             val output = stringWriter.getOutputAndClear()
63             assertStringNotContains(output, pollReasonNameOf(it))
64         }
65     }
66 
67     @Test
testDump_validnull68     fun testDump_valid() {
69         // Choose arbitrary set of reasons for testing.
70         val loggedReasons = listOf(
71             POLL_REASON_GLOBAL_ALERT,
72             POLL_REASON_FORCE_UPDATE,
73             POLL_REASON_DUMPSYS,
74             POLL_REASON_PERIODIC,
75             POLL_REASON_RAT_CHANGED
76         )
77         val nonLoggedReasons = listOf(
78             POLL_REASON_NETWORK_STATUS_CHANGED,
79             POLL_REASON_OPEN_SESSION,
80             POLL_REASON_REG_CALLBACK)
81 
82         // Add some valid records.
83         loggedReasons.forEach {
84             logger.logPollEvent(TEST_PERSIST_FLAG, PollEvent(it))
85         }
86 
87         // Collect dumps.
88         logger.dumpRecentPollEvents(pw)
89         val outputRecentEvents = stringWriter.getOutputAndClear()
90         logger.dumpPollCountsPerReason(pw)
91         val outputCountsPerReason = stringWriter.getOutputAndClear()
92 
93         // Verify the output contains at least necessary information.
94         loggedReasons.forEach {
95             // Verify all events are shown in the recent event dump.
96             val eventString = PollEvent(it).toString()
97             assertStringContains(outputRecentEvents, TEST_PERSIST_FLAG.toString())
98             assertStringContains(eventString, pollReasonNameOf(it))
99             assertStringContains(outputRecentEvents, eventString)
100             // Verify counts are 1 for each reason.
101             assertCountForReason(outputCountsPerReason, it, 1)
102         }
103 
104         // Verify the output remains untouched for other reasons.
105         nonLoggedReasons.forEach {
106             assertStringNotContains(outputRecentEvents, PollEvent(it).toString())
107             assertCountForReason(outputCountsPerReason, it, 0)
108         }
109     }
110 
111     @Test
testDump_maxEventLogsnull112     fun testDump_maxEventLogs() {
113         // Choose arbitrary reason.
114         val reasonToBeTested = POLL_REASON_PERIODIC
115         val repeatCount = NetworkStatsEventLogger.MAX_EVENTS_LOGS * 2
116 
117         // Collect baseline.
118         logger.dumpRecentPollEvents(pw)
119         val lineCountBaseLine = getLineCount(stringWriter.getOutputAndClear())
120 
121         repeat(repeatCount) {
122             logger.logPollEvent(TEST_PERSIST_FLAG, PollEvent(reasonToBeTested))
123         }
124 
125         // Collect dump.
126         logger.dumpRecentPollEvents(pw)
127         val lineCountAfterTest = getLineCount(stringWriter.getOutputAndClear())
128 
129         // Verify line count increment is limited.
130         assertEquals(
131             NetworkStatsEventLogger.MAX_EVENTS_LOGS,
132             lineCountAfterTest - lineCountBaseLine
133         )
134 
135         // Verify count per reason increased for the testing reason.
136         logger.dumpPollCountsPerReason(pw)
137         val outputCountsPerReason = stringWriter.getOutputAndClear()
138         for (reason in 0..MAX_POLL_REASON) {
139             assertCountForReason(
140                 outputCountsPerReason,
141                 reason,
142                 if (reason == reasonToBeTested) repeatCount else 0
143             )
144         }
145     }
146 
getLineCountnull147     private fun getLineCount(multilineString: String) = multilineString.lines().size
148 
149     private fun assertStringContains(got: String, want: String) {
150         assertTrue(got.contains(want), "Wanted: $want, but got: $got")
151     }
152 
assertStringNotContainsnull153     private fun assertStringNotContains(got: String, unwant: String) {
154         assertFalse(got.contains(unwant), "Unwanted: $unwant, but got: $got")
155     }
156 
157     /**
158      * Assert the reason and the expected count are at the same line.
159      */
assertCountForReasonnull160     private fun assertCountForReason(dump: String, reason: Int, expectedCount: Int) {
161         // Matches strings like "GLOBAL_ALERT: 50" but not too strict since the format might change.
162         val regex = Regex(pollReasonNameOf(reason) + "[^0-9]+" + expectedCount)
163         assertEquals(
164             1,
165             regex.findAll(dump).count(),
166             "Unexpected output: $dump " + " for reason: " + pollReasonNameOf(reason)
167         )
168     }
169 
170     class TestStringWriter : StringWriter() {
<lambda>null171         fun getOutputAndClear() = toString().also { buffer.setLength(0) }
172     }
173 }
174