Nelz's Blog

28 October 2010

Project Begets Love for AppEngine and Python at Java’s Expense

Filed under: General, Java — nelz9999 @ 00:33

The Project

For the past year or two I’ve had an ongoing side project where I post to the Twitter account @bman_countdown. It started out as just a simple countdown, but I realized I could use it as an opportunity to provide more information about the event, so I started to tack on links to relevant content on the BurningMan.com website.

Over time I’ve increased the functionality from being a static set of links, to mixing in the most recent blog post from the Burning Blog. (Actually, this functionality just went live today.)

This has been a great ‘toy’ project that I use to experiment with different technologies.

The Environment

For the first couple of iterations it was a Ruby script that I ran off of my ‘media server’ (a Mac Mini which I had set up as recommended by MacMiniColo). To emulate cron functionality, I used launchd to run the script once a day.

Predictably, this setup caused some hiccups in the continuity of the service: when my ISP service went out; when my router borked; when the hard drive failed; when I moved; etc. (Yay for providing non-mission-critical projects!)

Around the time of the 2010 Burning Man event, Twitter removed the ability to use Basic Auth, which is what the library I used relied upon. I decided the service could take a break right after the event while I figured out what I was going to do with it.

I had done some minor playing with Google AppEngine in Java, so I was familiar with the basic services GAE provides. (I love AppEngine’s first-class cron support. And the TaskQueue concept ecourages truly asynchronous and scalable design.) But, since this project is what I use to experiment with stuff, I figured I’d try out Python.

Meeting Python

First, I had to get up to speed on Python itself. So, I got the book Programming in Python 3. I studied several chapters of this book and did a couple of the ‘programming assignments’ (which I thought was a great idea), until I felt I was familiar enough with the language to take a poke at upgrading the countdown.

I came to realize that the process of developing in Python is so easy! (Even more so in GAE, as the development server environment that you get is great, and shit just works: just save the changes to the file and you can hit the page, and you get instant feedback.)

I know I’m a latecomer and I am treading dangerously close to Programming Language War territory here, but I have to say that I am entirely fed up with the edit/build/deploy cycle that leaks time and energy in Java projects. Do you realize that in big Java shops, there are engineers whose entire function is to iterate on the build process? Remember that whole “Google App Engine in Maven + IntelliJ” blog post that I made? In Python, the build-cycle-via-build-tool process doesn’t exist. Imagine a future where you don’t need to wrestle through Maven’s bullshit to get stuff done. I can see this future in Python, and it gives me tingles in my naughty bits!

Sure, I’ve got rose-colored glasses on here. I am a native speaker of high-protocol Java (my kingdom for a native “?” operator!), who is currently a tourist in a strange land speaking a stilted pidgin version of Python. Admittedly, I have an incomplete grasp on what the costs and benefits are when moving from a compiled language to an interpreted one. But it sure seems easier so far.

Future of Java

I was originally pulling for the Java ecosystem, whether that comes from a selfish (it’s where my bread gets buttered) or a philanthropic (because I’ve seen so much good Open Source stuff come out of it) point of view, I’m not sure. I was happy when some very smart people talked about ways that at least the JVM could stay relevant by embracing more dynamic languages built on top of it.

But then there was last weeks announcement that Mac OS X would deprecate support for Java. This generated a lot of excellent discussion. My favorite post both described why this is a death knell for Java, while also outlining a strategy for ensuring Java could continue to function (by breaking up it’s fairly monolithic API into discrete modules).

Alas, because of a very specific interaction I had, I fear Chris Adamson’s cogent post will probably be ignored by Oracle. Back when the news came out that Oracle was buying Sun and therefore Java and MySQL, I spoke to a friend of mine who worked for Oracle. I told him I didn’t care if Oracle owned Java and MySQL as long as they didn’t fuck it up. His response: “Don’t worry. We’ll fuck it up.”

The mere fact that I heard this kind of pessimism coming from an employee within Oracle makes me think Java will be viewed more and more as a legacy system in the months and years to come.

6 October 2010

TestNG vs JUnit4

Filed under: Java — nelz9999 @ 14:06

JUnit has done huge things for the programming community. It really helped to usher “The Age of Testing” into being. I will always say that. However, I have to say that when starting a new Java project, using TestNG is the right choice.

