Skip to content

Commit 705ee44

Browse files
committed
extend tests
1 parent 9a94136 commit 705ee44

4 files changed

Lines changed: 306 additions & 7 deletions

File tree

rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
import java.util.Comparator;
44
import java.util.Optional;
5+
import java.util.ServiceLoader;
56
import javasabr.rlib.collections.array.Array;
67
import javasabr.rlib.collections.array.ArrayCollectors;
8+
import javasabr.rlib.collections.array.ArrayFactory;
79
import javasabr.rlib.logger.impl.config.LoggerConfig;
810
import javasabr.rlib.logger.impl.config.loader.impl.DefaultLoggerConfigLoader;
11+
import javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoader;
912

1013
/**
1114
* Resolver of logger configuration from available loaders.
@@ -14,12 +17,20 @@
1417
*/
1518
public class LoggerConfigResolver {
1619

17-
private static final Array<LoggerConfigLoader> LOADERS = Array
18-
.<LoggerConfigLoader>of(new DefaultLoggerConfigLoader())
19-
.stream()
20-
.sorted(Comparator.comparingInt(LoggerConfigLoader::order))
21-
.collect(ArrayCollectors.toArray(LoggerConfigLoader.class));
20+
private static final Array<LoggerConfigLoader> LOADERS;
2221

22+
static {
23+
var registeredProviders = ArrayFactory.mutableArray(LoggerConfigLoader.class);
24+
registeredProviders.add(new DefaultLoggerConfigLoader());
25+
registeredProviders.add(new PropertyLoggerConfigLoader());
26+
for (var provider : ServiceLoader.load(LoggerConfigLoadersProvider.class)) {
27+
registeredProviders.addAll(provider.getLoggerConfigLoaders());
28+
}
29+
LOADERS = registeredProviders.stream()
30+
.sorted(Comparator.comparingInt(LoggerConfigLoader::order))
31+
.collect(ArrayCollectors.toArray(LoggerConfigLoader.class));
32+
}
33+
2334
/**
2435
* Loads logger configuration.
2536
*

rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
public class PropertyLoggerConfigLoader implements LoggerConfigLoader {
1818

19-
public static final String FILE_MAIN = "/rlib.logger.properties";
20-
public static final String FILE_TEST = "/rlib.logger-test.properties";
19+
public static final String FILE_MAIN = "rlib.logger.properties";
20+
public static final String FILE_TEST = "rlib.logger-test.properties";
2121

2222
@Override
2323
public Optional<LoggerConfig> tryToLoad() {

rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package javasabr.rlib.logger.impl.config.loader.impl;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
45

6+
import java.io.ByteArrayInputStream;
57
import java.io.IOException;
8+
import java.io.InputStream;
9+
import java.nio.charset.StandardCharsets;
10+
import java.util.Map;
11+
import java.util.Optional;
612
import java.util.Properties;
13+
import java.util.function.Supplier;
14+
import java.util.stream.Collectors;
715
import javasabr.rlib.collections.array.Array;
816
import javasabr.rlib.collections.array.UnsafeArray;
917
import javasabr.rlib.logger.api.Logger;
@@ -14,6 +22,7 @@
1422
import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer;
1523
import javasabr.rlib.logger.impl.config.consumer.impl.ConsoleMessageConsumer;
1624
import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig;
25+
import javasabr.rlib.logger.impl.config.render.impl.SimpleLogMessageRender;
1726
import javasabr.rlib.logger.impl.config.render.impl.pattern.PatternLogMessageRender;
1827
import javasabr.rlib.logger.impl.config.render.impl.pattern.node.DateTimePatternRenderNode;
1928
import javasabr.rlib.logger.impl.config.render.impl.pattern.node.LevelPatternRenderNode;
@@ -100,4 +109,187 @@ void shouldLoadLoggerConfigCorrectly() throws IOException {
100109
.returns(false, Logger::warnEnabled)
101110
.returns(true, Logger::errorEnabled);
102111
}
112+
113+
@Test
114+
void shouldPreferTestPropertiesOverMainProperties() {
115+
// given:
116+
var loader = new PropertyLoggerConfigLoader();
117+
var contextClassLoader = new ResourceClassLoader(Map.of(
118+
PropertyLoggerConfigLoader.FILE_TEST, "logger.level.ROOT=TRACE",
119+
PropertyLoggerConfigLoader.FILE_MAIN, "logger.level.ROOT=ERROR"));
120+
121+
// when:
122+
Optional<LoggerConfig> loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad);
123+
124+
// then:
125+
assertThat(loadedConfig).isPresent();
126+
127+
// when:
128+
var loggerService = new DefaultLoggerService(loadedConfig.orElseThrow());
129+
DefaultLogger logger = loggerService.getLogger("example.logger");
130+
131+
// then:
132+
assertThat(logger)
133+
.returns(true, Logger::traceEnabled)
134+
.returns(true, Logger::debugEnabled)
135+
.returns(true, Logger::infoEnabled)
136+
.returns(true, Logger::warnEnabled)
137+
.returns(true, Logger::errorEnabled);
138+
}
139+
140+
@Test
141+
void shouldFallbackToMainPropertiesWhenTestMissing() {
142+
// given:
143+
var loader = new PropertyLoggerConfigLoader();
144+
var contextClassLoader = new ResourceClassLoader(Map.of(
145+
PropertyLoggerConfigLoader.FILE_MAIN, "logger.level.ROOT=ERROR"));
146+
147+
// when:
148+
Optional<LoggerConfig> loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad);
149+
150+
// then:
151+
assertThat(loadedConfig).isPresent();
152+
153+
// when:
154+
var loggerService = new DefaultLoggerService(loadedConfig.orElseThrow());
155+
DefaultLogger logger = loggerService.getLogger("example.logger");
156+
157+
// then:
158+
assertThat(logger)
159+
.returns(false, Logger::traceEnabled)
160+
.returns(false, Logger::debugEnabled)
161+
.returns(false, Logger::infoEnabled)
162+
.returns(false, Logger::warnEnabled)
163+
.returns(true, Logger::errorEnabled);
164+
}
165+
166+
@Test
167+
void shouldReturnEmptyWhenNoPropertiesFound() {
168+
// given:
169+
var loader = new PropertyLoggerConfigLoader();
170+
var contextClassLoader = new ResourceClassLoader(Map.of());
171+
172+
// when:
173+
Optional<LoggerConfig> loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad);
174+
175+
// then:
176+
assertThat(loadedConfig).isEmpty();
177+
}
178+
179+
@Test
180+
void shouldUseRootLevelForUnconfiguredLogger() {
181+
// given:
182+
var loader = new PropertyLoggerConfigLoader();
183+
var contextClassLoader = new ResourceClassLoader(Map.of(
184+
PropertyLoggerConfigLoader.FILE_MAIN,
185+
"logger.level.ROOT=WARNING\nlogger.level.configured.logger=TRACE"));
186+
187+
// when:
188+
Optional<LoggerConfig> loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad);
189+
190+
// then:
191+
assertThat(loadedConfig).isPresent();
192+
193+
// when:
194+
var loggerService = new DefaultLoggerService(loadedConfig.orElseThrow());
195+
DefaultLogger unconfiguredLogger = loggerService.getLogger("unknown.logger");
196+
DefaultLogger configuredLogger = loggerService.getLogger("configured.logger");
197+
198+
// then:
199+
assertThat(unconfiguredLogger)
200+
.returns(false, Logger::traceEnabled)
201+
.returns(false, Logger::debugEnabled)
202+
.returns(false, Logger::infoEnabled)
203+
.returns(true, Logger::warnEnabled)
204+
.returns(true, Logger::errorEnabled);
205+
assertThat(configuredLogger)
206+
.returns(true, Logger::traceEnabled)
207+
.returns(true, Logger::debugEnabled)
208+
.returns(true, Logger::infoEnabled)
209+
.returns(true, Logger::warnEnabled)
210+
.returns(true, Logger::errorEnabled);
211+
}
212+
213+
@Test
214+
void shouldUseSimpleMessageRenderWhenPatternIsAbsent() {
215+
// given:
216+
var loader = new PropertyLoggerConfigLoader();
217+
var properties = new Properties();
218+
properties.setProperty("logger.level.ROOT", "INFO");
219+
220+
// when:
221+
LoggerConfig loggerConfig = loader.loadFromProperties(properties);
222+
223+
// then:
224+
assertThat(loggerConfig)
225+
.isInstanceOf(DefaultLoggerConfig.class);
226+
227+
// when:
228+
var defaultLoggerConfig = (DefaultLoggerConfig) loggerConfig;
229+
var loggerService = new DefaultLoggerService(loggerConfig);
230+
DefaultLogger logger = loggerService.getLogger("example.logger");
231+
UnsafeArray<LogMessageConsumer> consumers = defaultLoggerConfig.resolveConsumers(
232+
logger,
233+
LoggerLevel.TRACE);
234+
235+
// then:
236+
assertThat(consumers.size())
237+
.isEqualTo(1);
238+
assertThat(consumers.get(0))
239+
.isInstanceOf(ConsoleMessageConsumer.class)
240+
.extracting("logMessageRender")
241+
.isInstanceOf(SimpleLogMessageRender.class);
242+
}
243+
244+
@Test
245+
void shouldThrowExceptionWhenLevelValueIsInvalid() {
246+
// given:
247+
var loader = new PropertyLoggerConfigLoader();
248+
var properties = new Properties();
249+
properties.setProperty("logger.level.ROOT", "INF0");
250+
251+
// when/then:
252+
assertThatThrownBy(() -> loader.loadFromProperties(properties))
253+
.isInstanceOf(IllegalArgumentException.class);
254+
}
255+
256+
private static <T> T withContextClassLoader(ClassLoader contextClassLoader, Supplier<T> action) {
257+
Thread currentThread = Thread.currentThread();
258+
ClassLoader previousClassLoader = currentThread.getContextClassLoader();
259+
try {
260+
currentThread.setContextClassLoader(contextClassLoader);
261+
return action.get();
262+
} finally {
263+
currentThread.setContextClassLoader(previousClassLoader);
264+
}
265+
}
266+
267+
private static class ResourceClassLoader extends ClassLoader {
268+
269+
private final Map<String, byte[]> resources;
270+
271+
private ResourceClassLoader(Map<String, String> resources) {
272+
super(Thread
273+
.currentThread()
274+
.getContextClassLoader());
275+
this.resources = resources
276+
.entrySet()
277+
.stream()
278+
.collect(Collectors.toUnmodifiableMap(
279+
Map.Entry::getKey,
280+
entry -> entry.getValue().getBytes(StandardCharsets.UTF_8)));
281+
}
282+
283+
@Override
284+
public InputStream getResourceAsStream(String name) {
285+
byte[] loaded = resources.get(name);
286+
if (loaded != null) {
287+
return new ByteArrayInputStream(loaded);
288+
}
289+
if (PropertyLoggerConfigLoader.FILE_TEST.equals(name) || PropertyLoggerConfigLoader.FILE_MAIN.equals(name)) {
290+
return null;
291+
}
292+
return super.getResourceAsStream(name);
293+
}
294+
}
103295
}

rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package javasabr.rlib.logger.impl.config.render.impl.pattern;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
45

56
import javasabr.rlib.collections.array.Array;
67
import javasabr.rlib.logger.impl.config.render.impl.pattern.node.DateTimePatternRenderNode;
@@ -45,4 +46,99 @@ void shouldParseCorrectlyPattern1() {
4546
assertThat(parsed.get(7))
4647
.isInstanceOf(MessagePatternRenderNode.class);
4748
}
49+
50+
@Test
51+
void shouldParsePatternWithOnlyLiteralText() {
52+
// given:
53+
var pattern = "just a literal string";
54+
55+
// when:
56+
Array<PatternRenderNode> parsed = PatternRenderNodesParser.parse(pattern);
57+
58+
// then:
59+
assertThat(parsed.size())
60+
.isEqualTo(1);
61+
assertThat(parsed.get(0))
62+
.isInstanceOf(StringPatternRenderNode.class)
63+
.isEqualTo(new StringPatternRenderNode("just a literal string"));
64+
}
65+
66+
@Test
67+
void shouldParsePatternWithMessageBetweenLiteralTexts() {
68+
// given:
69+
var pattern = "prefix %msg suffix";
70+
71+
// when:
72+
Array<PatternRenderNode> parsed = PatternRenderNodesParser.parse(pattern);
73+
74+
// then:
75+
assertThat(parsed.size())
76+
.isEqualTo(3);
77+
assertThat(parsed.get(0))
78+
.isInstanceOf(StringPatternRenderNode.class)
79+
.isEqualTo(new StringPatternRenderNode("prefix "));
80+
assertThat(parsed.get(1))
81+
.isInstanceOf(MessagePatternRenderNode.class);
82+
assertThat(parsed.get(2))
83+
.isInstanceOf(StringPatternRenderNode.class)
84+
.isEqualTo(new StringPatternRenderNode(" suffix"));
85+
}
86+
87+
@Test
88+
void shouldParsePatternWithSimpleNodeSequence() {
89+
// given:
90+
var pattern = "%level %msg %shortLogger";
91+
92+
// when:
93+
Array<PatternRenderNode> parsed = PatternRenderNodesParser.parse(pattern);
94+
95+
// then:
96+
assertThat(parsed.size())
97+
.isEqualTo(5);
98+
assertThat(parsed.get(0))
99+
.isInstanceOf(LevelPatternRenderNode.class);
100+
assertThat(parsed.get(1))
101+
.isInstanceOf(StringPatternRenderNode.class)
102+
.isEqualTo(new StringPatternRenderNode(" "));
103+
assertThat(parsed.get(2))
104+
.isInstanceOf(MessagePatternRenderNode.class);
105+
assertThat(parsed.get(3))
106+
.isInstanceOf(StringPatternRenderNode.class)
107+
.isEqualTo(new StringPatternRenderNode(" "));
108+
assertThat(parsed.get(4))
109+
.isInstanceOf(ShortLoggerPatternRenderNode.class);
110+
}
111+
112+
@Test
113+
void shouldThrowWhenNodeNameIsUnknown() {
114+
// given:
115+
var pattern = "%unknown";
116+
117+
// when/then:
118+
assertThatThrownBy(() -> PatternRenderNodesParser.parse(pattern))
119+
.isInstanceOf(IllegalArgumentException.class)
120+
.hasMessageContaining("Unexpected node name:[unknown]");
121+
}
122+
123+
@Test
124+
void shouldThrowWhenDateTimeNodeHasNoOpeningBrace() {
125+
// given:
126+
var pattern = "%dateTime yyyy-MM-dd";
127+
128+
// when/then:
129+
assertThatThrownBy(() -> PatternRenderNodesParser.parse(pattern))
130+
.isInstanceOf(IllegalArgumentException.class)
131+
.hasMessageContaining("Missed '{'");
132+
}
133+
134+
@Test
135+
void shouldThrowWhenDateTimeNodeHasNoClosingBrace() {
136+
// given:
137+
var pattern = "%dateTime{yyyy-MM-dd";
138+
139+
// when/then:
140+
assertThatThrownBy(() -> PatternRenderNodesParser.parse(pattern))
141+
.isInstanceOf(IllegalArgumentException.class)
142+
.hasMessageContaining("Missed closing '}'");
143+
}
48144
}

0 commit comments

Comments
 (0)