diff options
author | Martin Polden <mpolden@mpolden.no> | 2022-01-07 10:56:41 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2022-01-07 14:43:37 +0100 |
commit | ae843dd9bd28be5c8445adf10dc7c0a6a69f2d97 (patch) | |
tree | 7d7c5b2fc602c54e3d634d0a0c07ab13d0ab1981 /config-model-api/src/test | |
parent | e11472ccb26601fe74004a2400b44ea000c88d6f (diff) |
Support date range in block window
Diffstat (limited to 'config-model-api/src/test')
-rw-r--r-- | config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java | 51 | ||||
-rw-r--r-- | config-model-api/src/test/java/com/yahoo/config/application/api/TimeWindowTest.java | 137 |
2 files changed, 145 insertions, 43 deletions
diff --git a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java index 43ccc34284f..2fa2ba83291 100644 --- a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java +++ b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java @@ -2,12 +2,15 @@ package com.yahoo.config.application.api; import com.google.common.collect.ImmutableSet; +import com.yahoo.config.application.api.xml.DeploymentSpecXmlReader; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.RegionName; +import com.yahoo.test.ManualClock; import org.junit.Test; import java.io.StringReader; +import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.time.ZoneId; @@ -771,6 +774,7 @@ public class DeploymentSpecTest { " <instance id='default'>" + " <block-change revision='false' days='mon,tue' hours='15-16'/>" + " <block-change days='sat' hours='10' time-zone='CET'/>" + + " <block-change days='mon-sun' hours='0-23' time-zone='CET' from-date='2022-01-01' to-date='2022-01-15'/>" + " <prod>" + " <region active='true'>us-west-1</region>" + " </prod>" + @@ -778,7 +782,7 @@ public class DeploymentSpecTest { "</deployment>" ); DeploymentSpec spec = DeploymentSpec.fromXml(r); - assertEquals(2, spec.requireInstance("default").changeBlocker().size()); + assertEquals(3, spec.requireInstance("default").changeBlocker().size()); assertTrue(spec.requireInstance("default").changeBlocker().get(0).blocksVersions()); assertFalse(spec.requireInstance("default").changeBlocker().get(0).blocksRevisions()); assertEquals(ZoneId.of("UTC"), spec.requireInstance("default").changeBlocker().get(0).window().zone()); @@ -795,6 +799,8 @@ public class DeploymentSpecTest { assertTrue(spec.requireInstance("default").canUpgradeAt(Instant.parse("2017-09-23T09:15:30.00Z"))); assertFalse(spec.requireInstance("default").canUpgradeAt(Instant.parse("2017-09-23T08:15:30.00Z"))); // 10 in CET assertTrue(spec.requireInstance("default").canUpgradeAt(Instant.parse("2017-09-23T10:15:30.00Z"))); + + assertFalse(spec.requireInstance("default").canUpgradeAt(Instant.parse("2022-01-15T16:00:00.00Z"))); } @Test @@ -812,11 +818,13 @@ public class DeploymentSpecTest { DeploymentSpec spec = DeploymentSpec.fromXml(r); - String inheritedChangeBlocker = "change blocker revision=false version=true window=time window for hour(s) [15, 16] on [monday, tuesday] in UTC"; + String inheritedChangeBlocker = "change blocker revision=false version=true window=time window for hour(s) " + + "[15, 16] on [monday, tuesday] in time zone UTC and date range [any date, any date]"; assertEquals(2, spec.requireInstance("instance1").changeBlocker().size()); assertEquals(inheritedChangeBlocker, spec.requireInstance("instance1").changeBlocker().get(0).toString()); - assertEquals("change blocker revision=true version=true window=time window for hour(s) [10] on [saturday] in CET", + assertEquals("change blocker revision=true version=true window=time window for hour(s) [10] on " + + "[saturday] in time zone CET and date range [any date, any date]", spec.requireInstance("instance1").changeBlocker().get(1).toString()); assertEquals(1, spec.requireInstance("instance2").changeBlocker().size()); @@ -1269,10 +1277,45 @@ public class DeploymentSpecTest { spec.requireInstance("main").endpoints()); } + @Test + public void disallowExcessiveUpgradeBlocking() { + List<String> specs = List.of( + "<deployment>\n" + + " <block-change/>\n" + + "</deployment>", + + "<deployment>\n" + + " <block-change days=\"mon-wed\"/>\n" + + " <block-change days=\"tue-sun\"/>\n" + + "</deployment>", + + "<deployment>\n" + + " <block-change to-date=\"2023-01-01\"/>\n" + + "</deployment>", + + // Convoluted example of blocking too long + "<deployment>\n" + + " <block-change days=\"sat-sun\"/>\n" + + " <block-change days=\"mon-fri\" hours=\"0-10\" from-date=\"2023-01-01\" to-date=\"2023-01-15\"/>\n" + + " <block-change days=\"mon-fri\" hours=\"11-23\" from-date=\"2023-01-01\" to-date=\"2023-01-15\"/>\n" + + " <block-change from-date=\"2023-01-14\" to-date=\"2023-01-31\"/>" + + "</deployment>" + ); + ManualClock clock = new ManualClock(); + clock.setInstant(Instant.parse("2022-01-05T15:00:00.00Z")); + for (var spec : specs) { + assertInvalid(spec, "Cannot block Vespa upgrades for longer than 21 consecutive days", clock); + } + } + private static void assertInvalid(String deploymentSpec, String errorMessagePart) { + assertInvalid(deploymentSpec, errorMessagePart, new ManualClock()); + } + + private static void assertInvalid(String deploymentSpec, String errorMessagePart, Clock clock) { if (errorMessagePart.isEmpty()) throw new IllegalArgumentException("Message part must be non-empty"); try { - DeploymentSpec.fromXml(deploymentSpec); + new DeploymentSpecXmlReader(true, clock).read(deploymentSpec); fail("Expected exception"); } catch (IllegalArgumentException e) { assertTrue("\"" + e.getMessage() + "\" contains \"" + errorMessagePart + "\"", diff --git a/config-model-api/src/test/java/com/yahoo/config/application/api/TimeWindowTest.java b/config-model-api/src/test/java/com/yahoo/config/application/api/TimeWindowTest.java index 98a53dfd3df..a76f156ebb1 100644 --- a/config-model-api/src/test/java/com/yahoo/config/application/api/TimeWindowTest.java +++ b/config-model-api/src/test/java/com/yahoo/config/application/api/TimeWindowTest.java @@ -3,7 +3,11 @@ package com.yahoo.config.application.api; import org.junit.Test; +import java.time.DayOfWeek; import java.time.Instant; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import static java.time.DayOfWeek.FRIDAY; import static java.time.DayOfWeek.MONDAY; @@ -11,7 +15,6 @@ import static java.time.DayOfWeek.SATURDAY; import static java.time.DayOfWeek.THURSDAY; import static java.time.DayOfWeek.TUESDAY; import static java.time.DayOfWeek.WEDNESDAY; -import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -25,71 +28,106 @@ public class TimeWindowTest { @Test public void includesInstant() { { - TimeWindow tw = TimeWindow.from("mon", "10,11", "UTC"); + TimeWindow tw = TimeWindow.from("mon", "10,11", "UTC", "", ""); Instant i0 = Instant.parse("2017-09-17T11:15:30.00Z"); // Wrong day Instant i1 = Instant.parse("2017-09-18T09:15:30.00Z"); // Wrong hour Instant i2 = Instant.parse("2017-09-18T10:15:30.00Z"); Instant i3 = Instant.parse("2017-09-18T11:15:30.00Z"); Instant i4 = Instant.parse("2017-09-18T12:15:30.00Z"); // Wrong hour Instant i5 = Instant.parse("2017-09-19T11:15:30.00Z"); // Wrong day - - assertFalse("Instant " + i0 + " is not in window", tw.includes(i0)); - assertFalse("Instant " + i1 + " is not in window", tw.includes(i1)); - assertTrue("Instant " + i2 + " is in window", tw.includes(i2)); - assertTrue("Instant " + i3 + " is in window", tw.includes(i3)); - assertFalse("Instant " + i4 + " is not in window", tw.includes(i4)); - assertFalse("Instant " + i5 + " is not in window", tw.includes(i5)); + assertOutside(tw, i0); + assertOutside(tw, i1); + assertInside(tw, i2); + assertInside(tw, i3); + assertOutside(tw, i4); + assertOutside(tw, i5); } { - TimeWindow tw = TimeWindow.from("mon", "12,13", "CET"); + TimeWindow tw = TimeWindow.from("mon", "12,13", "CET", "", ""); Instant i0 = Instant.parse("2017-09-17T11:15:30.00Z"); Instant i1 = Instant.parse("2017-09-18T09:15:30.00Z"); Instant i2 = Instant.parse("2017-09-18T10:15:30.00Z"); // Including offset this matches hour 12 Instant i3 = Instant.parse("2017-09-18T11:15:30.00Z"); // Including offset this matches hour 13 Instant i4 = Instant.parse("2017-09-18T12:15:30.00Z"); Instant i5 = Instant.parse("2017-09-19T11:15:30.00Z"); - assertFalse("Instant " + i0 + " is not in window", tw.includes(i0)); - assertFalse("Instant " + i1 + " is not in window", tw.includes(i1)); - assertTrue("Instant " + i2 + " is in window", tw.includes(i2)); - assertTrue("Instant " + i3 + " is in window", tw.includes(i3)); - assertFalse("Instant " + i4 + " is not in window", tw.includes(i4)); - assertFalse("Instant " + i5 + " is not in window", tw.includes(i5)); + assertOutside(tw, i0); + assertOutside(tw, i1); + assertInside(tw, i2); + assertInside(tw, i3); + assertOutside(tw, i4); + assertOutside(tw, i5); + } + { + TimeWindow tw = TimeWindow.from("mon-sun", "0-23", "CET", "2022-01-15", "2022-02-15"); + Instant i0 = Instant.parse("2022-01-14T12:00:00.00Z"); // Before window + Instant i1 = Instant.parse("2022-01-14T23:00:00.00Z"); // Inside window because of time zone offset + Instant i2 = Instant.parse("2022-02-05T12:00:00.00Z"); + Instant i3 = Instant.parse("2022-02-14T23:00:00.00Z"); + Instant i4 = Instant.parse("2022-02-15T23:00:00.00Z"); // After window because of time zone offset + Instant i5 = Instant.parse("2022-02-16T12:00:00.00Z"); // After window + assertOutside(tw, i0); + assertInside(tw, i1); + assertInside(tw, i2); + assertInside(tw, i3); + assertOutside(tw, i4); + assertOutside(tw, i5); + + TimeWindow tw2 = TimeWindow.from("sun", "1", "CET", "2022-01-01", "2022-01-02"); + Instant i6 = Instant.parse("2022-01-01T00:00:00.00Z"); // Wrong day + Instant i7 = Instant.parse("2022-01-02T01:00:00.00Z"); // Wrong hour because of time zone offset + Instant i8 = Instant.parse("2022-01-02T00:00:00.00Z"); + assertOutside(tw2, i6); + assertOutside(tw2, i7); + assertInside(tw2, i8); + + TimeWindow tw3 = TimeWindow.from("", "", "CET", "2022-01-02", ""); + Instant i9 = Instant.parse("2022-02-15T00:00:00.00Z"); + assertOutside(tw3, i6); + assertInside(tw3, i7); + assertInside(tw3, i8); + assertInside(tw3, i9); } } @Test public void validWindows() { { - TimeWindow fz = TimeWindow.from("fri", "8,17-19", "UTC"); - assertEquals(asList(FRIDAY), fz.days()); - assertEquals(asList(8, 17, 18, 19), fz.hours()); + TimeWindow tw = TimeWindow.from("fri", "8,17-19", "UTC", "", ""); + assertEquals(List.of(FRIDAY), tw.days()); + assertEquals(List.of(8, 17, 18, 19), tw.hours()); } { - TimeWindow fz = TimeWindow.from("sat,", "8,17-19", "UTC"); - assertEquals(asList(SATURDAY), fz.days()); - assertEquals(asList(8, 17, 18, 19), fz.hours()); + TimeWindow tw = TimeWindow.from("sat,", "8,17-19", "UTC", "", ""); + assertEquals(List.of(SATURDAY), tw.days()); + assertEquals(List.of(8, 17, 18, 19), tw.hours()); } { - TimeWindow fz = TimeWindow.from("tue,sat", "0,3,7,10", "UTC"); - assertEquals(asList(TUESDAY, SATURDAY), fz.days()); - assertEquals(asList(0, 3, 7, 10), fz.hours()); + TimeWindow tw = TimeWindow.from("tue,sat", "0,3,7,10", "UTC", "", ""); + assertEquals(List.of(TUESDAY, SATURDAY), tw.days()); + assertEquals(List.of(0, 3, 7, 10), tw.hours()); } { - TimeWindow fz = TimeWindow.from("mon,wed-thu", "0,17-19", "UTC"); - assertEquals(asList(MONDAY, WEDNESDAY, THURSDAY), fz.days()); - assertEquals(asList(0, 17, 18, 19), fz.hours()); + TimeWindow tw = TimeWindow.from("mon,wed-thu", "0,17-19", "UTC", "", ""); + assertEquals(List.of(MONDAY, WEDNESDAY, THURSDAY), tw.days()); + assertEquals(List.of(0, 17, 18, 19), tw.hours()); + } + { // Empty results in default values + TimeWindow tw = TimeWindow.from("", "", "", "", ""); + assertEquals(List.of(DayOfWeek.values()), tw.days()); + assertEquals(IntStream.rangeClosed(0, 23).boxed().collect(Collectors.toList()), tw.hours()); + assertEquals("UTC", tw.zone().getId()); } { // Full day names is allowed - TimeWindow fz = TimeWindow.from("monday,wednesday-thursday", "0,17-19", "UTC"); - assertEquals(asList(MONDAY, WEDNESDAY, THURSDAY), fz.days()); - assertEquals(asList(0, 17, 18, 19), fz.hours()); + TimeWindow tw = TimeWindow.from("monday,wednesday-thursday", "0,17-19", "UTC", "", ""); + assertEquals(List.of(MONDAY, WEDNESDAY, THURSDAY), tw.days()); + assertEquals(List.of(0, 17, 18, 19), tw.hours()); } { // Duplicate day and overlapping range is allowed - TimeWindow fz = TimeWindow.from("mon,wed-thu,mon", "3,1-4", "UTC"); - assertEquals(asList(MONDAY, WEDNESDAY, THURSDAY), fz.days()); - assertEquals(asList(1, 2, 3, 4), fz.hours()); + TimeWindow tw = TimeWindow.from("mon,wed-thu,mon", "3,1-4", "UTC", "", ""); + assertEquals(List.of(MONDAY, WEDNESDAY, THURSDAY), tw.days()); + assertEquals(List.of(1, 2, 3, 4), tw.hours()); } } @@ -99,7 +137,6 @@ public class TimeWindowTest { assertInvalidZone("foo", "Invalid time zone 'foo'"); // Malformed day input - assertInvalidDays("", "Invalid day ''"); assertInvalidDays("foo-", "Invalid range 'foo-'"); assertInvalidDays("foo", "Invalid day 'foo'"); assertInvalidDays("f", "Invalid day 'f'"); @@ -107,16 +144,29 @@ public class TimeWindowTest { assertInvalidDays("fri-tue", "Invalid day range 'fri-tue'"); // Malformed hour input - assertInvalidHours("", "Invalid hour ''"); assertInvalidHours("24", "Invalid hour '24'"); assertInvalidHours("-1-9", "Invalid range '-1-9'"); // Window crossing day boundary is disallowed assertInvalidHours("23-1", "Invalid hour range '23-1'"); + + // Invalid date range + assertInvalidDateRange("", "foo", "bar", "Could not parse date range 'foo' and 'bar'"); + assertInvalidDateRange("", "2022-01-15", "2022-01-01", "Invalid date range: start date 2022-01-15 is after end date 2022-01-01"); + assertInvalidDateRange("wed", "2022-01-06", "2022-01-09", "Invalid day: date range [2022-01-06, 2022-01-09] does not contain WEDNESDAY"); + assertInvalidDateRange("mon-sun", "2022-01-03", "2022-01-07", "Invalid day: date range [2022-01-03, 2022-01-07] does not contain SATURDAY"); + } + + private static void assertOutside(TimeWindow window, Instant instant) { + assertFalse("Instant " + instant + " is not in window", window.includes(instant)); + } + + private static void assertInside(TimeWindow window, Instant instant) { + assertTrue("Instant " + instant + " is in window", window.includes(instant)); } private static void assertInvalidZone(String zoneSpec, String exceptionMessage) { try { - TimeWindow.from("mon", "1", zoneSpec); + TimeWindow.from("mon", "1", zoneSpec, "", ""); fail("Expected exception"); } catch (IllegalArgumentException e) { assertEquals(exceptionMessage, e.getMessage()); @@ -125,7 +175,7 @@ public class TimeWindowTest { private static void assertInvalidDays(String daySpec, String exceptionMessage) { try { - TimeWindow.from(daySpec, "1", "UTC"); + TimeWindow.from(daySpec, "1", "UTC", "", ""); fail("Expected exception"); } catch (IllegalArgumentException e) { assertEquals(exceptionMessage, e.getMessage()); @@ -134,11 +184,20 @@ public class TimeWindowTest { private static void assertInvalidHours(String hourSpec, String exceptionMessage) { try { - TimeWindow.from("mon", hourSpec, "UTC"); + TimeWindow.from("mon", hourSpec, "UTC", "", ""); fail("Expected exception"); } catch (IllegalArgumentException e) { assertEquals(exceptionMessage, e.getMessage()); } } + private static void assertInvalidDateRange(String daySpec, String startDate, String endDate, String message) { + try { + TimeWindow.from(daySpec, "", "UTC", startDate, endDate); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertEquals(message, e.getMessage()); + } + } + } |