Spring Boot can't run single test in IntelliJ - java

This started happening recently, but I'm not sure what changed to cause it.
When I run all tests from IntelliJ, all is well. Also the gradle build is fine.
When I run a single unit test, all is well.
When I run a single web integration test, it fails because a config class has all null properties.
The config class looks like (Kotlin):
#Component
#ConfigurationProperties(prefix = "api")
public open class ApiConfigImpl : ApiConfig
{
A test looks like:
#RunWith(SpringJUnit4ClassRunner::class)
#ContextConfiguration(classes = arrayOf(ApplicationAssembly::class), loader = SpringApplicationContextLoader::class)
#WebIntegrationTest
open class CandidateProfileControllerTest
{
#Inject lateinit var profileRepo: CandidateProfileRepository
//etc a few more deps used to setup test data
#Test
open fun getById()
{
val greg = CandidateProfile("123", "12312", "Greg", "Jones", dateOfBirth = Date(), gender = Gender.MALE,
biography = "ABC", maxMatchableAge = null, maxMatchableDistance = null)
profileRepo.save(greg)
val auth = given().header("content-type", "application/json")
.body(testCredentials)
.post("/authorization/social").peek().asString()
val accessToken: String = from(auth).get("accessToken")
given().header("Access-Token", accessToken).
header("API-Key", testAPIKey()).
get("/profile/${greg.id}").
peek().then().
body("stageName", notNullValue())
}
I'm not sure what information I can add. Based on the limited information provided:
Is this a known problem with a known solution?

This is a bug, logged in the IntelliJ/Kotlin tracker, with a pending fix.

Related

Spring Boot R2DBC with MySQL - Exception: Table not found

I'm extremely new to String Boot and backend development (maybe three days or less) and I have the desire to build REST API to consume from different clients.
So I started by a simple demo app that has an endpoint called /register. We post a JSON string with username and password to create a new user if not exist.
I was using JPA with HSQLDB and it worked fine persisting on memory. But recently I wanted to use RxJava since I'm familiar with on Android, so I switched to R2DBC with MySQL.
MySQL server is running fine on port 3306 and the app was tested using PostMan on localhost:8080
The problem occurs when I try to query users table or insert entities and it looks like this:
{
"timestamp": "2020-03-22T11:54:43.466+0000",
"status": 500,
"error": "Internal Server Error",
"message": "execute; bad SQL grammar [UPDATE user_entity SET username = $1, password = $2 WHERE user_entity.id = $3]; nested exception is io.r2dbc.spi.R2dbcBadGrammarException: [42102] [42S02] Table \"USER_ENTITY\" not found; SQL statement:\nUPDATE user_entity SET username = $1, password = $2 WHERE user_entity.id = $3 [42102-200]",
"path": "/register"
}
Here's the full logfile for the exception.
I Have been looking for a solution for hours and I seem like not finding it anywhere, so I hope that I will find it here.
Let's break down the project so it's easier to find the solution:
1. database:
2. application.properties:
logging.level.org.springframework.data.r2dbc=DEBUG
spring.datasource.url=jdbc:mysql://localhost:3306/demodb
spring.datasource.username=root
spring.datasource.password=root
3. DatabaseConfiguration:
#Configuration
#EnableR2dbcRepositories
class DatabaseConfiguration : AbstractR2dbcConfiguration() {
override fun connectionFactory(): ConnectionFactory
= ConnectionFactories.get(
builder().option(DRIVER, "mysql")
.option(HOST, "localhost")
.option(USER, "root")
.option(PASSWORD, "root")
.option(DATABASE, "demodb")
.build()
)
}
4. RegistrationController:
#RequestMapping("/register")
#RestController
class RegistrationController #Autowired constructor(private val userService: UserService) {
#PostMapping
fun login(#RequestBody registrationRequest: RegistrationRequest): Single<ResponseEntity<String>>
= userService.userExists(registrationRequest.username)
.flatMap { exists -> handleUserExistance(exists, registrationRequest) }
private fun handleUserExistance(exists: Boolean, registrationRequest: RegistrationRequest): Single<ResponseEntity<String>>
= if (exists) Single.just(ResponseEntity("Username already exists. Please try an other one", HttpStatus.CONFLICT))
else userService.insert(User(registrationRequest.username, registrationRequest.password)).map { user ->
ResponseEntity("User was successfully created with the id: ${user.id}", HttpStatus.CREATED)
}
}
5. UserService:
#Service
class UserService #Autowired constructor(override val repository: IRxUserRepository) : RxSimpleService<User, UserEntity>(repository) {
override val converter: EntityConverter<User, UserEntity> = UserEntity.Converter
fun userExists(username: String): Single<Boolean>
= repository.existsByUsername(username)
}
6. RxSimpleService:
abstract class RxSimpleService<T, E>(protected open val repository: RxJava2CrudRepository<E, Long>) {
protected abstract val converter: EntityConverter<T, E>
open fun insert(model: T): Single<T>
= repository.save(converter.fromModel(model))
.map(converter::toModel)
open fun get(id: Long): Maybe<T>
= repository.findById(id)
.map(converter::toModel)
open fun getAll(): Single<ArrayList<T>>
= repository.findAll()
.toList()
.map(converter::toModels)
open fun delete(model: T): Completable
= repository.delete(converter.fromModel(model))
}
7. RxUserRepository:
#Repository
interface IRxUserRepository : RxJava2CrudRepository<UserEntity, Long> {
#Query("SELECT CASE WHEN EXISTS ( SELECT * FROM ${UserEntity.TABLE_NAME} WHERE username = :username) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END")
fun existsByUsername(username: String): Single<Boolean>
}
8. And finally, here's my UserEntity
#Table(TABLE_NAME)
data class UserEntity(
#Id
val id: Long,
val username: String,
val password: String
) {
companion object {
const val TABLE_NAME = "user_entity"
}
object Converter : EntityConverter<User, UserEntity> {
override fun fromModel(model: User): UserEntity
= with(model) { UserEntity(id, username, password) }
override fun toModel(entity: UserEntity): User
= with(entity) { User(id, username, password) }
}
}
User and RegistrationRequest are just simple objects with username and password.
What I have missed?
Please leave a comment if you need more code.
I finally managed to solve this mistake!
The problems were so simple yet so sneaky for a beginner:
I was using JDBC in my URL instead of R2DBC
I was using the H2 runtime implementation so it was
expecting an H2 in-memory database
My ConnectionFactory was not very correct
So what I did was the following:
Updated my build.gradle:
Added:
implementation("io.r2dbc:r2dbc-pool") , implementation("dev.miku:r2dbc-mysql:0.8.1.RELEASE") and
runtimeOnly("mysql:mysql-connector-java")
Removed: runtimeOnly("io.r2dbc:r2dbc-h2")
It now looks like this:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.2.5.RELEASE"
id("io.spring.dependency-management") version "1.0.9.RELEASE"
kotlin("jvm") version "1.3.61"
kotlin("plugin.spring") version "1.3.61"
}
group = "com.tamimattafi.backend"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
maven(url = "https://repo.spring.io/milestone")
}
dependencies {
//SPRING BOOT
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot.experimental:spring-boot-starter-data-r2dbc")
//KOTLIN
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
//RX JAVA
implementation("io.reactivex.rxjava2:rxjava:2.2.0")
implementation("io.reactivex:rxjava-reactive-streams:1.2.1")
//MYSQL
implementation("dev.miku:r2dbc-mysql:0.8.1.RELEASE")
implementation("io.r2dbc:r2dbc-pool")
runtimeOnly("mysql:mysql-connector-java")
//TEST
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
testImplementation("org.springframework.security:spring-security-test")
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.springframework.boot.experimental:spring-boot-test-autoconfigure-r2dbc")
}
dependencyManagement {
imports {
mavenBom("org.springframework.boot.experimental:spring-boot-bom-r2dbc:0.1.0.M3")
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "1.8"
}
}
Updated my application.properties to this:
spring.r2dbc.url=r2dbc:pool:mysql://127.0.0.1:3306/demodb
spring.r2dbc.username=root
spring.r2dbc.password=root
Updated my DatabaseConfiguration to this (Note that I removed the #EnableR2dbcRepositories because it should be elsewhere) :
#Configuration
class DatabaseConfiguration : AbstractR2dbcConfiguration() {
override fun connectionFactory(): ConnectionFactory
= MySqlConnectionFactory.from(
MySqlConnectionConfiguration.builder()
.host("127.0.0.1")
.username("root")
.port(3306)
.password("root")
.database("demodb")
.connectTimeout(Duration.ofSeconds(3))
.useServerPrepareStatement()
.build()
)
}
Updated my Application class (I brought the annotation here):
#SpringBootApplication
#EnableR2dbcRepositories
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
IT WORKS NOW! I hope someone will find this helpful, Happy Coding!
In application.properties you need to set the spring.jpa.hibernate.ddl-auto property.
The options are:
validate: validate the schema, makes no changes to the database.
update: update the schema.
create: creates the schema, destroying previous data.
create-drop: drop the schema when the SessionFactory is closed explicitly, typically when the application is stopped.
none: does nothing with the schema, makes no changes to the database

Camel : ClassCastException: DefaultMessage cannot be cast to class SnmpMessage

I'm getting the following ClassCastException from a unit test when I try to call testTemplate.sendBody(String, Object) below:
SnmpRoute.kt
.process { exchange ->
val message = exchange.getIn() as SnmpMessage
SnmpRouteTest.kt
#RunWith(CamelSpringBootRunner::class)
#CamelSpringBootTest
#SpringBootTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#DisableJmx(false)
#MockEndpoints("log:*")
class SnmpRouteTest {
object SnmpConstants {
const val SNMP_TRAP = "<snmp><entry><oid>1.3.6.1.2.1.1.3.0</oid><value>6 days, 3:44:57.82</value></entry><entry><oid>1.3.6.1.6.3.1.1.4.1.0</oid><value>1.3.6.1.4.1.8072.2.3.0.1</value></entry><entry><oid>1.3.6.1.4.1.8072.2.3.2.1</oid><value>123456</value></entry></snmp>"
}
#Autowired
lateinit var camelContext: CamelContext
#Produce
lateinit var testTemplate: ProducerTemplate
...
...
#Test
#Throws(Exception::class)
fun testSnmpRoute() {
AdviceWithRouteBuilder.adviceWith(camelContext, "CamelSnmpTrapRoute") { routeBuilder -> routeBuilder.replaceFromWith(SnmpConstants.DIRECT_SNMP_ENDPOINT) }
testTemplate.sendBody(SnmpConstants.DIRECT_SNMP_ENDPOINT, SnmpConstants.SNMP_TRAP)
...
}
}
Exception
java.lang.ClassCastException: class org.apache.camel.support.DefaultMessage cannot be cast to class
org.apache.camel.component.snmp.SnmpMessage (org.apache.camel.support.DefaultMessage and org.apache.
camel.component.snmp.SnmpMessage are in unnamed module of loader 'app')
I have tried to construct an SnmpMessage object and use that in the sendBody() call, as when I test this route manually with the snmptrap utility, I see the following in the logs:
Get In[SnmpMessage: <snmp><entry><oid>1.3.6.1.2.1.1.3.0</oid><value>12 days, 8:40:47.70</value></entry><entry><oid>1.3.6.1.6.3.1.1.4.1.0</oid><value>1.3.6.1.4.1.8072.2.3.0.1</value></entry><entry><oid>1.3.6.1.4.1.8072.2.3.2.1</oid><value>123456</value></entry></snmp>]
However I'm getting the same issue with this approach.
I am using Apache Camel v3.0.0-RC3
Thanks to #ShellDragon for help so far with this.
Your processor is casting to a SmppMessage, but your unit test, replaces the consumer (from endpoint) from a smpp to direct component and therefore the message implementation is DefaultMessage.
This is what worked for me. I needed to overwrite the exchange.getIn() message with an SnmpMessage, and add a PDU object, rather than the XML String block.
#CamelSpringBootTest
#SpringBootTest(classes = [SnmpTrapReceiverApplication::class])
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#DisableJmx(false)
#ExtendWith(MockitoExtension::class)
#EnableAutoConfiguration
class SnmpTrapRouteTest {
#MockBean
lateinit var repo: PojoRepo
#Produce
lateinit var producerTemplate: ProducerTemplate
#Autowired
lateinit var camelContext: CamelContext
#Test
#Throws(Exception::class)
fun testSnmpRoute() {
AdviceWithRouteBuilder.adviceWith(camelContext, "snmp-trap-route") { routeBuilder ->
routeBuilder.replaceFromWith("direct:snmp-from")
}
// Create a PDU object to send to the SNMP endpoint, rather than SNMP XML
val trap = PDU()
trap.type = PDU.TRAP
trap.requestID = Integer32(123456789)
trap.add(VariableBinding(OID("1.2.3.4.5"), OctetString("snmp-trap-payload")))
// Create a new DefaultExchange and add an SnmpMessage object as the in-message,
// constructed with the camelContext and the PDU object
val exchange = DefaultExchange(camelContext)
exchange.setIn(SnmpMessage(camelContext, trap))
producerTemplate.setDefaultEndpointUri("direct:snmp-from")
producerTemplate.send(exchange)
verify(repo, atLeast(1)).save(any())
}
}
Since I am using JUnit 5, I changed #RunWith(CamelSpringBootRunner::class) to #CamelSpringBootTest, as after downloading the 3.0.0-RC3 release source, I found a comment saying to do so.

How to dynamically inject property values from a configuration file into Hystrix's annotations

I am learning Spring Cloud now.
We know that If the remote configuration file is updated, by accessing the “localhost:10000/refresh”, we can dynamically obtain the values of custom properties of the remote configuration file on the configuration server. I would like to ask, how do I dynamically inject these values into Hystrix's annotations.
My remote configuration file “licenseservice.yml”, I put it in a git repository:
example.property: I am the default. I am from git now.
example.timeoutInMilliseconds: 12000
server:
port: 10000
eureka:
instance:
prefer-ip-address: true
...
The java class I used to get the values in the configuration file:
#Component
#RefreshScope
public class ServiceConfig {
#Value("${example.property}")
private String exampleProperty;
#Value("${example.timeoutInMilliseconds}")
private String timeoutInMilliseconds;
public String getExampleProperty() {
return exampleProperty;
}
public String getTimeoutInMilliseconds(){
return timeoutInMilliseconds;
}
}
The java method that uses the Hystrix annotations:
#HystrixCommand(fallbackMethod = "buildFallbackLicenseList",
threadPoolKey = "licenseByOrgThreadPool",
threadPoolProperties = {
#HystrixProperty(name = "coreSize",value = "30"),
#HystrixProperty(name = "maxQueueSize", value = "10")
},
commandProperties = {
#HystrixProperty(name =
"circuitBreaker.requestVolumeThreshold",value = "10"),
#HystrixProperty(name =
"circuitBreaker.errorThresholdPercentage",value = "75"),
#HystrixProperty(name =
"circuitBreaker.sleepWindowInMilliseconds",value = "7000"),
#HystrixProperty(name =
"metrics.rollingStats.timeInMilliseconds",value = "15000"),
#HystrixProperty(name =
"metrics.rollingStats.numBuckets",value = "5"),
#HystrixProperty(name =
"execution.isolation.thread.timeoutInMilliseconds",value = ???)
})
public List<License> getLicensesByOrg(String organizationId){
System.out.println("SERVICE CONFIG TEST
"+serviceConfig.getExampleProperty());
System.out.println("SERVICE CONFIG TEST
"+serviceConfig.getTimeoutInMilliseconds());
randomlyRunLong();
return licenseRepository.findByOrganizationId(organizationId);
}
My problem is, I want to dynamically change the value of the variable "execution.isolation.thread.timeoutInMilliseconds"(by using the value of "example.timeoutInMilliseconds" in the .yml file). You can see that I wrote three question marks in that place, because I don't know what to write, can someone please? Tell me, thank you.

How to print full path to script files in #sql annotation in spring boot test

In a multi-module project I want to be sure that Spring's #sql annotation uses correct resources. Is there a way to log full path of those files to console somehow?
Spring does log script file name before execution, but in tests for different modules those file names are the same sometimes.
SqlScriptsTestExecutionListener - responsible for the processing of #Sql, for the first step you can change to debug related log by adding property logging.level.org.springframework.test.context.jdbc=debug, but the debug message is not fully and if is not enough you should create your own TestExecutionListener and declare on test class #TestExecutionListeners(listeners = SqlScriptsCustomTestExecutionListener.class)
for example:
public class SqlScriptsCustomTestExecutionListener extends AbstractTestExecutionListener {
#Override
public void beforeTestMethod(TestContext testContext) {
List<Resource> scriptResources = new ArrayList<>();
Set<Sql> sqlAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(testContext.getTestMethod(), Sql.class);
for (Sql sqlAnnotation : sqlAnnotations) {
String[] scripts = sqlAnnotation.scripts();
scripts = TestContextResourceUtils.convertToClasspathResourcePaths(testContext.getTestClass(), scripts);
scriptResources.addAll(TestContextResourceUtils.convertToResourceList(testContext.getApplicationContext(), scripts));
}
if (!scriptResources.isEmpty()) {
String debugString = scriptResources.stream().map(r -> {
try {
return r.getFile().getAbsolutePath();
} catch (IOException e) {
System.out.println("Unable to found file resource");
}
return null;
}).collect(Collectors.joining(","));
System.out.println(String.format("Execute sql script :[%s]", debugString));
}
}
It is just quick example and it works. Most of source code i copied from SqlScriptsTestExecutionListener just for explanation. It is just realization in case of #Sql annotation on method level, and not included class level.
I hope it will be helps you.

How to remove custome properties from SOAPUI test case using java?

I have some custom properties for all the test cases in SoapUI.
I am able to delete using Groovy script step as described in below question:
How to remove Custom Properties from a SoapUI TestCase using Groovy?
testRunner.testCase.removeProperty( "Testcase_Property" );
But I wanted to delete these properties from JAVA. Below is the code I wrote:
String soapuiProjectPath = "ProjectLocation";
WsdlProject project = new WsdlProject(soapuiProjectPath);
StringToObjectMap context = new StringToObjectMap();
TestSuite testSuite = project.getTestSuiteByName("TestSuiteName");
WsdlTestSuite wsdlSuite = (WsdlTestSuite) testSuite;
List<TestCase> allTestCaseList = wsdlSuite.getTestCaseList();
for (TestCase testCase : allTestCaseList) {
WsdlTestCaseRunner testCaseRunner = new WsdlTestCaseRunner((WsdlTestCase) testCase, context);
List<TestProperty> testCasePropertyList = testCase.getPropertyList();
for (TestProperty testProperty : testCasePropertyList) {
WsdlTestRunContext runContext = testCaseRunner.getRunContext();
runContext.removeProperty(testProperty.getName());
}
}
System.out.println("Completed execution.");
project.save();
It is not throwing any exception. But not actually removing the custom properties as well.
Because you've to apply the removeProperty in WsdlTestCase not in WsdlTestRunContext. You can change your testCase loop code for something like:
for(TestCase testCase : allTestCaseList) {
List<TestProperty> testCasePropertyList = testCase.getPropertyList();
for (TestProperty testProperty : testCasePropertyList) {
((WsdlTestCase) testCase).removeProperty(testProperty.getName());
}
}
Hope it helps,

Categories

Resources