Tuesday, 17 January 2012

Refamiliarising oneself with Selenium

My main focus over the last few years has been Information Security and more specifically Application Security.  As such I've not cut much production code of late and have probably let much of my development practices atrophy.  However, recently I've had the opportunity to get back on the development bike and ride around a little.

I'm used to, as of course we all are, writing unit tests at the service layer, the persistence layer and of course the presentation layer, so nothing new there.

As an aside, I remember many years ago having a conversation with a front-end 'Architect' that stated you cannot unit test a front-end; cue HTMLUnit/HTTPUnit/JWebUnit and some red faces.  (I wonder how those frameworks have progressed in the last few years - perhaps the topic for a future post).

Anyway, I've been kicking around some front end code whilst picking up jQuery and what not, so I thought I'd wheel out some of the old favourite *Unit frameworks and I thought I'd also reacquaint myself with Fitnesse and Selenium skills.  But one step at a time.  I thought I'd get back into Selenium slowly and rather than jumping straight into the client/server setup, I went with the Selenium IDE - the Firefox plugin.  This is a post recording said reacquaintance process over the last day or so.

Getting Started
Download http://seleniumhq.org/download/
  Selenium IDE 1.5.0
  I'm running Firefox 9.0.1

Once you restart Firefox you'll want to bring up the Selenium UI.
  1. Firefox -> Web Developer -> Selenium IDE.
I have created a small 'admin app' for the purposes of this post - slightly contrived - that allows me to CRUD an entity.  Its mainly basic HTML with some jQuery, and so that I can include more of the Selenium commands I've included other elements such as some frames; I have a navigation frame at the top of the page and a main frame below that which essentially acts as a content container.

So to the first test suite
The navigation frame is a good place to start.  To keep this as simple as possible I'm going to create a test case for each of the items in the navigation frame and verify the result by testing for the existence of some text in the content frame.


                                               "Home", "Search", "Create", "List", "Report"

Let the testing commence
  1. Bring up the context in the left panel and select New Test Case.  
  2. Rename the test by selecting properties. 
  3. Hit record - the red circle up on the right hand side Selenium. 
  4. On the browser, select Home. 
  5. Wait for the frame to display, select some unique text to that page. 
  6. Bring up the context menu and select 'verifyTextPresent your_unique_text' 
  7. Run the test case.  The bar is red...

Oh dear.  What happened there?   The error is:
[error] There was an unexpected Alert! [Error! Status = 0 Message = error Message = ]

So from that, you can deduce the cause; its simple.  Well, it is and its not depending on your Selenium experience.   You'll have to change the logging level to figure out more information on the problem.  I set this at 'Debug', it's a fair bit more verbose, but its worth doing it to begin with.  When you select this level it becomes much clearer.  Selenium is failing when its trying to select the content frame.  Okay, so lets clickAndWait; tell Selenium to wait for the page that we just requested to finish loading.  Let try running that test again.  The bar is red....


Grrrr.  What happened there?  The error is:
[error] There was an unexpected Alert! [Error! Status = 0 Message = error Message = ]

