Loren Halvorson's Blog

If your only tool is a hammer...

March 2004 - Posts

Using an Ambient Orb to show continuous integration build status

A while ago I wrote that one of our developers was going to get an Ambient Orb and use it to signal the status of our continuous integration builds.  I'm just following up to say that we have it working. The orb is sitting up above the cubes on a shelf where you can see it from anywhere on the floor. It glows green when the build is successful, and slowly pulses red when the build is broken.

What an interesting device. It's plugged into a power outlet, that's all. It receives commands to change color through a wireless network. You trigger a color change by hitting a URL with some parameters telling it the color.

It was simple to integrate. We're using CruiseControl.NET to drive our NAnt builds, and in the build script we simply did this:

<project name="MyProject" default="build">
    <property name="nant.onsuccess" value="success"/>
    <property name="nant.onfailure" value="failure"/>

    <target name="build" description="builds the system">
        ...
    </target>

    <!-- invoked automatically when build is successful -->
    <target name="success" description="Target to run when build was successful">
        <echo message="Woo Hoo, the build was successful!" />
        <get src="
https://myambient.com/java/my_devices/submitdata.jsp?devID=123-456-789&amp;color=12&amp;anim=0&amp;comment=build+succeeded" dest="out.html" failonerror="false"/>
    </target>

    <!-- invoked automatically when a build fails -->
    <target name="failure" description="Target to run when build failed">
        <echo message="Oh Oh, where's that build monkey?" />
        <get src="
https://myambient.com/java/my_devices/submitdata.jsp?devID=123-456-789&amp;color=0&amp;anim=2&amp;comment=build+failed" dest="out.html" failonerror="false"/>
    </target>

</project>

Simple technique to test drive a browser application

A while ago, I needed to do some profiling of a complex wizard-type ASP.NET application. I needed a script to drive a reproducible path through the application so I could compare the effect of code changes from run to run. Filling in each form was tedious and error prone. ACT would have probably done the trick, but the application utilized lots of hidden fields, viewstate, and Server.Transfers that made writing an ACT test difficult. I was in search of a quick and dirty, low-tech solution.

The solution I arrived at after some trial and error was to simply write a JScript script that uses SendKeys to emulate a user banging away at the keyboard. If you can drive your application from the keyboard through a sequence of characters, tabs, arrows, enter keys etc, this technique may be useful to you. In addition to profiling, developers found this technique useful to drive through a set of prerequisite forms to get down to the screens they were working on more quickly.

The trick was to use the Internet Explorer events to prevent overdriving the app by sending the keys too early. Trapping the DocumentComplete event allows the script wait until the page has completely downloaded before sending the next keystrokes.

Here is a simplified version of the script. You can get much fancier by passing in parameters such as initial URL and username/password, allowing to switch between multiple test cases, and logging page timings. Using something like “ie.Document.frames.item(0).document.all["Busy"]”, you can even walk into the document object model of the displayed page to do things like sense error conditions and branch your test accordingly.

var gShell = new ActiveXObject("Wscript.Shell");
var isOperationComplete = false;
var navigateCount = 0;
var currentUrl = "";

// Create Internet Explorer and wire up its events
var ie = WScript.CreateObject("InternetExplorer.Application","ie_");
ie.Visible = true;
gShell.AppActivate("Microsoft Internet Explorer");

////////////////////////////////////
// Test script

ie.Navigate("http://localhost/WebApplication1/Default.aspx");
Wait();

// Enter the user name
// tab to password field and enter password
// then press enter (~)

Go("username{TAB}password~");

// etc...
Go("field1{TAB}field2{TAB}{DOWN}{TAB}~");

// Close the browser by sending Alt-F4
gShell.SendKeys("%{F4}");

////////////////////////////////////
// Utilities

function Go(keys) {
    gShell.SendKeys(keys);
    Wait();
}

function Wait() {
    isOperationComplete = false;
    var start = new Date();
    while (!isOperationComplete) {
        WScript.Sleep(100);
    }
    var end = new Date();
    isOperationComplete = false;
    return (end-start);
}

////////////////////////////////////
// Internet Explorer Event Handlers

function ie_NavigateComplete2(ie, url) {
    navigateCount++;
}

function ie_DocumentComplete(ie, url) {
    navigateCount--;
    if (navigateCount <= 0) {
        currentUrl = url;
        navigateCount = 0;
        isOperationComplete = true;
    }
}

function ie_OnQuit() {
    WScript.Quit(1);
}

 

 

Cargo-cult programming and Leaky Abstractions

Scott Hanselman recently wrote about cargo-cult programming which reminded me of Joel Spolsky's piece on Leaky Abstractions (which I think about often when working with ASP.NET).

“...tools which pretend to abstract out something, like all abstractions, leak, and the only way to deal with the leaks competently is to learn about how the abstractions work and what they are abstracting. So the abstractions save us time working, but they don't save us time learning.“

Just “getting by” without knowing what's going on under the covers is especially dangerous with new abstractions (which we are always dealing with in technology). After a while things do seem to settle in so that you can begin to forget about the underlying technology. I think this isn't so much because the law of leaky abstractions doesn't apply anymore, but rather because things seem to get more stable over time, and just break down less often. Today we can drive a car while being ignorant of how a car engine works because they rarely break down, but this was not the case in the very early days of automobiles where you had to be able to fix them on the road with spare parts you always carried with you.

But when something goes wrong and you are responsible for fixing it, accept this fact...at some point you will need to learn what's going on under the abstraction, unless you can pay for a mechanic who does. Like the soldier probing for mines in Scott's post, the approach of just sprinkling a little code here and there and praying that it fixes it will eventually blow up, if not this time, then next time.

More Posts