I am new to Grails and Groovy however my problem is a simple but strange one.
I am making calls to a remote web service as follows:
public Boolean addInvites(eventid,sessionkey ){
String url = this.API_URL+"AddInvites?apikey=${sessionkey}&eventid=${eventid}&userids[]=5&userids[]=23";
def callurl = new URL(url);
println callurl;
def jsonResponse = callurl.getText();
println jsonResponse;
def jsonParsedObject = JSON.parse(jsonResponse);
if(jsonParsedObject){
println jsonParsedObject;
if(jsonParsedObject.code == 200){
return true;
}
}
}
return false;
}
The API_URL here is a "https://api..com/"
Normally making these calls works fine. Json gets returned and parsed. However with the above method, if I add only one userids[]=5 then it works fine but if i add a second one everything hangs after the "println callurl;"
I've checked on the webservice side and the call happens and everything works as expected. If I call it in the browser it works fine. but from the grails web app it simply hangs. I know I'm probably doing something silly here, but I am really stuck. Hope you guys can help.
Are you sure that the [] characters are supposed to be there? If you use the following at the end of your query string, it will effectively pass userids=[5,23] to the server:
&userids=5&userids=23
If the brackets really are necessary, use the URL-escaped values %5B and %5D for them instead.
first of all, you should consider the following bug entry:
http://jira.codehaus.org/browse/GROOVY-3921
URL.getText() does not specify a connection timeout.
if you have access to the server logs check if requests from your grails app are actually received (when adding a second userids[] parameter). if this is not the case, you will probably have to use tcpdump or Wireshark in order to debug on TCP level.
Related
I'm fairly new to Groovy and Jenkins, so hopefully this question is coherent.
I have a Jenkinsfile written in Groovy and would like to validate one of the params as a valid URI. Without writing my own regex check, is there a library I could easily invoke during Jenkins startup?
You can try this:
try {
def foo = new java.net.URL("yourURI").openStream()
if (foo.getClass() == sun.net.www.protocol.http.HttpURLConnection$HttpInputStream) {
println 'valid'
foo.close()
}
}
catch (java.io.FileNotFoundException e) {
println 'not valid'
return
}
Unfortunately URL.toUri is not allowed at least in our setup. (It could possibly be allowed with a separate config.) Apparently opening the url (trying to connect to the host) could be possible, but that feels like it could cause other problems.
I ended up with this:
// Validation URLs in Jenkins script is hard (URL.toUri is banned). This regex roughly matches the subset of
// URLs we might want to use (and some invalid but harmless URLs). You can get a rough sense what
// this matches with a generation tool like https://www.browserling.com/tools/text-from-regex .
def saneUrlPattern = ~/^https:\/\/[-\w]{1,32}(\.[-\w]{1,32}){0,4}(:[0-9]{1,5})?(\/|(\/[-\w]{1,32}){1,10})?(\?([-\w]{1,32}=[-\w]{0,40}(&[-\w]{1,32}=[-\w]{0,40}){1,8})?)?(#[-\w]{0,40})?$/
if (!(params.sourceUrl =~ saneUrlPattern)) {
return [error: "Invalid url ${params.sourceUrl}. A simple https URL is expected."]
}
I realise that trying to validate URLs with a regular expression is difficult. I tried to strike a balance between strict and correct enough validation and a regular expression that has some hope of being understood by looking at it and being reasonably convinced as to what it actually matches.
I have list List<Mono<String>>. Each Mono represents API call where I wait on I/O for result. The problem is that some times some calls return nothing (empty String), and I need repeat them again on that case.
Now it looks like this:
val firstAskForItemsRetrieved = firstAskForItems.map {
it["statistic"] = (it["statistic"] as Mono<Map<Any, Any>>).block()
it
}
I'm waiting for all Monos to finish, then in case of empty body I repeat request
val secondAskForItem = firstAskForItemsRetrieved
.map {
if ((it["statistic"] as Map<Any, Any>).isEmpty()) {
// repeat request
it["statistic"] = getUserItem(userName) // return Mono
} else
it["statistic"] = Mono.just(it["statistic"])
it
}
And then block on each item again
val secondAskForItemsRetrieved = secondAskForItems.map {
it["statistic"] = (it["statistic"] as Mono<Map<Any, Any>>).block()
it
}
I see that looks ugly
Are any other ways to retry call in Mono if it fails, without doing it manually?
Is it block on each item a right way to get them all?
How to make the code better?
Thank you.
There are 2 operators I believe can help your:
For the "wait for all Mono" use case, have a look at the static methods when and zip.
when just cares about completion, so even if the monos are empty it will just signal an onComplete whenever all of the monos have finished. You don't get the data however.
zip cares about the values and expects all Monos to be valued. When all Monos are valued, it combines their values according to the passed Function. Otherwise it just completes empty.
To retry the empty Monos, have a look at repeatWhenEmpty. It resubscribes to an empty Mono, so if that Mono is "cold" it would restart the source (eg. make another HTTP request).
I have a controller that needs to run several asynchronous methods that interact with the data on the client and make no calls to the server. I have one method working fine in the browser, but I want to drive the methods with tests and I can't get it to work in the test environment (Karma and Mocha). The reason is that the empty array that $resource.query() returns never gets populated in the test environment because the promise doesn't get resolved. Here is my beforeEach in the test suite.
beforeEach(inject(function($rootScope, $controller, scheduleService){
scope = $rootScope.$new();
sc = $controller('scheduleCtrl', {
$scope: scope, service: scheduleService
});
scope.$apply();
}));
scheduleCtrl has a property schedule that is assigned to the result of Resource.query() in it's constructor. I can see the three returned objects loaded into the MockHttpExpectation.
But when I go to run the test sc.schedule is an still an empty array, so the test fails. How do I get the Resource.query() to resolve in the test?
Resource.query() works with promisses, which is a assync process.
It happens that your test execute before the assynchronous request have completed and before array gets populated.
You could use $httpBackend so you can call expect after $httpBackend.flush().
Or you could retrieve the $promisse returned from Resource.query().$promisse on your test and do the expectation inside its implementation.
Ex:
$scope.promisse = Resource.query().$promisse;
sc.promisse(function(values) {
expect(values.length).not.toBe(0);
});
I'm running a test with Grails 2.3.8 and an external configuration, yet the value doesn't seem to be coming through. I've tried this in older versions and am not seeing the same error. Did something change or am I missing something that I fat fingered? I am using an absolute path and the file definitely exists because Grails sees the key.
Config.groovy
reliable.string = "This string is working"
grails.config.locations = ["file:/home/howes/Project/project/test-config.groovy"]
/home/howes/Project/project/test-config.groovy
test.externalstring = "this is a test"
To test it I made a controller and just called grailsApplication to pull out the values. The first time I load the page I get a blank map, and when I refresh I see the key but no value. To make sure I am pulling everything correctly I am outputting the test-config.groovy item and one from the basic Config.groovy.
TestContoller.groovy
class TestController {
def grailsApplication
def index() {
println grailsApplication.config.test
println grailsApplication.config.reliable
return [ext:grailsApplication.config.test.externalstring, ext2:grailsApplication.config.reliable.string]
}
}
Console Output (First Load)
[:]
[string:This string is working]
Console Output (Page Refresh)
[externalstring:[:]]
[string:This string is working]
What am I missing here?
class MyController {
def startTwoMinuteTask = {
response.contentType = 'text/html'
def out = response.outputStream.destination
out.println 'Starting ...'
out.flush()
for (int i=0;i<10;i++) {
out.println " <br> $i"
out.flush()
Thread.sleep(1000)
}
return null
}
}
I'd like this to display 1 through 10 as status updates, alas grails is buffering the the entire thing. How do I make this work? Thanks!
I know this isn't the actual answer to your question, but why aren't you using a background Thread?
Using something like the Quartz plugin will let you spin off the long-running process. You can have the browser poll for changes periodically (or using a feature like Atmosphere for push if you can).
The benefit of this is you aren't locking open a connection. Also, not all browsers will wait that long — sometimes they'll time out. HTTP isn't really intended as a long-running connection, especially if no information is being passed.