1 /* 2 * Copyright (C) 2018 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 package com.android.server.devicepolicy; 17 18 import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE; 19 import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG; 20 import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_DUPLICATE_OR_OVERLAP; 21 import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE; 22 import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_LONG; 23 24 import static com.google.common.truth.Truth.assertThat; 25 import static com.google.common.truth.Truth.assertWithMessage; 26 27 import static org.junit.Assert.fail; 28 29 import android.app.admin.FreezePeriod; 30 import android.app.admin.SystemUpdatePolicy; 31 import android.os.Parcel; 32 import android.util.Xml; 33 34 import androidx.test.runner.AndroidJUnit4; 35 36 import com.android.internal.util.FastXmlSerializer; 37 import com.android.modules.utils.TypedXmlPullParser; 38 import com.android.modules.utils.TypedXmlSerializer; 39 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 import org.xmlpull.v1.XmlPullParser; 43 import org.xmlpull.v1.XmlSerializer; 44 45 import java.io.ByteArrayInputStream; 46 import java.io.ByteArrayOutputStream; 47 import java.io.InputStreamReader; 48 import java.nio.charset.StandardCharsets; 49 import java.time.LocalDate; 50 import java.time.LocalDateTime; 51 import java.time.MonthDay; 52 import java.time.ZoneId; 53 import java.util.ArrayList; 54 import java.util.List; 55 import java.util.concurrent.TimeUnit; 56 57 /** 58 * Unit tests for {@link android.app.admin.SystemUpdatePolicy}. 59 * 60 * <p>NOTE: Throughout this test, we use {@code "MM-DD"} format to denote dates without year. 61 * 62 * <p>Run this test with: 63 * 64 * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.SystemUpdatePolicyTest} 65 */ 66 @RunWith(AndroidJUnit4.class) 67 public final class SystemUpdatePolicyTest { 68 69 private static final int DUPLICATE_OR_OVERLAP = ERROR_DUPLICATE_OR_OVERLAP; 70 private static final int TOO_LONG = ERROR_NEW_FREEZE_PERIOD_TOO_LONG; 71 private static final int TOO_CLOSE = ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE; 72 private static final int COMBINED_TOO_LONG = ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG; 73 private static final int COMBINED_TOO_CLOSE = ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE; 74 75 @Test testSimplePeriod()76 public void testSimplePeriod() throws Exception { 77 testFreezePeriodsSucceeds("01-01", "01-02"); 78 testFreezePeriodsSucceeds("01-31", "01-31"); 79 testFreezePeriodsSucceeds("11-01", "01-15"); 80 testFreezePeriodsSucceeds("02-01", "02-29"); // Leap year 81 testFreezePeriodsSucceeds("02-01", "03-01"); 82 testFreezePeriodsSucceeds("12-01", "01-30"); // Wrapped Period 83 testFreezePeriodsSucceeds("11-02", "01-30", "04-01", "04-30"); // Wrapped Period 84 } 85 86 @Test testCanonicalizationValidation()87 public void testCanonicalizationValidation() throws Exception { 88 testFreezePeriodsSucceeds("03-01", "03-31", "09-01", "09-30"); 89 testFreezePeriodsSucceeds("06-01", "07-01", "09-01", "09-30"); 90 testFreezePeriodsSucceeds("10-01", "10-31", "12-31", "01-31"); 91 testFreezePeriodsSucceeds("01-01", "01-30", "04-01", "04-30"); 92 testFreezePeriodsSucceeds("01-01", "02-28", "05-01", "06-30", "09-01", "10-31"); 93 94 // One interval fully covers the other 95 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "03-01", "03-31", "03-15", "03-31"); 96 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "03-01", "03-31", "03-15", "03-16"); 97 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "11-15", "01-31", "12-01", "12-31"); 98 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "01-31", "01-01", "01-15"); 99 100 // Partial overlap 101 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "03-01", "03-31", "03-15", "01-01"); 102 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "11-15", "01-31", "12-01", "02-28"); 103 104 // No gap between two intervals 105 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "01-31", "01-31", "02-01", "02-01"); 106 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "12-15", "12-15", "02-01"); 107 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "12-15", "12-16", "02-01"); 108 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "01-15", "01-15", "02-01"); 109 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "01-15", "01-16", "02-01"); 110 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "01-01", "01-30", "12-01", "12-31"); 111 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "12-31", "04-01", "04-01", 112 "01-01", "01-30"); 113 } 114 115 @Test testLengthValidation()116 public void testLengthValidation() throws Exception { 117 testFreezePeriodsSucceeds("03-01", "03-31"); 118 testFreezePeriodsSucceeds("03-03", "03-03", "12-31", "01-01"); 119 testFreezePeriodsSucceeds("01-01", "03-31", "06-01", "08-29"); 120 // entire year 121 testFreezePeriodsFails(TOO_LONG, "01-01", "12-31"); 122 // long period spanning across year end 123 testFreezePeriodsSucceeds("11-01", "01-29"); 124 testFreezePeriodsFails(TOO_LONG, "11-01", "01-30"); 125 // Leap year handling 126 testFreezePeriodsSucceeds("12-01", "02-28"); 127 testFreezePeriodsSucceeds("12-01", "02-29"); 128 testFreezePeriodsFails(TOO_LONG, "12-01", "03-01"); 129 // Regular long period 130 testFreezePeriodsSucceeds("01-01", "03-31", "06-01", "08-29"); 131 testFreezePeriodsFails(TOO_LONG, "01-01", "03-31", "06-01", "08-30"); 132 } 133 134 @Test testSeparationValidation()135 public void testSeparationValidation() throws Exception { 136 testFreezePeriodsSucceeds("01-01", "03-31", "06-01", "08-29"); 137 testFreezePeriodsFails(TOO_CLOSE, "01-01", "01-01", "01-03", "01-03"); 138 testFreezePeriodsFails(TOO_CLOSE, "03-01", "03-31", "05-01", "05-31"); 139 // Short interval spans across end of year 140 testFreezePeriodsSucceeds("01-31", "03-01", "11-01", "12-01"); 141 testFreezePeriodsFails(TOO_CLOSE, "01-30", "03-01", "11-01", "12-01"); 142 // Short separation is after wrapped period 143 testFreezePeriodsSucceeds("03-03", "03-31", "12-31", "01-01"); 144 testFreezePeriodsFails(TOO_CLOSE, "03-02", "03-31", "12-31", "01-01"); 145 // Short separation including Feb 29 146 testFreezePeriodsSucceeds("12-01", "01-15", "03-17", "04-01"); 147 testFreezePeriodsFails(TOO_CLOSE, "12-01", "01-15", "03-16", "04-01"); 148 // Short separation including Feb 29 149 testFreezePeriodsSucceeds("01-01", "02-28", "04-30", "06-01"); 150 testFreezePeriodsSucceeds("01-01", "02-29", "04-30", "06-01"); 151 testFreezePeriodsFails(TOO_CLOSE, "01-01", "03-01", "04-30", "06-01"); 152 } 153 154 @Test testValidateTotalLengthWithPreviousPeriods()155 public void testValidateTotalLengthWithPreviousPeriods() throws Exception { 156 testPrevFreezePeriodSucceeds("2018-01-19", "2018-01-19", /* now */"2018-01-19", 157 "07-01", "07-31", "10-01", "11-30"); 158 testPrevFreezePeriodSucceeds("2018-01-01", "2018-01-19", /* now */"2018-01-19", 159 "01-01", "03-30"); 160 testPrevFreezePeriodSucceeds("2018-01-01", "2018-02-01", /* now */"2018-02-01", 161 "11-01", "12-31"); 162 163 testPrevFreezePeriodSucceeds("2017-11-01", "2018-01-02", /* now */"2018-01-02", 164 "01-01", "01-29"); 165 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2018-01-02", "2018-01-02", 166 "01-01", "01-30"); 167 testPrevFreezePeriodSucceeds("2017-11-01", "2018-01-02", /* now */"2018-01-01", 168 "01-02", "01-29"); 169 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2018-01-02", "2018-01-01", 170 "01-02", "01-30"); 171 172 testPrevFreezePeriodSucceeds("2017-11-01", "2017-12-01", /* now */"2017-12-01", 173 "11-15", "01-29"); 174 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2017-12-01", "2017-12-01", 175 "11-15", "01-30"); 176 177 testPrevFreezePeriodSucceeds("2017-11-01", "2018-01-01", /* now */"2018-01-01", 178 "11-15", "01-29"); 179 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2018-01-01", "2018-01-01", 180 "11-15", "01-30"); 181 182 testPrevFreezePeriodSucceeds("2018-03-01", "2018-03-31", /* now */"2018-03-31", 183 "04-01", "05-29"); 184 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2018-03-01", "2018-03-31", "2018-03-31", 185 "04-01", "05-30"); 186 187 // Leap year handing 188 testPrevFreezePeriodSucceeds("2017-12-01", "2018-01-02", /* now */"2018-01-02", 189 "01-01", "02-28"); 190 testPrevFreezePeriodSucceeds("2017-12-01", "2018-01-02", /* now */"2018-01-02", 191 "01-01", "02-29"); 192 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-12-01", "2018-01-02", "2018-01-02", 193 "01-01", "03-01"); 194 195 testPrevFreezePeriodSucceeds("2016-01-01", "2016-02-28", /* now */"2016-02-28", 196 "02-01", "03-31"); 197 testPrevFreezePeriodSucceeds("2016-01-01", "2016-02-28", /* now */"2016-02-29", 198 "02-01", "03-31"); 199 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2016-01-01", "2016-02-28", "2016-02-29", 200 "02-01", "04-01"); 201 202 } 203 204 @Test testValidateSeparationWithPreviousPeriods()205 public void testValidateSeparationWithPreviousPeriods() throws Exception { 206 testPrevFreezePeriodSucceeds("2018-01-01", "2018-01-02", /* now */"2018-03-04", 207 "01-01", "03-30"); 208 testPrevFreezePeriodSucceeds("2018-01-01", "2018-01-02", /* now */"2018-01-19", 209 "04-01", "06-29"); 210 testPrevFreezePeriodSucceeds("2017-01-01", "2017-03-30", /* now */"2018-12-01", 211 "01-01", "03-30"); 212 213 testPrevFreezePeriodSucceeds("2018-01-01", "2018-02-01", "2018-02-01", 214 "04-03", "06-01"); 215 testPrevFreezePeriodFails(COMBINED_TOO_CLOSE, "2018-01-01", "2018-02-01", "2018-02-01", 216 "04-02", "06-01"); 217 218 testPrevFreezePeriodSucceeds("2018-04-01", "2018-06-01", "2018-08-01", 219 "07-01", "08-30"); 220 testPrevFreezePeriodFails(COMBINED_TOO_CLOSE, "2018-04-01", "2018-06-01", "2018-07-30", 221 "07-01", "08-30"); 222 223 224 testPrevFreezePeriodSucceeds("2018-03-01", "2018-04-01", "2018-06-01", 225 "05-01", "07-01"); 226 testPrevFreezePeriodFails(COMBINED_TOO_CLOSE, "2018-03-01", "2018-04-01", "2018-05-31", 227 "05-01", "07-01"); 228 } 229 230 @Test testDistanceWithoutLeapYear()231 public void testDistanceWithoutLeapYear() { 232 assertThat(FreezePeriod.distanceWithoutLeapYear( 233 LocalDate.of(2016, 12, 31), LocalDate.of(2016, 1, 1))).isEqualTo(364); 234 assertThat(FreezePeriod.distanceWithoutLeapYear( 235 LocalDate.of(2017, 1, 1), LocalDate.of(2016, 1, 1))).isEqualTo(365); 236 assertThat(FreezePeriod.distanceWithoutLeapYear( 237 LocalDate.of(2017, 2, 28), LocalDate.of(2016, 2, 29))).isEqualTo(365); 238 assertThat(FreezePeriod.distanceWithoutLeapYear( 239 LocalDate.of(2016, 1, 1), LocalDate.of(2017, 1, 1))).isEqualTo(-365); 240 assertThat(FreezePeriod.distanceWithoutLeapYear( 241 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 29))).isEqualTo(1); 242 assertThat(FreezePeriod.distanceWithoutLeapYear( 243 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 28))).isEqualTo(1); 244 assertThat(FreezePeriod.distanceWithoutLeapYear( 245 LocalDate.of(2016, 2, 29), LocalDate.of(2016, 2, 28))).isEqualTo(0); 246 assertThat(FreezePeriod.distanceWithoutLeapYear( 247 LocalDate.of(2016, 2, 28), LocalDate.of(2016, 2, 28))).isEqualTo(0); 248 249 assertThat(FreezePeriod.distanceWithoutLeapYear( 250 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 1, 1))).isEqualTo(59); 251 assertThat(FreezePeriod.distanceWithoutLeapYear( 252 LocalDate.of(2017, 3, 1), LocalDate.of(2017, 1, 1))).isEqualTo(59); 253 254 assertThat(FreezePeriod.distanceWithoutLeapYear( 255 LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1))).isEqualTo(365 * 40); 256 257 assertThat(FreezePeriod.distanceWithoutLeapYear( 258 LocalDate.of(2019, 3, 1), LocalDate.of(2017, 3, 1))).isEqualTo(365 * 2); 259 assertThat(FreezePeriod.distanceWithoutLeapYear( 260 LocalDate.of(2018, 3, 1), LocalDate.of(2016, 3, 1))).isEqualTo(365 * 2); 261 assertThat(FreezePeriod.distanceWithoutLeapYear( 262 LocalDate.of(2017, 3, 1), LocalDate.of(2015, 3, 1))).isEqualTo(365 * 2); 263 264 } 265 266 @Test testInstallationOptionWithoutFreeze()267 public void testInstallationOptionWithoutFreeze() { 268 // Also duplicated at com.google.android.gts.deviceowner.SystemUpdatePolicyTest 269 final long millis_2018_01_01 = toMillis(2018, 1, 1); 270 271 SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy(); 272 assertInstallationOption(SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, Long.MAX_VALUE, 273 millis_2018_01_01, p); 274 275 p = SystemUpdatePolicy.createPostponeInstallPolicy(); 276 assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, Long.MAX_VALUE, 277 millis_2018_01_01, p); 278 279 p = SystemUpdatePolicy.createWindowedInstallPolicy(120, 180); // 2:00 - 3:00 280 // 00:00 is two hours before the next window 281 assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(2), 282 millis_2018_01_01, p); 283 // 02:00 is within the current maintenance window, and one hour until the window ends 284 assertInstallationOption( 285 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), 286 millis_2018_01_01 + TimeUnit.HOURS.toMillis(2), p); 287 // 04:00 is 22 hours from the window next day 288 assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22), 289 millis_2018_01_01 + TimeUnit.HOURS.toMillis(4), p); 290 291 p = SystemUpdatePolicy.createWindowedInstallPolicy(22 * 60, 2 * 60); // 22:00 - 2:00 292 // 21:00 is one hour from the next window 293 assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(1), 294 millis_2018_01_01 + TimeUnit.HOURS.toMillis(21), p); 295 // 00:00 is two hours from the end of current window 296 assertInstallationOption( 297 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(2), 298 millis_2018_01_01, p); 299 // 03:00 is 22 hours from the window today 300 assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19), 301 millis_2018_01_01 + TimeUnit.HOURS.toMillis(3), p); 302 } 303 304 @Test testInstallationOptionWithFreeze()305 public void testInstallationOptionWithFreeze() throws Exception { 306 final long millis_2016_02_29 = toMillis(2016, 2, 29); 307 final long millis_2017_01_31 = toMillis(2017, 1, 31); 308 final long millis_2017_02_28 = toMillis(2017, 2, 28); 309 final long millis_2018_01_01 = toMillis(2018, 1, 1); 310 final long millis_2018_08_01 = toMillis(2018, 8, 1); 311 312 SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy(); 313 setFreezePeriods(p, "01-01", "01-31"); 314 // Inside a freeze period 315 assertInstallationOption( 316 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(31), 317 millis_2018_01_01, p); 318 // Device is outside freeze between 2/28 to 12/31 inclusive 319 assertInstallationOption( 320 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(307), 321 millis_2017_02_28, p); 322 323 // Freeze period contains leap day Feb 29 324 p = SystemUpdatePolicy.createPostponeInstallPolicy(); 325 setFreezePeriods(p, "02-01", "03-05"); 326 // Freezed until 3/5, note 2016 is a leap year 327 assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6), 328 millis_2016_02_29, p); 329 // Freezed until 3/5, note 2017 is not a leap year 330 assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6), 331 millis_2017_02_28, p); 332 // Next freeze is 2018/2/1 333 assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, TimeUnit.DAYS.toMillis(31), 334 millis_2018_01_01, p); 335 336 // Freeze period start on or right after leap day 337 p = SystemUpdatePolicy.createAutomaticInstallPolicy(); 338 setFreezePeriods(p, "03-01", "03-31"); 339 assertInstallationOption( 340 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1), 341 millis_2016_02_29, p); 342 assertInstallationOption( 343 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1), 344 millis_2017_02_28, p); 345 setFreezePeriods(p, "02-28", "03-05"); 346 assertInstallationOption( 347 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6), 348 millis_2016_02_29, p); 349 assertInstallationOption( 350 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6), 351 millis_2017_02_28, p); 352 353 // Freeze period end on or right after leap day 354 p = SystemUpdatePolicy.createAutomaticInstallPolicy(); 355 setFreezePeriods(p, "02-01", "02-28"); 356 assertInstallationOption( 357 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1), 358 millis_2016_02_29, p); 359 assertInstallationOption( 360 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1), 361 millis_2017_02_28, p); 362 p = SystemUpdatePolicy.createAutomaticInstallPolicy(); 363 setFreezePeriods(p, "02-01", "03-01"); 364 assertInstallationOption( 365 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2), 366 millis_2016_02_29, p); 367 assertInstallationOption( 368 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2), 369 millis_2017_02_28, p); 370 371 // Freeze period with maintenance window 372 p = SystemUpdatePolicy.createWindowedInstallPolicy(23 * 60, 1 * 60); // 23:00 - 1:00 373 setFreezePeriods(p, "02-01", "02-28"); 374 // 00:00 is within the current window, outside freeze period 375 assertInstallationOption( 376 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), 377 millis_2018_01_01, p); 378 // Last day of feeze period, which ends in 22 hours 379 assertInstallationOption( 380 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22), 381 millis_2017_02_28 + TimeUnit.HOURS.toMillis(2), p); 382 // Last day before the next freeze, and within window 383 assertInstallationOption( 384 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), 385 millis_2017_01_31, p); 386 // Last day before the next freeze, and there is still a partial maintenance window before 387 // the freeze. 388 assertInstallationOption( 389 SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19), 390 millis_2017_01_31 + TimeUnit.HOURS.toMillis(4), p); 391 392 // Two freeze periods 393 p = SystemUpdatePolicy.createAutomaticInstallPolicy(); 394 setFreezePeriods(p, "05-01", "06-01", "10-15", "01-10"); 395 // automatic policy for July, August, September and October until 15th 396 assertInstallationOption( 397 SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(31 + 30 + 14), 398 millis_2018_08_01, p); 399 } 400 assertInstallationOption(int expectedType, long expectedTime, long now, SystemUpdatePolicy p)401 private void assertInstallationOption(int expectedType, long expectedTime, long now, 402 SystemUpdatePolicy p) { 403 assertThat(p.getInstallationOptionAt(now).getType()).isEqualTo(expectedType); 404 assertThat(p.getInstallationOptionAt(now).getEffectiveTime()).isEqualTo(expectedTime); 405 } 406 testFreezePeriodsSucceeds(String...dates)407 private void testFreezePeriodsSucceeds(String...dates) throws Exception { 408 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 409 setFreezePeriods(p, dates); 410 } 411 testFreezePeriodsFails(int expectedError, String... dates)412 private void testFreezePeriodsFails(int expectedError, String... dates) throws Exception { 413 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 414 try { 415 setFreezePeriods(p, dates); 416 fail("Invalid periods (" + expectedError + ") not flagged: " + String.join(" ", dates)); 417 } catch (SystemUpdatePolicy.ValidationFailedException e) { 418 assertWithMessage("Exception not expected: %s", e.getMessage()).that(e.getErrorCode()) 419 .isEqualTo(expectedError); 420 } 421 } 422 testPrevFreezePeriodSucceeds(String prevStart, String prevEnd, String now, String... dates)423 private void testPrevFreezePeriodSucceeds(String prevStart, String prevEnd, String now, 424 String... dates) throws Exception { 425 createPrevFreezePeriod(prevStart, prevEnd, now, dates); 426 } 427 testPrevFreezePeriodFails(int expectedError, String prevStart, String prevEnd, String now, String... dates)428 private void testPrevFreezePeriodFails(int expectedError, String prevStart, String prevEnd, 429 String now, String... dates) throws Exception { 430 try { 431 createPrevFreezePeriod(prevStart, prevEnd, now, dates); 432 fail("Invalid period (" + expectedError + ") not flagged: " + String.join(" ", dates)); 433 } catch (SystemUpdatePolicy.ValidationFailedException e) { 434 assertWithMessage("Exception not expected: %s", e.getMessage()).that(e.getErrorCode()) 435 .isEqualTo(expectedError); 436 } 437 } 438 createPrevFreezePeriod(String prevStart, String prevEnd, String now, String... dates)439 private void createPrevFreezePeriod(String prevStart, String prevEnd, String now, 440 String... dates) throws Exception { 441 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 442 setFreezePeriods(p, dates); 443 p.validateAgainstPreviousFreezePeriod(parseLocalDate(prevStart), 444 parseLocalDate(prevEnd), parseLocalDate(now)); 445 } 446 447 // "MM-DD" format for date setFreezePeriods(SystemUpdatePolicy policy, String... dates)448 private void setFreezePeriods(SystemUpdatePolicy policy, String... dates) throws Exception { 449 List<FreezePeriod> periods = new ArrayList<>(); 450 MonthDay lastDate = null; 451 for (String date : dates) { 452 MonthDay currentDate = parseMonthDay(date); 453 if (lastDate != null) { 454 periods.add(new FreezePeriod(lastDate, currentDate)); 455 lastDate = null; 456 } else { 457 lastDate = currentDate; 458 } 459 } 460 policy.setFreezePeriods(periods); 461 testSerialization(policy, periods); 462 } 463 testSerialization(SystemUpdatePolicy policy, List<FreezePeriod> expectedPeriods)464 private void testSerialization(SystemUpdatePolicy policy, 465 List<FreezePeriod> expectedPeriods) throws Exception { 466 // Test parcel / unparcel 467 Parcel parcel = Parcel.obtain(); 468 policy.writeToParcel(parcel, 0); 469 parcel.setDataPosition(0); 470 SystemUpdatePolicy q = SystemUpdatePolicy.CREATOR.createFromParcel(parcel); 471 checkFreezePeriods(q, expectedPeriods); 472 parcel.recycle(); 473 474 // Test XML serialization 475 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 476 final TypedXmlSerializer outXml = Xml.newFastSerializer(); 477 outXml.setOutput(outStream, StandardCharsets.UTF_8.name()); 478 outXml.startDocument(null, true); 479 outXml.startTag(null, "ota"); 480 policy.saveToXml(outXml); 481 outXml.endTag(null, "ota"); 482 outXml.endDocument(); 483 outXml.flush(); 484 485 ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); 486 TypedXmlPullParser parser = Xml.newFastPullParser(); 487 parser.setInput(new InputStreamReader(inStream)); 488 assertThat(parser.next()).isEqualTo(XmlPullParser.START_TAG); 489 checkFreezePeriods(SystemUpdatePolicy.restoreFromXml(parser), expectedPeriods); 490 } 491 checkFreezePeriods(SystemUpdatePolicy policy, List<FreezePeriod> expectedPeriods)492 private void checkFreezePeriods(SystemUpdatePolicy policy, 493 List<FreezePeriod> expectedPeriods) { 494 int i = 0; 495 for (FreezePeriod period : policy.getFreezePeriods()) { 496 assertThat(period.getStart()).isEqualTo(expectedPeriods.get(i).getStart()); 497 assertThat(period.getEnd()).isEqualTo(expectedPeriods.get(i).getEnd()); 498 i++; 499 } 500 } 501 502 // MonthDay is of format MM-dd parseMonthDay(String date)503 private MonthDay parseMonthDay(String date) { 504 return MonthDay.of(Integer.parseInt(date.substring(0, 2)), 505 Integer.parseInt(date.substring(3, 5))); 506 } 507 508 // LocalDat is of format YYYY-MM-dd parseLocalDate(String date)509 private LocalDate parseLocalDate(String date) { 510 return parseMonthDay(date.substring(5)).atYear(Integer.parseInt(date.substring(0, 4))); 511 } 512 513 toMillis(int year, int month, int day)514 private long toMillis(int year, int month, int day) { 515 return LocalDateTime.of(year, month, day, 0, 0, 0).atZone(ZoneId.systemDefault()) 516 .toInstant().toEpochMilli(); 517 } 518 } 519