Nelz's Blog

27 October 2009

Motorcycle Diary

Filed under: General — nelz9999 @ 20:13

Scenic bike picture.As I mentioned in a previous post, I recently took a “where the wind blows me” vacation in France, and I’m gonna tell you about that wind.

I started out my trip in Bordeaux, where I found a pretty nice hotel to be my ‘base of operations’ whilst I tried to work out my motorcycle rental. I managed to find the website and then the physical location of Bordeaux Scooters, and this is where I rented the motorcycle for one whole week.

For the first day, I just rode around the city of Bordeaux a very little bit, trying to accustom myself to the Yamaha Fazer 650 (since I normally ride a Kawasaki Ninja 500).

On my first full day on the bike, I got out of Bordeaux and hit a bunch of secondary (C and D) roads. I hit places like Biscarosse(-en-Plage), Mimizan, and Léon, before I stopped for the night in Hasparren where I stayed at a cute Hôtes de Chambre (Bed & Breakfast). I was feeling pretty good and confident, both in my motorcycling ability and my language ability to operate in the hinterlands of France.

For my second day of riding, I figured I’d take some more scenic roads, and even cross over the Spanish border for a bit. I made it through the border just fine, and was cheerfully enjoying the nice big sweeping roads on the way to Elizondo, and then turned on the road towards Erratzu to make my way back into France near Saint-Etienne-de-Baïgorry.

It was just after a hairpin turn, not more than 1km from the French border and the summit of the hill. I noticed the old stone barn on the left side of the road, then I looked uphill and contemplated that I should be careful because of all the mountain mist that was probably making the road slippery. I brought my attention back to the road, and was alarmed to find that I had drifted close to the side of the road. I started to panic. I was so worried about the side of the road that I couldn’t look away, and motorcyclists know that’s exactly where I ended up.

Now that I was on the edge of the road, I made a snap decision to bite the bullet and take the bike off the road and try to stop before anything untoward happened. Something untoward happened. The mist I had been worrying about mere milliseconds before was coating the grass I was on and the front tire slipped sideways, dumping me and the bike onto our left sides.

I am lucky because I had just recently come out of a tight turn and I wasn’t going all that fast. I landed face down with my torso on the pavement, and did only about 1 1/2 horizontal pirouettes before I came to a rest. While the helmet I was wearing was scraping across the pavement, I remember thinking “Boy, a helmet is a really good idea!”

I was up in an instant, just in time to see that the hard case (holding most of my possessions) rolling down the hill. In my adrenaline-addled mind, I decided that I really needed to get my stuff back. So, I went careening down the side of the mountain in my full gear. I found the case 1 1/2 switchbacks down. I brought it up to the road (1 full switchback below the motorcycle) and only then did I decide to take off some of my gear and inspect for damage. Other than a little bit of scuffed up skin, I was actually fine.

As I was walking back up to inspect the bike, a younger French guy in a car stopped to give me a hand. He helped me turn the bike over, and point it away from downhill. He told me he expected insurance (assurance in French) could be found in any town, and that they’d have me set back up in no time. I thanked him for his help and advice, and sent him on his way, while I figured out what I needed to do.

After I got all my stuff assembled, and took a couple of pictures, I sat down and tried to call the rental shop. I ended up calling Ryan (in the U.K) for some research help because I didn’t know what the country-code is for France. After we got that figured out, I realized the rental shop was on their stated lunch break until 2PM. (It had just turned about 12:30PM.) I sat there for a bit trying to keep myself calm and counting my lucky stars. After I changed into some less-sweaty and warmer clothes, I decided that I should try to get to ‘civilization’, preferably on the French side of the border since the motorcycle was rented from France.

Eventually a nice (German?) couple on motorcycles stopped to give me a hand. We were formulating an elaborate me-plus-my-stuff-on-their-bikes plan, when I realized it was a bit soon for me to be riding on a motorcycle again. I got them to help me flag down a passing carpenter, who agreed to take me and my stuff in his truck to the mechanic’s in Saint-Etienne-de-Baïgorry. The local mechanic was of no help, other than trying to help me call the rental shop again, which I knew was still closed. After he basically told me to go away because he didn’t deal with motorcycles and he was on his lunch break, I walked towards town center and sat on the steps of a hotel/brasserie that was also closed for lunch. I decided to wait out the remaining hour or so until the rental shop opened up by chilling out and reading my Kindle on those steps.

