TCPServer/TCPClient usage

5,814 views
Skip to first unread message

Alexandre Souza

unread,
May 28, 2013, 9:19:32 PM5/28/13
to jac...@googlegroups.com
Hello, I'm starting to use JaCoCo for code coverage.

I've setup a tcpserver agent listening to port 6300 on a Websphere 7 server and a tcpclient on my Maven test project.

The thing is: the client connect to server, but a little before it finishes the tests I get this:

java.lang.RuntimeException: java.net.SocketException: Socket closed
    at org.jacoco.agent.rt.internal_5d10cad.core.data.ExecutionDataWriter.visitSessionInfo(ExecutionDataWriter.java:86)
    at org.jacoco.agent.rt.internal_5d10cad.core.runtime.RuntimeData.collect(RuntimeData.java:86)
    at org.jacoco.agent.rt.internal_5d10cad.output.TcpConnection.visitDumpCommand(TcpConnection.java:102)
    at org.jacoco.agent.rt.internal_5d10cad.output.TcpConnection.writeExecutionData(TcpConnection.java:82)
    at org.jacoco.agent.rt.internal_5d10cad.output.TcpClientOutput.writeExecutionData(TcpClientOutput.java:72)
    at org.jacoco.agent.rt.internal_5d10cad.Agent.shutdown(Agent.java:143)
    at org.jacoco.agent.rt.internal_5d10cad.Agent$1.run(Agent.java:60)
Caused by: java.net.SocketException: Socket closed
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:116)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
    at java.io.DataOutputStream.write(DataOutputStream.java:107)
    at java.io.DataOutputStream.writeUTF(DataOutputStream.java:401)
    at java.io.DataOutputStream.writeUTF(DataOutputStream.java:323)
    at org.jacoco.agent.rt.internal_5d10cad.core.data.ExecutionDataWriter.visitSessionInfo(ExecutionDataWriter.java:82)
    ... 6 more


I need to run the tests in integration-test phase and I need to it with the server classes (we're using a remote EJB interface, and if I setup the default agent on coverage it show "_REMOTE_STUB_CLASS_" instead of the actual EJB implementation).

Is there a right way to do it?

Thanks,
Alexandre L.A. Souza

Marc R. Hoffmann

unread,
May 29, 2013, 12:52:36 AM5/29/13
to jac...@googlegroups.com
Hi Alexandre,

it looks like your client closes the connection or the client terminates
while the server is dumping the data. How does your client
implementation look like?

Note that JaCoCo documentation contains a working client example:

http://www.eclemma.org/jacoco/trunk/doc/examples/java/ExecutionDataClient.java

Best regards,
-marc
> --
> You received this message because you are subscribed to the Google
> Groups "JaCoCo and EclEmma Users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to jacoco+un...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>

Alexandre Souza

unread,
May 29, 2013, 8:55:40 AM5/29/13
to jac...@googlegroups.com
Hi Marc. Thanks for the quick reply.

I'm configuring the client on JaCoCo Maven plugin like this:

<plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.6.2.201302030002</version>
                <executions>
                    <execution>
                        <id>agent</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <propertyName>jacoco.arg.argLine</propertyName>
                            <classDumpDir>${project.build.directory}/classes/</classDumpDir>
                            <includes>
                                <include>my.company.*</include>
                            </includes>
                            <excludes>
                                <exclude>my.company.test*</exclude>
                            </excludes>
                            <output>tcpclient</output>
                            <address>localhost</address>
                            <port>6300</port>
                        </configuration>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

And using ${jacoco.arg.argLine} as argLine to run the tests on Failsafe Plugin. So I'm using default destfile parameter.

I even tried to set "dumponexit" parameter to false on server ('cause I'm not stopping it after the test), but I got a CORBA exception saying that my EJB object doesn't exists. But if I run the tests with the default argLine (not setting tcpclient), they run OK, but I get that "_REMOTE_STUB_CLASS_" on my report (and I'm not able to see which lines I've covered).

Do I need to implement the client?
I mean, I think Maven plugins must be independent of the project (more generic, you know?).
And implementing a client to use the JaCoCo plugin is quiet an inconvenient.

I'm not complaining here! Don't get me wrong, I'm trying to suggest an improvement.

I tried the same configuration on my Glassfish 3 server at home, and I got the same "Socket closed" problem :S

It looks like it's closing the connection right after tests execution, and when it tries to write the *.exec file, the client fails, since it has no connection.

Best regards,
Alexandre L.A. Souza


> Date: Wed, 29 May 2013 06:52:36 +0200
> From: hoff...@mountainminds.com
> To: jac...@googlegroups.com
> Subject: Re: [java code coverage] TCPServer/TCPClient usage
> You received this message because you are subscribed to a topic in the Google Groups "JaCoCo and EclEmma Users" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/jacoco/LlqoJpuacak/unsubscribe?hl=en.
> To unsubscribe from this group and all its topics, send an email to jacoco+un...@googlegroups.com.

Marc Hoffmann

unread,
May 30, 2013, 1:47:14 AM5/30/13
to jac...@googlegroups.com
Hi Alexandre,

interesting idea to connect two JaCoCo agents with each other --
unfortunatelly this is not the way how it works. In any case (output
mode file, tcpserver, tcpclient) every agent produced execution
information and dumps it to a file os sends it over a tcp/ip connection.
But JaCoCo agents do not consume execution data.

In your setup there are two options:

1) let the JaCoCo agents dump the data to the file system, could be the
same file for client and server if both run on the same machine.
2) Beside APIs the only tool to request remote dumps is the Ant task
"dump", see documentation.

