I am trying to upgrade my application from grails 2 to grails 3. However, the functional test which is working in grails 2 fails to run now. In grails 2, I use RestBuilder to send request and get response. In grails 3, there is no corresponding RestBuilder release. How can I send my post and get request in grails 3 functional test?
Thanks very much.
My test code in grails 2:
void testRequestNewEnvironment() {
setup:
def rest = new RestBuilder(connectTimeout:1000, readTimeout:20000)
int timeout = 10
String environmentId = 0
String environmentStatus = "Not Ready"
when:
/**
* PostMethod. Send out a post and response status should be 200 and the body of response include env_id
*/
def resp = rest.post('http://localhost:8080/test-environment-manager/environment') {
contentType "multipart/form-data"
buildfile= new File('script.sh')
username = "apps"
keepEnvflag = "false"
env_flavor = "default"
}
then:
resp.getStatus() == 200
environmentId = resp.json.env_id
println "Environment ID: $environmentId"
println ("Environment Status"+resp.json.Status)
I use RESTClient for executing HTTP requests in Grails functional tests. It's a class from the HTTPBuilder library, so it should work in every Grails version (because it has dependency on Grails).
Some example usages are shown here. Before you can use it, you'll need to add a dependency on this library by adding the following to build.gradle
compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1'
I added :
compile ":rest-client-builder:2.1.1"
and it works fine.
Related
My application requires the app to run in https since the browser sends payment data to payment gateway through javascript library.
If the app is run in http then this error is thrown by the payment gateway.
I have created a simple hello world app and wrote a simple geb spec.
I dont seem to find a way to run the server in https mode. I dont find any helpful resource in the web as well.
Right now it is running in http mode in random port
Grails application running at http://localhost:54461 in environment: test
I have tried adding https port in build.gradle as
integrationTest {
systemProperty "webdriver.chrome.driver", "C:\\webdrivers\\chromedriver.exe"
jvmArgs(
'-Dgrails.server.port.https=8443'
)
}
But that seems to get ignored.
I have also tried setting the https port in intellij run configuration as shown below.
I have published the app code in github for reference.
https://github.com/learningcscience/gebhttps
I appreciate any help. Thanks!
UPDATE:
Today i think i made a little more progress.
I could now run the app in a fixed port. I ran the app in 8443 which is for https.
I did this using the spring boot test annotation
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
In the console now it shows
Grails application running at http://localhost:8443 in environment: test
Starting ChromeDriver 100.0.4896.20 (f9d71f93d32a6487809d6f35a9670c879fe97dfe-refs/branch-heads/4896#{#203}) on port 31898
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
https://docs.grails.org/latest/guide/testing.html
Now i just need to make the app run using the https rather than http.
I have updated the code in github repo.
https://github.com/learningcscience/gebhttps
I appreciate any help! Thanks!
ok. The problem is finally solved.
The last help came from the grails community at https://grails.slack.com/
Thanks Mattias Reichel for the help.
I am now going to put step by step process so that others might not get stuck with this issue.
In order to run functional geb test in https you first need to put SpringBootTest annotation as mentioned in above UPDATE: section.
I am pasting here again
#Integration
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class EventCreationSpec extends GebSpec {
After that you set baseurl in src/integration-test/resources/GebConfig.groovy.
I put baseUrl = "https://localhost:8443/"
My GebConfig looks like this
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.chrome.ChromeOptions
import org.openqa.selenium.firefox.FirefoxDriver
environments {
// run via “./gradlew -Dgeb.env=chrome iT”
chrome {
driver = {
System.setProperty('webdriver.chrome.driver', 'C:\\webdrivers\\chromedriver.exe')
new ChromeDriver()
}
}
// run via “./gradlew -Dgeb.env=chromeHeadless iT”
chromeHeadless {
driver = {
ChromeOptions o = new ChromeOptions()
o.addArguments('headless')
new ChromeDriver(o)
}
}
// run via “./gradlew -Dgeb.env=firefox iT”
firefox {
driver = { new FirefoxDriver() }
}
}
baseUrl = "https://localhost:8443/"
After that you need to create a application-test.yml file in src/integration-test/resources/
The application-test.yml file looks like this
server:
port: 8443
ssl:
enabled: true
keyStore: c:/Users/user/selfsigned.jks
keyStorePassword: pepsicola
keyAlias: tomcat
you need to create self signed certificate.
You can go through this process to create the certificate
https://grails.org/blog/2017-06-28.html
In the configuration above
my certificate was in selfsigned.jks keystore in the path c:/Users/user/selfsigned.jks
After that the functional test will fire in https mode
In my case
http://localhost:8443/roadrace
here is what the gebspec should look like
Note the SpringBootTest annotation at the top.
#Integration
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
#Stepwise
class EventCreationSpec extends GebSpec {
def grailsApplication
def springSecurityService
def timeService
def setup() {
}
def cleanup() {
}
void "Create and publish event"() {
when:"The home page is visited"
go '/roadrace/'
$("#details-button").click()
$("#proceed-link").click()
... rest of gebspock test steps....
then:"The title is correct"
title == "Homepage"
}
}
Please note that i had to go to /roadrace/ because the roadrace is the app context path.
If you dont have context path you can go to go '/'
The final hurdle can be when the browser fires up in https it might show
For this using geb you can click on the Advanced and then Proceed to localhost (unsafe) links
I just click the links like this
go '/roadrace/'
$("#details-button").click()
$("#proceed-link").click()
That's all! Now the geb functional test runs in https. Since it is https you can also now communicate to test payment gateway.
I am able to send messages with rabbitmq by using this
private void SendRabbitMqCommand(string queueName, object message)
{
var hostname = ConfigurationManager.AppSettings["ExportQueueHostname"];
var uri = new Uri(string.Concat(hostname, "/", queueName));
var sendEndpoint = this._bus.GetSendEndpoint(uri).Result;
sendEndpoint.Send(message);
}
But now I need to switch to SQS. I have been trying to figure out how to build the "uri" for the GetSendEndpoint method and cannot seem to find an example in the documentation.
BTW, I am using the latest MassTransit production build 5.5.6 and my company does not like using development builds. I read that in version 6 it will be possible to do following below:
var uri = new Uri("queue:" + queueName)
But I cannot use version 6 as it is not yet released as a production build.
Description
I am working with Grails 3.1.4 and I am having problems documenting my Controller classes with the Swagger Api.
grails -version gives me this output:
| Grails Version: 3.1.4
| Groovy Version: 2.4.6
| JVM Version: 1.8.0_73
I tried to integrate Swagger into the project using these sources:
- https://grails.org/plugin/swaggydoc
- https://rahulsom.github.io/swaggydoc/
According to these sources I have to do the following things:
1. Add dependencies to build.gradle:
compile 'io.swagger:swagger-core:1.5.7'
compile 'io.swagger:swagger-jaxrs:1.5.7'
compile "com.github.rahulsom:swaggydoc-commons:0.24.0"
compile "org.grails.plugins:swaggydoc:0.27.0"
2. Add another repository to build.gradle:
`jcenter()`
3. Annotate my Controller in the following fashion:
#Api(value = "myValue", description = "this controller does something")
#Path("/myapproot/myDomainClassX")
MyDomainClassXController{
#GET
#Path("/myFunction")
def myFunction(){
render "MyDomainClassXController, myFunction(), did something"
}
}
4. In the file application.yml I added:
grails:
mime:
disable:
accept:
header:
userAgents: []
5. The aforementioned sources write about a Config.groovy which I do not have, so instead of writing:
swaggydoc {
contact = "developer#coer.com"
description = "API description"
title = "My Swagger Doc for my awesome project"
apiVersion = "0.2cents"
}
6. into the non-existent Config.groovy, I added the same text into the file application.yml using the yml syntax:
swaggydoc:
contact: "developer#coder.com"
description: "API Description"
title: "My Swagger Doc for my awesome project"
apiVersion: "0.2cents"
Result
What works is:
I am running my Grails application with the bootRun task and browse to http://localhost:8080/myapproot/myDomainClassX/myFunction and see the String "MyDomainClassXController, myFunction(), did something" in my browser.
What not works is:
When I browse to http://localhost:8080/myapproot/api I get the "Page Not Found (404)" Error. Here i expected to see the magic of the Swagger annotations producing a documentation.
Question
What did I do wrong in the configuration of the Swagger plugin mentioned in the sources?
If you are getting a 404 on /myapproot/api check your UrlMappings.groovy file.
Either leave this default mapping in there:
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
or at least allow
get "/api/$action?"(controller: 'api')
That should let you at least hit the swaggy controller with that URL.
I have an API built using Spray that handles file uploads.
I am trying to write a test for the upload functionality but I'm not getting anywhere fast. I'm nots sure how to structure the test to simulate a file upload.
I have the following test...
"Valid POST Requests should return success" in {
Post("/upload", HttpEntity(MediaTypes.`multipart/form-data`, """{"filename":"a.wav"}""")) ~>
sealRoute(uploadRoute) ~> check {
response.status should be equalTo OK
responseAs[String] === "..."
}
}
Running this produces the following error message...
Content-Type with a multipart media type must have a non-empty 'boundary' parameter' is not equal to ...
This seems like an error message similar to how to mock POST/Upload requests using apache bench where you have to specify a post file and the boundary to separate the form items.
I was hoping for something closer to how CURL works.
Either way, can anyone point me in the right direction as to how I correctly structure such a test?
Thanks
So I managed to get this working by cobbling together some code from a variety of posts I found - primarily posts relating to using spray-client to do file uploads.
Probably not the prettiest but works for me! :)
"Valid POST Requests should return success" in {
val file = new File("a.wav")
val httpEntity = HttpEntity(MediaTypes.`multipart/form-data`, HttpData(file)).asInstanceOf[HttpEntity.NonEmpty]
val formFile = FormFile("file", httpEntity)
val mfd = MultipartFormData(Seq(BodyPart(formFile, "file")))
Post("/upload", mfd) ~> sealRoute(uploadRoute) ~> check {
response.status should be equalTo OK
body.contentType.toString() === "application/json; charset=UTF-8"
responseAs[String] === "Success!"
}
}
I have the same issue, or question.
Try adding a boundary by doing:
Post("/upload", HttpEntity(MediaTypes.multipart/form-data.withBoundary("-somerandomboundary"), """{"filename":"a.wav"}""")) ~>
Although, you might face the next bump I face, which is an error saying it requires a start boundary.
I want to setup a proxy inspection tool such as fiddler or Charles proxy (I have both), so I can see what is being sent and received - without this you are blind.
The question is, how to i tell grails 2.4.4 or the wslite-0.7.2.0 plugin to use my local proxy server?
Sadly, there is only 1 page of documentation for the plugin, with examples which are completely different to the groovy-wslite library it is supposed to bring in.
e.g. https://github.com/jwagenleitner/groovy-wslite
says I should be able to do this:
def proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress('proxy.example.com', 8080))
def client = new SOAPClient("https://www.example.com/ExampleService")
def response = client.send(proxy:proxy) {
But when I try this format, I just get:
No signature of method: wslite.soap.SOAPClient.send() is applicable for argument types: (java.net.Proxy,
Found the answer.
def client = new SOAPClient('https://bla')
def proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress('localhost', 8888))
client.httpClient.proxy = proxy
def response = client.send(SOAPAction: 'blabla') {