blob: 2ed12bdff9221bef3454d81e3ce526680aa9e8fe [file] [log] [blame]
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -07001/*
2 * Copyright (C) 2021 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
17package com.android.car.telemetry.publisher;
18
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -070019import static com.android.car.telemetry.AtomsProto.Atom.APP_START_MEMORY_STATE_CAPTURED_FIELD_NUMBER;
20import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_MEMORY_STATE_FIELD_NUMBER;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070021import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_START_MEMORY_STATE_CAPTURED;
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -070022import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_STATE;
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -070023import static com.android.car.telemetry.publisher.StatsPublisher.APP_START_MEMORY_STATE_CAPTURED_ATOM_MATCHER_ID;
24import static com.android.car.telemetry.publisher.StatsPublisher.APP_START_MEMORY_STATE_CAPTURED_EVENT_METRIC_ID;
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -070025import static com.android.car.telemetry.publisher.StatsPublisher.PROCESS_MEMORY_STATE_FIELDS_MATCHER;
26import static com.android.car.telemetry.publisher.StatsPublisher.PROCESS_MEMORY_STATE_GAUGE_METRIC_ID;
27import static com.android.car.telemetry.publisher.StatsPublisher.PROCESS_MEMORY_STATE_MATCHER_ID;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070028
29import static com.google.common.truth.Truth.assertThat;
30
Zhomart Mukhamejanovfb4f29d2021-08-26 17:28:07 -070031import static org.mockito.ArgumentMatchers.any;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070032import static org.mockito.ArgumentMatchers.anyLong;
Zhomart Mukhamejanovfb4f29d2021-08-26 17:28:07 -070033import static org.mockito.Mockito.doThrow;
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -070034import static org.mockito.Mockito.times;
35import static org.mockito.Mockito.verify;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070036import static org.mockito.Mockito.when;
37
Zhomart Mukhamejanovfb4f29d2021-08-26 17:28:07 -070038import android.app.StatsManager;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070039import android.os.Looper;
40import android.os.Message;
Max Dashoukdafdd222021-08-20 10:42:25 -070041import android.os.PersistableBundle;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070042import android.os.SystemClock;
43
Howard Hao2f22ed02021-09-28 11:53:37 -070044import com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured;
45import com.android.car.telemetry.AtomsProto.Atom;
46import com.android.car.telemetry.AtomsProto.ProcessMemoryState;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070047import com.android.car.telemetry.StatsLogProto;
Howard Hao2f22ed02021-09-28 11:53:37 -070048import com.android.car.telemetry.StatsLogProto.ConfigMetricsReport;
49import com.android.car.telemetry.StatsLogProto.DimensionsValue;
50import com.android.car.telemetry.StatsLogProto.DimensionsValueTuple;
51import com.android.car.telemetry.StatsLogProto.EventMetricData;
52import com.android.car.telemetry.StatsLogProto.GaugeBucketInfo;
53import com.android.car.telemetry.StatsLogProto.GaugeMetricData;
54import com.android.car.telemetry.StatsLogProto.StatsLogReport;
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -070055import com.android.car.telemetry.StatsdConfigProto;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070056import com.android.car.telemetry.TelemetryProto;
57import com.android.car.telemetry.databroker.DataSubscriber;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070058import com.android.car.test.FakeHandlerWrapper;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070059
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070060import com.google.common.collect.Range;
61
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070062import org.junit.Before;
63import org.junit.Test;
64import org.junit.runner.RunWith;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070065import org.mockito.ArgumentCaptor;
66import org.mockito.Captor;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070067import org.mockito.Mock;
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -070068import org.mockito.Mockito;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070069import org.mockito.junit.MockitoJUnitRunner;
70
Rui Qiuda9f0ba2021-09-14 12:15:37 -070071import java.io.File;
72import java.io.FileInputStream;
73import java.nio.file.Files;
Howard Hao2f22ed02021-09-28 11:53:37 -070074import java.util.Arrays;
Rui Qiuda9f0ba2021-09-14 12:15:37 -070075
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070076@RunWith(MockitoJUnitRunner.class)
77public class StatsPublisherTest {
78 private static final TelemetryProto.Publisher STATS_PUBLISHER_PARAMS_1 =
79 TelemetryProto.Publisher.newBuilder()
80 .setStats(TelemetryProto.StatsPublisher.newBuilder()
81 .setSystemMetric(APP_START_MEMORY_STATE_CAPTURED))
82 .build();
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -070083 private static final TelemetryProto.Publisher STATS_PUBLISHER_PARAMS_2 =
84 TelemetryProto.Publisher.newBuilder()
85 .setStats(TelemetryProto.StatsPublisher.newBuilder()
86 .setSystemMetric(PROCESS_MEMORY_STATE))
87 .build();
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070088 private static final TelemetryProto.Subscriber SUBSCRIBER_1 =
89 TelemetryProto.Subscriber.newBuilder()
90 .setHandler("handler_fn_1")
91 .setPublisher(STATS_PUBLISHER_PARAMS_1)
92 .build();
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -070093 private static final TelemetryProto.Subscriber SUBSCRIBER_2 =
94 TelemetryProto.Subscriber.newBuilder()
95 .setHandler("handler_fn_2")
96 .setPublisher(STATS_PUBLISHER_PARAMS_2)
97 .build();
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -070098 private static final TelemetryProto.MetricsConfig METRICS_CONFIG =
99 TelemetryProto.MetricsConfig.newBuilder()
100 .setName("myconfig")
101 .setVersion(1)
102 .addSubscribers(SUBSCRIBER_1)
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700103 .addSubscribers(SUBSCRIBER_2)
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700104 .build();
105
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700106 private static final long SUBSCRIBER_1_HASH = -8101507323446050791L; // Used as ID.
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700107 private static final long SUBSCRIBER_2_HASH = 2778197004730583271L; // Used as ID.
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700108
109 private static final StatsdConfigProto.StatsdConfig STATSD_CONFIG_1 =
110 StatsdConfigProto.StatsdConfig.newBuilder()
111 .setId(SUBSCRIBER_1_HASH)
112 .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
113 .setId(APP_START_MEMORY_STATE_CAPTURED_ATOM_MATCHER_ID)
114 .setSimpleAtomMatcher(
115 StatsdConfigProto.SimpleAtomMatcher.newBuilder()
116 .setAtomId(
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700117 APP_START_MEMORY_STATE_CAPTURED_FIELD_NUMBER)))
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700118 .addEventMetric(StatsdConfigProto.EventMetric.newBuilder()
119 .setId(APP_START_MEMORY_STATE_CAPTURED_EVENT_METRIC_ID)
120 .setWhat(APP_START_MEMORY_STATE_CAPTURED_ATOM_MATCHER_ID))
121 .addAllowedLogSource("AID_SYSTEM")
122 .build();
123
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700124 private static final StatsdConfigProto.StatsdConfig STATSD_CONFIG_2 =
125 StatsdConfigProto.StatsdConfig.newBuilder()
126 .setId(SUBSCRIBER_2_HASH)
127 .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
128 // The id must be unique within StatsdConfig/matchers
129 .setId(PROCESS_MEMORY_STATE_MATCHER_ID)
130 .setSimpleAtomMatcher(StatsdConfigProto.SimpleAtomMatcher.newBuilder()
131 .setAtomId(PROCESS_MEMORY_STATE_FIELD_NUMBER)))
132 .addGaugeMetric(StatsdConfigProto.GaugeMetric.newBuilder()
133 // The id must be unique within StatsdConfig/metrics
134 .setId(PROCESS_MEMORY_STATE_GAUGE_METRIC_ID)
135 .setWhat(PROCESS_MEMORY_STATE_MATCHER_ID)
136 .setDimensionsInWhat(StatsdConfigProto.FieldMatcher.newBuilder()
137 .setField(PROCESS_MEMORY_STATE_FIELD_NUMBER)
138 .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
139 .setField(1)) // ProcessMemoryState.uid
140 .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
141 .setField(2)) // ProcessMemoryState.process_name
142 )
143 .setGaugeFieldsFilter(StatsdConfigProto.FieldFilter.newBuilder()
144 .setFields(PROCESS_MEMORY_STATE_FIELDS_MATCHER))
145 .setSamplingType(
146 StatsdConfigProto.GaugeMetric.SamplingType.RANDOM_ONE_SAMPLE)
147 .setBucket(StatsdConfigProto.TimeUnit.FIVE_MINUTES)
148 )
149 .addAllowedLogSource("AID_SYSTEM")
150 .addPullAtomPackages(StatsdConfigProto.PullAtomPackages.newBuilder()
151 .setAtomId(PROCESS_MEMORY_STATE_FIELD_NUMBER)
152 .addPackages("AID_SYSTEM"))
153 .build();
154
Howard Hao2f22ed02021-09-28 11:53:37 -0700155 private static final EventMetricData EVENT_DATA =
156 EventMetricData.newBuilder()
157 .setElapsedTimestampNanos(99999999L)
158 .setAtom(Atom.newBuilder()
159 .setAppStartMemoryStateCaptured(
160 AppStartMemoryStateCaptured.newBuilder()
161 .setUid(1000)
162 .setActivityName("activityName")
163 .setRssInBytes(1234L)))
164 .build();
165
166 private static final GaugeMetricData GAUGE_DATA =
167 GaugeMetricData.newBuilder()
168 .addBucketInfo(GaugeBucketInfo.newBuilder()
169 .addAtom(Atom.newBuilder()
170 .setProcessMemoryState(ProcessMemoryState.newBuilder()
171 .setRssInBytes(4567L)))
172 .addElapsedTimestampNanos(445678901L))
173 .addDimensionLeafValuesInWhat(DimensionsValue.newBuilder()
174 .setValueInt(234))
175 .build();
176
177 private static final StatsLogProto.ConfigMetricsReportList STATS_REPORT =
178 StatsLogProto.ConfigMetricsReportList.newBuilder()
179 .addReports(ConfigMetricsReport.newBuilder()
180 .addMetrics(StatsLogReport.newBuilder()
181 .setMetricId(APP_START_MEMORY_STATE_CAPTURED_EVENT_METRIC_ID)
182 .setEventMetrics(
183 StatsLogReport.EventMetricDataWrapper.newBuilder()
184 .addData(EVENT_DATA))))
185 .addReports(ConfigMetricsReport.newBuilder()
186 .addMetrics(StatsLogReport.newBuilder()
187 .setMetricId(PROCESS_MEMORY_STATE_GAUGE_METRIC_ID)
188 .setGaugeMetrics(
189 StatsLogReport.GaugeMetricDataWrapper.newBuilder()
190 .addData(GAUGE_DATA))
191 .setDimensionsPathInWhat(DimensionsValue.newBuilder()
192 .setValueTuple(DimensionsValueTuple.newBuilder()
193 .addDimensionsValue(DimensionsValue.newBuilder()
194 .setField(1))))))
195 .build();
196
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700197 private static final StatsLogProto.ConfigMetricsReportList EMPTY_STATS_REPORT =
198 StatsLogProto.ConfigMetricsReportList.newBuilder().build();
199
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700200 private static final DataSubscriber DATA_SUBSCRIBER_1 =
201 new DataSubscriber(null, METRICS_CONFIG, SUBSCRIBER_1);
202
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700203 private final FakeHandlerWrapper mFakeHandlerWrapper =
204 new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.QUEUEING);
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700205
206 private File mRootDirectory;
207 private StatsPublisher mPublisher; // subject
Zhomart Mukhamejanovfb4f29d2021-08-26 17:28:07 -0700208 private Throwable mPublisherFailure;
209
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700210 @Mock private StatsManagerProxy mStatsManager;
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700211
Max Dashoukdafdd222021-08-20 10:42:25 -0700212 @Captor private ArgumentCaptor<PersistableBundle> mBundleCaptor;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700213
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700214 @Before
215 public void setUp() throws Exception {
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700216 mRootDirectory = Files.createTempDirectory("telemetry_test").toFile();
Zhomart Mukhamejanova16bfc92021-08-25 18:36:16 -0700217 mPublisher = createRestartedPublisher();
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700218 }
219
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700220 /**
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700221 * Emulates a restart by creating a new StatsPublisher. StatsManager and PersistableBundle
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700222 * stays the same.
223 */
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700224 private StatsPublisher createRestartedPublisher() throws Exception {
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700225 return new StatsPublisher(
Zhomart Mukhamejanova16bfc92021-08-25 18:36:16 -0700226 this::onPublisherFailure,
227 mStatsManager,
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700228 mRootDirectory,
Zhomart Mukhamejanova16bfc92021-08-25 18:36:16 -0700229 mFakeHandlerWrapper.getMockHandler());
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700230 }
231
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700232 @Test
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700233 public void testAddDataSubscriber_registersNewListener() throws Exception {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700234 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700235
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700236 verify(mStatsManager, times(1))
237 .addConfig(SUBSCRIBER_1_HASH, STATSD_CONFIG_1.toByteArray());
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700238 assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isTrue();
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700239 }
240
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700241 @Test
242 public void testAddDataSubscriber_sameVersion_addsToStatsdOnce() throws Exception {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700243 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
244 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700245
246 verify(mStatsManager, times(1))
247 .addConfig(SUBSCRIBER_1_HASH, STATSD_CONFIG_1.toByteArray());
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700248 assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isTrue();
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700249 }
250
251 @Test
252 public void testAddDataSubscriber_whenRestarted_addsToStatsdOnce() throws Exception {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700253 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700254 StatsPublisher publisher2 = createRestartedPublisher();
255
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700256 publisher2.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700257
258 verify(mStatsManager, times(1))
259 .addConfig(SUBSCRIBER_1_HASH, STATSD_CONFIG_1.toByteArray());
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700260 assertThat(publisher2.hasDataSubscriber(DATA_SUBSCRIBER_1)).isTrue();
261 }
262
263 @Test
264 public void testAddDataSubscriber_forProcessMemoryState_generatesStatsdMetrics()
265 throws Exception {
266 DataSubscriber processMemoryStateSubscriber =
267 new DataSubscriber(null, METRICS_CONFIG, SUBSCRIBER_2);
268
269 mPublisher.addDataSubscriber(processMemoryStateSubscriber);
270
271 verify(mStatsManager, times(1))
272 .addConfig(SUBSCRIBER_2_HASH, STATSD_CONFIG_2.toByteArray());
273 assertThat(mPublisher.hasDataSubscriber(processMemoryStateSubscriber)).isTrue();
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700274 }
275
276 @Test
277 public void testRemoveDataSubscriber_removesFromStatsd() throws Exception {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700278 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700279
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700280 mPublisher.removeDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700281
282 verify(mStatsManager, times(1)).removeConfig(SUBSCRIBER_1_HASH);
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700283 assertThat(getSavedStatsConfigs().keySet()).isEmpty();
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700284 assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse();
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700285 }
286
287 @Test
288 public void testRemoveDataSubscriber_ifNotFound_nothingHappensButCallsStatsdRemove()
289 throws Exception {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700290 mPublisher.removeDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700291
292 // It should try removing StatsdConfig from StatsD, in case it was added there before and
293 // left dangled.
294 verify(mStatsManager, times(1)).removeConfig(SUBSCRIBER_1_HASH);
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700295 assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse();
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700296 }
297
298 @Test
299 public void testRemoveAllDataSubscriber_whenRestarted_removesFromStatsdAndClears()
300 throws Exception {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700301 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700302 StatsPublisher publisher2 = createRestartedPublisher();
303
304 publisher2.removeAllDataSubscribers();
305
306 verify(mStatsManager, times(1)).removeConfig(SUBSCRIBER_1_HASH);
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700307 assertThat(getSavedStatsConfigs().keySet()).isEmpty();
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700308 assertThat(publisher2.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse();
Zhomart Mukhamejanov7d5ecf02021-08-22 17:21:35 -0700309 }
310
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700311 @Test
312 public void testAddDataSubscriber_queuesPeriodicTaskInTheHandler() {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700313 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700314
315 assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(1);
316 Message msg = mFakeHandlerWrapper.getQueuedMessages().get(0);
317 long expectedPullPeriodMillis = 10 * 60 * 1000; // 10 minutes
318 assertThatMessageIsScheduledWithGivenDelay(msg, expectedPullPeriodMillis);
319 }
320
321 @Test
Zhomart Mukhamejanovfb4f29d2021-08-26 17:28:07 -0700322 public void testAddDataSubscriber_whenFails_notifiesFailureConsumer() throws Exception {
323 doThrow(new StatsManager.StatsUnavailableException("fail"))
324 .when(mStatsManager).addConfig(anyLong(), any());
325
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700326 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanovfb4f29d2021-08-26 17:28:07 -0700327
328 assertThat(mPublisherFailure).hasMessageThat().contains("Failed to add config");
329 }
330
331 @Test
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700332 public void testRemoveDataSubscriber_removesPeriodicStatsdReportPull() {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700333 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700334
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700335 mPublisher.removeDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700336
337 assertThat(mFakeHandlerWrapper.getQueuedMessages()).isEmpty();
338 }
339
340 @Test
341 public void testRemoveAllDataSubscriber_removesPeriodicStatsdReportPull() {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700342 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700343
344 mPublisher.removeAllDataSubscribers();
345
346 assertThat(mFakeHandlerWrapper.getQueuedMessages()).isEmpty();
347 }
348
349 @Test
350 public void testAfterDispatchItSchedulesANewPullReportTask() throws Exception {
Zhomart Mukhamejanov60a049d2021-09-07 14:40:48 -0700351 mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1);
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700352 Message firstMessage = mFakeHandlerWrapper.getQueuedMessages().get(0);
353 when(mStatsManager.getReports(anyLong())).thenReturn(EMPTY_STATS_REPORT.toByteArray());
354
355 mFakeHandlerWrapper.dispatchQueuedMessages();
356
357 assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(1);
358 Message newMessage = mFakeHandlerWrapper.getQueuedMessages().get(0);
359 assertThat(newMessage).isNotEqualTo(firstMessage);
360 long expectedPullPeriodMillis = 10 * 60 * 1000; // 10 minutes
361 assertThatMessageIsScheduledWithGivenDelay(newMessage, expectedPullPeriodMillis);
362 }
363
364 @Test
Howard Hao2f22ed02021-09-28 11:53:37 -0700365 public void testPullStatsdReport_correctlyPushesBundlesToSubscribers() throws Exception {
366 DataSubscriber subscriber1 = Mockito.mock(DataSubscriber.class);
367 when(subscriber1.getSubscriber()).thenReturn(SUBSCRIBER_1);
368 when(subscriber1.getMetricsConfig()).thenReturn(METRICS_CONFIG);
369 when(subscriber1.getPublisherParam()).thenReturn(SUBSCRIBER_1.getPublisher());
370 mPublisher.addDataSubscriber(subscriber1);
371 DataSubscriber subscriber2 = Mockito.mock(DataSubscriber.class);
372 when(subscriber2.getSubscriber()).thenReturn(SUBSCRIBER_2);
373 when(subscriber2.getMetricsConfig()).thenReturn(METRICS_CONFIG);
374 when(subscriber2.getPublisherParam()).thenReturn(SUBSCRIBER_2.getPublisher());
375 mPublisher.addDataSubscriber(subscriber2);
376 when(mStatsManager.getReports(anyLong())).thenReturn(STATS_REPORT.toByteArray());
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700377
378 mFakeHandlerWrapper.dispatchQueuedMessages();
379
Howard Hao2f22ed02021-09-28 11:53:37 -0700380 verify(subscriber1).push(mBundleCaptor.capture());
381 PersistableBundle bundle1 = mBundleCaptor.getValue();
382 assertThat(bundle1.getLongArray("elapsed_timestamp_nanos"))
383 .asList().containsExactly(99999999L);
384 assertThat(bundle1.getIntArray("uid")).asList().containsExactly(1000);
385 assertThat(Arrays.asList(bundle1.getStringArray("activity_name")))
386 .containsExactly("activityName");
387 assertThat(bundle1.getLongArray("rss_in_bytes")).asList().containsExactly(1234L);
388 verify(subscriber2).push(mBundleCaptor.capture());
389 PersistableBundle bundle2 = mBundleCaptor.getValue();
390 assertThat(bundle2.getIntArray("uid")).asList().containsExactly(234);
391 assertThat(bundle2.getLongArray("rss_in_bytes")).asList().containsExactly(4567L);
392 assertThat(bundle2.getLongArray("elapsed_timestamp_nanos"))
393 .asList().containsExactly(445678901L);
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700394 }
395
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700396 private PersistableBundle getSavedStatsConfigs() throws Exception {
397 File savedConfigsFile = new File(mRootDirectory, StatsPublisher.SAVED_STATS_CONFIGS_FILE);
398 try (FileInputStream fileInputStream = new FileInputStream(savedConfigsFile)) {
399 return PersistableBundle.readFromStream(fileInputStream);
400 }
401 }
402
Zhomart Mukhamejanovfb4f29d2021-08-26 17:28:07 -0700403 private void onPublisherFailure(AbstractPublisher publisher, Throwable error) {
404 mPublisherFailure = error;
405 }
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700406
407 private static void assertThatMessageIsScheduledWithGivenDelay(Message msg, long delayMillis) {
408 long expectedTimeMillis = SystemClock.uptimeMillis() + delayMillis;
409 long deltaMillis = 1000; // +/- 1 seconds is good enough for testing
410 assertThat(msg.getWhen()).isIn(Range
411 .closed(expectedTimeMillis - deltaMillis, expectedTimeMillis + deltaMillis));
412 }
Zhomart Mukhamejanovdc4f4502021-07-08 09:29:31 -0700413}