mandag 28. januar 2013

html to xsl in groovy

I work with a cms where we use xslt in order to render html out on the pages.
When we write xslt it's usually based on a prototype we did in html. I wrote a quick script to render the html-tags into xsl (in groovy).



def output = ""
new File(args[0]).eachLine { line ->
def txt = line.find(/<(span|img|h2|a|form|p|div|label|input|textarea)(.*)>/)
if(txt){
output+="<xsl:element name=\""+txt.find(/span|img|h2|a|form|p|div|label|input|textarea/)+"\">\n"
txt.eachMatch(/(id|class|href|src|for|type|method|rows|src)=\"(.*?)\"/){it->
output+="<xsl:attribute name=\"" + it[1] + "\">"+ it[2] +"</xsl:attribute>\n"
}
}
if( line.find( />(.*?)<\// ) ){
output += "</xsl:element> <!-- $line -->\n"
}
if( line.replaceAll(/\s/,"").find(/^<\//) ){
output += "</xsl:element><!-- $line --> \n"
}
}
println output

Could be useful for other people than me, I guess.

onsdag 12. desember 2012

Really cheap regression testing of pages.

Regression testing is usually an expensive experience. I suggest a cheap alternative.

Given scenario:
-You have a 500-page website, and have made improvements to 10 of the pages with style changes.
-All of the 500 pages share the same set of css-files.

How can you be certain that only the 10 pages were affected by your changes?

One solution could be
1) Take screenshots of all the pages. This is how it looks now.
2) Write and commit the change. Potentially your change should only have changed what you intended to change.
3) finally take another set of screenshots. Compare the screenshots with the original screenshots. The difference should only be visible on the 10 of the screenshots.

Warning : The code is meant for pages without too much dynamic content. Elements like for instance a clock (something that changes all the time) will trigger a difference between two screenshots. It's also nice if the pages load quickly. If not maybe all of the elements haven't loaded in time for the screenshots (which will produce different pictures).

The code to take screenshots
Notes on the code:
-The argument given here is the name of the directory you'd like to put the files in.
-In this example I read each line of a file with one url on each line.

import org.openqa.selenium.WebDriver
import org.openqa.selenium.OutputType
import org.openqa.selenium.TakesScreenshot
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.apache.commons.io.FileUtils;

if(args[0]){
def lines = new File("links.txt").text
WebDriver driver = new FirefoxDriver();
lines.eachLine{ url, counter ->
println "$counter. Getting snapshot of " + url;
driver.get(url);
sleep 500 
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
url = url.replaceAll("\\.","_")
println "Saving : " + url
FileUtils.copyFile(screenshot, new File(args[0] + "/" + url +  "_skjermskudd.png"));
}
driver.quit();
}

The code to compare screenshots 
Note:
-The first argument is the "before" screenshots directory. The second is the "after" screenshots directory.
- I wrote this because I found that you can't use regular linux diff as it is too strict. You need to account for atleast 100 bytes in difference
-The code is crude, please just use it as an example :)

def dir1 = args[0]
def dir2 = args[1]

def okCounter = 0
def totalCounter = 0
def doesNotEqualCounter = 0
def didNotFindCounter = 0

println "\n\nComparing..\n\n"

new File(dir1).traverse { file1->
def fileName = file1.toString().replaceAll(dir1,"")
def file2 = new File(dir2 + fileName)
totalCounter++

if(file2.exists()){
if(file2.size() > (file1.size() + 100) || file2.size() < (file1.size() - 100)){
doesNotEqualCounter++
println "\n$doesNotEqualCounter. File has changed. File name is : \n" +
"open */" + fileName
} else {
okCounter++
}
} else {
didNotFindCounter++
println "File has was not found. File name is : " + fileName
}
}

println "\n\nOn the bright side there was $okCounter/$totalCounter matches."
if(didNotFindCounter!=0){
println "Did not find $didNotFindCounter occurrances.\n\n"
}

mandag 18. juli 2011

Using soap webservices with curl

So I was in this situation where I was going to use a webservice that I didn't have any access to, since the service was located in a production like environment. What I did have was access to ssh to the server, so I found I could use the websevice like this in groovy;

