how to run geb functional test in https? - grails

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.

Related

Ember/Rails end-to-end testing error

I have an Ember CLI app with a Rails back-end API. I am trying to set up end-to-end testing by configuring the Ember app test suite to send requests to a copy of the Rails API. My tests are working, but I am getting the following strange error frequently:
{}
Expected: true
Result: false
at http://localhost:7357/assets/test-support.js:4519:13
at exports.default._emberTestingAdaptersAdapter.default.extend.exception (http://localhost:7357/assets/vendor.js:52144:7)
at onerrorDefault (http://localhost:7357/assets/vendor.js:42846:24)
at Object.exports.default.trigger (http://localhost:7357/assets/vendor.js:67064:11)
at Promise._onerror (http://localhost:7357/assets/vendor.js:68030:22)
at publishRejection (http://localhost:7357/assets/vendor.js:66337:15)
This seems to occur whenever a request is made to the server. An example test script which would recreate this is below. This is a simple test which checks that if a user clicks a 'login' button without entering any email/password information they are not logged in. The test passes, but additionally I get the above error before the test passes. I think this is something to do with connecting to the Rails server, but have no idea how to investigate or fix it - I'd be very grateful for any help.
Many thanks.
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'mercury-ember/tests/helpers/start-app';
module('Acceptance | login test', {
beforeEach: function() {
this.application = startApp();
},
afterEach: function() {
Ember.run(this.application, 'destroy');
}
});
test('Initial Login Test', function(assert)
{
visit('/');
andThen(function()
{
// Leaving identification and password fields blank
click(".btn.login-submit");
andThen(function()
{
equal(currentSession().get('user_email'), null, "User fails to login when identification and password fields left blank");
});
});
});
You can check in the Network panel of Chrome or Firefox developer tools that the request is being made. At least with ember-qunit you can do this by getting ember-cli to run the tests within the browser rather than with Phantom.js/command-line.
That would help you figure out if it's hitting the Rails server at all (the URL could be incorrect or using the wrong port number?)
You may also want to see if there is code that needs to be torn down. Remember that in a test environment the same browser instance is used so all objects need to be torn down; timeouts/intervals need to be stopped; events need to be unbound, etc.
We had that issue a few times where in production there is no error with a utility that sent AJAX requests every 30 seconds, but in testing it was a problem because it bound itself to the window (outside of the iframe) so it kept making requests even after the tests were torn down.

Showing Status Message on the Top of Grails Views whenever Some Service went Down

I am Developing grails application with multiple services and Quartz Jobs. Within Grails Quartz Jobs, I inject some services which make requests to server and perform some operation based upon the result, returned from server.
Now, Sometimes that server goes down due to some reasons and the service which communicates with that server gets connectionException. As all this is happening at back end and user doesn't know about it. I want to show message to user (No matter in which GSP page currently user is when server went down) at the top of the GSP whenever my service encounters that server is Down.
And that message will be disappeared when my service started communicating server (when server is up). As far I know, FLASH can be used here but that persists within single request but I want to show this message until server becomes accessible.
What are the different options for me to achieve this in Grails ? What will be best option ?
Thanks in Advance :)
Create a status service that keeps a volatile stats property, set it to reflect the status when it changes and use a tag library to read the status and include it in your layout/GSPs.
Here is a very quick example of that
First the Service:
// MyStatusService
package com.example
class MyStatusService {
boolean isServerDown = false
...
}
Then within your code:
// From within your code, setting the status
def myStatusService // assumes you can inject it
...
myStatusService.isServerDown = true // or false depending on your code
...
A tag library:
// MyStatus TagLibrary
package com.example
class MyStatusTagLib {
def myStatusService
static namespace = "myStatus"
def checkStatus = { attrs ->
if (myStatusService.isServerDown) {
out << "Server is down message here."
}
}
}
Then finally in your GSP or even your layout:
<myStatus:checkStatus />
Hope that helps.

websocket connection not happening using grails event-push plugin

I am trying to integrate grails events-push plugin to push events to browser however its not working. I made below changes for it
BuildConfig.groovy
grails.tomcat.nio = true
compile ":events-push:1.0.M7"
Config.groovy
events.push.servlet.initParams = [
'org.atmosphere.cpr.cometSupport': 'org.atmosphere.container.Tomcat7CometSupport',
"org.atmosphere.cpr.CometSupport.maxInactiveActivity": "100000"
]
tomcat.nio=true
Deleted context.xml(generated by plugin) from META-INF folder as tomcat was not working with it
In Client side i.e angular js
window.grailsEvents = new grails.Events('http://localhost:8080');
I managed to start my application successfully. I also below message in log
DEBUG cpr.DefaultBroadcaster - Broadcaster eventsbus doesn't have any associated resource. Message will be cached in the configured BroadcasterCache
Bu when I open my application in browser websocket do not work.
In serve end I see below meesage
2014-05-01 15:19:56,365 [http-nio-8080-exec-3] DEBUG cpr.AsynchronousProcessor - Timing out the connection for request AtmosphereRequest{ contextPath= servletPath=/g-eventsbus pathInfo=/eventsbus requestURI=/g-eventsbus/eventsbus requestURL=http://localhost:8080/g-eventsbus/eventsbus destroyable=false}
2014-05-01 15:19:56,366 [http-nio-8080-exec-3] WARN websocket.DefaultWebSocketProcessor - Unable to retrieve AtmosphereResource for org.apache.catalina.websocket.WsOutbound#269dd750
2014-05-01 15:19:57,783 [http-nio-8080-exec-5] DEBUG cpr.AsynchronousProcessor - Timing out the connection for request AtmosphereRequest{ contextPath= servletPath=/g-eventsbus pathInfo=/eventsbus requestURI=/g-eventsbus/eventsbus requestURL=http://localhost:8080/g-eventsbus/eventsbus destroyable=false}
I browser console end I see
WebSocket connection to 'ws://localhost:8080/g-eventsbus/eventsbus?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=1.1.0.beta3&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&topics=eventsbus' failed: WebSocket is closed before the connection is established.
Guys please help me I am struggling with this plugin from long time.
I'm using grails-events-push and almost everything works well.
In BuildConfig:
grails.servlet.version = "3.0"
grails.tomcat.nio=true
...
dependencies {
...
compile 'org.grails.plugins:events:1.0.0.BUILD-SNAPSHOT'
compile 'org.atmosphere:atmosphere-runtime:2.1.4'
}
plugins {
...
build ":tomcat:7.0.52.1"
runtime ":events-push:1.0.0.BUILD-SNAPSHOT"
}
You have to create one file to declare your events: mine is EasyRestaurantEvents.groovy
import static reactor.event.selector.Selectors.*
includes = ['push']
doWithReactor = {
reactor('grailsReactor'){
ext 'browser', [
(R('oneMessage-([0-9]+)')) : true
]
}
reactor('browser'){
ext 'browser', [
'oneMessageFromBrowser' : true
]
}
}
In the controller or service I can send an event in this way:
event('oneMessage-' + someId, mapObject)
In the client app I can receive this message in this way:
grailsEvents.on("oneMessage-666",
function(event){
alert("oneMessage was received for client 666");
});
In the server app, I can receive a message from the browser, in this way:
import reactor.spring.annotation.ReplyTo
import reactor.spring.annotation.Selector
class OneService {
#Selector(reactor = 'browser')
#ReplyTo
def oneMessageFromBrowser(Map data){
//do some work
}
}
To send an event from the browser yo can do:
grailsEvents.send('oneMessageFromBrowser', {message:'hello from browser'});
I hope this helps! I struggled with this plugin a lot! =(
But is very easy to use (when you make it work)
PS: I used another application created in angular to communicate with the server so I have to import the js manually:
"atmosphere.js": 2.1.5-javascript
"jquery.atmosphere.js": 2.1.5-jquery
Thanks mpccolorado for you reply. I got it working actually issue was in JS grails.Events should be created with globalTopicName.
var grailsEvents = new grails.Events(GRAILS_EVENT_URL, {globalTopicName: 'newReview'});

Grails 2.1.0 app tomcat 7.0.22 Session empty after redirect

I am just learning grails and have a problem with an app that works fine when I run it in Netbeans but shows strange behavior when deployed to Tomcat 7.0.22 on a Centos 5.4 server. I am using the proxy_ajp to make the app available with apache.
The problem seems to be with the session not being maintained after a redirect so that I lose the login information causing the app to try to login again.
My proxy_ajp settings are
<Location /PreyerBooks >
ProxyPass ajp://localhost:8011/PreyerBooks
ProxyPassReverse ajp://localhost:8011/PreyerBooks
</Location>
the app is deploying without errors and the connectivity to the database and LDAP is working. I tested this by logging in the authenticate method as follows
UserController - authentication function
def authenticate = {
def password=passhash(params.password)
log.info " login attempt ${params.login} - ${params.password} - ${password}"
def match = User.findAll(
directory: "user",
filter: "(&(uid=${params.login})(userpassword=${password}))"
)
log.info " match ${match}"
if (match) {
def user = Employee.findByLogin(params.login)
log.info " user ${user} - ${user?.role}"
if(user){
session.user = user
log.info "success"
flash.message = "Hello ${user.firstname}!"
redirect(controller:"Book", action:"index")
}else{
log.error "failed login attempt mismatch to ldap ${params.login}"
flash.message = "Sorry, ${params.login}. Please try again."
redirect(action:"login")
}
}else{
log.error "failed login attempt ${params.login} - ${params.password}"
flash.message = "Sorry, ${params.login}. Please try again."
redirect(action:"login")
}
}
BookController - auth function (checks if logged in)
def beforeInterceptor = [action:this.&auth, except:[]]
def auth() {
log.info "BookController:auth() ${session}"
if(!session.user) {
redirect(controller:"User", action:"login")
return false
}
log.info "BookController:auth() working"
return true
}
The log shows
INFO books.UserController - login attempt username - password - passwordhash
INFO books.UserController - match [de.preyer.books.User#d4a1cc]
INFO books.UserController - user username - admin
INFO books.UserController - success
INFO books.BookController - BookController:auth() Session Content:
The session.user variable has vanished. I checked the passwordhash and it correctly matches against the LDAP server (hence the object reference in match). This user is correctly found in the database where it gains its role.
I cannot access the app directly avoiding the apache ajp as the port is blocked in the firewall and I cannot open it. Thus I cannot test if the problem is in the ajp or tomcat in general
I have tried searching for the criteria specified as the title but find nothing relevant.
a) browser cookies are enabled and working, I tried Safari, Firefox and Chrome without success. I do not think this is a browser issue as the same browsers work with the app in NetBeans (using jetty I think)
b) I have set grails.serverURL = "http://servername/PreyerBooks" to the fully qualified domain
If I turn of the auth the app works.
I must be doing something wrong or have missed a step in the deployment.
Now I know I can include a plugin using Spring Core but this is overkill for my application and adds a further level of complexity to the debugging. I wish to get the current implementation working before moving on. The logic is copied from the Grails 2.1.0 documentation so it should work.
I read in httpSession that things must be serializable but if the example in the documentation does not work why does the app work when I run it in NetBeans?
I am at a loss. Any help would be much appreciated.
Use the spring-security-core plugin (or Shiro, or any established, proven security implementation). It's not complex, and rolling your own security is a quick path to getting hacked.

Twitter oAuth callbackUrl - localhost development

Is anyone else having a difficult time getting Twitters oAuth's callback URL to hit their localhost development environment.
Apparently it has been disabled recently. http://code.google.com/p/twitter-api/issues/detail?id=534#c1
Does anyone have a workaround. I don't really want to stop my development
Alternative 1.
Set up your .hosts (Windows) or etc/hosts file to point a live domain to your localhost IP. such as:
127.0.0.1 xyz.example
where xyz.example is your real domain.
Alternative 2.
Also, the article gives the tip to alternatively use a URL shortener service. Shorten your local URL and provide the result as callback.
Alternative 3.
Furthermore, it seems that it works to provide for example http://127.0.0.1:8080 as callback to Twitter, instead of http://localhost:8080.
I just had to do this last week. Apparently localhost doesn't work but 127.0.0.1 does Go figure.
This of course assumes that you are registering two apps with Twitter, one for your live www.mysite.example and another for 127.0.0.1.
Just put http://127.0.0.1:xxxx/ as the callback URL, where xxxx is the port for your framework
Yes, it was disabled because of the recent security issue that was found in OAuth. The only solution for now is to create two OAuth applications - one for production and one for development. In the development application you set your localhost callback URL instead of the live one.
Callback URL edited
http://localhost:8585/logintwitter.aspx
Convert to
http://127.0.0.1:8585/logintwitter.aspx
This is how i did it:
Registered Callback URL:
http://127.0.0.1/Callback.aspx
OAuthTokenResponse authorizationTokens =
OAuthUtility.GetRequestToken(ConfigSettings.getConsumerKey(),
ConfigSettings.getConsumerSecret(),
"http://127.0.0.1:1066/Twitter/Callback.aspx");
ConfigSettings:
public static class ConfigSettings
{
public static String getConsumerKey()
{
return System.Configuration.ConfigurationManager.AppSettings["ConsumerKey"].ToString();
}
public static String getConsumerSecret()
{
return System.Configuration.ConfigurationManager.AppSettings["ConsumerSecret"].ToString();
}
}
Web.config:
<appSettings>
<add key="ConsumerKey" value="xxxxxxxxxxxxxxxxxxxx"/>
<add key="ConsumerSecret" value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>
</appSettings>
Make sure you set the property 'use dynamic ports' of you project to 'false' and enter a static port number instead. (I used 1066).
I hope this helps!
Use http://smackaho.st
What it does is a simple DNS association to 127.0.0.1 which allows you to bypass the filters on localhost or 127.0.0.1 :
smackaho.st. 28800 IN A 127.0.0.1
So if you click on the link, it will display you what you have on your local webserver (and if you don't have one, you'll get a 404). You can of course set it to any page/port you want :
http://smackaho.st:54878/twitter/callback
I was working with Twitter callback url on my localhost. If you are not sure how to create a virtual host ( this is important ) use Ampps. He is really cool and easy. In a few steps you have your own virtual host and then every url will work on it. For example:
download and install ampps
Add new domain. ( here you can set for example twitter.local) that means your virtual host will be http://twitter.local and it will work after step 3.
I am working on Win so go under to your host file -> C:\Windows\System32\Drivers\etc\hosts and add line: 127.0.0.1 twitter.local
Restart your Ampps and you can use your callback. You can specify any url, even if you are using some framework MVC or you have htaccess url rewrite.
Hope This Help!
Cheers.
Seems nowadays http://127.0.0.1 also stopped working.
A simple solution is to use http://localtest.me instead of http://localhost it is always pointing to 127.0.0.1 And you can even add any arbitrary subdomain to it, and it will still point to 127.0.0.1
See Website
When I develop locally, I always set up a locally hosted dev name that reflects the project I'm working on. I set this up in xampp through xampp\apache\conf\extra\httpd-vhosts.conf and then also in \Windows\System32\drivers\etc\hosts.
So if I am setting up a local dev site for example.com, I would set it up as example.dev in those two files.
Short Answer: Once this is set up properly, you can simply treat this url (http://example.dev) as if it were live (rather than local) as you set up your Twitter Application.
A similar answer was given here: https://dev.twitter.com/discussions/5749
Direct Quote (emphasis added):
You can provide any valid URL with a domain name we recognize on the
application details page. OAuth 1.0a requires you to send a
oauth_callback value on the request token step of the flow and we'll
accept a dynamic locahost-based callback on that step.
This worked like a charm for me. Hope this helps.
It can be done very conveniently with Fiddler:
Open menu Tools > HOSTS...
Insert a line like 127.0.0.1 your-production-domain.com, make sure that "Enable remapping of requests..." is checked. Don't forget to press Save.
If access to your real production server is needed, simply exit Fiddler or disable remapping.
Starting Fiddler again will turn on remapping (if it is checked).
A pleasant bonus is that you can specify a custom port, like this:
127.0.0.1:3000 your-production-domain.com (it would be impossible to achieve this via the hosts file). Also, instead of IP you can use any domain name (e.g., localhost).
This way, it is possible (but not necessary) to register your Twitter app only once (provided that you don't mind using the same keys for local development and production).
edit this function on TwitterAPIExchange.php at line #180
public function performRequest($return = true)
{
if (!is_bool($return))
{
throw new Exception('performRequest parameter must be true or false');
}
$header = array($this->buildAuthorizationHeader($this->oauth), 'Expect:');
$getfield = $this->getGetfield();
$postfields = $this->getPostfields();
$options = array(
CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLOPT_URL => $this->url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false
);
if (!is_null($postfields))
{
$options[CURLOPT_POSTFIELDS] = $postfields;
}
else
{
if ($getfield !== '')
{
$options[CURLOPT_URL] .= $getfield;
}
}
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
if ($return) { return $json; }
}
I had the same challenge and I was not able to give localhost as a valid callback URL. So I created a simple domain to help us developers out:
https://tolocalhost.com
It will redirect any path to your localhost domain and port you need. Hope it can be of use to other developers.
set callbackurl in twitter app : 127.0.0.1:3000
and set WEBrick to bind on 127.0.0.1 instead of 0.0.0.0
command : rails s -b 127.0.0.1
Looks like Twitter now allows localhost alongside whatever you have in the Callback URL settings, so long as there is a value there.
I struggled with this and followed a dozen solutions, in the end all I had to do to work with any ssl apis on local host was:
Go download: cacert.pem file
In php.ini * un-comment and change:
curl.cainfo = "c:/wamp/bin/php/php5.5.12/cacert.pem"
You can find where your php.ini file is on your machine by running php --ini in your CLI
I placed my cacert.pem in the same directory as php.ini for ease.
These are the steps that worked for me to get Facebook working with a local application on my laptop:
goto apps.twitter.com
enter the name, app description and your site URL
Note: for localhost:8000, use 127.0.0.1:8000 since the former will not work
enter the callback URL matching your callback URL defined in TWITTER_REDIRECT_URI your application
Note: eg: http://127.0.0.1/login/twitter/callback (localhost will not work).
Important enter both the "privacy policy" and "terms of use" URLs if you wish to request the user's email address
check the agree to terms checkbox
click [Create Your Twitter Application]
switch to the [Keys and Access Tokens] tab at the top
copy the "Consumer Key (API Key)" and "Consumer Secret (API Secret)" to TWITTER_KEY and TWITTER_SECRET in your application
click the "Permissions" tab and set appropriately to "read only", "read and write" or "read, write and direct message" (use the least intrusive option needed for your application, for just and OAuth login "read only" is sufficient
Under "Additional Permissions" check the "request email addresses from users" checkbox if you wish for the user's email address to be returned to the OAuth login data (in most cases check yes)

Resources