aboutsummaryrefslogtreecommitdiffstats
path: root/config-model-api/src/test
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2022-01-07 10:56:41 +0100
committerMartin Polden <mpolden@mpolden.no>2022-01-07 14:43:37 +0100
commitae843dd9bd28be5c8445adf10dc7c0a6a69f2d97 (patch)
tree7d7c5b2fc602c54e3d634d0a0c07ab13d0ab1981 /config-model-api/src/test
parente11472ccb26601fe74004a2400b44ea000c88d6f (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.java51
-rw-r--r--config-model-api/src/test/java/com/yahoo/config/application/api/TimeWindowTest.java137
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());
+ }
+ }
+
}