Best regards,
-marc
> [1].
>
>
>
> Links:
> ------
> [1] https://groups.google.com/groups/opt_out

Alexandre Souza

unread,
May 30, 2013, 2:03:22 AM5/30/13
to jac...@googlegroups.com
Hmmm.
Ok. I think I know what to do now.
But I still don't understand how the agent sends data through tcp/ip connection.
Do you have a config example?


Isn't it possible to implement this Ant task as a Maven plugin goal?

I know I'm being a bit annoying, but I REALLY love the idea of instrumentation on the fly =)
We use Jenkins to do Continous Integration builds, but we need another build to do reporting, since Cobertura only instruments classes (actually bytecode) offline.

I thought the agents would connect each other (just like a socket attach when you connect a debugger to an Application Server).
Sadly, I was wrong. I'll try to use the Ant task then.



Best regards,
Alexandre L.A. Souza


> Date: Thu, 30 May 2013 07:47:14 +0200
> From: hoff...@mountainminds.com
> To: jac...@googlegroups.com
> Subject: RE: [java code coverage] TCPServer/TCPClient usage

Marc Hoffmann

unread,
May 30, 2013, 5:43:57 AM5/30/13
to jac...@googlegroups.com
> But I still don't understand how the agent sends data through tcp/ip
> connection. Do you have a config example?

See Ant task documentation:
http://www.eclemma.org/jacoco/trunk/doc/ant.html#dump

Basically what the task does is to connect to an JaCoCo agent (running
in tcpserver mode) and sends a command to the agent to trigger a exec
data dump. In turn the agent responds with the execution data which is
written to file by the task.

> Isn't it possible to implement this Ant task as a Maven plugin goal?

Of course, you can open a feature request for this.

> I thought the agents would connect each other (just like a socket
> attach when you connect a debugger to an Application Server).

As I said before: A JaCoCo agent is always the *source* of execution
data (regardless of the output mode). It cannot consume execution data
nor request execution data from other agents.

Cheers,
-marc

Neil Russell

unread,
Aug 29, 2013, 9:32:17 AM8/29/13
to jac...@googlegroups.com
Hi,

I'm re-using this topic since the headline is exactly my issue.
I am exploring any means for a webserver to dump coverage data to a remote continuous integration machine which will then run the sonar report plugin on the data.
I do not wish to halt the webserver to get the coverage data. I want to run a series of tests, and collect the data from each test suite.
I suppose ultimately I could figure out how to stop the remote webserver, but it is inconvenient...

I have three small test classes. Two of them are just the client/server example code from the jacoco download. The third is just a dumb class that runs a few hundred iterations and calls a bunch of its own methods, and I'm instrumenting it with Jacoco offline mode from maven plugin.

This all works, except that

1. if I understand the documentation, I can run the agent in tcpserver mode, and fire the Ant task or the sample client to trigger transfer of the coverage data.
   This works for me, and I get get data...BUT... I am only running one process/one thread in my test "server". It seems to me that the jacoco agent is going
   to try to open multiple connections (one per thread?) as tcpserver, and most of the code base will fail. I have no control over the way the threads run of course.

2. If I understand the documentation, I can run the agent in tcpclient mode, and run the sample ExecutionDataServer to listen and collect results.
   There should be no port conflicts in this scenario, however, it seems that in tcpclient mode, the only option that sends data is "dumponexit=true",
   which requires the thread running the code under test to exit, which is not possible (or not desirable as noted above).

Is there any way to get this to work the way I'm hoping? Did I miss something in the documentation perhaps?

--N

Marc Hoffmann

