Skip to content

Commit ad5bce4

Browse files
Added tests and documentation for JMTE-Template resolving #7
1 parent 3779f50 commit ad5bce4

File tree

8 files changed

+269
-11
lines changed

8 files changed

+269
-11
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
V 1.2
2+
-----------
3+
* Added JMTE-Template resolving to values for custom labels and annotations
4+
15
V 1.1
26
-----------
37
* Added release artifact to GitHub releases

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ The values `startsAt`, `endsAt` and `generatorURL` will be transmitted to the Al
2929
`endsAt` will be set to the point of time when the condition triggered the alert plus the set grace time which is configured for the alert.
3030

3131
Additionally you can configure your own custom annotations and labels which should be submitted to the AlertManager (see screenshot below).
32+
You can use the [JMTE Template](https://cdn.rawgit.com/DJCordhose/jmte/master/doc/index.html) as you might already know from the [Graylog E-Mail Notification Callback](http://docs.graylog.org/en/2.5/pages/streams/alerts.html#email-alert-notification).
33+
34+
List of provided keys you can use inside JMTE Templates:
35+
* `stream_url` - The stream url.
36+
* `stream` - The specific stream object. There you can use the properties of the stream object e.g. `stream.title`
37+
* `alertCondition` - The specific triggered alert condition. There you can use the properties of the alert condition oject e.g. `alertCondition.createdAt`
38+
* `check_result` - The specific check result. There you can use the properties of the check result object e.g. `check_result.triggeredAt`
39+
* `backlog` - A list containing messages matching the triggered condition if any. You can iterate through them with `${foreach backlog message}${message} ${end}`
40+
* `backlog_size` - The amount of matching messages.
3241

3342
## How to deploy on Graylog
3443
You can easily build the plugin by executing `./gradlew build -x check --no-daemon`.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ serviceLoader {
2626
}
2727

2828
group = 'de.gdata.mobilelab'
29-
version = 1.1
29+
version = 1.2
3030

3131
sourceCompatibility = 1.8
3232
targetCompatibility = 1.8

src/main/java/de/gdata/mobilelab/alertmanagercallback/AlertManagerAlarmCallback.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ public ConfigurationRequest getRequestedConfiguration() {
7373
CONFIGURATION_KEY_CUSTOM_LABELS,
7474
"Custom AlertManager labels",
7575
"",
76-
"The custom AlertManager label key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "' to set for each alert. Please use the following notation: 'label1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "label2=value2'",
76+
"The custom AlertManager label key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR
77+
+ "' to set for each alert. Please use the following notation: 'label1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR
78+
+ "label2=value2"+ CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "streamtitle=${stream.title}'. You can use the JMTE-Template annotation within values of your custom labels to get live information from triggered alert.",
7779
Optional.OPTIONAL
7880
);
7981
configurationRequest.addField(customLabels);
@@ -83,7 +85,9 @@ public ConfigurationRequest getRequestedConfiguration() {
8385
CONFIGURATION_KEY_CUSTOM_ANNOTATIONS,
8486
"Custom AlertManager annotations",
8587
"",
86-
"The custom AlertManager annotation key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "' to set for each alert. Please use the following notation: 'annotation1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "annotation2=value2'",
88+
"The custom AlertManager annotation key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR
89+
+ "' to set for each alert. Please use the following notation: 'annotation1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR
90+
+ "annotation2=value2" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "streamtitle=${stream.title}'. You can use the JMTE-Template annotation within values of your custom annotations to get live information from triggered alert.",
8791
Optional.OPTIONAL
8892
);
8993
configurationRequest.addField(customAnnotations);

src/main/java/de/gdata/mobilelab/alertmanagercallback/AlertManagerPluginMetaData.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public URI getURL() {
3232

3333
@Override
3434
public Version getVersion() {
35-
return Version.from(1, 0, 0);
35+
return Version.from(1, 2, 0);
3636
}
3737

3838
@Override

src/test/java/de/gdata/mobilelab/alertmanagercallback/AlertManagerAlarmCallbackTest.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
import java.lang.reflect.Field;
1212
import java.util.Map;
1313

14-
import static org.junit.Assert.assertEquals;
15-
import static org.junit.Assert.assertNotNull;
16-
import static org.junit.Assert.fail;
14+
import static org.junit.Assert.*;
1715
import static org.mockito.Mockito.mock;
1816
import static org.mockito.Mockito.when;
1917

@@ -75,15 +73,15 @@ public void getRequestedConfiguration() {
7573
assertEquals(TextField.FIELD_TYPE, field.getFieldType());
7674
assertEquals("Custom AlertManager labels", field.getHumanName());
7775
assertEquals("", field.getDefaultValue());
78-
assertEquals("The custom AlertManager label key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "' to set for each alert. Please use the following notation: 'label1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "label2=value2'", field.getDescription());
76+
assertEquals("The custom AlertManager label key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "' to set for each alert. Please use the following notation: 'label1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "label2=value2" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "streamtitle=${stream.title}'. You can use the JMTE-Template annotation within values of your custom labels to get live information from triggered alert.", field.getDescription());
7977
assertEquals(ConfigurationField.Optional.OPTIONAL, field.isOptional());
8078

8179
field = configurationRequest.getField("alertmanager_custom_annotations");
8280
assertNotNull(field);
8381
assertEquals(TextField.FIELD_TYPE, field.getFieldType());
8482
assertEquals("Custom AlertManager annotations", field.getHumanName());
8583
assertEquals("", field.getDefaultValue());
86-
assertEquals("The custom AlertManager annotation key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "' to set for each alert. Please use the following notation: 'annotation1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "annotation2=value2'", field.getDescription());
84+
assertEquals("The custom AlertManager annotation key-value-pairs separated by '" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "' to set for each alert. Please use the following notation: 'annotation1=value1" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "annotation2=value2" + CustomPropertiesTextFieldParser.KEY_VALUE_PAIR_SEPARATOR + "streamtitle=${stream.title}'. You can use the JMTE-Template annotation within values of your custom annotations to get live information from triggered alert.", field.getDescription());
8785
assertEquals(ConfigurationField.Optional.OPTIONAL, field.isOptional());
8886
}
8987

src/test/java/de/gdata/mobilelab/alertmanagercallback/AlertManagerPluginMetaDataTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void getURL() {
3838

3939
@Test
4040
public void getVersion() {
41-
assertEquals(Version.from(1, 0, 0), new AlertManagerPluginMetaData().getVersion());
41+
assertEquals(Version.from(1, 2, 0), new AlertManagerPluginMetaData().getVersion());
4242
}
4343

4444
@Test
Lines changed: 244 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,249 @@
11
package de.gdata.mobilelab.alertmanagercallback;
22

3+
import org.graylog2.plugin.Message;
4+
import org.graylog2.plugin.MessageSummary;
5+
import org.graylog2.plugin.alarms.AlertCondition;
6+
import org.graylog2.plugin.streams.Stream;
7+
import org.joda.time.DateTime;
8+
import org.joda.time.DateTimeZone;
9+
import org.junit.Test;
10+
11+
import java.lang.reflect.Field;
12+
import java.util.*;
13+
14+
import static org.junit.Assert.*;
15+
import static org.mockito.Mockito.mock;
16+
import static org.mockito.Mockito.when;
17+
318
public class CustomPropertiesJMTEResolverTest {
419

5-
// TODO: Add tests
20+
@Test
21+
public void testBuilder() {
22+
// when: building
23+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
24+
.Builder.newBuilder().build();
25+
26+
// then: should not be null
27+
assertNotNull(customPropertiesJMTEResolver);
28+
}
29+
30+
@Test
31+
public void testBuilderWithUrl() throws Exception {
32+
// given: An URL
33+
String url = "https://somealertmanager.alert/";
34+
35+
// and: access to private field for templateModel
36+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
37+
templateModelField.setAccessible(true);
38+
39+
// when: building with given url
40+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
41+
.Builder.newBuilder().withUrl(url).build();
42+
Map<String, Object> templateModel = (Map<String, Object>) templateModelField.get(customPropertiesJMTEResolver);
43+
44+
// then: templateModel should contain entry with URL
45+
assertEquals(url, templateModel.get("stream_url"));
46+
}
47+
48+
@Test
49+
public void testBuilderWithStream() throws Exception {
50+
// given: A Stream
51+
Stream stream = mock(Stream.class);
52+
53+
// and: access to private field for templateModel
54+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
55+
templateModelField.setAccessible(true);
56+
57+
// when: building with given stream
58+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
59+
.Builder.newBuilder().withStream(stream).build();
60+
Map<String, Object> templateModel = (Map<String, Object>) templateModelField.get(customPropertiesJMTEResolver);
61+
62+
// then: templateModel should contain entry with stream
63+
assertEquals(stream, templateModel.get("stream"));
64+
}
65+
66+
@Test
67+
public void testBuilderWithCheckResult() throws Exception {
68+
// given: A CheckResult
69+
AlertCondition.CheckResult checkResult = mock(AlertCondition.CheckResult.class);
70+
71+
// and: access to private field for templateModel
72+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
73+
templateModelField.setAccessible(true);
74+
75+
// when: building with given checkResult
76+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
77+
.Builder.newBuilder().withCheckResult(checkResult).build();
78+
Map<String, Object> templateModel = (Map<String, Object>) templateModelField.get(customPropertiesJMTEResolver);
79+
80+
// then: templateModel should contain entry with checkResult
81+
assertEquals(checkResult, templateModel.get("check_result"));
82+
}
83+
84+
@Test
85+
public void testBuilderWithCheckResultContainingMessages() throws Exception {
86+
// given: A CheckResult
87+
AlertCondition.CheckResult checkResult = mock(AlertCondition.CheckResult.class);
88+
89+
// and: Message Mocks
90+
Message messageOne = new Message("messageOne", "source", new DateTime(2015, 1, 1, 0, 0, DateTimeZone.UTC));
91+
Message messageTwo = new Message("messageTwo", "source", new DateTime(2015, 1, 1, 0, 0, DateTimeZone.UTC));
92+
MessageSummary messageSummaryOne = mock(MessageSummary.class);
93+
MessageSummary messageSummaryTwo = mock(MessageSummary.class);
94+
List<MessageSummary> messageSummaryList = Arrays.asList(messageSummaryOne, messageSummaryTwo);
95+
when(messageSummaryOne.getRawMessage()).thenReturn(messageOne);
96+
when(messageSummaryTwo.getRawMessage()).thenReturn(messageTwo);
97+
when(checkResult.getMatchingMessages()).thenReturn(messageSummaryList);
98+
99+
// and: access to private field for templateModel
100+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
101+
templateModelField.setAccessible(true);
102+
103+
// when: building with given checkResult
104+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
105+
.Builder.newBuilder().withCheckResult(checkResult).build();
106+
Map<String, Object> templateModel = (Map<String, Object>) templateModelField.get(customPropertiesJMTEResolver);
107+
108+
// then: templateModel should contain entry with checkResult
109+
assertEquals(checkResult, templateModel.get("check_result"));
110+
111+
// and: templateModel contains those messages from above
112+
assertEquals(2, templateModel.get("backlog_size"));
113+
assertEquals(2, ((List<Message>) templateModel.get("backlog")).size());
114+
assertTrue(((List<Message>) templateModel.get("backlog")).contains(messageOne));
115+
assertTrue(((List<Message>) templateModel.get("backlog")).contains(messageTwo));
116+
}
117+
118+
@Test
119+
public void testBuilderWithCheckResultContainingNoMatchingMessages() throws Exception {
120+
// given: A CheckResult which returns null as matching messages
121+
AlertCondition.CheckResult checkResult = mock(AlertCondition.CheckResult.class);
122+
when(checkResult.getMatchingMessages()).thenReturn(null);
123+
124+
// and: access to private field for templateModel
125+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
126+
templateModelField.setAccessible(true);
127+
128+
// when: building with given checkResult
129+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
130+
.Builder.newBuilder().withCheckResult(checkResult).build();
131+
Map<String, Object> templateModel = (Map<String, Object>) templateModelField.get(customPropertiesJMTEResolver);
132+
133+
// then: templateModel should contain entry with checkResult
134+
assertEquals(checkResult, templateModel.get("check_result"));
135+
136+
// and: templateModel contains those messages from above
137+
assertEquals(0, templateModel.get("backlog_size"));
138+
assertTrue(((List<Message>) templateModel.get("backlog")).isEmpty());
139+
}
140+
141+
@Test
142+
public void testBuilderWithCheckResultContainingTriggeredCondition() throws Exception {
143+
// given: A CheckResult which returns a triggered condition
144+
AlertCondition.CheckResult checkResult = mock(AlertCondition.CheckResult.class);
145+
AlertCondition triggeredCondition = mock(AlertCondition.class);
146+
when(checkResult.getTriggeredCondition()).thenReturn(triggeredCondition);
147+
148+
// and: access to private field for templateModel
149+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
150+
templateModelField.setAccessible(true);
151+
152+
// when: building with given checkResult
153+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
154+
.Builder.newBuilder().withCheckResult(checkResult).build();
155+
Map<String, Object> templateModel = (Map<String, Object>) templateModelField.get(customPropertiesJMTEResolver);
156+
157+
// then: templateModel should contain entry with checkResult
158+
assertEquals(checkResult, templateModel.get("check_result"));
159+
160+
// and: templateModel contains an alertCondition
161+
assertEquals(triggeredCondition, templateModel.get("alertCondition"));
162+
}
163+
164+
@Test
165+
public void testTransformTemplateValuesWithEmptyTemplateModelMap() throws Exception {
166+
// given: an empty Map
167+
Map<String, Object> emptyMap = Collections.emptyMap();
168+
169+
// and: a CustomPropertiesJMTEResolver instance
170+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
171+
.Builder.newBuilder().build();
172+
173+
// and: access to private field for templateModel
174+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
175+
templateModelField.setAccessible(true);
176+
177+
// and: resolver has given map
178+
templateModelField.set(customPropertiesJMTEResolver, emptyMap);
179+
180+
// and: A custom value map
181+
Map<String, Object> customValueMap = new HashMap<>();
182+
customValueMap.put("test1", "${a_unknown_key_for_template}");
183+
customValueMap.put("test2", "${a_unknown_key_for_template2}sometext${another_one}");
184+
customValueMap.put("test3", 1337);
185+
186+
// when: calling transformTemplateValues
187+
Map<String, Object> result = customPropertiesJMTEResolver.transformTemplateValues(customValueMap);
188+
189+
// then: values which do not exist will be replaced with an empty string
190+
assertTrue(result.containsKey("test1"));
191+
assertTrue(result.containsKey("test2"));
192+
assertTrue(result.containsKey("test3"));
193+
assertEquals("", result.get("test1"));
194+
assertEquals("sometext", result.get("test2"));
195+
assertEquals(1337, result.get("test3"));
196+
}
197+
198+
@Test
199+
public void testTransformTemplateValuesWithCustomTemplateModelMap() throws Exception {
200+
// given: a custom templateModelMap
201+
Map<String, Object> customTemplateModelMap = new HashMap<>();
202+
customTemplateModelMap.put("a_known_key_for_template", "bla");
203+
customTemplateModelMap.put("a_known_key_for_template2", "blubb");
204+
customTemplateModelMap.put("another_one", "hello");
205+
customTemplateModelMap.put("backlog", Arrays.asList("Message 1: Hello", "Message2: World"));
206+
customTemplateModelMap.put("existing_value", "Hello World!");
207+
208+
// and: a CustomPropertiesJMTEResolver instance
209+
CustomPropertiesJMTEResolver customPropertiesJMTEResolver = CustomPropertiesJMTEResolver
210+
.Builder.newBuilder().build();
211+
212+
// and: access to private field for templateModel
213+
Field templateModelField = CustomPropertiesJMTEResolver.class.getDeclaredField("templateModel");
214+
templateModelField.setAccessible(true);
215+
216+
// and: resolver has given map
217+
templateModelField.set(customPropertiesJMTEResolver, customTemplateModelMap);
218+
219+
// and: A custom value map
220+
Map<String, Object> customValueMap = new HashMap<>();
221+
customValueMap.put("test1", "${a_known_key_for_template}");
222+
customValueMap.put("test2", "${a_known_key_for_template2}sometext${another_one}");
223+
customValueMap.put("test3", 1337);
224+
customValueMap.put("test4", "${an_unknown_key_for_template}");
225+
customValueMap.put("foreachTest", "${foreach backlog message}${message} ${end}");
226+
customValueMap.put("ifTest", "${if not_existing_value}${not_existing_value}${else}unknown${end}");
227+
customValueMap.put("ifTest2", "${if existing_value}${existing_value}${else}unknown${end}");
228+
229+
// when: calling transformTemplateValues
230+
Map<String, Object> result = customPropertiesJMTEResolver.transformTemplateValues(customValueMap);
231+
232+
// then: values should be replaced if they exist inside the templateModelMap
233+
assertTrue(result.containsKey("test1"));
234+
assertTrue(result.containsKey("test2"));
235+
assertTrue(result.containsKey("test3"));
236+
assertTrue(result.containsKey("test4"));
237+
assertTrue(result.containsKey("foreachTest"));
238+
assertTrue(result.containsKey("ifTest"));
239+
assertTrue(result.containsKey("ifTest2"));
240+
assertEquals("bla", result.get("test1"));
241+
assertEquals("blubbsometexthello", result.get("test2"));
242+
assertEquals(1337, result.get("test3"));
243+
assertEquals("", result.get("test4"));
244+
assertEquals("Message 1: Hello Message2: World ", result.get("foreachTest"));
245+
assertEquals("unknown", result.get("ifTest"));
246+
assertEquals("Hello World!", result.get("ifTest2"));
247+
}
248+
6249
}

0 commit comments

Comments
 (0)