def payload = ?
def user = ?
def host = ?
def response = "ssh ${user}@${host} curl -d \"${payload}\" -H \"Content-Type: text/xml\" ${wsUrl}".execute.text


That's a very short post from me :)

tirsdag 3. mai 2011

Appending contextual logs to your selenium/tellurium tests.

So we have some selenium tests we run, and they either succeeed or fail. When it fails we usually know what it is, and some other times we need to go into the logs to figure out what went wrong. Since we had a lot of things going wrong for us, we found it a bit annoying that we had to go into the logs all the time.

Solution:
So this applies to any test case using junit4, but is probably only relevant to applications that runs and logs what happens to it :) Typically I think this could suit a selenium test. We used telliurium+groovy as the dsl for out tests. We wrote a watchman called LogWatchMan that extends the "org.junit.rules.TestWatchman". We override the starting-method and call

"ssh ${user}@${host} wc -l ${path}".execute().text 

Where the ${path} placeholder is the path to the log and ${user}@${host} is the user and the host. This will give us the count of lines in the given log(s). Take the count of lines and store it in a map with the logname. You will use the number of lines when you override finished

This requires you to do a password less login with ssh, because you don't want to have to answer a prompt. (or you could alternativly implement something like Expect in groovy).

Check out how to do a passwordless login here; http://rcsg-gsir.imsb-dsgi.nrc-cnrc.gc.ca/documents/internet/node31.html

Right, so when the tests have been run, the finished-method in the watchman will be called. In this method you will iterate over your previous result and repeat the action for each of the logs you've checked and get the line count of the logs. You will compare the line numbers, and if the line count is different, perform the following call

"ssh ${user}@${host} sed -n ${countBefore},${countNow}p '${path}'".execute().text

Where the ${countBefore} placeholder is our previous count of the given log, and the ${countNow} placeholder is the current count of the given log. The ${path} placeholder is in this case the path to the log. And then you write out the log to a file, f.ex.

This gives very little overhead to the tests, and will give you the contextual log of whatever system you are testing.

If you feel like implementing it yourself, and need an example, don't hesitate to get in touch.

onsdag 2. mars 2011

Logs - use groovy+grep to find trends in your logs

Sometimes it might be useful to see the real state of your application for instance in a test phase of a project by getting some statistics on exceptions that are thrown.

The problem: We have logs, and we look through them whenever something goes wrong. And we usually know that something goes wrong, when someone says something or when everything goes to hell. But we never really use them for anything else. I don't.

