Scripting: Switch watcher to use joda bwc time objects (#35966)

This commit converts the watcher execution context to use the joda
compat java time objects. It also again removes the joda methods from
the painless whitelist.
This commit is contained in:
Ryan Ernst 2018-12-10 17:29:25 -08:00 committed by GitHub
parent 99f89cd3b4
commit a0da390df2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 97 additions and 95 deletions

View File

@ -12,13 +12,13 @@ to test if a response is necessary.
`ctx['watch_id']` (`String`, read-only)::
The id of the watch.
`ctx['execution_time']` (`DateTime`, read-only)::
`ctx['execution_time']` (`ZonedDateTime`, read-only)::
The start time for the watch.
`ctx['trigger']['scheduled_time']` (`DateTime`, read-only)::
`ctx['trigger']['scheduled_time']` (`ZonedDateTime`, read-only)::
The scheduled trigger time for the watch.
`ctx['trigger']['triggered_time']` (`DateTime`, read-only)::
`ctx['trigger']['triggered_time']` (`ZonedDateTime`, read-only)::
The actual trigger time for the watch.
`ctx['metadata']` (`Map`, read-only)::

View File

@ -12,13 +12,13 @@ data into a new payload for use in a response to a condition.
`ctx['watch_id']` (`String`, read-only)::
The id of the watch.
`ctx['execution_time']` (`DateTime`, read-only)::
`ctx['execution_time']` (`ZonedDateTime`, read-only)::
The start time for the watch.
`ctx['trigger']['scheduled_time']` (`DateTime`, read-only)::
`ctx['trigger']['scheduled_time']` (`ZonedDateTime`, read-only)::
The scheduled trigger time for the watch.
`ctx['trigger']['triggered_time']` (`DateTime`, read-only)::
`ctx['trigger']['triggered_time']` (`ZonedDateTime`, read-only)::
The actual trigger time for the watch.
`ctx['metadata']` (`Map`, read-only)::

View File

@ -48,8 +48,7 @@ public final class Whitelist {
"java.util.txt",
"java.util.function.txt",
"java.util.regex.txt",
"java.util.stream.txt",
"joda.time.txt"
"java.util.stream.txt"
};
public static final List<Whitelist> BASE_WHITELISTS =

View File

@ -1,60 +0,0 @@
#
# Licensed to Elasticsearch under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# Painless definition file. This defines the hierarchy of classes,
# what methods and fields they have, etc.
#
# NOTE: this just minimal whitelisting of joda time, just to provide
# convenient access via the scripting API. classes are fully qualified to avoid
# any confusion with java.time
class org.joda.time.ReadableInstant {
boolean equals(Object)
long getMillis()
int hashCode()
boolean isAfter(org.joda.time.ReadableInstant)
boolean isBefore(org.joda.time.ReadableInstant)
boolean isEqual(org.joda.time.ReadableInstant)
String toString()
}
class org.joda.time.ReadableDateTime {
int getCenturyOfEra()
int getDayOfMonth()
int getDayOfWeek()
int getDayOfYear()
int getEra()
int getHourOfDay()
int getMillisOfDay()
int getMillisOfSecond()
int getMinuteOfDay()
int getMinuteOfHour()
int getMonthOfYear()
int getSecondOfDay()
int getSecondOfMinute()
int getWeekOfWeekyear()
int getWeekyear()
int getYear()
int getYearOfCentury()
int getYearOfEra()
String toString(String)
String toString(String,Locale)
}

View File

@ -22,6 +22,8 @@ package org.elasticsearch.script;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.time.DateFormatter;
import org.elasticsearch.common.time.DateFormatters;
import org.elasticsearch.common.time.DateUtils;
import org.joda.time.DateTime;
@ -42,11 +44,13 @@ import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.WeekFields;
import java.util.Locale;
import java.util.Objects;
/**
* A wrapper around ZonedDateTime that exposes joda methods for backcompat.
*/
public class JodaCompatibleZonedDateTime {
private static final DateFormatter DATE_FORMATTER = DateFormatters.forPattern("strict_date_time");
private static final DeprecationLogger deprecationLogger =
new DeprecationLogger(LogManager.getLogger(JodaCompatibleZonedDateTime.class));
@ -75,7 +79,10 @@ public class JodaCompatibleZonedDateTime {
@Override
public boolean equals(Object o) {
return dt.equals(o);
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JodaCompatibleZonedDateTime that = (JodaCompatibleZonedDateTime) o;
return Objects.equals(dt, that.dt);
}
@Override
@ -85,7 +92,7 @@ public class JodaCompatibleZonedDateTime {
@Override
public String toString() {
return dt.toString();
return DATE_FORMATTER.format(dt);
}
public boolean isAfter(ZonedDateTime o) {

View File

@ -97,6 +97,10 @@ public class JodaCompatibleZonedDateTimeTests extends ESTestCase {
assertDeprecation(assertions, "Use of the joda time method [" + oldMethod + "] is deprecated. Use [" + newMethod + "] instead.");
}
public void testEquals() {
assertThat(javaTime, equalTo(javaTime));
}
public void testToString() {
assertThat(javaTime.toString(), equalTo(jodaTime.toString()));
}

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.DateFieldMapper;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@ -35,6 +36,9 @@ public class WatcherDateTimeUtils {
if (value instanceof DateTime) {
return (DateTime) value;
}
if (value instanceof JodaCompatibleZonedDateTime) {
return new DateTime(((JodaCompatibleZonedDateTime) value).toInstant().toEpochMilli(), DateTimeZone.UTC);
}
if (value instanceof String) {
return parseDateMath((String) value, DateTimeZone.UTC, clock);
}

View File

@ -8,10 +8,13 @@ package org.elasticsearch.xpack.core.watcher.trigger;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.xpack.core.watcher.support.WatcherDateTimeUtils;
import org.joda.time.DateTime;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
@ -25,7 +28,8 @@ public abstract class TriggerEvent implements ToXContentObject {
this.jobName = jobName;
this.triggeredTime = triggeredTime;
this.data = new HashMap<>();
data.put(Field.TRIGGERED_TIME.getPreferredName(), triggeredTime);
data.put(Field.TRIGGERED_TIME.getPreferredName(),
new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(triggeredTime.getMillis()), ZoneOffset.UTC));
}
public String jobName() {

View File

@ -5,9 +5,12 @@
*/
package org.elasticsearch.xpack.watcher.support;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.core.watcher.watch.Payload;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
@ -34,7 +37,8 @@ public final class Variables {
Map<String, Object> ctxModel = new HashMap<>();
ctxModel.put(ID, ctx.id().value());
ctxModel.put(WATCH_ID, ctx.id().watchId());
ctxModel.put(EXECUTION_TIME, ctx.executionTime());
ctxModel.put(EXECUTION_TIME,
new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(ctx.executionTime().getMillis()), ZoneOffset.UTC));
ctxModel.put(TRIGGER, ctx.triggerEvent().data());
if (payload != null) {
ctxModel.put(PAYLOAD, payload.data());

View File

@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.xpack.core.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent;
import org.joda.time.DateTime;
@ -16,6 +17,8 @@ import org.joda.time.DateTimeZone;
import java.io.IOException;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;
public class ScheduleTriggerEvent extends TriggerEvent {
@ -28,7 +31,8 @@ public class ScheduleTriggerEvent extends TriggerEvent {
public ScheduleTriggerEvent(String jobName, DateTime triggeredTime, DateTime scheduledTime) {
super(jobName, triggeredTime);
this.scheduledTime = scheduledTime;
data.put(Field.SCHEDULED_TIME.getPreferredName(), scheduledTime);
data.put(Field.SCHEDULED_TIME.getPreferredName(),
new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(scheduledTime.getMillis()), ZoneOffset.UTC));
}
@Override

View File

@ -16,6 +16,7 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.core.watcher.common.secret.Secret;
@ -52,6 +53,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -129,6 +132,7 @@ public class EmailActionTests extends ESTestCase {
Map<String, Object> metadata = MapBuilder.<String, Object>newMapBuilder().put("_key", "_val").map();
DateTime now = DateTime.now(DateTimeZone.UTC);
JodaCompatibleZonedDateTime jodaJavaNow = new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(now.getMillis()), ZoneOffset.UTC);
Wid wid = new Wid("watch1", now);
WatchExecutionContext ctx = mockExecutionContextBuilder("watch1")
@ -139,14 +143,14 @@ public class EmailActionTests extends ESTestCase {
.buildMock();
Map<String, Object> triggerModel = new HashMap<>();
triggerModel.put("triggered_time", now);
triggerModel.put("scheduled_time", now);
triggerModel.put("triggered_time", jodaJavaNow);
triggerModel.put("scheduled_time", jodaJavaNow);
Map<String, Object> ctxModel = new HashMap<>();
ctxModel.put("id", ctx.id().value());
ctxModel.put("watch_id", "watch1");
ctxModel.put("payload", data);
ctxModel.put("metadata", metadata);
ctxModel.put("execution_time", now);
ctxModel.put("execution_time", jodaJavaNow);
ctxModel.put("trigger", triggerModel);
ctxModel.put("vars", emptyMap());
Map<String, Object> expectedModel = singletonMap("ctx", ctxModel);

View File

@ -16,6 +16,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
@ -35,6 +36,8 @@ import org.joda.time.DateTimeZone;
import org.junit.Before;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@ -78,6 +81,7 @@ public class HipChatActionTests extends ESTestCase {
Map<String, Object> metadata = MapBuilder.<String, Object>newMapBuilder().put("_key", "_val").map();
DateTime now = DateTime.now(DateTimeZone.UTC);
JodaCompatibleZonedDateTime jodaJavaNow = new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(now.getMillis()), ZoneOffset.UTC);
Wid wid = new Wid(randomAlphaOfLength(5), now);
WatchExecutionContext ctx = mockExecutionContextBuilder(wid.watchId())
@ -88,14 +92,14 @@ public class HipChatActionTests extends ESTestCase {
.buildMock();
Map<String, Object> triggerModel = new HashMap<>();
triggerModel.put("triggered_time", now);
triggerModel.put("scheduled_time", now);
triggerModel.put("triggered_time", jodaJavaNow);
triggerModel.put("scheduled_time", jodaJavaNow);
Map<String, Object> ctxModel = new HashMap<>();
ctxModel.put("id", ctx.id().value());
ctxModel.put("watch_id", wid.watchId());
ctxModel.put("payload", data);
ctxModel.put("metadata", metadata);
ctxModel.put("execution_time", now);
ctxModel.put("execution_time", jodaJavaNow);
ctxModel.put("trigger", triggerModel);
ctxModel.put("vars", Collections.emptyMap());
Map<String, Object> expectedModel = singletonMap("ctx", ctxModel);

View File

@ -10,6 +10,7 @@ import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.SuppressLoggerChecks;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
@ -22,6 +23,8 @@ import org.joda.time.DateTime;
import org.junit.Before;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
@ -55,18 +58,19 @@ public class LoggingActionTests extends ESTestCase {
public void testExecute() throws Exception {
final DateTime now = DateTime.now(UTC);
JodaCompatibleZonedDateTime jodaJavaNow = new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(now.getMillis()), ZoneOffset.UTC);
WatchExecutionContext ctx = WatcherTestUtils.mockExecutionContextBuilder("_watch_id")
.time("_watch_id", now)
.buildMock();
Map<String, Object> triggerModel = new HashMap<>();
triggerModel.put("scheduled_time", now);
triggerModel.put("triggered_time", now);
triggerModel.put("scheduled_time", jodaJavaNow);
triggerModel.put("triggered_time", jodaJavaNow);
Map<String, Object> ctxModel = new HashMap<>();
ctxModel.put("id", ctx.id().value());
ctxModel.put("watch_id", "_watch_id");
ctxModel.put("execution_time", now);
ctxModel.put("execution_time", jodaJavaNow);
ctxModel.put("payload", emptyMap());
ctxModel.put("metadata", emptyMap());
ctxModel.put("vars", emptyMap());

View File

@ -13,6 +13,7 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
@ -33,6 +34,8 @@ import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@ -78,6 +81,7 @@ public class PagerDutyActionTests extends ESTestCase {
Map<String, Object> metadata = MapBuilder.<String, Object>newMapBuilder().put("_key", "_val").map();
DateTime now = DateTime.now(DateTimeZone.UTC);
JodaCompatibleZonedDateTime jodaJavaNow = new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(now.getMillis()), ZoneOffset.UTC);
Wid wid = new Wid(randomAlphaOfLength(5), now);
WatchExecutionContext ctx = mockExecutionContextBuilder(wid.watchId())
@ -92,10 +96,10 @@ public class PagerDutyActionTests extends ESTestCase {
ctxModel.put("watch_id", wid.watchId());
ctxModel.put("payload", data);
ctxModel.put("metadata", metadata);
ctxModel.put("execution_time", now);
ctxModel.put("execution_time", jodaJavaNow);
Map<String, Object> triggerModel = new HashMap<>();
triggerModel.put("triggered_time", now);
triggerModel.put("scheduled_time", now);
triggerModel.put("triggered_time", jodaJavaNow);
triggerModel.put("scheduled_time", jodaJavaNow);
ctxModel.put("trigger", triggerModel);
ctxModel.put("vars", Collections.emptyMap());
Map<String, Object> expectedModel = new HashMap<>();

View File

@ -12,6 +12,7 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
@ -31,6 +32,8 @@ import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -75,6 +78,7 @@ public class SlackActionTests extends ESTestCase {
Map<String, Object> metadata = MapBuilder.<String, Object>newMapBuilder().put("_key", "_val").map();
DateTime now = DateTime.now(DateTimeZone.UTC);
JodaCompatibleZonedDateTime jodaJavaNow = new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(now.getMillis()), ZoneOffset.UTC);
Wid wid = new Wid(randomAlphaOfLength(5), now);
WatchExecutionContext ctx = mockExecutionContextBuilder(wid.watchId())
@ -85,14 +89,14 @@ public class SlackActionTests extends ESTestCase {
.buildMock();
Map<String, Object> triggerModel = new HashMap<>();
triggerModel.put("triggered_time", now);
triggerModel.put("scheduled_time", now);
triggerModel.put("triggered_time", jodaJavaNow);
triggerModel.put("scheduled_time", jodaJavaNow);
Map<String, Object> ctxModel = new HashMap<>();
ctxModel.put("id", ctx.id().value());
ctxModel.put("watch_id", wid.watchId());
ctxModel.put("payload", data);
ctxModel.put("metadata", metadata);
ctxModel.put("execution_time", now);
ctxModel.put("execution_time", jodaJavaNow);
ctxModel.put("trigger", triggerModel);
ctxModel.put("vars", emptyMap());
Map<String, Object> expectedModel = singletonMap("ctx", ctxModel);

View File

@ -20,6 +20,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.script.GeneralScriptException;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptException;
import org.elasticsearch.script.ScriptMetaData;
@ -66,9 +67,10 @@ public class ScriptConditionTests extends ESTestCase {
scripts.put("return true", s -> true);
scripts.put("return new Object()", s -> new Object());
scripts.put("ctx.trigger.scheduled_time.getMillis() < new Date().time", vars -> {
DateTime scheduledTime = (DateTime) XContentMapValues.extractValue("ctx.trigger.scheduled_time", vars);
return scheduledTime.getMillis() < new Date().getTime();
scripts.put("ctx.trigger.scheduled_time.toInstant().toEpochMill() < new Date().time", vars -> {
JodaCompatibleZonedDateTime scheduledTime =
(JodaCompatibleZonedDateTime) XContentMapValues.extractValue("ctx.trigger.scheduled_time", vars);
return scheduledTime.toInstant().toEpochMilli() < new Date().getTime();
});
scripts.put("null.foo", s -> {
@ -194,8 +196,8 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testScriptConditionAccessCtx() throws Exception {
ScriptCondition condition = new ScriptCondition(mockScript("ctx.trigger.scheduled_time.getMillis() < new Date().time"),
scriptService);
ScriptCondition condition = new ScriptCondition(
mockScript("ctx.trigger.scheduled_time.toInstant().toEpochMill() < new Date().time"), scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 0, 500L, ShardSearchFailure.EMPTY_ARRAY,
SearchResponse.Clusters.EMPTY);
WatchExecutionContext ctx = mockExecutionContext("_name", new DateTime(DateTimeZone.UTC),
@ -209,6 +211,8 @@ public class ScriptConditionTests extends ESTestCase {
when(watcherContext.id()).thenReturn(mock(Wid.class));
when(watcherContext.watch()).thenReturn(mock(Watch.class));
when(watcherContext.triggerEvent()).thenReturn(mock(TriggerEvent.class));
DateTime now = DateTime.now(DateTimeZone.UTC);
when(watcherContext.executionTime()).thenReturn(now);
WatcherConditionScript watcherScript = new WatcherConditionScript(Collections.emptyMap(), watcherContext) {
@Override
public boolean execute() {

View File

@ -5,16 +5,20 @@
*/
package org.elasticsearch.xpack.watcher.support;
import org.elasticsearch.common.xcontent.ObjectPath;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.core.watcher.execution.Wid;
import org.elasticsearch.common.xcontent.ObjectPath;
import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent;
import org.elasticsearch.xpack.core.watcher.watch.Payload;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.hamcrest.Matchers;
import org.joda.time.DateTime;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Map;
import static java.util.Collections.singletonMap;
@ -44,9 +48,13 @@ public class VariablesTests extends ESTestCase {
assertThat(model, notNullValue());
assertThat(model.size(), is(1));
JodaCompatibleZonedDateTime jodaJavaExecutionTime =
new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(executionTime.getMillis()), ZoneOffset.UTC);
assertThat(ObjectPath.eval("ctx", model), instanceOf(Map.class));
assertThat(ObjectPath.eval("ctx.id", model), is(wid.value()));
assertThat(ObjectPath.eval("ctx.execution_time", model), is(executionTime));
// NOTE: we use toString() here because two ZonedDateTime are *not* equal, we need to check with isEqual
// for date/time equality, but no hamcrest matcher exists for that
assertThat(ObjectPath.eval("ctx.execution_time", model), Matchers.hasToString(jodaJavaExecutionTime.toString()));
assertThat(ObjectPath.eval("ctx.trigger", model), is(event.data()));
assertThat(ObjectPath.eval("ctx.payload", model), is(payload.data()));
assertThat(ObjectPath.eval("ctx.metadata", model), is(metatdata));

View File

@ -22,6 +22,8 @@ import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent;
import org.elasticsearch.xpack.core.watcher.watch.Payload;
import org.elasticsearch.xpack.core.watcher.watch.Watch;
import org.elasticsearch.xpack.watcher.Watcher;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.Collections;
import java.util.HashMap;
@ -191,6 +193,8 @@ public class ScriptTransformTests extends ESTestCase {
when(watcherContext.id()).thenReturn(mock(Wid.class));
when(watcherContext.watch()).thenReturn(mock(Watch.class));
when(watcherContext.triggerEvent()).thenReturn(mock(TriggerEvent.class));
DateTime now = DateTime.now(DateTimeZone.UTC);
when(watcherContext.executionTime()).thenReturn(now);
Payload payload = mock(Payload.class);
WatcherTransformScript watcherScript = new WatcherTransformScript(Collections.emptyMap(), watcherContext, payload) {
@Override