/configuration/src/test/java/io/airlift/configuration/ConfigurationFactoryTest.java
Java | 464 lines | 399 code | 49 blank | 16 comment | 0 complexity | d34b39dc457f375bf4c52a655b3e5463 MD5 | raw file
1/*
2 * Copyright 2010 Proofpoint, Inc.
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 io.airlift.configuration;
17
18import com.google.common.collect.Maps;
19import com.google.inject.Binder;
20import com.google.inject.CreationException;
21import com.google.inject.Guice;
22import com.google.inject.Injector;
23import com.google.inject.Module;
24import com.google.inject.spi.Message;
25import io.airlift.testing.Assertions;
26import org.testng.Assert;
27import org.testng.annotations.Test;
28
29import javax.validation.constraints.Max;
30import javax.validation.constraints.Min;
31import javax.validation.constraints.NotNull;
32import java.util.List;
33import java.util.Map;
34import java.util.TreeMap;
35
36public class ConfigurationFactoryTest
37{
38
39 @Test
40 public void testAnnotatedGettersThrows()
41 {
42 Map<String, String> properties = new TreeMap<String, String>();
43 properties.put("string-value", "some value");
44 properties.put("boolean-value", "true");
45 TestMonitor monitor = new TestMonitor();
46 try {
47 createInjector(properties, monitor, new Module()
48 {
49 public void configure(Binder binder)
50 {
51 ConfigurationModule.bindConfig(binder).to(AnnotatedGetter.class);
52 }
53 });
54
55 Assert.fail("Expected an exception in object creation due to conflicting configuration");
56 } catch (CreationException e) {
57 monitor.assertNumberOfErrors(2);
58 Assertions.assertContainsAllOf(e.getMessage(), "not a valid setter", "getStringValue") ;
59 Assertions.assertContainsAllOf(e.getMessage(), "not a valid setter", "isBooleanValue") ;
60 }
61 }
62
63 @Test
64 public void testAnnotatedSetters()
65 {
66 Map<String, String> properties = new TreeMap<String, String>();
67 properties.put("string-value", "some value");
68 properties.put("boolean-value", "true");
69 TestMonitor monitor = new TestMonitor();
70 Injector injector = createInjector(properties, monitor, new Module()
71 {
72 public void configure(Binder binder)
73 {
74 ConfigurationModule.bindConfig(binder).to(AnnotatedSetter.class);
75 }
76 });
77 AnnotatedSetter annotatedSetter = injector.getInstance(AnnotatedSetter.class);
78 monitor.assertNumberOfErrors(0);
79 monitor.assertNumberOfWarnings(0);
80 Assert.assertNotNull(annotatedSetter);
81 Assert.assertEquals(annotatedSetter.getStringValue(), "some value");
82 Assert.assertEquals(annotatedSetter.isBooleanValue(), true);
83 }
84
85 @Test
86 public void testConfigurationDespiteLegacyConfig()
87 {
88 Map<String, String> properties = new TreeMap<String, String>();
89 properties.put("string-a", "this is a");
90 properties.put("string-b", "this is b");
91 TestMonitor monitor = new TestMonitor();
92 Injector injector = createInjector(properties, monitor, new Module()
93 {
94 public void configure(Binder binder)
95 {
96 ConfigurationModule.bindConfig(binder).to(LegacyConfigPresent.class);
97 }
98 });
99 LegacyConfigPresent legacyConfigPresent = injector.getInstance(LegacyConfigPresent.class);
100 monitor.assertNumberOfErrors(0);
101 monitor.assertNumberOfWarnings(0);
102 Assert.assertNotNull(legacyConfigPresent);
103 Assert.assertEquals(legacyConfigPresent.getStringA(), "this is a");
104 Assert.assertEquals(legacyConfigPresent.getStringB(), "this is b");
105 }
106
107 @Test
108 public void testConfigurationThroughLegacyConfig()
109 {
110 Map<String, String> properties = new TreeMap<String, String>();
111 properties.put("string-value", "this is a");
112 properties.put("string-b", "this is b");
113 TestMonitor monitor = new TestMonitor();
114 Injector injector = createInjector(properties, monitor, new Module()
115 {
116 public void configure(Binder binder)
117 {
118 ConfigurationModule.bindConfig(binder).to(LegacyConfigPresent.class);
119 }
120 });
121 LegacyConfigPresent legacyConfigPresent = injector.getInstance(LegacyConfigPresent.class);
122 monitor.assertNumberOfErrors(0);
123 monitor.assertNumberOfWarnings(1);
124 monitor.assertMatchingWarningRecorded("string-value", "replaced", "Use 'string-a'");
125 Assert.assertNotNull(legacyConfigPresent);
126 Assert.assertEquals(legacyConfigPresent.getStringA(), "this is a");
127 Assert.assertEquals(legacyConfigPresent.getStringB(), "this is b");
128 }
129
130 @Test
131 public void testConfigurationWithRedundantLegacyConfig()
132 {
133 Map<String, String> properties = new TreeMap<String, String>();
134 properties.put("string-value", "this is a");
135 properties.put("string-a", "this is a");
136 properties.put("string-b", "this is b");
137 TestMonitor monitor = new TestMonitor();
138 Injector injector = createInjector(properties, monitor, new Module()
139 {
140 public void configure(Binder binder)
141 {
142 ConfigurationModule.bindConfig(binder).to(LegacyConfigPresent.class);
143 }
144 });
145 LegacyConfigPresent legacyConfigPresent = injector.getInstance(LegacyConfigPresent.class);
146 monitor.assertNumberOfErrors(0);
147 monitor.assertNumberOfWarnings(1);
148 monitor.assertMatchingWarningRecorded("string-value", "replaced", "Use 'string-a'");
149 Assert.assertNotNull(legacyConfigPresent);
150 Assert.assertEquals(legacyConfigPresent.getStringA(), "this is a");
151 Assert.assertEquals(legacyConfigPresent.getStringB(), "this is b");
152 }
153
154 @Test
155 public void testConfigurationWithConflictingLegacyConfigThrows()
156 {
157 Map<String, String> properties = new TreeMap<String, String>();
158 properties.put("string-value", "this is the old value");
159 properties.put("string-a", "this is a");
160 properties.put("string-b", "this is b");
161 TestMonitor monitor = new TestMonitor();
162 try {
163 createInjector(properties, monitor, new Module()
164 {
165 public void configure(Binder binder)
166 {
167 ConfigurationModule.bindConfig(binder).to(LegacyConfigPresent.class);
168 }
169 });
170
171 Assert.fail("Expected an exception in object creation due to conflicting configuration");
172 } catch (CreationException e) {
173 monitor.assertNumberOfErrors(1);
174 monitor.assertNumberOfWarnings(1);
175 monitor.assertMatchingWarningRecorded("string-value", "replaced", "Use 'string-a'");
176 Assertions.assertContainsAllOf(e.getMessage(), "string-value", "conflicts with property", "string-a") ;
177 }
178 }
179
180 @Test
181 public void testConfigurationDespiteDeprecatedConfig()
182 {
183 Map<String, String> properties = new TreeMap<String, String>();
184 properties.put("string-b", "this is b");
185 TestMonitor monitor = new TestMonitor();
186 Injector injector = createInjector(properties, monitor, new Module()
187 {
188 public void configure(Binder binder)
189 {
190 ConfigurationModule.bindConfig(binder).to(DeprecatedConfigPresent.class);
191 }
192 });
193 DeprecatedConfigPresent deprecatedConfigPresent = injector.getInstance(DeprecatedConfigPresent.class);
194 monitor.assertNumberOfErrors(0);
195 monitor.assertNumberOfWarnings(0);
196 Assert.assertNotNull(deprecatedConfigPresent);
197 Assert.assertEquals(deprecatedConfigPresent.getStringA(), "defaultA");
198 Assert.assertEquals(deprecatedConfigPresent.getStringB(), "this is b");
199 }
200
201 @Test
202 public void testConfigurationThroughDeprecatedConfig()
203 {
204 Map<String, String> properties = new TreeMap<String, String>();
205 properties.put("string-a", "this is a");
206 properties.put("string-b", "this is b");
207 TestMonitor monitor = new TestMonitor();
208 Injector injector = createInjector(properties, monitor, new Module()
209 {
210 public void configure(Binder binder)
211 {
212 ConfigurationModule.bindConfig(binder).to(DeprecatedConfigPresent.class);
213 }
214 });
215 DeprecatedConfigPresent deprecatedConfigPresent = injector.getInstance(DeprecatedConfigPresent.class);
216 monitor.assertNumberOfErrors(0);
217 monitor.assertNumberOfWarnings(1);
218 monitor.assertMatchingWarningRecorded("string-a", "deprecated and should not be used");
219 Assert.assertNotNull(deprecatedConfigPresent);
220 Assert.assertEquals(deprecatedConfigPresent.getStringA(), "this is a");
221 Assert.assertEquals(deprecatedConfigPresent.getStringB(), "this is b");
222 }
223
224 @Test
225 public void testDefunctPropertyInConfigThrows()
226 {
227 Map<String, String> properties = Maps.newTreeMap();
228 properties.put("string-value", "this is a");
229 properties.put("defunct-value", "this shouldn't work");
230 TestMonitor monitor = new TestMonitor();
231 try {
232 createInjector(properties, monitor, new Module()
233 {
234 public void configure(Binder binder)
235 {
236 ConfigurationModule.bindConfig(binder).to(DefunctConfigPresent.class);
237 }
238 });
239
240 Assert.fail("Expected an exception in object creation due to use of defunct config");
241 } catch (CreationException e) {
242 monitor.assertNumberOfErrors(1);
243 monitor.assertNumberOfWarnings(0);
244 monitor.assertMatchingErrorRecorded("Defunct property", "'defunct-value", "cannot be configured");
245 }
246 }
247
248 @Test
249 public void testSuccessfulBeanValidation()
250 {
251 Map<String, String> properties = Maps.newHashMap();
252 properties.put("string-value", "has a value");
253 properties.put("int-value", "50");
254 TestMonitor monitor = new TestMonitor();
255 Injector injector = createInjector(properties, monitor, new Module()
256 {
257 public void configure(Binder binder)
258 {
259 ConfigurationModule.bindConfig(binder).to(BeanValidationClass.class);
260 }
261 });
262 BeanValidationClass beanValidationClass = injector.getInstance(BeanValidationClass.class);
263 monitor.assertNumberOfErrors(0);
264 monitor.assertNumberOfWarnings(0);
265 Assert.assertNotNull(beanValidationClass);
266 Assert.assertEquals(beanValidationClass.getStringValue(), "has a value");
267 Assert.assertEquals(beanValidationClass.getIntValue(), 50);
268 }
269
270 @Test
271 public void testFailedBeanValidation()
272 {
273 Map<String, String> properties = Maps.newHashMap();
274 // string-value left at invalid default
275 properties.put("int-value", "5000"); // out of range
276 TestMonitor monitor = new TestMonitor();
277 try {
278 Injector injector = createInjector(properties, monitor, new Module()
279 {
280 public void configure(Binder binder)
281 {
282 ConfigurationModule.bindConfig(binder).to(BeanValidationClass.class);
283 }
284 });
285 } catch (CreationException e) {
286 monitor.assertNumberOfErrors(2);
287 monitor.assertNumberOfWarnings(0);
288 monitor.assertMatchingErrorRecorded("Constraint violation", "intValue", "must be less than or equal to 100", "BeanValidationClass");
289 monitor.assertMatchingErrorRecorded("Constraint violation", "stringValue", "may not be null", "BeanValidationClass");
290 }
291 }
292
293
294 private Injector createInjector(Map<String, String> properties, TestMonitor monitor, Module module)
295 {
296 ConfigurationFactory configurationFactory = new ConfigurationFactory(properties, monitor);
297 List<Message> messages = new ConfigurationValidator(configurationFactory, null).validate(module);
298 return Guice.createInjector(new ConfigurationModule(configurationFactory), module, new ValidationErrorModule(messages));
299 }
300
301
302 public static class AnnotatedGetter {
303 private String stringValue;
304 private boolean booleanValue;
305
306 @Config("string-value")
307 public String getStringValue()
308 {
309 return stringValue;
310 }
311
312 public void setStringValue(String stringValue)
313 {
314 this.stringValue = stringValue;
315 }
316
317 @Config("boolean-value")
318 public boolean isBooleanValue()
319 {
320 return booleanValue;
321 }
322
323 public void setBooleanValue(boolean booleanValue)
324 {
325 this.booleanValue = booleanValue;
326 }
327 }
328
329 public static class AnnotatedSetter {
330 private String stringValue;
331 private boolean booleanValue;
332
333 public String getStringValue()
334 {
335 return stringValue;
336 }
337
338 @Config("string-value")
339 public void setStringValue(String stringValue)
340 {
341 this.stringValue = stringValue;
342 }
343
344 public boolean isBooleanValue()
345 {
346 return booleanValue;
347 }
348
349 @Config("boolean-value")
350 public void setBooleanValue(boolean booleanValue)
351 {
352 this.booleanValue = booleanValue;
353 }
354 }
355
356 public static class LegacyConfigPresent
357 {
358 private String stringA = "defaultA";
359 private String stringB = "defaultB";
360
361 public String getStringA()
362 {
363 return stringA;
364 }
365
366 @Config("string-a")
367 @LegacyConfig("string-value")
368 public void setStringA(String stringValue)
369 {
370 this.stringA = stringValue;
371 }
372
373 public String getStringB()
374 {
375 return stringB;
376 }
377
378 @Config("string-b")
379 public void setStringB(String stringValue)
380 {
381 this.stringB = stringValue;
382 }
383 }
384
385 public static class DeprecatedConfigPresent
386 {
387 private String stringA = "defaultA";
388 private String stringB = "defaultB";
389
390 @Deprecated
391 public String getStringA()
392 {
393 return stringA;
394 }
395
396 @Deprecated
397 @Config("string-a")
398 public void setStringA(String stringValue)
399 {
400 this.stringA = stringValue;
401 }
402
403 public String getStringB()
404 {
405 return stringB;
406 }
407
408 @Config("string-b")
409 public void setStringB(String stringValue)
410 {
411 this.stringB = stringValue;
412 }
413 }
414
415 @DefunctConfig("defunct-value")
416 public static class DefunctConfigPresent
417 {
418 private String stringValue;
419 private boolean booleanValue;
420
421 public String getStringValue()
422 {
423 return stringValue;
424 }
425
426 @Config("string-value")
427 public void setStringValue(String stringValue)
428 {
429 this.stringValue = stringValue;
430 }
431 }
432
433 public static class BeanValidationClass
434 {
435 @NotNull
436 private String stringValue = null;
437
438 private int myIntValue;
439
440 public String getStringValue()
441 {
442 return stringValue;
443 }
444
445 @Config("string-value")
446 public void setStringValue(String value)
447 {
448 this.stringValue = value;
449 }
450
451 @Min(1)
452 @Max(100)
453 public int getIntValue()
454 {
455 return myIntValue;
456 }
457
458 @Config("int-value")
459 public void setIntValue(int value)
460 {
461 this.myIntValue = value;
462 }
463 }
464}