/**
* Copyright 2014-2016 Netflix, Inc.
*
* Licensed 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.
*/
package com.netflix.spectator.impl;
import com.netflix.spectator.api.RegistryConfig;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.time.Duration;
import java.time.Instant;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.time.zone.ZoneRulesException;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
@RunWith(JUnit4.class)
public class ConfigTest {
@Test
public void usingMap() {
Map<String, String> props = new HashMap<>();
//props.put("propagateWarnings", "false");
RegistryConfig cfg = Config.usingMap(props);
Assert.assertFalse(cfg.propagateWarnings());
}
private void assertNoSuchElement(TestConfig cfg, Consumer<TestConfig> f) {
try {
f.accept(cfg);
Assert.fail("should have thrown exception for missing key");
} catch (NoSuchElementException e) {
// This is expected, other exceptions should propagate and fail
}
}
private void assertNumberFormat(TestConfig cfg, Consumer<TestConfig> f) {
try {
f.accept(cfg);
Assert.fail("should have thrown exception for malformed input");
} catch (NumberFormatException e) {
// This is expected, other exceptions should propagate and fail
}
}
private void assertStringIndexOutOfBounds(TestConfig cfg, Consumer<TestConfig> f) {
try {
f.accept(cfg);
Assert.fail("should have thrown exception for malformed input");
} catch (StringIndexOutOfBoundsException e) {
// This is expected, other exceptions should propagate and fail
}
}
private void assertDateTimeParse(TestConfig cfg, Consumer<TestConfig> f) {
try {
f.accept(cfg);
Assert.fail("should have thrown exception for malformed input");
} catch (DateTimeParseException e) {
// This is expected, other exceptions should propagate and fail
}
}
private void assertZoneRules(TestConfig cfg, Consumer<TestConfig> f) {
try {
f.accept(cfg);
Assert.fail("should have thrown exception for malformed input");
} catch (ZoneRulesException e) {
// This is expected, other exceptions should propagate and fail
}
}
@Test
public void proxyBooleanWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueBoolean);
props.put("valueBoolean", "false");
Assert.assertFalse(cfg.valueBoolean());
props.put("valueBoolean", "true");
Assert.assertTrue(cfg.valueBoolean());
props.put("valueBoolean", "abc");
Assert.assertFalse(cfg.valueBoolean());
}
@Test
public void proxyBooleanPrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveBoolean);
props.put("primitiveBoolean", "false");
Assert.assertFalse(cfg.primitiveBoolean());
props.put("primitiveBoolean", "true");
Assert.assertTrue(cfg.primitiveBoolean());
props.put("primitiveBoolean", "abc");
Assert.assertFalse(cfg.primitiveBoolean());
}
@Test
public void proxyByteWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueByte);
props.put("valueByte", "0");
Assert.assertEquals(Byte.valueOf((byte) 0), cfg.valueByte());
props.put("valueByte", "42");
Assert.assertEquals(Byte.valueOf((byte) 42), cfg.valueByte());
props.put("valueByte", "abczyx");
assertNumberFormat(cfg, TestConfig::valueByte);
}
@Test
public void proxyBytePrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveByte);
props.put("primitiveByte", "0");
Assert.assertEquals((byte) 0, cfg.primitiveByte());
props.put("primitiveByte", "42");
Assert.assertEquals((byte) 42, cfg.primitiveByte());
props.put("primitiveByte", "abczyx");
assertNumberFormat(cfg, TestConfig::primitiveByte);
}
@Test
public void proxyShortWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueShort);
props.put("valueShort", "0");
Assert.assertEquals(Short.valueOf((short) 0), cfg.valueShort());
props.put("valueShort", "42");
Assert.assertEquals(Short.valueOf((short) 42), cfg.valueShort());
props.put("valueShort", "abczyx");
assertNumberFormat(cfg, TestConfig::valueShort);
}
@Test
public void proxyShortPrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveShort);
props.put("primitiveShort", "0");
Assert.assertEquals((short) 0, cfg.primitiveShort());
props.put("primitiveShort", "42");
Assert.assertEquals((short) 42, cfg.primitiveShort());
props.put("primitiveShort", "abczyx");
assertNumberFormat(cfg, TestConfig::primitiveShort);
}
@Test
public void proxyIntegerWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueInteger);
props.put("valueInteger", "0");
Assert.assertEquals(Integer.valueOf(0), cfg.valueInteger());
props.put("valueInteger", "42");
Assert.assertEquals(Integer.valueOf(42), cfg.valueInteger());
props.put("valueInteger", "abczyx");
assertNumberFormat(cfg, TestConfig::valueInteger);
}
@Test
public void proxyIntegerPrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveInteger);
props.put("primitiveInteger", "0");
Assert.assertEquals(0, cfg.primitiveInteger());
props.put("primitiveInteger", "42");
Assert.assertEquals(42, cfg.primitiveInteger());
props.put("primitiveInteger", "abczyx");
assertNumberFormat(cfg, TestConfig::primitiveInteger);
}
@Test
public void proxyLongWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueLong);
props.put("valueLong", "0");
Assert.assertEquals(Long.valueOf(0L), cfg.valueLong());
props.put("valueLong", "42");
Assert.assertEquals(Long.valueOf(42L), cfg.valueLong());
props.put("valueLong", "abczyx");
assertNumberFormat(cfg, TestConfig::valueLong);
}
@Test
public void proxyLongPrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveLong);
props.put("primitiveLong", "0");
Assert.assertEquals(0L, cfg.primitiveLong());
props.put("primitiveLong", "42");
Assert.assertEquals(42L, cfg.primitiveLong());
props.put("primitiveLong", "abczyx");
assertNumberFormat(cfg, TestConfig::primitiveLong);
}
@Test
public void proxyFloatWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueFloat);
props.put("valueFloat", "0");
Assert.assertEquals(Float.valueOf(0.0f), cfg.valueFloat());
props.put("valueFloat", "42");
Assert.assertEquals(Float.valueOf(42.0f), cfg.valueFloat());
props.put("valueFloat", "abczyx");
assertNumberFormat(cfg, TestConfig::valueFloat);
}
@Test
public void proxyFloatPrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveFloat);
props.put("primitiveFloat", "0");
Assert.assertEquals(0.0f, cfg.primitiveFloat(), 1e-9);
props.put("primitiveFloat", "42");
Assert.assertEquals(42.0f, cfg.primitiveFloat(), 1e-9);
props.put("primitiveFloat", "abczyx");
assertNumberFormat(cfg, TestConfig::primitiveFloat);
}
@Test
public void proxyDoubleWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueDouble);
props.put("valueDouble", "0");
Assert.assertEquals(Double.valueOf(0.0), cfg.valueDouble());
props.put("valueDouble", "42");
Assert.assertEquals(Double.valueOf(42.0), cfg.valueDouble());
props.put("valueDouble", "abczyx");
assertNumberFormat(cfg, TestConfig::valueDouble);
}
@Test
public void proxyDoublePrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveDouble);
props.put("primitiveDouble", "0");
Assert.assertEquals(0.0, cfg.primitiveDouble(), 1e-9);
props.put("primitiveDouble", "42");
Assert.assertEquals(42.0, cfg.primitiveDouble(), 1e-9);
props.put("primitiveDouble", "abczyx");
assertNumberFormat(cfg, TestConfig::primitiveDouble);
}
@Test
public void proxyCharacterWrapper() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueCharacter);
props.put("valueCharacter", "0");
Assert.assertEquals(Character.valueOf('0'), cfg.valueCharacter());
props.put("valueCharacter", "42");
Assert.assertEquals(Character.valueOf('4'), cfg.valueCharacter());
props.put("valueCharacter", "");
assertStringIndexOutOfBounds(cfg, TestConfig::valueCharacter);
}
@Test
public void proxyCharacterPrimitive() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::primitiveCharacter);
props.put("primitiveCharacter", "0");
Assert.assertEquals('0', cfg.primitiveCharacter());
props.put("primitiveCharacter", "42");
Assert.assertEquals('4', cfg.primitiveCharacter());
props.put("primitiveCharacter", "");
assertStringIndexOutOfBounds(cfg, TestConfig::primitiveCharacter);
}
@Test
public void proxyString() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueString);
props.put("valueString", "0");
Assert.assertEquals("0", cfg.valueString());
props.put("valueString", "forty-two: 42");
Assert.assertEquals("forty-two: 42", cfg.valueString());
props.put("valueString", "");
Assert.assertEquals("", cfg.valueString());
}
@Test
public void proxyDuration() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueDuration);
props.put("valueDuration", "PT5M");
Assert.assertEquals(Duration.ofMinutes(5), cfg.valueDuration());
props.put("valueDuration", "abczyx");
assertDateTimeParse(cfg, TestConfig::valueDuration);
}
@Test
public void proxyPeriod() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valuePeriod);
props.put("valuePeriod", "P7M");
Assert.assertEquals(Period.ofMonths(7), cfg.valuePeriod());
props.put("valuePeriod", "abczyx");
assertDateTimeParse(cfg, TestConfig::valuePeriod);
}
@Test
public void proxyInstant() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueInstant);
props.put("valueInstant", "2007-12-03T10:15:30.00Z");
Instant expected = ZonedDateTime.of(2007, 12, 3, 10, 15, 30, 0, ZoneOffset.UTC).toInstant();
Assert.assertEquals(expected, cfg.valueInstant());
props.put("valueInstant", "abczyx");
assertDateTimeParse(cfg, TestConfig::valueInstant);
}
@Test
public void proxyZonedDateTime() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueZonedDateTime);
props.put("valueZonedDateTime", "2007-12-03T10:15:30.00Z");
ZonedDateTime expected = ZonedDateTime.of(2007, 12, 3, 10, 15, 30, 0, ZoneOffset.UTC);
Assert.assertEquals(expected, cfg.valueZonedDateTime());
props.put("valueZonedDateTime", "abczyx");
assertDateTimeParse(cfg, TestConfig::valueZonedDateTime);
}
@Test
public void proxyZoneId() {
Map<String, String> props = new HashMap<>();
TestConfig cfg = Config.usingMap(TestConfig.class, props);
assertNoSuchElement(cfg, TestConfig::valueZoneId);
props.put("valueZoneId", "UTC");
Assert.assertEquals(ZoneId.of("UTC"), cfg.valueZoneId());
props.put("valueZoneId", "US/Pacific");
Assert.assertEquals(ZoneId.of("US/Pacific"), cfg.valueZoneId());
props.put("valueZoneId", "abczyx");
assertZoneRules(cfg, TestConfig::valueZoneId);
}
public interface TestConfig {
Boolean valueBoolean();
boolean primitiveBoolean();
Byte valueByte();
byte primitiveByte();
Short valueShort();
short primitiveShort();
Integer valueInteger();
int primitiveInteger();
Long valueLong();
long primitiveLong();
Float valueFloat();
float primitiveFloat();
Double valueDouble();
double primitiveDouble();
Character valueCharacter();
char primitiveCharacter();
String valueString();
Duration valueDuration();
Period valuePeriod();
Instant valueInstant();
ZonedDateTime valueZonedDateTime();
ZoneId valueZoneId();
}
}