I've sometimes grepped my way through the logs to find patterns of exceptions, so I decided that this might be interesting as a tool. The premise for the script I wrote is that the log files were going to be rolled daily, so the files (hopefully) won't be too big. I read the whole file into memory in the script (something you can tweak if you need to use it on large files). You also have to have groovy(I'm on 1.6 I think) available and be on a unix machine :)

(Anyway, you needn't really do this in groovy, the principal is easy to get and you can do this in other types of scripts. Grep on the other hand is probably nice to have as it is very quick.)

I tested it on files over 10mb, and it runs quite fast.

Here's what you get:

-How many occurances of exceptions in general are in the log.
-How many unique exceptions are in the log.
-A file with the list of each of the unique exceptions, how many there are of each of them and at what line(s) in the log file you can find them.

The print out is written to a csv-file in the directory you are standing. If you run it every day, like with a cron tab, you can probably combine the files to see some interesting trends.

If you want the same sort of statistics, go to my github-space and check it out.
https://github.com/esschul/GroovyGrepExceptions

tirsdag 22. februar 2011

play framework, showing gravatars

Gravatar enables you to show a picture of a person, as long as you have their email-address, and they are registered at gravatar. But you have to do some work :)

So this post is about showing gravatars in play and how we did it when we had a lot of them.
So our stack for this example is jquery and the play! framework v1.1 (using grails templating).

So first the hashing method for getting the gravatar hash. We kept it on the model, but you can also put it in your controller if you have usage beyond the domain.

public static String gravatarhash(String gravatarId){
    if(gravatarId != null)
        return Codec.hexMD5(gravatarId.toLowerCase().trim());
     return null;
}

You call it from the html-file like this;

${models.Person.gravatarhash(person?.email).raw()}

where person in this case is a person with an email attribute populated from a controller.

So that's the hash that gravatar needs. If you have an email registered in gravatar and hash it using the method previosly specified, you ought to get a nice picture out with an img-tag

<img src="http://www.gravatar.com/avatar/${models.Person.gravatarhash(person.email).raw()}"/>
(If there is no email registered at gravatar, it will use a defaulted image. A default you can tweak, just check out their website).

So first off, if you have hundreds of gravatars; you don't put your gravatar url in a img-tag. The general browser will look at that as a resource it has to get on page load. Even with http caching, you don't want to load more resources than the user needs.

So in our case we had a button, and on the push of that button we want to show some pictures. We don't want it to take a long time to get in to the page initially, so what do we do? We load the images with javascript, and don't do it before the user pushes the button.

So we did something like this;
<a href="javascript" onclick="$('people').html('#{list items:people, as:'person' }<img src= quot;http://www.gravatar.com/avatar/${models.Person.gravatarhash(person.email).raw()}quot; alt=quot;${person.name}quot;/>#{/list}');$('people').toggle();">show me a hundred pictures!</a>

<div id="people" style="display:none"></div>


So now go out and add some pictures to your website!

fredag 18. februar 2011

play framework, adding ical

So here's my really quick guide to making ical available in your playapp. This is what you need;

Add ical4j's jars. Or just add the dependency to your pom.xml if you use that
The repo is;



<repository>
      <id>modularity-releases</id>
      <name>Modularity Releases Repository</name>
      <url>http://m2.modularity.net.au/releases</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>


the dependency:

<dependency>
      <groupId>net.fortuna.ical4j</groupId>
      <artifactId>ical4j</artifactId>
      <version>1.0-rc1</version>
    </dependency>

Then install it with play mvn:up if you use the maven plugin. if not, then just download the jar and put it in the lib-directory.
Then you need to write some code to create a calendar instance. here's what I wrote for now;



public static Calendar createCalendar(Event event) throws SocketException {
        TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
        TimeZone timezone = registry.getTimeZone("Europe/Oslo");
        VTimeZone tz = timezone.getVTimeZone();
        // Create the event
        VEvent meeting = new VEvent(new DateTime(event.date), new DateTime(event.date), "javaBin: " + event.title);
        // Add timezone info..
        meeting.getProperties().add(tz.getTimeZoneId());
        UidGenerator ug = new UidGenerator(event.title);
        Uid uid = ug.generateUid();
        meeting.getProperties().add(uid);

        // Create a calendar
        net.fortuna.ical4j.model.Calendar icsCalendar = new net.fortuna.ical4j.model.Calendar();
        icsCalendar.getProperties().add(new ProdId("-//Events Calendar//iCal4j 1.0//EN"));
        icsCalendar.getProperties().add(CalScale.GREGORIAN);
        icsCalendar.getProperties().add(Version.VERSION_2_0);
        icsCalendar.getComponents().add(meeting);
        return icsCalendar;
}


Where as you can see the calendar is based on an event, and it's title.
Don't worry about any of the different types as "VEvent", as they are part of ical4j.

Then you need to render the file to the user, right?

Well, first go to iconfinder.net and find a nice icon for your ical-link.
In your html, write a link like this;



<a href="@{Application.ical(event?.id)}"><img src="/public/images/ical.png" alt="calendar"/></a>


then you write the rendering code in your controller;

public static void ical(Long id){
        try {
            Event event = Event.findById(id);
            Calendar calendar = ICalUtil.createCalendar(event);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            CalendarOutputter outputter = new CalendarOutputter();
            outputter.output(calendar, bos);
            response.setHeader("Content-Type", "application/ics");
            InputStream is = new ByteArrayInputStream(bos.toByteArray());
            renderBinary(is,"javaBin.ics");
            bos.close();
            is.close();
        } catch (IOException e) {
            Logger.error("Io feil ved ical", e);
        } catch (ValidationException e) {
            Logger.error("Feil ved generering av ical", e);
        }
    }


Out of it you get an ical-calendar-item that people can use and enjoy ;) That's it.

 
 
Copyright © >> /dev/null
Blogger Theme by BloggerThemes Design by Diovo.com