Dropwizard: Unable to test configuration file with parameter

Created on 26 Jul 2019  路  5Comments  路  Source: dropwizard/dropwizard

Hi there. I'm trying to test a dropwizard configuration file following the guidelines set out here: https://www.dropwizard.io/1.3.13/docs/manual/testing.html#testing-configurations

This works fine for simple configuration files, but unfortunately doesn't cater for more complex configuration files involving parameters.

For example, the following configuration will fail to parse:

Config file:

import io.dropwizard.Configuration;
import lombok.Getter;

@Getter
public class SomeConfigurationFile extends Configuration {
    private long someAttribute;
}

YAML file:

server:
  applicationConnectors:
    - type: http
      port: 1234

  adminConnectors:
    - type: http
      port: 5678

someAttribute: ${SOME_ENV_VAR:-3000}

When attempting to run this, i get the following error:

io.dropwizard.configuration.ConfigurationParsingException: src/main/resources/config.yaml has an error:
  * Incorrect type of value at: pollingFrequency; is of type: String, expected: long

    at io.dropwizard.configuration.ConfigurationParsingException$Builder.build(ConfigurationParsingException.java:279)
    at io.dropwizard.configuration.BaseConfigurationFactory.build(BaseConfigurationFactory.java:149)
    at io.dropwizard.configuration.BaseConfigurationFactory.build(BaseConfigurationFactory.java:89)
    at io.dropwizard.configuration.ConfigurationFactory.build(ConfigurationFactory.java:28)
    at <myTest>.<myTestMethod>(<myTest>.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.contrib.java.lang.system.EnvironmentVariables$EnvironmentVariablesStatement.evaluate(EnvironmentVariables.java:122)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `long` from String "${someAttribute:-3000}": not a valid Long value
 at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: <myConfigFile>["someAttribute"])
    at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1549)

The reason for this is that i have no way to define a ConfigurationSourceProvider within this test. When running the full application, i can initialise this using the Application.initialize() method as follows:

bootstrap.setConfigurationSourceProvider(
    new SubstitutingSourceProvider(
        bootstrap.getConfigurationSourceProvider(),
        new EnvironmentVariableSubstitutor(false))
);

This is not available in the test however. Does anyone know how this could be achieved?

My test class:

import com.fasterxml.jackson.databind.ObjectMapper;
import io.dropwizard.configuration.EnvironmentVariableSubstitutor;
import io.dropwizard.configuration.SubstitutingSourceProvider;
import io.dropwizard.configuration.YamlConfigurationFactory;
import io.dropwizard.jackson.Jackson;
import io.dropwizard.jersey.validation.Validators;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.testing.ResourceHelpers;
import io.dropwizard.testing.junit.DropwizardAppRule;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;

import javax.validation.Validator;
import java.io.File;

import static org.junit.Assert.*;

public class MyConfigurationTest {

    private YamlConfigurationFactory<MyConfiguration> factory;

    @Before
    public void setUp() {
        ObjectMapper objectMapper = Jackson.newObjectMapper();
        Validator validator = Validators.newValidator();
        factory = new YamlConfigurationFactory<>(MyConfiguration.class, validator, objectMapper, "dw");
    }

    @Test
    public void testAppConfigurationIsValid() throws Exception {
        File yaml = new File("src/main/resources/config.yaml");
        final MyConfiguration config = factory.build(yaml);
        assertNotNull(config);
    }
}

Most helpful comment

Did you know about / try:

factory.build(
    new SubstitutingSourceProvider(
        new ResourceConfigurationSourceProvider(),
        new EnvironmentVariableSubstitutor(false)
    ), "config.yaml");

or is it not applicable?

All 5 comments

Did you know about / try:

factory.build(
    new SubstitutingSourceProvider(
        new ResourceConfigurationSourceProvider(),
        new EnvironmentVariableSubstitutor(false)
    ), "config.yaml");

or is it not applicable?

Did you know about / try:

factory.build(
    new SubstitutingSourceProvider(
        new ResourceConfigurationSourceProvider(),
        new EnvironmentVariableSubstitutor(false)
    ), "config.yaml");

or is it not applicable?

This actually works FLAWLESSLY :D Thanks very much!

In all my trawling of the documentation, this is something I didn't stumble upon. May be worth adding this to the documentation under the section for testing configurations.

@jamesalfei Would you mind creating a PR to add this to the documentation?

@joschi Sure thing, I'll get that up over the next couple of days.

I've opened PR https://github.com/dropwizard/dropwizard/pull/2874 for this. I'll close this ticket now and any conversation can now take place on the PR. Thanks for the help all!

Was this page helpful?
0 / 5 - 0 ratings