Home > Blockchain >  java.net.ConnectionException - GitHub workflow for kotlin spring boot project w/ mysql database test
java.net.ConnectionException - GitHub workflow for kotlin spring boot project w/ mysql database test

Time:11-29

I am trying to create a workflow in GitHub Actions that runs my integration tests in my spring boot project written in kotlin, packaged with gradle and utilizing a mysql database. I keep getting this error when reaching the build and test step, and for each test, running ./gradlew clean build:

Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98
            Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804
                Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
                    Caused by: org.hibernate.exception.JDBCConnectionException at SQLStateConversionDelegate.java:112
                        Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException at SQLError.java:174
                            Caused by: com.mysql.cj.exceptions.CJCommunicationsException at NativeConstructorAccessorImpl.java:-2
                                Caused by: java.net.ConnectException at PlainSocketImpl.java:-2

Here is my gradle.yml:

name: CI with Gradle

on: [push]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest
    container: openjdk:11
    services:
      mysql:
        image: mysql:latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
    - name: Grant execute permission for gradlew
      run: chmod  x gradlew
    - name: Build & Test with Gradle
      uses: gradle/gradle-build-action@v2
      with:
          arguments: build

Here is my application.properties:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/wct?useSSL=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=pw
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database=mysql

server.port=8081

And here is an example of one of all of my JUnit tests that are failing:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
internal class CustomerControllerTests(
    @Autowired val context: WebApplicationContext,
    @Autowired val mapper: ObjectMapper,
    @Autowired val customerRepository: CustomerRepository,
) {

    private val mvc: MockMvc = (MockMvcBuilders.webAppContextSetup(context).apply<DefaultMockMvcBuilder>(
        SecurityMockMvcConfigurers.springSecurity()).build())

    @Test
    fun `GET customers should return an empty list of customers and 200 OK if one of the required roles is provided`() {
        val response = mvc.perform(
            MockMvcRequestBuilders.get("/customers")
                .contentType(MediaType.APPLICATION_JSON)
        ).andExpect(MockMvcResultMatchers.status().isOk).andReturn().response

       response.contentLength shouldBe 0

    }
}

What am I doing wrong here/am missing?

CodePudding user response:

I can see at least four problems in your setup:

1. Incorrect datasource URL

You are using localhost:3306 as the <hostname>:<port> in the connection url (spring.datasource.url) but according to the GitHub Actions docs:

When you run jobs in a container, GitHub connects service containers to the job using Docker's user-defined bridge networks.

Running the job and services in a container simplifies network access. You can access a service container using the label you configure in the workflow. The hostname of the service container is automatically mapped to the label name.

So, in your case the url property for the test should look like this:

spring.datasource.url=jdbc:mysql://mysql:3306/wct?useSSL=true&serverTimezone=UTC

2. Missing MySql root password

According to the MySql Official Docker image page and numerous examples with GitHub Actions MySql setup you have to specify at least one mandatory env variable, which is MYSQL_ROOT_PASSWORD:

This variable is mandatory and specifies the password that will be set for the MySQL root superuser account.

In your case that will be as follows (in the env block of mysql service):

MYSQL_ROOT_PASSWORD: pw

3. Requested database not created

As far as I can see from the connection string, you are trying to connect to the wct database but I don't see that database being created in your configuration. To do that you will have to use the MYSQL_DATABASE env variable as per the MySql Official Docker image page. It will look like this in your env block:

MYSQL_DATABASE: wct

4. MySql is not awaited until it's up

As per the Official GitHub Actions Postgres example you had better wait until your MySql instance is ready to server the requests. It can be done like this:

    services:
      mysql:
        options: >-
          --health-cmd mysqladmin ping
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

So, given you are using the root user in the tests (according to your code) your final-ish "gradle.yml" mysql part will look like this:

    services:
      mysql:
        image: mysql:latest
        env:
          MYSQL_DATABASE: wct
          MYSQL_ROOT_PASSWORD: pw
        options: >-
          --health-cmd mysqladmin ping
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

And don't forget to fix the spring.datasource.url as outlined in the first "Incorrect datasource URL" problem above.

Also, I believe it must cover everything or at least the major problems in your configuration. But I wouldn't not be surprised if some minor misconfig errors were not covered in this answer. You could let me know how it goes.

  • Related