Unit test problem with a embedded database process

I have a problem when running the unit test (run by gradle build).
I use ru.yandex.qatools.embed:postgresql-embedded:2.4 to create a embedded postgres database in unit test. It work properly with CircleCI 1.0, but when upgrading to CircleCI 2.0, the unit test have been failed with the logs:

org.springframework.transaction.CannotCreateTransactionException
        Caused by: org.hibernate.exception.JDBCConnectionException
            Caused by: org.postgresql.util.PSQLException
                Caused by: java.net.ConnectException
    java.lang.NullPointerException at AccountControllerTest

That’s probably not enough information to help. CircleCI 2.0 is a different environment, to be sure, but I’d expect transactions to still work. May we see your config.yml?

It may be worth showing the Java unit test code too, but there’s a point when this becomes a unit test question (possibly for Stack Overflow etc) rather than a CircleCI question.

I post some codes here, please help me find out what problem is. Thank you very much.

config.yml

version: 2
jobs:
    checkout:
        docker: 
            - image: circleci/buildpack-deps:16.04-curl-browsers
        environment:
            TZ: "/usr/share/zoneinfo/Asia/Tokyo"
        steps:
            - checkout
            - persist_to_workspace:
                root: .
                paths:
                    - service/
                    - artifacts

    build-java:
        docker:
            - image: circleci/openjdk:8-jdk-node-browsers
        environment:
            TZ: "/usr/share/zoneinfo/Asia/Tokyo"
        steps:
            - attach_workspace:
                at: ./    
            - run:
                name: build iot-service
                pwd: service/iot-service
                command: ./gradlew clean build
            - run:
                name: collect test result
                command: |
                    mkdir /tmp/test-results
                    find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} /tmp/test-results/ \;
                    find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} /tmp/test-results/ \;
            - store_test_results:
                path: /tmp/test-results
            - persist_to_workspace:
                root: .
                paths: 
                    - service/

    collect-artifacts:
        docker:
            - image: circleci/buildpack-deps:16.04-curl-browsers
        environment:
            TZ: "/usr/share/zoneinfo/Asia/Tokyo"
        steps:
            - attach_workspace:
                at: ./
            - run:
                name: collect artifact
                command: tar zcfp ./projectg-iot.tar.gz -T artifacts
            - store_artifacts:
                path: ./projectg-iot.tar.gz

workflows:
    version: 2
    build:
        jobs:
            - checkout
            - build-java:
                requires:
                    - checkout
            - collect-artifacts:
                requires:
                    - build-java

embedded datasource

@Configuration
@Profile(Profiles.TEST)
@AutoConfigureOrder(value = Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(DataSource.class)
@Import(ApiConfig.class)
public class TestConfig
{
	@Autowired
	private Environment m_env;

	private PostgresConfig m_dbConfig;


	@Bean(destroyMethod = "stop")
	public PostgresProcess databaseServer() throws Exception
	{
		final String host = "127.0.0.1";
		final String port = "12345";
		final String name = "postgres";
		final String username = "postgres";
		final String password = "postgres";

		m_dbConfig = new PostgresConfig(
				Version.Main.PRODUCTION,
				new AbstractPostgresConfig.Net(host, Integer.parseInt(port)),
				new AbstractPostgresConfig.Storage(name),
				new AbstractPostgresConfig.Timeout(),
				new AbstractPostgresConfig.Credentials(username, password)
		);

		m_dbConfig.getAdditionalInitDbParams().addAll(asList(
				"-E", "UTF-8",
				"--locale=en_US.UTF-8",
				"--lc-collate=en_US.UTF-8",
				"--lc-ctype=en_US.UTF-8"
		));

		final PostgresStarter<PostgresExecutable, PostgresProcess> runtime = PostgresStarter.getDefaultInstance();
		PostgresExecutable exec = runtime.prepare(m_dbConfig);
		PostgresProcess process = exec.start();

		File sqlDir = new File(getClass().getClassLoader().getResource("sql").getFile());
		File[] sqlFiles = sqlDir.listFiles();
		Arrays.sort(sqlFiles);

		for (File sqlFile : sqlFiles) {
			process.importFromFile(sqlFile);
		}

		return process;
	}
}

Unit test code

@Transactional
@ActiveProfiles(Profiles.TEST)
@RunWith(SpringRunner.class)
@SpringBootTest
public class AccountControllerTest
{
	@Autowired
	private WebApplicationContext m_appContext;

	@Autowired
	private AccountService m_accountService;

	private static final String REQUEST_URL = ApiPath.ACCOUNT_API_PATH;

	@Autowired
	private LibProperty m_libProperty;

	@Autowired
	private RestTemplate m_restTemplate;

	private MockRestServiceServer m_mockServer;

	@Autowired
	private ResourceFactory m_resourceFactory;

	@Before
	public void setUp() throws Exception
	{
		m_mockServer = MockRestServiceServer.bindTo(m_restTemplate).ignoreExpectOrder(true).build();
	}

	@After
	public void tearDown()
	{
		m_mockServer.verify();
	}

	@Test
	public void testCreateAccountReturnIsCreated() throws Exception
	{
		final String json = "{\"account\":\"" + ACCOUNT_ID + "\"}";
		ResultActions resultActions = TestUtils.perform(m_appContext, post(REQUEST_URL)
				.content(json)
				.contentType(MediaType.APPLICATION_JSON_UTF8))
				.andExpect(status().isCreated());
		assertAccountResponseBodyMatch(resultActions, ACCOUNT_ID);

		Account account = m_accountService.find(ACCOUNT_ID);
		assertNotNull(account);
	}
}

That’s certainly some useful information, but now this is “will a volunteer fix my tests for me”? The answer is probably no :smiley_cat:

However, with this information, you may find people will chip in to make suggestions of things you can try.

I have not encountered embedded Postgres before, but consider these things:

  • Does is spawn a process? PostgresExecutable makes me think it does. If so, does that process start? How can you verify that it has started?
  • Does this process produce logs? If so, do they have any failures in them?
  • Could you get a SSH on a failed build and add some debug statements into your code, to see where it is failing? Use nano to edit and apk add to install things (nano, jdk, etc).