SystemUpdatePolicyTest.java revision 29b9a7d1f4168d888ee2f4a0ff3882523f655e6b
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 */ 16package com.android.server.devicepolicy; 17 18import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE; 19import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG; 20import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_DUPLICATE_OR_OVERLAP; 21import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE; 22import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_LONG; 23import static org.junit.Assert.assertEquals; 24import static org.junit.Assert.assertTrue; 25import static org.junit.Assert.fail; 26 27import android.app.admin.FreezeInterval; 28import android.app.admin.SystemUpdatePolicy; 29import android.os.Parcel; 30import android.support.test.runner.AndroidJUnit4; 31import android.util.Pair; 32import android.util.Xml; 33 34import com.android.internal.util.FastXmlSerializer; 35 36import org.junit.Test; 37import org.junit.runner.RunWith; 38import org.xmlpull.v1.XmlPullParser; 39import org.xmlpull.v1.XmlSerializer; 40 41import java.io.ByteArrayInputStream; 42import java.io.ByteArrayOutputStream; 43import java.io.InputStreamReader; 44import java.nio.charset.StandardCharsets; 45import java.time.LocalDate; 46import java.util.ArrayList; 47import java.util.List; 48 49/** 50 * Unit tests for {@link android.app.admin.SystemUpdatePolicy}. 51 * Throughout this test, we use "MM-DD" format to denote dates without year. 52 * 53 * atest com.android.server.devicepolicy.SystemUpdatePolicyTest 54 * runtest -c com.android.server.devicepolicy.SystemUpdatePolicyTest frameworks-services 55 */ 56@RunWith(AndroidJUnit4.class) 57public final class SystemUpdatePolicyTest { 58 59 private static final int DUPLICATE_OR_OVERLAP = ERROR_DUPLICATE_OR_OVERLAP; 60 private static final int TOO_LONG = ERROR_NEW_FREEZE_PERIOD_TOO_LONG; 61 private static final int TOO_CLOSE = ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE; 62 private static final int COMBINED_TOO_LONG = ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG; 63 private static final int COMBINED_TOO_CLOSE = ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE; 64 65 @Test 66 public void testSimplePeriod() throws Exception { 67 testFreezePeriodsSucceeds("01-01", "01-02"); 68 testFreezePeriodsSucceeds("01-31", "01-31"); 69 testFreezePeriodsSucceeds("11-01", "01-15"); 70 testFreezePeriodsSucceeds("02-01", "02-29"); // Leap year 71 testFreezePeriodsSucceeds("02-01", "03-01"); 72 testFreezePeriodsSucceeds("12-01", "01-30"); // Wrapped Period 73 testFreezePeriodsSucceeds("11-02", "01-30", "04-01", "04-30"); // Wrapped Period 74 } 75 76 @Test 77 public void testCanonicalizationValidation() throws Exception { 78 testFreezePeriodsSucceeds("03-01", "03-31", "09-01", "09-30"); 79 testFreezePeriodsSucceeds("06-01", "07-01", "09-01", "09-30"); 80 testFreezePeriodsSucceeds("10-01", "10-31", "12-31", "01-31"); 81 testFreezePeriodsSucceeds("01-01", "01-30", "04-01", "04-30"); 82 testFreezePeriodsSucceeds("01-01", "02-28", "05-01", "06-30", "09-01", "10-31"); 83 84 // One interval fully covers the other 85 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "03-01", "03-31", "03-15", "03-31"); 86 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "03-01", "03-31", "03-15", "03-16"); 87 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "11-15", "01-31", "12-01", "12-31"); 88 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "01-31", "01-01", "01-15"); 89 90 // Partial overlap 91 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "03-01", "03-31", "03-15", "01-01"); 92 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "11-15", "01-31", "12-01", "02-28"); 93 94 // No gap between two intervals 95 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "01-31", "01-31", "02-01", "02-01"); 96 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "12-15", "12-15", "02-01"); 97 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "12-15", "12-16", "02-01"); 98 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "01-15", "01-15", "02-01"); 99 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "01-15", "01-16", "02-01"); 100 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "01-01", "01-30", "12-01", "12-31"); 101 testFreezePeriodsFails(DUPLICATE_OR_OVERLAP, "12-01", "12-31", "04-01", "04-01", 102 "01-01", "01-30"); 103 } 104 105 @Test 106 public void testLengthValidation() throws Exception { 107 testFreezePeriodsSucceeds("03-01", "03-31"); 108 testFreezePeriodsSucceeds("03-03", "03-03", "12-31", "01-01"); 109 testFreezePeriodsSucceeds("01-01", "03-31", "06-01", "08-29"); 110 // entire year 111 testFreezePeriodsFails(TOO_LONG, "01-01", "12-31"); 112 // long period spanning across year end 113 testFreezePeriodsSucceeds("11-01", "01-29"); 114 testFreezePeriodsFails(TOO_LONG, "11-01", "01-30"); 115 // Leap year handling 116 testFreezePeriodsSucceeds("12-01", "02-28"); 117 testFreezePeriodsSucceeds("12-01", "02-29"); 118 testFreezePeriodsFails(TOO_LONG, "12-01", "03-01"); 119 // Regular long period 120 testFreezePeriodsSucceeds("01-01", "03-31", "06-01", "08-29"); 121 testFreezePeriodsFails(TOO_LONG, "01-01", "03-31", "06-01", "08-30"); 122 } 123 124 @Test 125 public void testSeparationValidation() throws Exception { 126 testFreezePeriodsSucceeds("01-01", "03-31", "06-01", "08-29"); 127 testFreezePeriodsFails(TOO_CLOSE, "01-01", "01-01", "01-03", "01-03"); 128 testFreezePeriodsFails(TOO_CLOSE, "03-01", "03-31", "05-01", "05-31"); 129 // Short interval spans across end of year 130 testFreezePeriodsSucceeds("01-31", "03-01", "11-01", "12-01"); 131 testFreezePeriodsFails(TOO_CLOSE, "01-30", "03-01", "11-01", "12-01"); 132 // Short separation is after wrapped period 133 testFreezePeriodsSucceeds("03-03", "03-31", "12-31", "01-01"); 134 testFreezePeriodsFails(TOO_CLOSE, "03-02", "03-31", "12-31", "01-01"); 135 // Short separation including Feb 29 136 testFreezePeriodsSucceeds("12-01", "01-15", "03-17", "04-01"); 137 testFreezePeriodsFails(TOO_CLOSE, "12-01", "01-15", "03-16", "04-01"); 138 // Short separation including Feb 29 139 testFreezePeriodsSucceeds("01-01", "02-28", "04-30", "06-01"); 140 testFreezePeriodsSucceeds("01-01", "02-29", "04-30", "06-01"); 141 testFreezePeriodsFails(TOO_CLOSE, "01-01", "03-01", "04-30", "06-01"); 142 } 143 144 @Test 145 public void testValidateTotalLengthWithPreviousPeriods() throws Exception { 146 testPrevFreezePeriodSucceeds("2018-01-19", "2018-01-19", /* now */"2018-01-19", 147 "07-01", "07-31", "10-01", "11-30"); 148 testPrevFreezePeriodSucceeds("2018-01-01", "2018-01-19", /* now */"2018-01-19", 149 "01-01", "03-30"); 150 testPrevFreezePeriodSucceeds("2018-01-01", "2018-02-01", /* now */"2018-02-01", 151 "11-01", "12-31"); 152 153 testPrevFreezePeriodSucceeds("2017-11-01", "2018-01-02", /* now */"2018-01-02", 154 "01-01", "01-29"); 155 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2018-01-02", "2018-01-02", 156 "01-01", "01-30"); 157 testPrevFreezePeriodSucceeds("2017-11-01", "2018-01-02", /* now */"2018-01-01", 158 "01-02", "01-29"); 159 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2018-01-02", "2018-01-01", 160 "01-02", "01-30"); 161 162 testPrevFreezePeriodSucceeds("2017-11-01", "2017-12-01", /* now */"2017-12-01", 163 "11-15", "01-29"); 164 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2017-12-01", "2017-12-01", 165 "11-15", "01-30"); 166 167 testPrevFreezePeriodSucceeds("2017-11-01", "2018-01-01", /* now */"2018-01-01", 168 "11-15", "01-29"); 169 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-11-01", "2018-01-01", "2018-01-01", 170 "11-15", "01-30"); 171 172 testPrevFreezePeriodSucceeds("2018-03-01", "2018-03-31", /* now */"2018-03-31", 173 "04-01", "05-29"); 174 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2018-03-01", "2018-03-31", "2018-03-31", 175 "04-01", "05-30"); 176 177 // Leap year handing 178 testPrevFreezePeriodSucceeds("2017-12-01", "2018-01-02", /* now */"2018-01-02", 179 "01-01", "02-28"); 180 testPrevFreezePeriodSucceeds("2017-12-01", "2018-01-02", /* now */"2018-01-02", 181 "01-01", "02-29"); 182 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2017-12-01", "2018-01-02", "2018-01-02", 183 "01-01", "03-01"); 184 185 testPrevFreezePeriodSucceeds("2016-01-01", "2016-02-28", /* now */"2016-02-28", 186 "02-01", "03-31"); 187 testPrevFreezePeriodSucceeds("2016-01-01", "2016-02-28", /* now */"2016-02-29", 188 "02-01", "03-31"); 189 testPrevFreezePeriodFails(COMBINED_TOO_LONG, "2016-01-01", "2016-02-28", "2016-02-29", 190 "02-01", "04-01"); 191 192 } 193 194 @Test 195 public void testValidateSeparationWithPreviousPeriods() throws Exception { 196 testPrevFreezePeriodSucceeds("2018-01-01", "2018-01-02", /* now */"2018-03-04", 197 "01-01", "03-30"); 198 testPrevFreezePeriodSucceeds("2018-01-01", "2018-01-02", /* now */"2018-01-19", 199 "04-01", "06-29"); 200 testPrevFreezePeriodSucceeds("2017-01-01", "2017-03-30", /* now */"2018-12-01", 201 "01-01", "03-30"); 202 203 testPrevFreezePeriodSucceeds("2018-01-01", "2018-02-01", "2018-02-01", 204 "04-03", "06-01"); 205 testPrevFreezePeriodFails(COMBINED_TOO_CLOSE, "2018-01-01", "2018-02-01", "2018-02-01", 206 "04-02", "06-01"); 207 208 testPrevFreezePeriodSucceeds("2018-04-01", "2018-06-01", "2018-08-01", 209 "07-01", "08-30"); 210 testPrevFreezePeriodFails(COMBINED_TOO_CLOSE, "2018-04-01", "2018-06-01", "2018-07-30", 211 "07-01", "08-30"); 212 213 214 testPrevFreezePeriodSucceeds("2018-03-01", "2018-04-01", "2018-06-01", 215 "05-01", "07-01"); 216 testPrevFreezePeriodFails(COMBINED_TOO_CLOSE, "2018-03-01", "2018-04-01", "2018-05-31", 217 "05-01", "07-01"); 218 } 219 220 @Test 221 public void testDistanceWithoutLeapYear() { 222 assertEquals(364, FreezeInterval.distanceWithoutLeapYear( 223 LocalDate.of(2016, 12, 31), LocalDate.of(2016, 1, 1))); 224 assertEquals(365, FreezeInterval.distanceWithoutLeapYear( 225 LocalDate.of(2017, 1, 1), LocalDate.of(2016, 1, 1))); 226 assertEquals(365, FreezeInterval.distanceWithoutLeapYear( 227 LocalDate.of(2017, 2, 28), LocalDate.of(2016, 2, 29))); 228 assertEquals(-365, FreezeInterval.distanceWithoutLeapYear( 229 LocalDate.of(2016, 1, 1), LocalDate.of(2017, 1, 1))); 230 assertEquals(1, FreezeInterval.distanceWithoutLeapYear( 231 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 29))); 232 assertEquals(1, FreezeInterval.distanceWithoutLeapYear( 233 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 28))); 234 assertEquals(0, FreezeInterval.distanceWithoutLeapYear( 235 LocalDate.of(2016, 2, 29), LocalDate.of(2016, 2, 28))); 236 assertEquals(0, FreezeInterval.distanceWithoutLeapYear( 237 LocalDate.of(2016, 2, 28), LocalDate.of(2016, 2, 28))); 238 239 assertEquals(59, FreezeInterval.distanceWithoutLeapYear( 240 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 1, 1))); 241 assertEquals(59, FreezeInterval.distanceWithoutLeapYear( 242 LocalDate.of(2017, 3, 1), LocalDate.of(2017, 1, 1))); 243 244 assertEquals(365 * 40, FreezeInterval.distanceWithoutLeapYear( 245 LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1))); 246 247 assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear( 248 LocalDate.of(2019, 3, 1), LocalDate.of(2017, 3, 1))); 249 assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear( 250 LocalDate.of(2018, 3, 1), LocalDate.of(2016, 3, 1))); 251 assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear( 252 LocalDate.of(2017, 3, 1), LocalDate.of(2015, 3, 1))); 253 254 } 255 256 private void testFreezePeriodsSucceeds(String...dates) throws Exception { 257 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 258 setFreezePeriods(p, dates); 259 } 260 261 private void testFreezePeriodsFails(int expectedError, String... dates) throws Exception { 262 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 263 try { 264 setFreezePeriods(p, dates); 265 fail("Invalid periods (" + expectedError + ") not flagged: " + String.join(" ", dates)); 266 } catch (SystemUpdatePolicy.ValidationFailedException e) { 267 assertTrue("Exception not expected: " + e.getMessage(), 268 e.getErrorCode() == expectedError); 269 } 270 } 271 272 private void testPrevFreezePeriodSucceeds(String prevStart, String prevEnd, String now, 273 String... dates) throws Exception { 274 createPrevFreezePeriod(prevStart, prevEnd, now, dates); 275 } 276 277 private void testPrevFreezePeriodFails(int expectedError, String prevStart, String prevEnd, 278 String now, String... dates) throws Exception { 279 try { 280 createPrevFreezePeriod(prevStart, prevEnd, now, dates); 281 fail("Invalid period (" + expectedError + ") not flagged: " + String.join(" ", dates)); 282 } catch (SystemUpdatePolicy.ValidationFailedException e) { 283 assertTrue("Exception not expected: " + e.getMessage(), 284 e.getErrorCode() == expectedError); 285 } 286 } 287 288 private void createPrevFreezePeriod(String prevStart, String prevEnd, String now, 289 String... dates) throws Exception { 290 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 291 setFreezePeriods(p, dates); 292 p.validateAgainstPreviousFreezePeriod(parseDate(prevStart), parseDate(prevEnd), 293 parseDate(now)); 294 } 295 296 // "MM-DD" format for date 297 private void setFreezePeriods(SystemUpdatePolicy policy, String... dates) throws Exception { 298 List<Pair<Integer, Integer>> periods = new ArrayList<>(); 299 LocalDate lastDate = null; 300 for (String date : dates) { 301 LocalDate currentDate = parseDate(date); 302 if (lastDate != null) { 303 periods.add(new Pair<>(lastDate.getDayOfYear(), currentDate.getDayOfYear())); 304 lastDate = null; 305 } else { 306 lastDate = currentDate; 307 } 308 } 309 policy.setFreezePeriods(periods); 310 testSerialization(policy, periods); 311 } 312 313 private void testSerialization(SystemUpdatePolicy policy, 314 List<Pair<Integer, Integer>> expectedPeriods) throws Exception { 315 // Test parcel / unparcel 316 Parcel parcel = Parcel.obtain(); 317 policy.writeToParcel(parcel, 0); 318 parcel.setDataPosition(0); 319 SystemUpdatePolicy q = SystemUpdatePolicy.CREATOR.createFromParcel(parcel); 320 checkFreezePeriods(q, expectedPeriods); 321 parcel.recycle(); 322 323 // Test XML serialization 324 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 325 final XmlSerializer outXml = new FastXmlSerializer(); 326 outXml.setOutput(outStream, StandardCharsets.UTF_8.name()); 327 outXml.startDocument(null, true); 328 outXml.startTag(null, "ota"); 329 policy.saveToXml(outXml); 330 outXml.endTag(null, "ota"); 331 outXml.endDocument(); 332 outXml.flush(); 333 334 ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); 335 XmlPullParser parser = Xml.newPullParser(); 336 parser.setInput(new InputStreamReader(inStream)); 337 assertEquals(XmlPullParser.START_TAG, parser.next()); 338 checkFreezePeriods(SystemUpdatePolicy.restoreFromXml(parser), expectedPeriods); 339 } 340 341 private void checkFreezePeriods(SystemUpdatePolicy policy, 342 List<Pair<Integer, Integer>> expectedPeriods) { 343 int i = 0; 344 for (Pair<Integer, Integer> period : policy.getFreezePeriods()) { 345 assertEquals(expectedPeriods.get(i).first, period.first); 346 assertEquals(expectedPeriods.get(i).second, period.second); 347 i++; 348 } 349 } 350 351 private LocalDate parseDate(String date) { 352 // Use leap year when parsing date string to handle "02-29", but force round down 353 // to Feb 28th by overriding the year to non-leap year. 354 final int year; 355 boolean monthDateOnly = false; 356 if (date.length() == 5) { 357 year = 2000; 358 monthDateOnly = true; 359 } else { 360 year = Integer.parseInt(date.substring(0, 4)); 361 date = date.substring(5); 362 } 363 LocalDate result = LocalDate.of(year, Integer.parseInt(date.substring(0, 2)), 364 Integer.parseInt(date.substring(3, 5))); 365 if (monthDateOnly) { 366 return result.withYear(2001); 367 } else { 368 return result; 369 } 370 } 371} 372