I am now in trouble with the configuration variable GrailsApplication in my Integration Tests. I don't know why, but, I am not managing to get its value when testing my api. I am using Grails 3.3.11. The value of the variable is being null and, due to it, I can't authenticate to perform the tests. I would appreciate your help. I am using Grails 3.3.11.
package br.com.xxx.id.test.integration
//Imports were moved out to simplify understanding
class IdControllerSpec extends Specification {
def grailsApplication
#Value('${local.server.port}')
Integer serverPort
String accessToken
String baseUrl
JSONObject documentPropertiesForTesting
JSONObject documentForTesting
String partTest
String userTest
String typeIdTest
String refreshToken
void setup(){
baseUrl = "http://localhost:${serverPort}/cmbid/api/v1"
partTest = "partTest"
}
void "Saving a new and valid document properties"() {
when:
refreshToken = grailsApplication.config.getProperty('refreshToken')
accessToken = "Bearer " + authenticateXxxAut()
documentPropertiesForTesting = createNewTestDocumentProperties()
typeIdTest = documentPropertiesForTesting.get("message").toString().substring(20,52)
then:
documentPropertiesForTesting.get("status") == "ok"
documentPropertiesForTesting.get("message").contains("properly saved!")
cleanup:
DocumentProperties.withNewSession {
def dp = DocumentProperties.findById(typeIdTest)
dp.delete(flush: true)
}
}
def authenticateXxxAut() {
CloseableHttpClient httpClient = HttpClients.createDefault();
String response = ""
try {
JSONObject responseBody
println('****************************')
println(grailsApplication.config.getProperty('aut.newTokenUrl'))
println(grailsApplication.config.getProperty('refreshToken)'))
println('****************************')
def httpPost = new HttpPost(grailsApplication.config.getProperty('aut.newTokenUrl') + grailsApplication.config.getProperty('refreshToken)'))
CloseableHttpResponse httpResponse = httpClient.execute(httpPost)
if (httpResponse.getStatusLine().getStatusCode() == 200) {
responseBody = new JSONObject(EntityUtils.toString(httpResponse.getEntity()))
response = responseBody.get("access_token")
} else {
response = httpResponse.getStatusLine().getStatusCode().toString()
}
} catch (Exception e){
print(e.getLocalizedMessage())
} finally {
httpClient.close()
return response
}
}
I've been upgrading a Grails 2.x app to version 3.3.11 and just referencing the (provided) variable serverPort worked for me. The IDE shows it as being uninitialized but running the tests, it gets the correct value assigned. I also have my test classes annotated with #Integration(applicationClass = Application.class).
Here's how I get the URL to point against:
def url = "http://localhost:${serverPort}${grailsApplication.config.getProperty('server.contextPath', String, '')}"
When I run build I get this error:
ERROR SENDING EMAIL hudson.AbortException: No such library resource build/email.html.groovy could be found.
The file "email.html.groovy" is in the same directory.
An error appears on the line:
def fileContents = libraryResource(fileName)
My Groovy file with 2 functions:
package workflowlibs.manager;
import groovy.text.StreamingTemplateEngine
/**
* This method returns a string with the template filled with groovy variables
*/
def emailTemplate(params) {
def fileName = "build/email.html.groovy"
def fileContents = libraryResource(fileName)
def engine = new StreamingTemplateEngine()
return engine.createTemplate(fileContents).make(params).toString()
}
/**
* This method send an email generated with data from Jenkins
* #param buildStatus String with job result
* #param emailRecipients Array with emails: emailRecipients = []
*/
def notifyEmail(buildStatus, emailRecipients) {
try {
def icon = "✅"
def statusSuccess = true
def hasArtifacts = true
if(buildStatus != "SUCCESSFUL") {
icon = "❌"
statusSuccess = false
hasArtifacts = false
}
def body = emailTemplate([
"jenkinsText" : env.JOB_NAME,
"jenkinsUrl" : env.BUILD_URL,
"statusSuccess" : statusSuccess,
"hasArtifacts" : hasArtifacts,
"downloadUrl" : "www.downloadurl.com"
]);
mail (to: emailRecipients.join(","),
subject: "${icon} [ ${env.JOB_NAME} ] [${env.BUILD_NUMBER}] - ${buildStatus} ",
body: body,
mimeType: 'text/html'
);
} catch (e){
println "ERROR SENDING EMAIL ${e}"
}
}
return this;
I have a method in a shared library in my Jenkins pipeline. The idea is to use this library and upload files to a remote host. The library is imported in a singleton library.
import com.package.jobutil.UploadFile
def uploadFunc() {
def uploader = new UploadFile(this)
withCredentials ([usernamePassword(credentialsId: 'user', userNameVariable: 'username', passwordVariable:'password)]) {
uploader.uploadArtifact("${username}", "${password}", file.txt, location)
}
}
def call() {
uploadFunc()
}
The class that is instantiated looks like this:
class UploadFile {
def steps
UploadFile (steps) {
this.steps = steps
}
pulic uploadArtifct (String user, String password, String file, String location) {
Process proc
def cred = "${user}:${pass}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", file, location]
steps.println "CURL: ${cmd}"
proc = cmd.execute()
}
}
Even though I see the println line in the logs. I do not see the curl command being executed.
Is there something I am missing that does not invoke the cmd.execute to work?
EDIT
When I use the curl directly in the library, it works.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = "curl -v -u ${cred} --upload-file ${file} ${nexusLocation}/${file}"
try {
steps.sh cmd
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
However, when trying to use the Process it does not work.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}]
try {
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
The exception I get is:
java.lang.RuntimeException: Cannot execute curl, exception: [groovy.lang.MissingMethodException - 'No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
As explained here, you need to capture stdout/stderr to see anything.
At the very least:
def outputStream = new StringBuffer();
proc.waitForProcessOutput(outputStream, System.err)
//proc.waitForProcessOutput(System.out, System.err)
Or, as in this gist:
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
An example of blocking call would be:
println new ProcessBuilder( 'sh', '-c', 'du -h --max-depth=1 /var/foo/bar/folder\\ with\\ spaces | sort -hr').redirectErrorStream(true).start().text
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}/${file}]
No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
The '/' in '${location}/${file}' is interpreted as an '/ (div) operation instead of a string.
Try instead for that curl command argument:
${location}+"/"+${file}
As noted in your subsequent question, the all path needs to be between double-quotes.
I'm using Docker for a Spring Boot application and so far everything is working.
I have a resource file in src/main/resources/db/data/dummydata.csv
In a bootstrap class this file is used to import the dummy data into the database.
private fun getDummyData(): List {
var fileReader: BufferedReader? = null
val dummyData = ArrayList<DummyDataEntity>()
try {
var line: String?
val res = ResourceUtils.getFile("classpath:db/data/dummydata.csv")
fileReader = BufferedReader(FileReader(res.path))
// Read CSV header
fileReader.readLine()
... Processing the data ...
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
fileReader!!.close()
} catch (e: Exception) {
e.printStackTrace()
}
return dummyData
}
}
When I run the application in IntelliJ, everything works just fine, but when I'm running it in Docker it cannot be found.
The Jar and the Docker image are created using Kotlin DSL Gradle.
import com.palantir.gradle.docker.DockerExtension
import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension
import org.gradle.tooling.model.GradleTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.tasks.bundling.BootJar
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath(Libs.springBootGradlePlugin)
classpath(Libs.kotlinGradlePlugin)
classpath(Libs.kotlinAllOpen)
classpath(Libs.gradleDocker)
}
}
plugins {
// Apply the java-library plugin to add support for Java Library
`java-library`
}
apply {
plugin("kotlin")
plugin("kotlin-spring")
plugin("org.springframework.boot")
plugin("io.spring.dependency-management")
plugin("com.palantir.docker")
}
repositories {
mavenCentral()
}
dependencies {
compile(Libs.kotlinReflect)
// Spring Boot
compile(Libs.springBootStarterDataJpa)
}
configure<DependencyManagementExtension> {
imports {
mavenBom(Libs.vaadinBom)
}
}
val bootJar: BootJar by tasks
bootJar.baseName = "reporting-app-site"
bootJar.version = "0.0.1"
configure<DockerExtension> {
name = "brabantia/${bootJar.baseName}"
files(bootJar.archivePath)
buildArgs(mapOf("JAR_FILE" to bootJar.archiveName))
dependsOn(tasks["build"])
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions.jvmTarget = "1.8"
The Jar does contain BOOT-INF/classes/db/data/dummyData.csv but when the application is run the error that is thrown is
java.io.FileNotFoundException: class path resource [db/data/dummydata.csv] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/app.jar!/BOOT-INF/classes!/db/data/dummydata.csv
What am I missing here?
The below worked for me.., you need to use an InputStream and not a File.
...
#Autowired
private ResourceLoader resourceLoader;
...
Resource resource= resourceLoader.getResource("classpath:/account_info.html");
InputStream inputStream= resource.getInputStream();
Assert.notNull(inputStream,"Could not load template resource!");
String email = null;
try {
byte[] bdata = FileCopyUtils.copyToByteArray(inputStream);
email = new String(bdata, StandardCharsets.UTF_8);
} catch (IOException e) {
logger.warn("IOException", e);
}finally {
if ( inputStream != null) {
IOUtils.closeQuietly(inputStream);
}
}
I'm using Grails 2.2.1 with the recent Geb version. My Spec test files are under
functional/com.geb.mytest/
My GebConfig is on the same package as my Specs..
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.firefox.FirefoxProfile
driver = {
FirefoxProfile firefoxProfile = new FirefoxProfile()
new FirefoxDriver(firefoxProfile)
}
reportsDir = "target/test-reports"
baseUrl = 'http://myserver.com'
waiting {
timeout = 5
retryInterval = 0.5
presets {
slow {
timeout = 20
retryInterval = 1
}
quick {
timeout = 1.5
retryInterval = 0.3
}
}
}
environments {
}
When I run grails test-app -functional my baseUrl is not taken in consideration...instead I have a localhost url..
Is there a way to avoid putting the baseUrl as an argument in the grails test-app command?
Any idea?
Thanks in advance
Try setting up baseUrl in class which is extended for every test class you have:
class BaseUrlTest extends GroovyTestCase {
def baseURL
#Override
protected void setUp() throws Exception {
super.setUp();
baseURL = 'your url here'
}
}
then your test class looks like this
class myTests extends BaseUrlTest {
void testSomething() {}
}