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.