Skip to content
This repository has been archived by the owner on Dec 13, 2023. It is now read-only.

Commit

Permalink
I have completed all of the unit tests on the basic (non resource
Browse files Browse the repository at this point in the history
injection) implementation of the Eclipse Microprofile 3.0 configuration
definition.
  • Loading branch information
csturacloudreach committed Aug 27, 2019
1 parent 67e6dfc commit 563a3ad
Show file tree
Hide file tree
Showing 4 changed files with 473 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@

package org.eclipse.jemo.sys.microprofile;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.StreamSupport;

import javax.annotation.Priority;

Expand Down Expand Up @@ -55,7 +57,12 @@ public <T> T getValue(String propertyName, Class<T> propertyType) {

@Override
public <T> Optional<T> getOptionalValue(String propertyName, Class<T> propertyType) {
final String configVal = configSource.get().getValue(propertyName);
final String configVal = StreamSupport.stream(getConfigSources().spliterator(), false)
.filter(src -> src.getPropertyNames().contains(propertyName))
.limit(1)
.map(src -> src.getValue(propertyName))
.findFirst().orElse(null);

if(configVal == null) {
return Optional.empty();
} else {
Expand All @@ -64,8 +71,13 @@ public <T> Optional<T> getOptionalValue(String propertyName, Class<T> propertyTy
} else {
//we need to check if a data converter exists for this class type
Converter c = dataConverters.stream()
.filter(dc -> Arrays.asList(dc.getClass().getTypeParameters()[0].getBounds())
.filter(dc -> Arrays.asList(dc.getClass().getGenericInterfaces())
.stream()
.filter(i -> i instanceof ParameterizedType)
.map(i -> (ParameterizedType)i)
.filter(i -> Converter.class.isAssignableFrom(((Class)i.getRawType())))
.filter(i -> i.getActualTypeArguments().length == 1)
.map(i -> i.getActualTypeArguments()[0])
.filter(t -> t instanceof Class)
.map(t -> (Class)t)
.anyMatch(cls -> cls.isAssignableFrom(propertyType))
Expand Down Expand Up @@ -127,7 +139,12 @@ public void addDataConverter(Converter converter) {
@Override
public Iterable<ConfigSource> getConfigSources() {
ArrayList<ConfigSource> result = new ArrayList<>();
result.addAll(mpConfigSource.get() == null ? Arrays.asList(configSource.get()) : Arrays.asList(configSource.get(), mpConfigSource.get()));
if(mpConfigSource.get() != null) {
result.add(mpConfigSource.get());
}
if(configSource.get() != null) {
result.add(configSource.get());
}
result.addAll(otherSources);
result.sort((s1,s2) -> Integer.valueOf(s1.getOrdinal()).compareTo(Integer.valueOf(s2.getOrdinal())));
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public ConfigBuilder addDiscoveredSources() {
//of a specified type so we will use that instead and the effect will be the same.
classLoader.getClassList().stream()
.map(clsName -> Util.I(null, x -> Class.forName(clsName, false, classLoader)))
.filter(cls -> cls != null && ConfigSource.class.isAssignableFrom(cls))
.filter(cls -> ConfigSource.class.isAssignableFrom(cls))
.flatMap(cls -> Stream.of(cls.getConstructors()))
.filter(cstr -> cstr.getParameterCount() == 0)
.map(cstr -> Util.I(null, x -> (ConfigSource)cstr.newInstance()))
Expand All @@ -60,7 +60,7 @@ public ConfigBuilder addDiscoveredSources() {
public ConfigBuilder addDiscoveredConverters() {
classLoader.getClassList().stream()
.map(clsName -> Util.I(null, x -> Class.forName(clsName, false, classLoader)))
.filter(cls -> cls != null && Converter.class.isAssignableFrom(cls))
.filter(cls -> Converter.class.isAssignableFrom(cls))
.flatMap(cls -> Stream.of(cls.getConstructors()))
.filter(cstr -> cstr.getParameterCount() == 0)
.map(cstr -> Util.I(null, x -> (Converter)cstr.newInstance()))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
/*
********************************************************************************
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

package org.eclipse.jemo.sys.microprofile;

import static org.junit.Assert.*;

import java.io.ByteArrayOutputStream;
import java.util.AbstractMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.StreamSupport;

import org.eclipse.jemo.JemoGSMTest;
import org.eclipse.jemo.sys.JemoClassLoader;
import org.eclipse.jemo.sys.internal.Util;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.Converter;
import org.junit.Test;

/**
* The purpose of this test file is to ensure that the class org.eclipse.jemo.sys.microprofile.JemoConfigBuilder
* obtains 100% code coverage from a unit test standpoint.
*
* Because this class can only be used within an Active Jemo module we will need to instantiate the server to make sure these
* tests run correctly.
*
* @author Christopher Stura "cstura@gmail.com"
*/
public class JemoConfigBuilderTest extends JemoGSMTest {

public static class MyCustomerSource implements ConfigSource {

private Map<String,String> cfg = Util.MAP(new AbstractMap.SimpleEntry("custom", "value"));

@Override
public Map<String, String> getProperties() {
return cfg;
}

@Override
public String getValue(String propertyName) {
return cfg.get(propertyName);
}

@Override
public String getName() {
return "MyCustomerSource";
}

}

public static class MyUnacceptableSource implements ConfigSource {

public MyUnacceptableSource(String param1) {}

@Override
public Map<String, String> getProperties() { return null; }

@Override
public String getValue(String propertyName) { return null; }

@Override
public String getName() { return null; }

}

public static class ErrorThrowingSource implements ConfigSource {
public ErrorThrowingSource() {
throw new RuntimeException("Error");
}

@Override
public Map<String, String> getProperties() { return null; }

@Override
public String getValue(String propertyName) { return null; }

@Override
public String getName() { return null; }
}

public static class InstantiationErrorSource implements ConfigSource {

static {
Util.B(null, x -> { throw new RuntimeException("Error"); });
}

@Override
public Map<String, String> getProperties() { return null; }

@Override
public String getValue(String propertyName) { return null; }

@Override
public String getName() { return null; }
}

public static class LongConvereter implements Converter<Long> {

@Override
public Long convert(String value) {
return Long.valueOf(Util.crc(value.getBytes(Util.UTF8_CHARSET)));
}

}

public static interface MyConvereter<T,K> extends Converter<T> {}

public static class LongConverterWithTooManyParameters implements MyConvereter<Long, Long> {

@Override
public Long convert(String value) {
return null;
}

}

public static class ConverterWithBadConstructor implements Converter<Long> {

public ConverterWithBadConstructor(String param1) {}

@Override
public Long convert(String value) {
// TODO Auto-generated method stub
return null;
}

}

public static class ConverterWithErrorConstructor implements Converter<Long> {

public ConverterWithErrorConstructor() { throw new RuntimeException("Error"); }

@Override
public Long convert(String value) {
// TODO Auto-generated method stub
return null;
}

}

private byte[] getJarBytes() throws Throwable {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
Util.createJar(byteOut, JemoConfigBuilder.class, MyCustomerSource.class, MyUnacceptableSource.class,
ErrorThrowingSource.class, InstantiationErrorSource.class, LongConvereter.class,
LongConverterWithTooManyParameters.class, ConverterWithBadConstructor.class, ConverterWithErrorConstructor.class);
return byteOut.toByteArray();
}

private byte[] getEmptyJarBytes() throws Throwable {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
Util.createJar(byteOut, JemoConfigBuilder.class);
return byteOut.toByteArray();
}

private JemoClassLoader getTestClassLoader() throws Throwable {
JemoClassLoader loader = new JemoClassLoader(UUID.randomUUID().toString(), getJarBytes());
loader.setApplicationId(92001);
return loader;
}

private JemoClassLoader getEmptyTestClassLoader() throws Throwable {
JemoClassLoader loader = new JemoClassLoader(UUID.randomUUID().toString(), getEmptyJarBytes());
loader.setApplicationId(92001);
return loader;
}

@Test
public void testAddDefaultSources() throws Throwable {
byte[] jar = getJarBytes();
JemoConfigBuilder builder = new JemoConfigBuilder(getTestClassLoader());
builder.addDefaultSources();
Config config = builder.build();
assertEquals(2,StreamSupport.stream(config.getConfigSources().spliterator(),false)
.filter(src -> src instanceof MicroProfileConfigSource || src instanceof JemoConfigSource)
.count());
assertTrue(StreamSupport.stream(config.getConfigSources().spliterator(),false).anyMatch(src -> src instanceof MicroProfileConfigSource));
assertTrue(StreamSupport.stream(config.getConfigSources().spliterator(),false).anyMatch(src -> src instanceof JemoConfigSource));
}

@Test
public void testAddDiscoveredSources() throws Throwable {
JemoConfigBuilder builder = new JemoConfigBuilder(getTestClassLoader());
builder.addDiscoveredSources();
Config config = builder.build();
assertTrue(config instanceof JemoConfig);
assertTrue(config.getOptionalValue("custom", String.class).isPresent());
assertEquals("value",config.getValue("custom", String.class));
}

@Test
public void testAddDiscoveredConverters() throws Throwable {
JemoConfigBuilder builder = new JemoConfigBuilder(getTestClassLoader());
builder.addDiscoveredSources();
builder.addDiscoveredConverters();
Config config = builder.build();
assertTrue(config instanceof JemoConfig);
assertTrue(config.getOptionalValue("custom", Long.class).isPresent());
assertEquals(Long.valueOf(Util.crc("value".getBytes(Util.UTF8_CHARSET))),config.getValue("custom", Long.class));
}

@Test
public void testForClassLoader() throws Throwable {
JemoConfigBuilder builder = new JemoConfigBuilder(getTestClassLoader());
builder.addDiscoveredSources();
builder.addDiscoveredConverters();
//now we are going to set a non Jemo class loader derivative and we expect nothing to change.
builder.forClassLoader(new ClassLoader() {});
Config config = builder.build();
assertTrue(config instanceof JemoConfig);
assertTrue(config.getOptionalValue("custom", Long.class).isPresent());
assertEquals(Long.valueOf(Util.crc("value".getBytes(Util.UTF8_CHARSET))),config.getValue("custom", Long.class));
//now we are going to set a jemo class loader with nothing in it.
builder.forClassLoader(getEmptyTestClassLoader());
config = builder.build();
assertTrue(config instanceof JemoConfig);
assertFalse(config.getOptionalValue("custom", Long.class).isPresent());
}

@Test
public void testWithSources() throws Throwable {
JemoClassLoader classLoader = getTestClassLoader();
JemoConfigBuilder builder = new JemoConfigBuilder(classLoader);
builder.withSources(
new MicroProfileConfigSource(classLoader),
new JemoConfigSource(Util.MAP(new AbstractMap.SimpleEntry<>("custom2","value2"))),
new MyCustomerSource());
Config config = builder.build();
assertTrue(config instanceof JemoConfig);
assertTrue(config.getOptionalValue("custom", String.class).isPresent());
assertTrue(config.getOptionalValue("custom2", String.class).isPresent());
assertEquals("value", config.getValue("custom", String.class));
assertEquals("value2", config.getValue("custom2", String.class));
}

@Test
public void testWithConverters() throws Throwable {
JemoClassLoader classLoader = getTestClassLoader();
JemoConfigBuilder builder = new JemoConfigBuilder(classLoader);
builder.withSources(
new MicroProfileConfigSource(classLoader),
new JemoConfigSource(Util.MAP(new AbstractMap.SimpleEntry<>("custom2","value2"))),
new MyCustomerSource());
builder.withConverters(new LongConvereter());
Config config = builder.build();
assertTrue(config instanceof JemoConfig);
assertTrue(config.getOptionalValue("custom", Long.class).isPresent());
assertEquals(Long.valueOf(Util.crc("value".getBytes(Util.UTF8_CHARSET))),config.getValue("custom", Long.class));
}

@Test
public void testWithConverter() throws Throwable {
JemoClassLoader classLoader = getTestClassLoader();
JemoConfigBuilder builder = new JemoConfigBuilder(classLoader);
builder.withSources(
new MicroProfileConfigSource(classLoader),
new JemoConfigSource(Util.MAP(new AbstractMap.SimpleEntry<>("custom2","value2"))),
new MyCustomerSource());
builder.withConverter(Long.class, 1, (v) -> Util.crc(v.getBytes(Util.UTF8_CHARSET)));
Config config = builder.build();
assertTrue(config instanceof JemoConfig);
assertTrue(config.getOptionalValue("custom", Long.class).isPresent());
assertEquals(Long.valueOf(Util.crc("value".getBytes(Util.UTF8_CHARSET))),config.getValue("custom", Long.class));
}
}
Loading

0 comments on commit 563a3ad

Please sign in to comment.