Same error as before.  I (thought I'd) found two distinct solutions for this.  The first is just to slow the speed at which the testsuite executes down.  You can do this by going to the slider and moving it slightly to the right.  This however does not address the root cause.


The second is, and I should have used this before trying clickAndWait tbh, to waitForFrameToLoad, or so I thought.  I added this after the clickAndWait (I could just revert this clickAndWait to just click), adding the name of the frame and a timeout, but I started to get the same error as above when I ran the tests at full pelt.  In the end I lost my patience, and as a rule of thumb I run the test at ~20% slower than full speed.  ISSUE_1 If someone know the solution to the root cause, please ping me; I'd rather not waste any more time on that particular issue.

So back to the tests
  1. Repeat the creation of test cases for each of the navigation elements.  Now you have five simple tests to run.  If the bar is green... and it is.  Sweet.
Now to save your work so far
  1. File -> Save Test Suite As... 
  2. Select a name and save. 
Now, let's simulate a cold start
  1. Firefox -> Web Developer -> Selenium IDE 
  2. File -> Open Test Suite...
Oh oh!


Ouch!  So what is going wrong here?  A quick look at the file that was written to disk only raises further questions. The file size for a start is only 1k.   On opening the file I'm presented with some html with only the test case names defined, no content.  Pants.  But, I was saving the testsuite after every change.  It turns out I wasn't saving the individual testcases.  I'll get my coat...  (This is so embarrassing I almost omitted it for this post)  Ah well, lesson learned, lets start again.  It is a bit annoying that you have to save each case individually, surely by saving the testsuite you're implicitly saying '...and save the testcases'.

I'm going to repeat the above, but this time save each individual testcase as I create it.  I've ended up with the following files:

Running the testsuite produces the following results; Runs: 5, Failures 0.  The bar is green...  Happy days.

Knock it up a notch

So these tests were really rather trivial, (barring the issue with waiting for a page to load...) so next we should tackle a form.
  1. Bring up the context menu and create a New Test Case.  
  2. Rename the test by selecting properties. 
  3. Hit record. 
  4. Hit Create on the navigation frame. 
  5. Fill in the form fields one by one.
  6. And stop recording.. 
Hey wait a minute.  Some of the form-filling didn't get recorded.  FFS!  ISSUE_2  After spending a bit of time searching the interweb, I found nothing to help me.  Grrr!  This didn't seem to make any sense, the form  tag was pretty standard, as were the input tags.

Well, it seems I was the architect of my own downfall; whilst trying to be a bit clever and have the input field label in the form field itself I'd inadvertently hit a Selenium edge case.  The issue was with the "placeholder" attribute of the input tag, after removing it from the input tag the actions were recorded as expected.  That was annoying.

    <input id="description" type="text" name="description" placeholder="some description" />

I could be lazy and remove all the placeholder attributes and record myself entering values into the form, but I'm going to use this as an opportunity to exercise my xpath skills.

Manual form filling

Doing this manually isn't that bad, plus I get some practice with xpath and with the Selenium IDE.  So for the first field of the form I want to emulate the user typing a unique identifier.

                   Basically this is saying, for the input field with the id attribute value of id, type in 667.

All of the fields follow the same pattern now all that needs to be done is to click the form submit button and verify that certain text is present.  Continuing in that vein I built up a sizeable set of tests always running the suite after each additional testcase.

After a while, working out the xpaths for elements became tedious, even for the more complex paths, so I ended up using FireBug (https://addons.mozilla.org/en-US/firefox/addon/firebug/)

Some tips
  1. Remember to select the correct frame
  2. Don't be clever and use the placeholder attribute
  3. Use a plugin that will help you with the xpaths
  4. Don't run the testsuite at maximum speed

Tuesday, 3 January 2012

MongoDB and CRUD, or should that be ISUD

I started this blog to remind myself of the solutions to development issues I have along the way and as a general hinting mechanism to remind myself what is going on when I have been away from it for a while. If any of this means that someone else reading this saves themself a world of hurt or going down the rabbit-hole of death, then I'm glad that recording it publically rather than privately was helpful (though conversely, it is always important to learn from one's owner experiences).

In my first posting Simple mongodb equivalents, I wanted to remind myself of some of the basic differences around selection between SQL and NoSQL, and to give concrete examples of what this would look like in Java. In this posting I'll go through the next stage, the hinting mechanism for CRUD.

For those that associate crud with filth, flattery, disgust or disappointment, then you may be on the wrong blog. CRUD stands for CREATE, RETRIEVE, UPDATE, DELETE - though the RETRIEVE is usually replaced by get or SELECT at implemention and CREATE is replaced with INSERT. So, perhaps I'll call it ISUD instead.

First, set up the database, a user and set up an index.

The CREATE (or INSERT) of CRUD (or ISUD)
Here we a setting up some basic data in a collection named 'stuff' that lives in the 'isud' database.

...this is how you would do it from the mongo shell...
...and the Java implementation...

The RETRIEVE (or SELECT) of CRUD (or ISUD)
The selection or retrieval of a document from the collection 'stuff' can be rather powerful, as per Simple mongodb equivalents.

...this is how you would do it from the mongo shell...
...and the Java implementation...
Now let's do a similar thing but this time specify the fields we want returned.

...this is how you would do it from the mongo shell...
...and the Java implementation...

The UPDATE of CRUD
Everyone knows his name was Eric, not Derek, so let's fix that with an update.

...this is how you would do it from the mongo shell...
...and the Java implementation...
Please refer to Updating a document using the default ObjectId for the reasoning behind DBObjectFactory


The DELETE of CRUD
Finally, we can delete a document.

...this is how you would do it from the mongo shell...
...and the Java implementation...
It's all relatively straight forward really. Though none of this is rocket science, I for one find this a useful and succinct reminder or as previously stated; a hinting mechanism.

Tuesday, 13 December 2011

Unsupported major.minor version 51.0

I've been away from the coalface, as it were, for a couple of years, only returning to it in the past few months. And I have to say, not much as changed and some things never change.  One of those things is the denvercoder9 moment, and that is the reason I started to blog; I feel the pain so you don't have to.

Let me set the scene briefly. I have full visibility of, and total control over my development environment; happy days. However, when it comes to UAT and Production environments I'm flying completely blind and at times I feel like I'm performing keyhole surgery with only a sledge hammer and a forklift, oh, and no keyhole.

I spent some time putting together a stack that I could use as a template, a reusable pattern where, from application to application I could recycle the initial pipework and pretty much only change the data model. What I needed was something completely stateless, all I really need was CRUD, so I opted for a REST based approach; and for me that meant reference implementation, Jersey. The other thing was that I strived to make it as simple to deploy as possible; essentially a WAR to be dropped into the application server that could then update the persistence layer when the application server started up.

Everything went swimmingly. Well, that's a bit of a lie, I found that some browsers still do not support PUT and DELETE.

RESTful Browser Verb Check

BrowserGETPOSTPUTDELETE
FF7YesYesYesYes
Chrome14YesYesYesYes
IE8YesYesConverts to GETConverts to GET


Anyhoo, I readied myself to deploy to the UAT environment. This consisted of listing everything component and detailing every step of configuration. As this was the bedding-in phase I needed the entire environment configured, which included the installation of the JRE, application server, database and the application. This could have been smoother if I had access to the boxes, but nevertheless we got there in the end.

So now I have my environment set up and my application deployed, let's kick the tyres. To my horror I got a 500 back from the service. Dang. I didn't have access to the logs and the only person with access was on leave that day. So I waited.

After a bit more waiting, I finally got a hold of the logs. And found the culprit, the little blighter was sticking out like a strawberry in a bowl of peas.


I've seen you before, I thought, and fired off a mail to the box admin (who was WFH; I'd ideally walk round and discuss face-to-face) to verify the JRE running on the UAT box. Some time later it was confirmed UAT was running JDK-Y. I was using JDK-X, so the UAT environment was running an earlier version than that which I build the WAR with - makes perfect sense and matches exactly to the exception. Fine:

  • Download/Install JDK-Y
  • Change JDK-X to JDK-X (Preferences -> Java -> Compiler)
  • Clean project
  • Rebuild
  • Redeploy locally
  • Redeploy UAT
