How to dynamically find and assign free ports within maven build. Running local clients and servers in parallel. With selenium example

By neokrates, written on May 28, 2010

howto

  • Join date: 11-30-99
  • Posts: 224
View Counter:
  • 974 views
Rate it
Ad
Poll
  • What build management tool does your project or firm use?

    View Results

    Loading ... Loading ...
Feeds:
  • bodytext bodytext bodytext

We have Hudson. It has some slaves per server. And we have selenium grid, which in our case has hard-coded ports for hub and for agents. There is a simple way to assign free ports and avoid conflict. Selenium is just an example, ports could be made available for any client – server running under maven.

Software:

✔ Selenium grid

✔ Maven

✔ Ant

✔ Linux

Should also work for:

✔ Any other OS which supports those tools

Preconditions:

In this example selenium grid is used. To run it system must be configured first. Like being able to run browser from command line.
If you want to setup jetty, db etc… something lightweight, then they will likely have no special environment needs.

Here, no complete solution and example to run selenium under maven and ant is given. You can find it elsewhere. The only point is to show how the free ports can be picked and propagated to the server instance, ensuring there will be no port conflict ever.

1

Find free ports, make them available

build-helper-maven-plugin:reserve-network-port (http://mojo.codehaus.org/build-helper-maven-plugin/) does two things:

⭐ find the free port;

⭐ make it available for the maven.

Here, we get 3 free ports seleniumHubPort, seleniumAgentPort1, seleniumAgentPort2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
     <plugin>
               <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId> 
        <executions>
 
          <execution>
            <id>reserve-ports</id>
            <phase>initialize</phase>
            <goals>
              <goal>reserve-network-port</goal>
            </goals>
            <configuration>
              <portNames>
                <portName>seleniumHubPort</portName>
                <portName>seleniumAgentPort1</portName>
                <portName>seleniumAgentPort2</portName>
              </portNames> 
            </configuration>
          </execution>
        </executions>
      </plugin>

2

Use generated ports to start the (selenium) server

Selenium may be started from ant script, ant will run inside maven.

We bind the call to start selenium hub and remote controls to the test maven lifecycle phase.

In your pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  <plugins>
....
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.3</version>
        <executions>
          <execution>
            <id>start-selenium</id>
            <phase>test</phase>
            <configuration>
              <tasks>
                <ant antfile="build.xml">
                  <property name="seleniumHubPort" value="${seleniumHubPort}" />
 
                  <target name="start-hub" />
                </ant>
                <ant antfile="build.xml">
                  <property name="seleniumHubPort" value="${seleniumHubPort}" />
                  <property name="seleniumAgentPorts" value="${seleniumAgentPort1},${seleniumAgentPort2}" />
 
                  <target name="launch-selenium-agents" />
                </ant>
              </tasks>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
....
</plugins>

 
build.xml in the same directory (showing only the code part which illustrates port propagation):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0"?>
<project name="Run Selenium instances" basedir=".">
 
<!-- ... -->
 
  <taskdef resource="net/sf/antcontrib/antcontrib.properties" 
           classpath="${basedir}/lib/ant-contrib-1.0b3.jar" />
 
<!-- ... -->
  <target name="start-hub" description="Start the Hub">
    <echo>Selenium hub will listen on port ${hubPort}</echo>
    <java taskname="launch-hub" 
          classname="com.thoughtworks.selenium.grid.hub.HubServer" 
          classpathref="hub.classpath" 
          fork="true" 
          spawn="true">
 
    </java>
 
  </target>
<!-- ... -->
<target name="launch-remote-control" description="Launch A Remote Control">
          <java taskname="launch-remote-control" 
          classpathref="remote-control.classpath" 
          classname="com.thoughtworks.selenium.grid.remotecontrol.SelfRegisteringRemoteControlLauncher" 
          fork="true" 
          spawn="true">
      <!-- ... -->
      <arg value="-port" />
      <arg value="${port}" />
      <!-- ... -->
    </java>
 
</target>
<!-- ... -->
<property name="ports" value="${seleniumAgentPorts}" />
<target name="launch-selenium-agents" description="Launch Remote Controls">
    <echo>Celenium agents will take ports: ${ports}</echo>
    <foreach list="${ports}" delimiter="," param="port" target="launch-remote-control" inheritall="true" parallel="true" />
</target>
 
<!-- ... -->
</project>

3

Selenium hub will also use grid_configuration.yml

Selenium needs grid_configuration.yml. It should be located in the directory where selenium is being started (selenium home dir).

In our case it must also always have the correct port, put there dynamically.

We will use the maven filtering to write the port into .yml file.

Put the .yml file into maven resources src/main/resources/grid_configuration.yml:

1
2
3
4
5
6
7
hub:
   port: ${seleniumHubPort}
   environments:
       - name: "Firefox on Windows"
         browser: "*firefox"
       - name: "Firefox on OS X"
         browser: "*firefox"

 
Then, in maven’s pom add:

1
2
3
4
5
6
7
8
9
10
11
12
    <resources>
<!-- ... -->
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/grid_configuration.yml</include>
        </includes>
        <filtering>true</filtering>
        <targetPath>../..</targetPath>
      </resource> 
<!-- ... -->
    </resources>

4

Conclusion

After the test maven phase, server (selenium) and agents are running. Also second instance of this maven project, i.e. with different test scenarios, can be started. Done.

💡 REMARKS:
– Selenium is very greedy, so if you run many hubs (selenium grid) in parallel, it will need large memory space, swap, good CPU, etc. Watch for the resource usage, you can use the unix top command to do that.
– I don’t know if reserve-network-port itself can handle a race condition. So, if it happens that some reserve-network-port search for free ports in the same time, there is a tiny chance they take the same port.

Have fun! ;-)

Be Sociable, Share!
 
Does that help to solve your problem?
VN:F [1.8.5_1061]
Rating: +1 (from 1 vote)
1 votes 'YES'  0 votes 'NO'


TAGS

SOCIAL
Be Sociable, Share!

INCOMING SEARCH TERMS


Leave a Reply