Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.car.telemetry.publisher; |
| 18 | |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 19 | import static com.android.car.telemetry.AtomsProto.Atom.APP_START_MEMORY_STATE_CAPTURED_FIELD_NUMBER; |
| 20 | import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_MEMORY_STATE_FIELD_NUMBER; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 21 | import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_START_MEMORY_STATE_CAPTURED; |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 22 | import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_STATE; |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 23 | import static com.android.car.telemetry.publisher.StatsPublisher.APP_START_MEMORY_STATE_CAPTURED_ATOM_MATCHER_ID; |
| 24 | import static com.android.car.telemetry.publisher.StatsPublisher.APP_START_MEMORY_STATE_CAPTURED_EVENT_METRIC_ID; |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 25 | import static com.android.car.telemetry.publisher.StatsPublisher.PROCESS_MEMORY_STATE_FIELDS_MATCHER; |
| 26 | import static com.android.car.telemetry.publisher.StatsPublisher.PROCESS_MEMORY_STATE_GAUGE_METRIC_ID; |
| 27 | import static com.android.car.telemetry.publisher.StatsPublisher.PROCESS_MEMORY_STATE_MATCHER_ID; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 28 | |
| 29 | import static com.google.common.truth.Truth.assertThat; |
| 30 | |
Zhomart Mukhamejanov | fb4f29d | 2021-08-26 17:28:07 -0700 | [diff] [blame] | 31 | import static org.mockito.ArgumentMatchers.any; |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 32 | import static org.mockito.ArgumentMatchers.anyLong; |
Zhomart Mukhamejanov | fb4f29d | 2021-08-26 17:28:07 -0700 | [diff] [blame] | 33 | import static org.mockito.Mockito.doThrow; |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 34 | import static org.mockito.Mockito.times; |
| 35 | import static org.mockito.Mockito.verify; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 36 | import static org.mockito.Mockito.when; |
| 37 | |
Zhomart Mukhamejanov | fb4f29d | 2021-08-26 17:28:07 -0700 | [diff] [blame] | 38 | import android.app.StatsManager; |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 39 | import android.os.Looper; |
| 40 | import android.os.Message; |
Max Dashouk | dafdd22 | 2021-08-20 10:42:25 -0700 | [diff] [blame] | 41 | import android.os.PersistableBundle; |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 42 | import android.os.SystemClock; |
| 43 | |
Howard Hao | 2f22ed0 | 2021-09-28 11:53:37 -0700 | [diff] [blame^] | 44 | import com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured; |
| 45 | import com.android.car.telemetry.AtomsProto.Atom; |
| 46 | import com.android.car.telemetry.AtomsProto.ProcessMemoryState; |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 47 | import com.android.car.telemetry.StatsLogProto; |
Howard Hao | 2f22ed0 | 2021-09-28 11:53:37 -0700 | [diff] [blame^] | 48 | import com.android.car.telemetry.StatsLogProto.ConfigMetricsReport; |
| 49 | import com.android.car.telemetry.StatsLogProto.DimensionsValue; |
| 50 | import com.android.car.telemetry.StatsLogProto.DimensionsValueTuple; |
| 51 | import com.android.car.telemetry.StatsLogProto.EventMetricData; |
| 52 | import com.android.car.telemetry.StatsLogProto.GaugeBucketInfo; |
| 53 | import com.android.car.telemetry.StatsLogProto.GaugeMetricData; |
| 54 | import com.android.car.telemetry.StatsLogProto.StatsLogReport; |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 55 | import com.android.car.telemetry.StatsdConfigProto; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 56 | import com.android.car.telemetry.TelemetryProto; |
| 57 | import com.android.car.telemetry.databroker.DataSubscriber; |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 58 | import com.android.car.test.FakeHandlerWrapper; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 59 | |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 60 | import com.google.common.collect.Range; |
| 61 | |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 62 | import org.junit.Before; |
| 63 | import org.junit.Test; |
| 64 | import org.junit.runner.RunWith; |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 65 | import org.mockito.ArgumentCaptor; |
| 66 | import org.mockito.Captor; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 67 | import org.mockito.Mock; |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 68 | import org.mockito.Mockito; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 69 | import org.mockito.junit.MockitoJUnitRunner; |
| 70 | |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 71 | import java.io.File; |
| 72 | import java.io.FileInputStream; |
| 73 | import java.nio.file.Files; |
Howard Hao | 2f22ed0 | 2021-09-28 11:53:37 -0700 | [diff] [blame^] | 74 | import java.util.Arrays; |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 75 | |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 76 | @RunWith(MockitoJUnitRunner.class) |
| 77 | public 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 Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 83 | 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 Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 88 | 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 Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 93 | 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 Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 98 | private static final TelemetryProto.MetricsConfig METRICS_CONFIG = |
| 99 | TelemetryProto.MetricsConfig.newBuilder() |
| 100 | .setName("myconfig") |
| 101 | .setVersion(1) |
| 102 | .addSubscribers(SUBSCRIBER_1) |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 103 | .addSubscribers(SUBSCRIBER_2) |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 104 | .build(); |
| 105 | |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 106 | private static final long SUBSCRIBER_1_HASH = -8101507323446050791L; // Used as ID. |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 107 | private static final long SUBSCRIBER_2_HASH = 2778197004730583271L; // Used as ID. |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 108 | |
| 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 Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 117 | APP_START_MEMORY_STATE_CAPTURED_FIELD_NUMBER))) |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 118 | .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 Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 124 | 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 Hao | 2f22ed0 | 2021-09-28 11:53:37 -0700 | [diff] [blame^] | 155 | 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 Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 197 | private static final StatsLogProto.ConfigMetricsReportList EMPTY_STATS_REPORT = |
| 198 | StatsLogProto.ConfigMetricsReportList.newBuilder().build(); |
| 199 | |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 200 | private static final DataSubscriber DATA_SUBSCRIBER_1 = |
| 201 | new DataSubscriber(null, METRICS_CONFIG, SUBSCRIBER_1); |
| 202 | |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 203 | private final FakeHandlerWrapper mFakeHandlerWrapper = |
| 204 | new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.QUEUEING); |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 205 | |
| 206 | private File mRootDirectory; |
| 207 | private StatsPublisher mPublisher; // subject |
Zhomart Mukhamejanov | fb4f29d | 2021-08-26 17:28:07 -0700 | [diff] [blame] | 208 | private Throwable mPublisherFailure; |
| 209 | |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 210 | @Mock private StatsManagerProxy mStatsManager; |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 211 | |
Max Dashouk | dafdd22 | 2021-08-20 10:42:25 -0700 | [diff] [blame] | 212 | @Captor private ArgumentCaptor<PersistableBundle> mBundleCaptor; |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 213 | |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 214 | @Before |
| 215 | public void setUp() throws Exception { |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 216 | mRootDirectory = Files.createTempDirectory("telemetry_test").toFile(); |
Zhomart Mukhamejanov | a16bfc9 | 2021-08-25 18:36:16 -0700 | [diff] [blame] | 217 | mPublisher = createRestartedPublisher(); |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 218 | } |
| 219 | |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 220 | /** |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 221 | * Emulates a restart by creating a new StatsPublisher. StatsManager and PersistableBundle |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 222 | * stays the same. |
| 223 | */ |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 224 | private StatsPublisher createRestartedPublisher() throws Exception { |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 225 | return new StatsPublisher( |
Zhomart Mukhamejanov | a16bfc9 | 2021-08-25 18:36:16 -0700 | [diff] [blame] | 226 | this::onPublisherFailure, |
| 227 | mStatsManager, |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 228 | mRootDirectory, |
Zhomart Mukhamejanov | a16bfc9 | 2021-08-25 18:36:16 -0700 | [diff] [blame] | 229 | mFakeHandlerWrapper.getMockHandler()); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 230 | } |
| 231 | |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 232 | @Test |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 233 | public void testAddDataSubscriber_registersNewListener() throws Exception { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 234 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 235 | |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 236 | verify(mStatsManager, times(1)) |
| 237 | .addConfig(SUBSCRIBER_1_HASH, STATSD_CONFIG_1.toByteArray()); |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 238 | assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isTrue(); |
Zhomart Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 239 | } |
| 240 | |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 241 | @Test |
| 242 | public void testAddDataSubscriber_sameVersion_addsToStatsdOnce() throws Exception { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 243 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
| 244 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 245 | |
| 246 | verify(mStatsManager, times(1)) |
| 247 | .addConfig(SUBSCRIBER_1_HASH, STATSD_CONFIG_1.toByteArray()); |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 248 | assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isTrue(); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 249 | } |
| 250 | |
| 251 | @Test |
| 252 | public void testAddDataSubscriber_whenRestarted_addsToStatsdOnce() throws Exception { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 253 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 254 | StatsPublisher publisher2 = createRestartedPublisher(); |
| 255 | |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 256 | publisher2.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 257 | |
| 258 | verify(mStatsManager, times(1)) |
| 259 | .addConfig(SUBSCRIBER_1_HASH, STATSD_CONFIG_1.toByteArray()); |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 260 | 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 Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 274 | } |
| 275 | |
| 276 | @Test |
| 277 | public void testRemoveDataSubscriber_removesFromStatsd() throws Exception { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 278 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 279 | |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 280 | mPublisher.removeDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 281 | |
| 282 | verify(mStatsManager, times(1)).removeConfig(SUBSCRIBER_1_HASH); |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 283 | assertThat(getSavedStatsConfigs().keySet()).isEmpty(); |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 284 | assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse(); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 285 | } |
| 286 | |
| 287 | @Test |
| 288 | public void testRemoveDataSubscriber_ifNotFound_nothingHappensButCallsStatsdRemove() |
| 289 | throws Exception { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 290 | mPublisher.removeDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 291 | |
| 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 Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 295 | assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse(); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | @Test |
| 299 | public void testRemoveAllDataSubscriber_whenRestarted_removesFromStatsdAndClears() |
| 300 | throws Exception { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 301 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 302 | StatsPublisher publisher2 = createRestartedPublisher(); |
| 303 | |
| 304 | publisher2.removeAllDataSubscribers(); |
| 305 | |
| 306 | verify(mStatsManager, times(1)).removeConfig(SUBSCRIBER_1_HASH); |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 307 | assertThat(getSavedStatsConfigs().keySet()).isEmpty(); |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 308 | assertThat(publisher2.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse(); |
Zhomart Mukhamejanov | 7d5ecf0 | 2021-08-22 17:21:35 -0700 | [diff] [blame] | 309 | } |
| 310 | |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 311 | @Test |
| 312 | public void testAddDataSubscriber_queuesPeriodicTaskInTheHandler() { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 313 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 314 | |
| 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 Mukhamejanov | fb4f29d | 2021-08-26 17:28:07 -0700 | [diff] [blame] | 322 | public void testAddDataSubscriber_whenFails_notifiesFailureConsumer() throws Exception { |
| 323 | doThrow(new StatsManager.StatsUnavailableException("fail")) |
| 324 | .when(mStatsManager).addConfig(anyLong(), any()); |
| 325 | |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 326 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | fb4f29d | 2021-08-26 17:28:07 -0700 | [diff] [blame] | 327 | |
| 328 | assertThat(mPublisherFailure).hasMessageThat().contains("Failed to add config"); |
| 329 | } |
| 330 | |
| 331 | @Test |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 332 | public void testRemoveDataSubscriber_removesPeriodicStatsdReportPull() { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 333 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 334 | |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 335 | mPublisher.removeDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 336 | |
| 337 | assertThat(mFakeHandlerWrapper.getQueuedMessages()).isEmpty(); |
| 338 | } |
| 339 | |
| 340 | @Test |
| 341 | public void testRemoveAllDataSubscriber_removesPeriodicStatsdReportPull() { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 342 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 343 | |
| 344 | mPublisher.removeAllDataSubscribers(); |
| 345 | |
| 346 | assertThat(mFakeHandlerWrapper.getQueuedMessages()).isEmpty(); |
| 347 | } |
| 348 | |
| 349 | @Test |
| 350 | public void testAfterDispatchItSchedulesANewPullReportTask() throws Exception { |
Zhomart Mukhamejanov | 60a049d | 2021-09-07 14:40:48 -0700 | [diff] [blame] | 351 | mPublisher.addDataSubscriber(DATA_SUBSCRIBER_1); |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 352 | 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 Hao | 2f22ed0 | 2021-09-28 11:53:37 -0700 | [diff] [blame^] | 365 | 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 Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 377 | |
| 378 | mFakeHandlerWrapper.dispatchQueuedMessages(); |
| 379 | |
Howard Hao | 2f22ed0 | 2021-09-28 11:53:37 -0700 | [diff] [blame^] | 380 | 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 Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 394 | } |
| 395 | |
Rui Qiu | da9f0ba | 2021-09-14 12:15:37 -0700 | [diff] [blame] | 396 | 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 Mukhamejanov | fb4f29d | 2021-08-26 17:28:07 -0700 | [diff] [blame] | 403 | private void onPublisherFailure(AbstractPublisher publisher, Throwable error) { |
| 404 | mPublisherFailure = error; |
| 405 | } |
Zhomart Mukhamejanov | cdcb4e1 | 2021-08-23 18:24:40 -0700 | [diff] [blame] | 406 | |
| 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 Mukhamejanov | dc4f450 | 2021-07-08 09:29:31 -0700 | [diff] [blame] | 413 | } |