Once I did get the rental shop on the phone, they told me that I needed to get the bike transported back to Bordeaux (250km) by whatever means necessary. The shop owner offered to see if he could find someone to do it, and I said I’d look around at my end. After our conversation, I had no idea if I would be stuck in the town of Saint-Etienne-de-Baïgorry overnight, but I figured I’d check into the hotel until things settled, and if I had to leave early, I could just lump one night’s charge.

As I was checking into Full-screenHotel Juantorena, I mentioned (or whined) to Mélanie (who I later found out was one of the owners) that I had just been in a motorcycle accident and needed to find a truck to bring the broken motorcycle back to Bordeaux. She said that her husband might be able to help me out. Bixente came out from the kitchen, and called around to some truck services in Biarritz, and found me a quote of €1,200. I thanked him and said I would call back to Bordeaux to see if the rental place had found me a better quote. The rental place said to call back in a couple of hours because the friend they were going to ask was out at the moment and it would be a while before they got an answer.

It turns out that Bixente is also a motorcyclist, and offered to take me (after he finished setting up his kitchen for the evening) to pick up the motorcycle on his motorcycle trailer to bring it down (the 10 km) to his hotel parking lot. I was kind of amazed at this, but just went with it after the day I was having. About a 1/2 hour later, after I had washed off some of my road rash, he called me down to the front of the hotel where he, his truck, and his motorcycle trailer were waiting for me. He drove me up to the crash spot where we loaded up the wreck, and brought it back to the hotel.

The ride up and back could have been horrible. But after figuring out my French skills needed just a bit of annunciation and a slower pace, Bixente actually took the time to get to know me. We had a really nice conversation, and I’ve come to look back upon that conversation as one of the nicest moments during my time in France.

After getting back to the hotel, I called the rental shop to tell them that the bike was now in the parking lot. In addition to the location of the bike, we had some (mis-)communication where I thought they said to wait several more hours to verify that the truck from Bordeaux would be interested in the job. So, I took a little nap, then read some more whilst having a beer in the bar. I was really surprised when Bixente told me the truck driver was at the other end of town and would be arriving soon. (Evidently, when I thought the rental shop was telling me that I was waiting for confirmation, they were actually telling me that I was waiting for the arrival of the truck.)

The truck driver, myself, and Bixente loaded up the bike into the truck. It was now about 8 or 9PM, and the driver hadn’t eaten, and neither had I, so we had dinner at the restaurant. The driver was kind of gruff, and not all that friendly, but I managed to get some small-talk in. After dinner, using Bixente as a patient go-between, we established that it was best if I went with the truck driver back to Bordeaux with the bike. (I didn’t realize there was more for me to do there.) So, I checked out of the hotel. I tried to convince Mélanie to keep my room charge, but she wouldn’t hear of it. She insisted that if I weren’t staying overnight they wouldn’t even think about keeping my money.

The driver brought be back to Bordeaux, and dropped me off at midnight at a hotel right near the rental shop. The next day, I went to the rental shop to find out that we were waiting for a verdict from the motorcycle repair shop. When I remembered that I hadn’t yet paid the driver from the evening before, the rental shop owner called him for the price. Since I was paying in cash for the truck ride, it only came out to €500, which is a great deal compared to the other quotes I had received.

Later that afternoon, the verdict came down that the bike’s frame was bent and therefore “totaled”. I went back over to the rental shop to sign the credit card slip for the €1800 security deposit that I had now forfeited. And thus ends my motorcycle adventure in France.

Looking Back

Now, people say all sorts of horrible things about the French. In general, I can tell you that much of this is wrong. In specific, I can tell you that Mélanie and Bixente are some of the warmest and most caring people I’ve ever run into in my travels. They took the time to patch up and help this stupid American with bad French and even worse motorcycle skills, and not ask for anything in exchange, other than an email greeting at some time in the future. I hugged Mélanie and Bixente fiercely, and I left their hotel with tears in my eyes because I felt really fortunate to have met these beautiful people.