Here is how I see things happening:

  1. Project starts. Choose the ‘industry standard’ JUnit. Heck, let’s even go with JUnit 4 because it supports Java 5 Annotations.
  2. JUnit works great for unit tests.
  3. Hey, we want to write an integration test (talking to a db? setting up a Spring ApplicationContext?) as well. We’re already using JUnit, so let’s keep using it for the new integration tests too.
  4. Let’s write a second (and third; and more) integration test within JUnit just like that first one we wrote.
  5. Hey, why is the build taking so long? Oh, hey, JUnit is causing us to do some heavyweight operations for each individual tests. Is there some way to only do the heavy operations once per a suite of tests?
  6. Blogosphere says: “JUnit is a unit testing framework, it’s not meant for integration testing”; “You are doing it wrong”; “Sure you can do that, here’s the horrible atrocity of code that you need to implement to make it possible”.
  7. Find that TestNG has a richer lifecycle and can help with this integration test scenario, while still being easy to use for unit tests. Shake your fist at the air in impotent rage that you didn’t just start with TestNG.

I’ve personally seen this happen in at least 2 large projects.

I am currently in the “impotent rage” phase of the cycle. My original impetus to write this blog post was to say that someone(*) should write the class that combines the org.junit.runners.Suite functionality and Spring’s AbstractTransactionalJUnit4SpringContextTests.

Here’s the straight scoop: You are probably going to want to do some integration testing in addition to unit testing. TestNG may only be a bit different from JUnit, but it is just enough different in all the right ways to make it the tool you want to use.

(*) I know I should consider doing it. I will add it directly to the top of my “Things That Should Get Done But Won’t Ever See the Light of Day” list.

19 January 2010

More Maven Angst

Filed under: Java — nelz9999 @ 15:20

I don’t want to just jump on Maven-bashing bandwagon here, but a casual perusal of my previous posts will show that I talk about Maven a lot. This is going to be another one of those posts.

I’ve been starting to play with Google App Engine, both for personal projects and at work. Since most of my environments are Maven-based, I thought I’d go out and find a Maven Archetype or some kind of a POM file to bring these projects into my environment. I did find several blog posts trying to help: here, here, etc… The annoying thing you’ll notice on those blog posts is that Brian Fox ((formerly?) of Sonatype) posts a comment pointing towards Jason van Zyl’s post describing his efforts to Maven-ize the GAE SDK.

That would be all well and good if things had actually progressed. If you look at JvZ’s post, you’ll see he ends with “hopefully I’ll be able to get this out for Maven users by the end of the week!” What happens after that? Bupkis, nil, nothing, NADA!

There’s comments as late as Dec ’09 expressing interest to use and/or help with the effort. But, there is NO RESPONSE from anyone at Sonatype.

I just find it galling that Sonatype would go on an all-out publicity spree talking people out of working on their own because JvZ himself was going to bring his skills to bear on the problem, only to completely fizzle out. I suspect the community at large would have been better off if those 4 or 5 early Maven + GAE adopters had continued on their own path, even if JvZ had succeeded.

Again: my patience with Maven/JvZ is waning. I’m eager to see what comes along next to take its place.

20 October 2009

Precompile JSPs for Tomcat 6

Filed under: Java — 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!

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

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!

28 May 2009

The Life of a boolean

Filed under: Java — nelz9999 @ 23:59

Java booleans came up in conversation today, and I wanted to point out a couple of things that I’ve noticed.

Firstly, when talking about (capital ‘B’) Booleans, it is possible to achieve a trinary state object: TRUE/FALSE/null. However, it is not recommended. In fact, I’d go so far as to recommend breaking the fingers of anyone who tried to perpetrate this horrible pattern in your code.

Secondly, I’d like to discuss booleans in your model objects. I agree that it frequently seems like a good idea to include one in your model object. However, I have seen so many occurrences where, over time, it becomes necessary to add a third (or fourth, or fifth) state. Even the RDBMSes are hedging their bets by storing boolean flags as TINYINTs. I would suggest that you seriously consider using an Enum to represent your two states as they exist at the beginning of their lifecycle… This way you won’t get stuck with a bunch of isXXX() accessors that all have to be refactored as soon as you add a third state.

13 May 2009

JDK 1.6 on OS X

Filed under: Java — nelz9999 @ 15:32

For Widgetbox I was recently tasked with investigating a new Java memcached client called xmemcached.

Things were going smoothly (except that the xmemcached documentation is written mostly in Chinese)… But then I hit a bump in the road: the xmemcached JAR file was compiled for JDK 1.6.

Up until this point, all our code was using JDK 1.5, and we had only vague plans to eventually upgrade to JDK 1.6. Upon discussion, I’m just gonna work on the 1.6 stuff in a branch until we get the rest of the development team and operating environments up to a JDK 1.6 standard.

So, I went about upping my chosen JDK via the "Java Preferences" dialog.

Now, I saw something like this:

$ java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06-153)
Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_07-b06-57, mixed mode)

Awesome. That’s exactly what I wanted!

But hold the phone, I was also getting this:

$ mvn -v
Maven version: 2.0.9
Java version: 1.5.0_16
OS name: "mac os x" version: "10.5.6" arch: "i386" Family: "unix"

So, I did some digging. With some hints, I found that the executable /usr/bin/mvn uses the symlink "CurrentJDK" to figure out which JDK to run, and the "Java Preferences" panel doesn’t update that when you change JDKs. (Dumb!)

So, here’s how I fixed it:

$ cd /System/Library/Frameworks/JavaVM.framework/Versions/
$ ls -la
...
lrwxr-xr-x   1 root  wheel    5 Sep 29  2008 1.5 -> 1.5.0
drwxr-xr-x   8 root  wheel  272 Feb 21  2008 1.5.0
lrwxr-xr-x   1 root  wheel    5 Sep 29  2008 1.6 -> 1.6.0
drwxr-xr-x   8 root  wheel  272 May  6  2008 1.6.0
lrwxr-xr-x   1 root  wheel    3 May 12 18:18 CurrentJDK -> 1.5
...
$ sudo rm CurrentJDK
$ sudo ln -s 1.6 CurrentJDK

Now, I am seeing the environment I want:

$ ls -la
...
lrwxr-xr-x   1 root  wheel    5 Sep 29  2008 1.5 -> 1.5.0
drwxr-xr-x   8 root  wheel  272 Feb 21  2008 1.5.0
lrwxr-xr-x   1 root  wheel    5 Sep 29  2008 1.6 -> 1.6.0
drwxr-xr-x   8 root  wheel  272 May  6  2008 1.6.0
lrwxr-xr-x   1 root  wheel    3 May 12 18:18 CurrentJDK -> 1.6
...
$ mvn -v
Maven version: 2.0.9
Java version: 1.6.0_07
OS name: "mac os x" version: "10.5.6" arch: "x86_64" Family: "mac"

25 March 2009

Java 5 Auto-Unbox Is Not NULL Safe

Filed under: Java — nelz9999 @ 16:03

Yuck!

I am kinda getting fed up with the way the language implementers of Java continually add all these conveniences, but leave them 1/2 baked.

Example:

01public class UnboxTest {
02    @Test
03    public void testUnbox() {
04        final Integer a = Integer.valueOf(10);
05        final Integer b = null;
06        unboxIt(a);
07        unboxIt(b);
08    }
09    void unboxIt(final int value) {
10        System.out.println("Value: " + value);
11    }
12}

Guess what happens when you run this code?

A big, fat NullPointerException on line 7.

Oh yeah… Autoboxing is supposed to be soo helpful, but they can’t default a frigging null to the default value of an int. (I.e. 0)

See my previous post for similar problems in the Java 5 foreach syntax.

9 January 2009

SeleniumRC and FireFox3

Filed under: Java — nelz9999 @ 14:21

We have started playing with Selenium for some automated testing at my day job. (I’ve been a proponent of Selenium, but I haven’t played with it directly for a bit.)

I ran into a problem, as described by the Space Vatican. Luckily, he also had the solution to the problem.

I took his command-line instructions and created two scripts to run those command on a given file (‘cuz my file was named differently than the one in his script). Here are the contents of the script:

jar xf $1 customProfileDirCUSTFFCHROME/extensions/readystate@openqa.org/install.rdf
jar xf $1 customProfileDirCUSTFFCHROME/extensions/{538F0036-F358-4f84-A764-89FB437166B4}/install.rdf
jar xf $1 customProfileDirCUSTFFCHROME/extensions/\{503A0CD4-EDC8-489b-853B-19E0BAA8F0A4\}/install.rdf
jar xf $1 customProfileDirCUSTFF/extensions/readystate\@openqa.org/install.rdf
jar xf $1 customProfileDirCUSTFF/extensions/\{538F0036-F358-4f84-A764-89FB437166B4\}/install.rdf
jar uf $1 customProfileDirCUSTFFCHROME/extensions/readystate@openqa.org/install.rdf
jar uf $1 customProfileDirCUSTFFCHROME/extensions/{538F0036-F358-4f84-A764-89FB437166B4}/install.rdf
jar uf $1 customProfileDirCUSTFFCHROME/extensions/\{503A0CD4-EDC8-489b-853B-19E0BAA8F0A4\}/install.rdf
jar uf $1 customProfileDirCUSTFF/extensions/readystate\@openqa.org/install.rdf
jar uf $1 customProfileDirCUSTFF/extensions/\{538F0036-F358-4f84-A764-89FB437166B4\}/install.rdf

And if you’d like, and feel like trusting me, here is the resultant, FF3-friendly, jar file : selenium-server-1.0-beta-1.jar

Older Posts »

Theme: Silver is the New Black. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.