Same 500 came back. Pants. Scratch of the head.

  • Let's change the Change JRE System Libraries (Right-click project -> Properties -> Java Build Path -> JRE System Library -- double-click and change to JDK-Y)
  • Clean project
  • Rebuild
  • Redeploy locally
  • Redeploy UAT
Same 500 came back. Starting to get a little annoyed now.

I Googled it. Every post said the same thing about the runtime and compile time JDKs being different, but I know that and I've told Eclipse. I checked that the Jersey binaries - built with Java SE Y. I've told Eclipse I want to use JDK-Y. How many times do I have to tell it? OK, I thought, everywhere I see JDK-X, I'll change it to JDK-Y, even if it seems irrelevant.
  • Change Target Platform (Window -> Preferences -> Plug-in Development -> Target Platform -- double-click and change JRE name under the Environment tab
  • Change Project Facet (Right-click project -> Properties -> Project Facets -> Java -> Select JDK-Y from drop down
  • Clean project
  • Rebuild
  • Redeploy locally
  • Redeploy UAT

SUCCESS

The moral of the story is, well I don't really know. What I do know is, it is annoying that you have to tell Eclipse four times in four totally different locations that you want to use a different JRE, and it's difficult to debug an application in an environment when you don't have access to said environment.

Monday, 12 December 2011

Testing your document structure for inconsistencies within MongoDB - Part II

In a previous post we looked at how to validate your collection for structural consistency. We did this by creating a DBObject with the 'template' document structure and comparing this against the relevant collection. Testing your document structure for inconsistencies within MongoDB
Now, it's not exactly a leap of faith to extend that and rather than code the template we can define this in a json document. Now all we need to do it to pass the json document and the collection name as parameters saving a recompile for each and every test. Happy days.




RFC 6455

There is a fair bit of chat going around regarding RFC 6455, better known as WebSockets, http://tools.ietf.org/html/rfc6455.  Wikipedia has already updated it's page to reflect the publication http://en.wikipedia.org/wiki/WebSocket so there is little point going into to it too much and as such we'll just focus on the key connection upgrade differences.

Connection Upgrade
Sec-WebSocket-Key1 and Sec-WebSocket-Key2, two 8 byte random tokens used by the server to prove to the client it has read the client request, have been replaced with; Sec-WebSocket-Key, a single 16 byte random token which is now base64 encoded prior to sending.
The corresponding change from the server is that it now use that base64 string and concatenates the WebSocket GUID. I'm not sure where exactly this is defined tbh, it's not in the RFC linked to from this RFC - anyhoo, it's not that important where it is, but it is a constant - 258EAFA5-E914-47DA-95CA-C5AB0DC85B11. Wikipedia calls this a "magic string", there is nothing magic about it - it's just a SALT essentially. Now you have the concatenated string, you now need to hash it (current choice is SHA-1 a change in hashing from MD5), base 64 encode and reply to request with status code of 101 - Switching Protocols.

Friday, 9 December 2011

jQuery and dot notation

I'm still a relative noob when it comes to jQuery, so I'm picking bits up all the time. The latest nugget is related to a previous post on converting an HTML to JSON which included the parsing of nested structures.
When it comes to populating a form with a nested structure there is potential to fall into a rabbit hole. Thankfully in this case the foxes had scared off the rabbits before they had the chance to dig too deeply.
The original issue manifested itself upon requesting a JSON resource with nested structure from a service and populating a form. Almost the opposite of the post linked to above. I went through the process of ensuring the JSON was valid, the path in the document matched the dot notation of the form and that the field had a value associated with it. The source presented below is a simplified test case designed to isolate the issue. What you see here is a form that is populated when the button is clicked. It looks rather innocent, however the "meh.feh" field doesn't get populated; exactly what I had seen in the original issue.

Simplied Example:

jQuery is treating the "." as CSS notation not as a literal. The solution? Escape them with a double backslash.

Simple fix:

For more information check the jQuery FAQ

Thursday, 8 December 2011

Updating a document using the default ObjectId

Here are a few facts about keys and the way MongoDB deals with them.
  • Documents in MongoDB require a key, _id, which uniquely identifies them.  
  • This is a 12-byte binary value, read more from the source of truth, ObjectId.
  • When inserting a new document, MongoDB will generate an ObjectId where one is not specified.
  • There is a 'reasonable' chance that this will be unique at the time of creation.  
  • All of the officially-supported MongoDB drivers use this type by default for _id values.

An annoyance I had with MongoDB, when I first started to use it, was the explicit update required on the default _id key/value pair.  To illusrate this here is a concrete example of what I mean.

I wanted to do this:
But I had to do this:
In this case, json is a JSON document passed from an HTML form via HTTP PUT, eventually ending up here at the DAO.  I was using the default _id implementation and thus would have expected save to do the figure that out and do the necessary work for me.

I just can't live those extraneous lines of code, it's too messy and too much to type every time.  I'll pull it out into a fromJson call, as I can see the pattern emerging and the odds of this reoccurring high.

I must have missed something in the API Docs as this cannot be an unusual requirement.  I would of at least expect to see it in a Util class...

Factory snippet:
Usage snippet:

I get to do what I wanted to now, but it still feels wrong.  It feels a little bit dirty.  It feels like a hack-o-la.  How can I do it better?