unread,
Aug 29, 2013, 9:52:58 AM8/29/13
to jac...@googlegroups.com
1) In tcpserver mode the JaCoCo agent will one server socket per JVM.
This is independent of the number of threads within the JVM. If you run
multiple JVMs on the same node you need to specify different server
ports for every JVM.

2) Although this is not covered by the simple example included with
JaCoCo documentation, also in tcpclient mode you can trigger dumps at
any point in time. Actually the EclEmma plug-in is implemented this way.

-marc

Neil Russell

unread,
Sep 11, 2013, 3:38:29 PM9/11/13
to jac...@googlegroups.com
Hi Marc,

We have run into an interesting scenario, with a possible easy fix.
I wanted to see if other users might have requested this same approach.

Basically we deploy our EAR with jacoco agent and instrumented class files.
All is well. We get TCP connections and remote dumps back to our CI server.

Now we unload the EAR, and deploy a new version. (Actually we have several EARs, and at some point this behavior
will be an issue I think...only one of the applications will succeed in running with instrumented coverage?)

The thread (org.jacoco.agent.rt.internal.Agent.java) for tcpserver mode tries to start again, because the detection is based
on the static variable, not on the actual socket usage or thread identity.

I think we might get around this by deploying a stub EAR project whose only purpose is to keep the JaCoCo agent server thread
running - however, I don't think this will work by itself based on the above. Any new EAR is going to look at its "local" static variable
and try to start another thread?

it would seem quite simple to either define a canonical name for the spawned thread, and check for that thread, or to read the properties
file and check the existence of a socket on the configured port, or both - before attempting to start another thread on same port.

Thoughts? Suggestions?

Thanks,

--N

Marc R. Hoffmann

unread,
Sep 11, 2013, 6:07:08 PM9/11/13
to jac...@googlegroups.com
Hi Neil,

if the two versions of the EARs are separated by class loaders and the
two JaCoCo runtime classes cannot see each other the same applies for
your instrumented application classes: The app classes in EAR 1 will
only see the JaCoCo runtime in EAR 1. Therefore a tcpserver running in
another EAR 2 will not be able to report execution data for EAR 1.

The only solution I see is to deploy the JaCoCo runtime into a
classloader shared by both EARs. Most app servers have an option to
install such shared libs.

Cheers,
-marc
> > send an email to jacoco+un...@googlegroups.com <javascript:>.
> <https://groups.google.com/groups/opt_out>
>
> --
> You received this message because you are subscribed to the Google
> Groups "JaCoCo and EclEmma Users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to jacoco+un...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Neil Russell

unread,
Sep 12, 2013, 12:14:05 PM9/12/13
to jac...@googlegroups.com
Hi Marc,

Yes, we see how to do that, more or less. I'm sorry I kind of confused the issues and didn't do a good job of asking one question:

How can I re-deploy an EAR to an app server, in an environment where I have multiple EARs to deploy, and continue to get code coverage
out of the app server?

Here is what we face:

EAR1 and EAR2 should be configured with separate JaCoCo server/port numbers.
I should be able to unload EAR1 and load a new version, without stopping the app server
or disturbing anything happening with EAR2 on that server.

It seems to me that a simple tweak to the way the JaCoCo tcpserver code checks for the port in use, would fix this scenario
without needing to modify how we deploy our app servers (with special packing of JaCoCo runtimes).
That would allow the server socket thread for the configured port, to just keep running in between EAR undeploy/re-deployments.

An alternative, less elegant perhaps, would be to provide a "command" over the port that allows the client side
to request that the server side thread should exit. A CI server or automation framework could orchestrate
the clean shutdown of the old thread, before attempting to re-deploy the EAR.

Would either of these features be something worthwhile to add to the project?

Thanks again for prompt and clear responses!

--N

Marc R. Hoffmann

unread,
Sep 15, 2013, 6:48:19 AM9/15/13
to jac...@googlegroups.com
Hi Neil,

I think now I got your requirement: Shutdown the JaCoCo runtime if the
JaCoCo runtime JAR was deployed with your application and the
application gets un-deployed.

Currently the JaCoCo shutdown process is hooked into the JVM shutdown,
as JaCoCo is typically used as an agent which has the same lifecycle
than the JVM.

I have no idea whether it is possible to somehow detect that the app was
unloaded (probably the JaCoCo server thread prevents exactly this anyways).

I opened a feature request for further discussion:
https://github.com/jacoco/jacoco/issues/134

Best regards,
-marc
> <https://groups.google.com/groups/opt_out>.
Reply all
Reply to author
Forward
This conversation is locked
You cannot reply and perform actions on locked conversations.
0 new messages