Merge pull request #33 from christophstrobl/data/jpa/data-jpa
Add data-jpa smoke test.
This commit is contained in:
1
data/data-jpa/README.adoc
Normal file
1
data/data-jpa/README.adoc
Normal file
@@ -0,0 +1 @@
|
||||
Tests if Spring Data JPA with Hibernate, MySQL & HikariCP is working.
|
||||
24
data/data-jpa/build.gradle
Normal file
24
data/data-jpa/build.gradle
Normal file
@@ -0,0 +1,24 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "org.springframework.boot"
|
||||
id "org.springframework.cr.smoke-test"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
|
||||
implementation("org.crac:crac:$cracVersion")
|
||||
implementation(project(":cr-listener"))
|
||||
|
||||
runtimeOnly("com.mysql:mysql-connector-j")
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
|
||||
appTestImplementation(project(":cr-smoke-test-support"))
|
||||
appTestImplementation("org.awaitility:awaitility:4.2.0")
|
||||
}
|
||||
|
||||
crSmokeTest {
|
||||
webApplication = false
|
||||
}
|
||||
10
data/data-jpa/docker-compose.yml
Normal file
10
data/data-jpa/docker-compose.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
version: '3.1'
|
||||
services:
|
||||
mysql:
|
||||
image: 'mysql/mysql-server:8.0'
|
||||
environment:
|
||||
- 'MYSQL_DATABASE=test'
|
||||
- 'MYSQL_USER=mysql'
|
||||
- 'MYSQL_PASSWORD=password'
|
||||
ports:
|
||||
- '3306'
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.data.jpa;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.cr.smoketest.support.assertj.AssertableOutput;
|
||||
import org.springframework.cr.smoketest.support.junit.ApplicationTest;
|
||||
|
||||
@ApplicationTest
|
||||
public class DataJpaApplicationTests {
|
||||
|
||||
@Test
|
||||
void connectionTest(AssertableOutput output) {
|
||||
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
|
||||
assertThat(output).hasLineMatching("Starting DataReader: was (INITIALIZED|STOPPED)");
|
||||
assertThat(output).hasLineMatching("count \\d+: Author\\{id=\\d, name='.*'}");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
79
data/data-jpa/src/main/java/com/example/data/jpa/Author.java
Normal file
79
data/data-jpa/src/main/java/com/example/data/jpa/Author.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.data.jpa;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Author {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
protected Author() {
|
||||
}
|
||||
|
||||
public Author(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Author author = (Author) o;
|
||||
return Objects.equals(id, author.id) && Objects.equals(name, author.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Author{" + "id=" + id + ", name='" + name + '\'' + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.data.jpa;
|
||||
|
||||
import org.springframework.data.repository.ListCrudRepository;
|
||||
|
||||
public interface AuthorRepository extends ListCrudRepository<Author, Integer> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.data.jpa;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableTransactionManagement
|
||||
public class DataJpaApplication {
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
SpringApplication.run(DataJpaApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
122
data/data-jpa/src/main/java/com/example/data/jpa/DataReader.java
Normal file
122
data/data-jpa/src/main/java/com/example/data/jpa/DataReader.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.data.jpa;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.hibernate.Session;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@Component
|
||||
@Transactional
|
||||
@EnableScheduling
|
||||
class DataReader implements SmartLifecycle {
|
||||
|
||||
private final Object lifecycleMonitor = new Object();
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
private State state = State.INITIALIZED;
|
||||
|
||||
private List<Integer> authorIds;
|
||||
|
||||
@Autowired
|
||||
private AuthorRepository authorRepository;
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
enum State {
|
||||
|
||||
INITIALIZED, STARTED, STOPPED
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
synchronized (lifecycleMonitor) {
|
||||
switch (state) {
|
||||
case INITIALIZED, STOPPED -> {
|
||||
System.out.printf("Starting DataReader: was %s\n", state);
|
||||
if (ObjectUtils.isEmpty(authorIds)) {
|
||||
authorIds = insertAuthors().stream().map(Author::getId).collect(Collectors.toList());
|
||||
}
|
||||
state = State.STARTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 1000)
|
||||
public void scheduled() {
|
||||
|
||||
if (isRunning()) {
|
||||
|
||||
int count = counter.incrementAndGet();
|
||||
Author author = authorRepository.findById(authorIds.get(count % 3)).orElse(null);
|
||||
System.out.printf("count %03d: %s\n", count, author);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
|
||||
synchronized (lifecycleMonitor) {
|
||||
switch (state) {
|
||||
case INITIALIZED, STARTED -> {
|
||||
System.out.printf("Stopping DataReader: was %s\n", state);
|
||||
state = State.STOPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return State.STARTED.equals(state);
|
||||
}
|
||||
|
||||
private List<Author> insertAuthors() {
|
||||
|
||||
List<Author> authors = authorRepository.saveAll(List.of( //
|
||||
new Author(null, "Brandon Sanderson"), //
|
||||
new Author(null, "Brent Weeks"), //
|
||||
new Author(null, "Peter V. Brett")));
|
||||
|
||||
em.flush();
|
||||
em.getEntityManagerFactory().getCache().evictAll();
|
||||
|
||||
Session session = em.unwrap(Session.class);
|
||||
|
||||
if (session != null) {
|
||||
session.clear(); // internal cache clear
|
||||
}
|
||||
|
||||
return authors;
|
||||
}
|
||||
|
||||
}
|
||||
7
data/data-jpa/src/main/resources/application.properties
Normal file
7
data/data-jpa/src/main/resources/application.properties
Normal file
@@ -0,0 +1,7 @@
|
||||
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
|
||||
spring.jpa.hibernate.ddl-auto=create
|
||||
|
||||
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT_3306:3306}/test
|
||||
spring.datasource.username=mysql
|
||||
spring.datasource.password=password
|
||||
spring.datasource.hikari.allow-pool-suspension=true
|
||||
Reference in New Issue
Block a user