I realize that I directly benefited from what I refer to as the Motorcyclist (a.k.a. Motard) Fraternity. Without knowing me, but because I spend time on two wheels like they spend time on two wheels, both the German couple and Bixente went way out of their ways to make sure I was taken care of. I guess it’s a similar thread amongst motorcyclists to help out your fellow motorcyclists.

Doing Them A Solid

In addition to adding Mélanie and Bixente to my Xmas card list, I have decided to send as many people as I can to them. So, if any of you readers are ever interested in a quaint village in the beautiful Basque region of France, might I suggest Hotel Juantorena? Also, spreading this info to motorcyclists far & wide would be much appreciated.

(I will try to scan in their pamphlet, but in the mean time, here’s their contact info:) t

Hotel Restaurant Juantorena

64430, Baigorry

Pyrénées-Atlantiques, Aquitaine, France

Lat/Long: 43.17405, -1.34875

Phone: 05 59 37 40 78

Email: hotel.juantorena@orange.fr

Their pamphlet shows that they have a website (http://www.hotelrestaurantjuantorena.fr) but it doesn’t seem to be working?

Widgetbox Rocks!

Filed under: General — nelz9999 @ 19:47

On a lark, I recently submitted a request to the Widgetbox HR person, Brittany, to see if I could get the company to allow me to attend the “Random Hacks of Kindness” event in mid-November. I was considering taking a PTO day, but I’m still at a negative balance after my recent European adventure, and I thought it’d be nice if I could get Widgetbox to support my efforts in what Brady Forest called a ‘Disaster Relief Code Jam’.

I was blown away today when I got an email from Brittany saying that not only will Widgetbox management support me in this endeavor, but they are going to add a 1 day per year allowance to our policies for all the employees to pursue similar efforts. Wow!

This just cements for me that I am totally working with the right set of people in a company that is just the right size for me. I feel appreciated, listened to, and respected, even when I bring forth crazy ideas like sending me off on our investors’ dime to save the world.

Yeah, my life: it doesn’t suck! :-D

20 October 2009

Precompile JSPs for Tomcat 6

Filed under: General — nelz9999 @ 16:34

At the day job, we are working to upgrade our Tomcat from 5.5.X to 6.0.Y. The biggest problem I found when running our app against Tomcat 6 was that a bunch of JSPs used some quote escaping patterns that the later version of the compile considered to be syntax errors.

To get a feel for how many of these problems existed (after I just-in-time fixed the individual JSPs that crossed my path), the boss wanted me to run a precompile against our whole JSP codebase.

I found the instructions on the Tomcat site, which proved to be incomplete and/or incorrect (of course).

Here is what I ended up with:

<project name="Webapp Precompilation" default="all" basedir=".">
   <import file="${tomcat.home}/bin/catalina-tasks.xml"/>
   <target name="jspc">
       <jasper
             validateXml="false"
             uriroot="${webapp.path}"
             webXmlFragment="${webapp.path}/WEB-INF/generated_web.xml"
             outputDir="${webapp.path}/WEB-INF/src"
             compilerTargetVM="1.5"
             compilerSourceVM="1.5"
             failOnError="false" />
  </target>

  <target name="compile">
    <mkdir dir="${webapp.path}/WEB-INF/classes"/>
    <mkdir dir="${webapp.path}/WEB-INF/lib"/>
    <javac destdir="${webapp.path}/WEB-INF/classes"
           optimize="off"
           debug="on" failonerror="false"
           srcdir="${webapp.path}/WEB-INF/src"
           source="1.5"
           target="1.5"
           excludes="**/*.smap">
      <classpath>
        <pathelement location="${webapp.path}/WEB-INF/classes"/>
        <fileset dir="${webapp.path}/WEB-INF/lib">
          <include name="*.jar"/>
        </fileset>
        <pathelement location="${tomcat.home}/lib"/>
        <fileset dir="${tomcat.home}/lib">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="${tomcat.home}/bin">
          <include name="*.jar"/>
        </fileset>
      </classpath>
      <include name="**" />
      <exclude name="tags/**" />
    </javac>
  </target>

  <target name="all" depends="jspc,compile"></target>

  <target name="cleanup">
        <delete>
        <fileset dir="${webapp.path}/WEB-INF/src"/>
        <fileset dir="${webapp.path}/WEB-INF/classes/org/apache/jsp"/>
        </delete>
  </target>
</project>

The real stroke of luck is this piece:

             compilerTargetVM="1.5"
             compilerSourceVM="1.5"

Their document said stuff about adding some parameters (source="1.5" target="1.5") to the “javac” target, but they neglected the “jasper” target. The error messages complained about the above two parameters being set to 1.4, so as an experiment I plugged them into the ANT target with 1.5’s and the compilation ran correctly!

Another word of note, the “showSuccess” directive did not work as their documentation states, but the “failOnError” directive does.

I hope this helps others!

26 September 2009

Facebook Connect: Nonconsensual Privacy Leak

Filed under: General — nelz9999 @ 17:57

The Problem

I do not like Facebook. I do not like it one bit. I want nothing to do with Facebook at all, and I’ve been very adamant about not signing up for an account despite the urging of everyone and their brother.

So, when I recently gained an understanding of how Facebook Connect works, I got a bit upset. Let me show you why with an example.

Let’s say I want to create an account at MapMyRun.com which implements Facebook Connect, I will use my primary email address of “nelz@example.xxx”. After my account gets created MapMyRun then encrypts my email address with a one-way hash, which for the sake of argument looks like “BIGBADHASH”, and sends this hash to Facebook. “So what?” you think. Sure, they can’t figure out anything about me from a single one-way-hash of my email address, right?

Well, then let’s say I register for an account at io9, again with my primary email address “nelz@example.xxx”. Since io9 also implements Facebook Connect, they also hash my email address and send it to Facebook. Guess what? The resulting string, “BIGBADHASH”, is the exact same as what MapMyRun just sent them.

Now, Facebook knows that someone with an email address that hashes to “BIGBADHASH” has an account on both MapMyRun and io9. Again you think “So what?” That one-way-hash protects my identity from being associated with any of these specific behaviors, right? Au contraire, mon frère.

Now one of my well-meaning friends, who doesn’t know how much I loathe Facebook, tells Facebook that they want to connect with someone at the address “nelz@example.com”.

This was the last piece of the puzzle that Facebook needed. Facebook need only apply the one-way-hash to the plaintext email that my friend just provided them with, and they get “BIGBADHASH”. Then, they look up in their database where they’ve seen that hash before, and now they know that a user with an email address of “nelz@example.com” has an account on both MapMyRun and io9.

Now I, who has never ever logged into Facebook, am getting tracked by Facebook whether I like it or not.

External Remediation

Okay. So what can we do about this?

I looked on Facebook.com, and I found a Privacy Policy. But everything on there requires that you have an account on Facebook. I guess I could create an account, then delete it, but I don’t want an account on Facebook! What Facebook really needs is some web form for non-members that says “Forget anything you have, or will, ever collect about email XYZ”. But, that’s not likely to happen.

What about the end-points, the sites that are implementing Facebook Connect? Personally, during their sign-up processes, I’d like to see a check box that says “Don’t sell me out to Facebook.” Again, that’s not likely to happen.

Personal Remediation

Now, don’t get me wrong, I’m not a n00b. I realize there are all sorts of sites tracking my footprints across the digital landscape every day. (Quantcast, DoubleClick, etc…) For most of them, if I were paranoid and technical enough I could purge their cookies or set up a proxy that doesn’t let my browser connect to those URLs.

But this Facebook thing is different, because it’s highly likely that the communication back to Facebook is not coming from my browser, but from the servers of sites like io9 and MapMyRun. And I have no way to stop it.

How about using a different email address for each site. Sure, that could work. If I had my own mail server, I could create “io9@nelzserver.xxx” for io9 and “mapmyrun@nelzserver.xxx” for MapMyRun, but how many people will have access or technical ability for something like that?

Gmail has a feature that could help out here. If I have an email address like “example@gmail.com”, I will still get the mail if it is sent to “example+io9@gmail.com” or “example+mapmyrun@gmail.com”. I found two challenges with this pattern: 1. it can break the “Forgot My Password” functionality if you forget what email you signed up with, and 2. emails with “+” in them don’t always pass the (incorrect) regex’s sites use to validate emails.

Conclusion

As I have said before, I am living life pretty openly on the internet. And like I said above, I know there are countless other companies doing much more specific tracking and profiling of me.

But Facebook’s hegemonic desires to run the internet frustrate me, and I don’t want to be a part of it. And it pisses me off that there’s nothing I can do to extract myself.

Update: Found this interesting blog post – “Dark Stalking on Facebook

21 September 2009

How To Rock In Life

Filed under: General — nelz9999 @ 18:50

Somewhere I found a link to this blog post: “How to Ensure Your Life is a Bull Run“. I found it amusing how they couched the whole conversation in financial market terms, but otherwise I really liked it, mostly just from a bullet-point list perspective.

So, here is the short version:

  1. Have Rocking Goals
  2. Be Ambitious
  3. Invest In Yourself
  4. Healthy Lifestyle
  5. Be Responsible
  6. Patience Is The key
  7. Never Give Up
  8. Learn From Failures
  9. Remain Positive
  10. Celebrate Success

26 August 2009

Leavin’ on a jet plane…

Filed under: General — nelz9999 @ 00:35

I am taking a vacation. w00t!

Normally at this time of year, I would be in full-on packing mode for Burning Man. Alas, my best friend from college decided to get married on the day the Man burns (in the U.K.). Then, to top it all off, my brother decided to get married on the 18th of September in Boston. This left me with little to no obligations from the 7th to the 17th of September, so I decided that I was going to rent a motorcycle and tour around the south of France.

What does a techie do when they plan a trip? They buy tech gadgets of course!

My first purchase was a netbook. I got an Asus EeePC 901 (Linux). I opted for the white model, because there was a $300 (100%) ‘black tax’. I opted to get some scull vinyl stickers ($13) instead. I dumped the default Xandros OS and installed Ubuntu.

My original thought was that I didn’t want to be tempted to work on work or side projects while I was traipsing around Europe, so I got a solid netbook that could provide me with email/Twitter/basic web surfing, but would lend itself to opening up an IDE. After a while, I realized that I should reserve my vacation for things I *want* to do, even if it includes working on a software
project. So, I’ve decided to forget the netbook and take my home laptop, a 15″ MacBook. (If you are reading this and want the netbook I described above, I have one for a decent price if you’d like it.)

The second bit of tech that I purchased was a Kindle (2nd gen, non-DX). I do enjoy ‘personal’ reading, but rarely take the personal time for it (except on vacations) because I’m usually caught up in some technical book. My usage of it has waxed and waned since my purchase, but it definitely addresses my criteria of reducing the amount of ’stuff’ that I am carrying whilst on-motorcycle in France. I do plan to put some entertaining books on my Kindle before I leave. (“Necronomicon” anyone?)

So, I’m down to my Kindle and my MacBook. What about my G1 mobile phone? Well, the surprising thing is that I’ll probably just stick to my current provider (T-Mobile). I was aghast when I heard their prices (something like: $0.99/min of phone usage, $0.35 per sent text message, free received text message, $0.35 ‘connection charge’ [for every time the phone checks for messages?], $15.00 per Megabyte of data), but in my subsequent research that’s about par for the course for prepaid SIM cards. I don’t like it, and I’m dubious that this is as good as it gets, but I don’t have the time or the inclination to fight
it too hard. I just have to accept that my Twitter addiction may cost me some. One of the positives though, is that when I told T-Mobile that I was considering using GSM cards purchased abroad they offered to help me unlock my phone. That should be a boon for me when I decide to replace it in the future and want to sell it.

I’m not planning on taking a camera, other than my G1 and my laptop. I am kind of hoping to take some videos using my MacBook’s built-in camera, but we’ll see if that even happens, because for most of my life I’ve been a forgetful and shitty photodocumentarian, and I don’t see that magically changing for this trip.

During my ‘where the wind blows’ tour of France, I’ll probably use CouchSurfing.org to meet people, or possibly even find shelter if I can plan that far in advance, but I’m purposly keeping my schedule unplanned so I don’t know if I’ll want to subject CouchSurfing hosts to my slapdash planning. The housing may just end up being, in order of preference: couches, hostels, B&B’s, or hotels. Like I said, I going *very* unplanned. I think I should be okay, because the annual French
holiday season is mostly done by the beginning of September. If not, it’ll be an exercise in creativity, right?

I’ve got 3 projects to work on while travelling. Firstly, I have visions of a Simple-Spring-Memcached v2, and I’ve already made a bit of progress starting that. Next, there is my as-yet-unannounced Ruby-on-Rails, Twitter based web service. And thirdly, I’ve decided that I want to do a presentation at Silicon Valley Code Camp in October about Simple-Spring-Memcached, and I can work on that presentation for a bit if I’m bored.

So, that’s my story. If I do get around to photodocumenting (or videodocumenting) any of my trip, I’ll be sure to post a link here.

20 August 2009

Maven Tomcat Plugin

Filed under: Java — nelz9999 @ 10:28

Maven. It is both fantastic, and stress-inducing. And more than just Maven itself, there is a whole community of Maven plugins which are just as frustrating.

Take the Maven Tomcat Plugin for example. It sounds so nice to just type “mvn tomcat:run” in your webapp module, and have it automagically run, dynamically loading any JSP changes. But, if you have a non-trivial webapp, you probably need to send in some system properties.

Let’s pretend that I require the following command-line parameters passed to Tomcat on the command line:

-Dexample.value.1=alpha -Dexample.value.2=beta

How would I send that in to the Tomcat plugin? Well, the documentation says there is a “systemProperties” element where you can sent them in. But what is the format?

Is the format perhaps like the Surefire Plugin?

<systemProperties>
  <property>
    <name>example.value.1</name>
    <value>alpha</value>
  </property>
  <property>
    <name>example.value.2</name>
    <value>beta</value>
  </property>
</systemProperties>

Or perhaps the format is like that of the Jetty Plugin?

<systemProperties>
  <systemProperty>
    <name>example.value.1</name>
    <value>alpha</value>
  </systemProperty>
  <systemProperty>
    <name>example.value.2</name>
    <value>beta</value>
  </systemProperty>
</systemProperties>

Nope. The format is like neither of those. It’s like this:

<systemProperties>
  <example.value.1>alpha</example.value.1>
  <example.value.2>beta</example.value.2>
</systemProperties>

I’ll admit that this format is a bit less verbose. But why, in the name of all that is holy, does it have to have it’s own 1-off syntax?!? And can you find this documented anywhere else? I was sure challenged finding it.

This is the kind of non-documentation and irregularity that gives Maven a bad name and keeps my blood pressure high.

UPDATE (1 Nov 09): As she says in the comments, Kathy actually took the time to submit a ticket to the Maven Tomcat Plugin maintainers, rather than going with my tactic of passively bitching. And today I get notified by herion that the suggestion was taken and there is now public documentation added about these properties.

30 July 2009

Code 2 HTML

Filed under: Links — nelz9999 @ 23:13

For all the code samples that I put into my blog, I’ve been using this handy-dandy online tool to convert from code to HTML:

http://www.palfrader.org/code2html/code2html.html

Maven, TestNG, and SeleniumRC

Filed under: Java — nelz9999 @ 23:01

Today, I set up a Maven module to run SeleniumRC (Java) tests via TestNG. It wasn’t a straightforward or easy task, so I thought I’d share some of what I found with you.

We opt to have all of our modules stay in lock-step version-wise, so we keep a pretty large structure in our SVN trunk. We include/exclude modules for compilation by using Maven profiles, so we don’t have to build the whole structure if we are only changing one small component. Our top-level pom.xml file looks similar to this:

<project>
  <groupId>...
  <artifactId>...
  <version>...
  <packaging>pom</packaging>
  <modules>
    <module>baseModule</module>
  </modules>
  <profiles>
    <profile>
      <id>all</id>
      <modules>
        <module>otherModule</module>
        ...
        <module>web-test</module>
      </modules>
    </profile>
    <profile>
      <id>web-test</id>
      <modules>
        <module>web-test</module>
      </modules>
    </profile>
  </profiles>
</project>

As you can see, running “mvn clean install” at this top level would only end up building the baseModule. To get all the modules, we run “mvn clean install -Pall” which builds baseModule along with otherModule and web-test and anything else as represented by the ellipse. The web-test module is the one we will be interested in.

For our heavy-weight tests (non-unit tests, like functional or web testing), we like to have the module compile, but not run unless we specifically trigger the tests. To achieve this, we create a pom.xml (for the web-test module) that looks something like this:

<project>
  <parent>...
  <artifactId>web-test</artifactId>
  <packaging>pom</packaging>
  <build>
    <testSourceDirectory>src/it/java</testSourceDirectory>
    <testResources>
      <testResource>
        <directory>src/it/resources</directory>
      </testResource>
    </testResources>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>testCompile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.4.2</version>
        <configuration>
          <testSourceDirectory>src/it/java</testSourceDirectory>
          <excludedGroups>web-test</excludedGroups>
        </configuration>
        <executions>
          <execution>
            <phase>integration-test</phase>
            <goals>
              <goal>test</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

This pom has several features:

  • It sets up src/it/java as the location holding the source code for the tests
  • It sets the surefire plugin (which runs your tests) to only run at the integration-test part of the Maven lifecycle
  • It says to ignore any tests in the TestNG “web-test” group
  • Note the packaging says this module is of the type “pom”. I found that if this is set to “jar”, the tests run twice for some unknown reason

Now, if you had tests in src/it/java (that were all annotated as “web-test”) and you ran “mvn clean install”, you’d see that zero tests ran. This is what we want! Now, we have to get the tests running if we pass a specific profile in. To achieve this, I added the following profile definition to the web-test pom.xml.

<profiles>
    <profile>
      <id>run-web-test</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.4.2</version>
            <configuration>
              <suiteXmlFiles>
                <suiteXmlFile>src/it/resources/testng.xml</suiteXmlFile>
              </suiteXmlFiles>
              <!--<groups>web-test</groups>-->
              <!--<forkMode>always</forkMode>-->
            </configuration>
            <executions>
              <execution>
                <phase>integration-test</phase>
                <goals>
                  <goal>test</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

This profile is invoked when you run “mvn clean install -Prun-web-test”. There are several things I’d like to point out here:

  • At runtime, this overrides the previously-declared surefire plugin configuration, but only when invoking the profile.
  • Originally, I was mostly getting stuff to work without the <suiteXmlFiles /> section, but with the <groups /> and <forkMode /> sections… But it was running every single test class as it’s own TestSuite.
  • To fix the multiple TestSuite (and @Before*, @After* problems that I’ll discuss later), I ended creating my own testng.xml file. Having this file and using the <suiteXmlFiles /> element made things a whole lot easier for configuring my TestNG executions than trying to configure the tests through the clumsy interference of the surefire plugin.
  • As much as I like Maven, I have to say that the lack of documentation and general obfuscation that happens when using their plugins can really drive a person BATTY!

Now, I need to start integrating the stuff I need for using SeleniumRC. I found some decent help on how to start up and shut down the selenium-server, however I disagree with using a post-integration-test phase to shut down the server, because if the tests fail in the integration-test, Maven won’t progress to the next phase and you’ll be left with a spuriously running selenium-server. The client API’s do have access to the command that the was being run to shut the server down, so it is just a matter of having some TestNG @AfterSuite or @AfterGroup method issue the Selenium.shutDownSeleniumServer() command.

This brings me to some of the TestNG wonkiness I saw. I decided to use a Singleton Data Provider (named  SeleniumFactory) to deliver the Selenium objects to the individual tests. (Selenium objects are time-expensive to create, so I wanted to only create 1 for the duration of the entire test suite.) I wanted to initialize the SeleniumFactory object in a @BeforeGroup method, deliver the Selenium object as a Data Provider, and then tear the SeleniumFactory down in a @AfterGroup method. (At first, I was fighting Maven’s handling of each test as its own test suite which was giving me sequence issues, which is why I ended up defining my own testng.xml file, as I stated above.) Let me start with some code to show you what I mean:

public class SequenceEndsTest {
    @BeforeGroups(groups = {"web-test"})
    public void startupSelenium() {
        System.out.println("-- > Called startup.");
    }
    @AfterGroups(groups = {"web-test"}, alwaysRun = true)
    public void cleanupSelenium() {
        System.out.println("-- > Called cleanup.");
    }
}
public class SeleniumFactory {
    @DataProvider(name = "selenium")
    public static Object[][] getSelenium() {
        System.out.println("-- > Called data provider.");
        return new Object[][] { new Object[] {null}};
    }
}
public class SequenceTest {
    @Test(groups={"web-test"},
            dataProvider = "selenium", dataProviderClass = SeleniumFactory.class)
    public void testSomething(final Selenium selenium) {
        System.out.println("-- > Called test.");
    }
}

This is what I expected to see after running this code:

-- > Called startup.
-- > Called data provider.
-- > Called test.
-- > Called cleanup.

But this is what I *actually* saw:

-- > Called data provider.
-- > Called startup.
-- > Called test.
-- > Called cleanup.

I would have assumed that an @BeforeGroup method got called before a data provider method, but I guess my assumption is wrong, eh? After I figured out this order-of-method-calls business, I was able to adapt my SeleniumFactory accordingly.

… And that is my story. To summarize: each of these tools could be better documented, but at the end of the day I was able to get a Maven module up and running SeleniumRC tests via TestNG. Now, on to the test-writing!

14 July 2009

Working With Amazon SimpleDB

Filed under: General — nelz9999 @ 22:56

At Widgetbox I’ve been playing with Amazon SimpleDB to implement some features that we’ll be releasing soon. I wanted to share some of my impressions with you, but another blogger has already posted a great writeup at http://www.royans.net/arch/2009/02/28/experimenting-with-simpledb-flagthiscom/. However, I’ll add my $.02 contribution to what he posted.

#1 (“Its not a relational database.”) is very, very important. You’ve really got to stretch your brain a bit to get out of the RDBMS headspace to see how it can be beneficial. Everything is stored as a string, so if you want to any kind of sorting with regards to numbers or dates, you have to format the values to be sorted lexicographically. (This reminds me of when I was working with Lucene.)

In addition to not having any kind of auto-increment (as mentioned in that blogs #5 point), there is no concept of an “increment” operation on a field. At first I was tempted to try for a Read-Increment-Update pattern, but if you think of how that would interact with Amazon’s concept of Eventual Consistency (which, for some inexplicable reason, I find absolutely hilarious), you will realize this is a sub-optimal pattern for data integrity. (The pattern I ended up using lends itself only to the specific interaction patterns I am designing for, so I won’t bore you with the details.)

Though there is no auto-increment, many blog posts have been published recommending UUID’s, which seems to be working for me as well.

As for that blogs #8 point, there is now a offered called Javascript Scratchpad for Amazon SimpleDB, which is just a small set of HTML/JS pages that you save locally and run in a browser. I think it’s actually a pretty cool lightweight and simple GUI tool to offer.

Looking at the price list, you might think that SimpleDB could get expensive fast. But, if you read carefully you’ll see the following: “Data transferred between Amazon SimpleDB and other Amazon Web Services within the same region is free of charge (i.e., $0.00 per GB).” That’s pretty cool. As long as whatever is hitting your SimpleDB instance resides on the Amazon cloud (in the same region), you don’t pay for data transfer.

I also gotta comment on the Java client provided by Amazon. Yeah, it works, but working with it is fairly “meh”. You get the source an everything for it, but it’s not Open Source and they definitely don’t give the impression that they’re looking for any contributions. I would’ve submitted a couple of lines of documentation for some of the methods at the very least.

I’ve heard some good things about the typica library, specifically that the interaction patterns with the library are nicer than the Amazon-provided library. There only seems to be one (maybe two?) developer working on it, but at least it’s hosted on Google Code so, unlike Amazon, maybe the developer would welcome contributions.

I haven’t used typica myself yet, but since I’m not too far down the other path, maybe I’ll check it out.

Older Posts »

Blog at WordPress.com.