How can I switch logging on and off in tests using slf4j and Maven? - maven

We're using slf4j along with a Maven build. When writing code we do not include a dependency to a slf4j implementation (such as logback), but only to slf4j itself.
In such a context when we run (unit) integration tests, slf4j falls back to a No-op implementation and all logs that the SUTs (systems under test) code produce are "ignored" as expected.
That's fine, however sometimes we need to display these SUT (debug) logs. Usually our developers add a dependency on logback with a test scope to achieve this and write logs to the console. I'm not a big fan of this approach, but as long as they do not forget to remove the dependency prior to committing code it's fine with me... However this switch on/off can occur multiple times and is thus error prone (and we end up with build logs being flooded).
Is there a better way to achieve this ? For instance leaving logback as a test scoped dependency all the time, but setting a property that would avoid logs to be generated unless the property is removed (some kind of "force No-Op" property) ?
Thanks in advance,

Let the logback test scoped dependencie
add a logback-test.xml under the src/test/resources folder with a root log level set to NONE
add the logback test file to .gitignore once commited (the dev will be able to set a custom log level without the risk to push the file mistakenly)
cf . https://logback.qos.ch/manual/configuration.html
If you are using Maven and if you place the logback-test.xml under the
src/test/resources folder, Maven will ensure that it won't be included
in the artifact produced. Thus, you can use a different configuration
file, namely logback-test.xml during testing, and another file,
namely, logback.xml, in production.

You could have 2 profiles
<profiles>
<profile>
<id>debug</id>
…
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
<scope>test</scope>
</dependency>
</dependencies>
…
</profile>
<profile>
<id>release</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
…
<dependencies>
<dependency>…</dependency>
</dependencies>
…
</profile>
</profiles>
Then add a logback-test.xml to src/test/resources which will only be picked up for tests if the logback dependency is present in the pom and will not be written to any release jar/war.
Then for debug use :
mvn clean install -Dprofile=debug

Related

Are Maven repository declarations transitive?

Suppose I have the following project, a library which declares some 3rd party repository that it needs to use to grab an artifact.
<project ...>
<groupId>com.mygroup</groupId>
<artifactId>library</artifactId>
<version>1.0.0</version>
<repositories>
<repository>
<id>some-id</id>
<url>https://some.repo.com</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.thirdparty</groupId>
<artifactId>used-at-compile-time</artifactId> <!-- like Lombok, say -->
<version>1.0.0</version>
<scope>provided</scope> <!-- so, not transitive -->
</dependency>
</dependencies>
</project>
Then I have a totally separate project which depends upon that library
<project ...>
<groupId>com.mygroup</groupId>
<artifactId>some-app</artifactId>
<version>2.0.0</version>
<dependencies>
<dependency>
<groupId>com.mygroup</groupId>
<artifactId>library</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
Does Maven try to include the repository definition in all dependent projects? Will some-app ever try to access https://some.repo.com?
I'd always been under the impression that this didn't happen, but I've started seeing build failures which contract that belief.
It might initially seem convenient if that's how it worked, but what if the repo was internal and was not publicly accessible over the internet? The project which declared it might use it for some compile-time dependencies, like in my example above. If that repo were dragged in, the dependent project might try to access a repository that it can't for some other non-Maven Central dependencies.
So I can see valid reasons for either behaviour, but as far as I can see, the documentation for repositories doesn't say one way or another what happens, and neither does the POM reference.
Repositories are context aware, in the context of their pom. Dependencies from com.mygroup:library can use the repo's central and some-id.
On the other hand, dependencies from com.mygroup:some-app will only use central.
When running Maven from the commandline, you'll see the repositories it'll try to download the artifacts from (in case the first one fails, it'll go for the next).
When publishing to Central, there are several requirements. However, based on the last paragraph repositories are not banned, you're advised not to use them.
You might wan't to read this classic article: Why Putting Repositories in your POMs is a Bad Idea

Turn off or configure java.util.Logging during Maven build

I want to clean up/unify the log output of a Maven build. Unfortunately, a dependency of a maven plugin uses java.util.Logging (JUL). Simply adding org.slf4j:jul-to-slf4j as an additional dependency to redirect the log output doesn't help. Exclusions also don't work of course, because it's JUL and therefore not a dependency.
Here's my configuration, containing the specific plugin and its dependency:
Configuration
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.7.11</version>
<executions>...</executions>
<configuration>
<defaultOptions>
<extraargs>
<extraarg>-xjc-Xbg</extraarg>
</extraargs>
</defaultOptions>
</configuration>
<dependencies>
<!-- This one uses JUL with logging level WARN -->
<dependency>
<groupId>org.apache.cxf.xjcplugins</groupId>
<artifactId>cxf-xjc-boolean</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
</plugin>
Update
I've managed to turn off/configure JUL itself by adding a logging.properties file with the following content to the project's root folder:
# Turn off any java.util.Loggers (or use SEVERE to see problems)
.level=OFF
Additionally, I have to execute Maven with the following parameter (or set it into MAVEN_OPTS):
mvn clean install -Djava.util.logging.config.file=${basedir}/logging.properties
Remaining Question
Is there any way to achieve the same result without extra files and/or JVM parameters (pom.xml only)?
Following configuration for the plugin cxf-codegen-plugin prevented to show DEBUG log entries when building my project with maven:
<configuration>
<fork>once</fork>
<additionalJvmArgs>
-Dorg.apache.cxf.Logger=null
</additionalJvmArgs>
</configuration>
Instead of a properties file or completely disabling all logging as suggested in another answer, you can also set the desired log level like this:
<additionalJvmArgs>-Dorg.apache.cxf.level=OFF</additionalJvmArgs>
The level needs to be one of the java.util.logging.Level.
I was having similar behavior: was getting WARNING messages from CXF 2.6.3 generated webservices classes when running my Struts2 test cases, polluting my test log.
Since the log trace wasn't showing from what package was sended, I was trying to config the wrong package.
I've added this to my setUp() test case method from my test that extends XWorkTestCase (or whatever you need):
public void setUp() throws Exception{
super.setUp();
java.util.logging.Logger.getLogger("org.apache.cxf").setLevel(Level.OFF);
}
Then no more logging messages from CXF appears when I run my tests from maven.

Can security JARS be loaded with Maven?

We have some unit tests that will fail unless you have two jars, local_policy.jar, and US_export_policy.jar in your $JAVA_HOME/jre/lib/security folder. I'm supposed to see if we can just put them in a project folder, then tell Maven to use them when it does a build("mvn install"). Maybe with something like the dependency tag? Yes, I know everyone should just install these in their $JAVA_HOME, but this is the task I've been asked to look into.
You are speaking about Maven dependency scope. Documentation here. You can say to Maven use some libraries just for testing using "test" scope.
You can add them as Maven systemPath dependencies.
systemPath
is used only if the the dependency scope is system. Otherwise, the build will fail if this element is set. The path must be absolute, so it is recommended to use a property to specify the machine-specific path (more on properties below), such as ${java.home}/lib. Since it is assumed that system scope dependencies are installed a priori, Maven will not check the repositories for the project, but instead checks to ensure that the file exists. If not, Maven will fail the build and suggest that you download and install it manually.
<dependencies>
<dependency>
<!-- The groupId can be anything. Use your own groupId for example -->
<groupId>anything</groupId>
<artifactId>local_policy</artifactId>
<!-- The version can be anything. Use the version of Java for example -->
<version>7.0</version>
<systemPath>${java.home}/lib/security/local_policy.jar</systemPath>
<scope>system</scope>
</dependency>
<dependency>
<!-- The groupId can be anything. Use your own groupId for example -->
<groupId>anything</groupId>
<artifactId>US_export_policy</artifactId>
<!-- The version can be anything. Use the version of Java for example -->
<version>7.0</version>
<systemPath>${java.home}/lib/security/US_export_policy.jar</systemPath>
<scope>system</scope>
</dependency>
</dependencies>

What is the difference in Maven between dependency and plugin tags in pom.xml?

Created project with Spring, Hibernate & Maven. My question is what is the logic behind plugin versus dependency ?
Both plugins and dependencies are Jar files.
But the difference between them is, most of the work in maven is done using plugins; whereas dependency is just a Jar file which will be added to the classpath while executing the tasks.
For example, you use a compiler-plugin to compile the java files. You can't use compiler-plugin as a dependency since that will only add the plugin to the classpath, and will not trigger any compilation. The Jar files to be added to the classpath while compiling the file, will be specified as a dependency.
Same goes with your scenario. You have to use spring-plugin to execute some spring executables [ I'm not sure what spring-plugins are used for. I'm just taking a guess here ]. But you need dependencies to execute those executables. And Junit is tagged under dependency since it is used by surefire-plugin for executing unit-tests.
So, we can say, plugin is a Jar file which executes the task, and dependency is a Jar which provides the class files to execute the task.
Hope that answers your question!
Maven itself can be described as food processor which has many different units that can be used to accomplish different tasks. Those units are called plugins. For example, to compile your project maven uses maven-compiler-plugin, to run tests - maven-surefire-plugin and so on.
Dependency in terms of maven is a packaged piece of classes that your project depends on. It can be jar, war etc. For example, if you want to be able to write JUnit test, you'll have to use JUnit annotations and classes thus you have to declare that your project depends on JUnit.
Plugins and dependencies are very different things and these are complementary.
What plugins are ?
Plugins perform tasks for a Maven build. These are not packaged in the application.
These are the heart of Maven.
Any task executed by Maven is performed by plugins.
There are two categories of plugins : the build and the reporting plugins :
Build plugins will be executed during the build and they should be configured in the <build/> element from the POM.
Reporting plugins will be executed during the site generation and they should be configured in the <reporting/> element from the POM.
According to the maven goal specified in the command line (for example mvn clean, mvn clean package or mvn site) , a specific lifecyle will be used and a specific set of plugins goals will be executed.
There are three built-in build lifecycles: default, clean and site. The default lifecycle handles your project deployment, the clean lifecycle handles project cleaning, while the site lifecycle handles the creation of your project's site documentation.
A plugin goal may be bound to a specific phase of a specific lifecyle.
For example the maven-compiler-plugin binds by default the compile goal to the lifecycle phase: compile.
Most of maven plugins (both core plugins and third party plugins) favor convention over configuration. So these generally bound a plugin goal to a specific phase to make their usage simpler.
That is neater and less error prone :
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
than :
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
What dependencies are ?
Dependencies are Maven artifacts/components required for the project.
Concretely most of dependencies are jar (that is libraries) but these may also be other kinds of archives : war, ear, test-jar, ejb-client ... or still POM or BOM.
In a pom.xml, dependencies may be specified at multiple places : the <build><dependencies> part , the dependencies management part or still in a plugin declaration ! Indeed some plugins may need to have some dependencies in the classpath during their execution. That is not common but that may happen.
Here is an example from the documentation that shows that plugin and dependency may work together :
For instance, the Maven Antrun Plugin version 1.2 uses Ant version
1.6.5, if you want to use the latest Ant version when running this plugin, you need to add <dependencies> element like the following:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2</version>
...
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
<version>1.7.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
...
</project>
In Maven, dependencies are referenced in a specific format :
groupId:artifactId:packaging:classifier:version.
The classifier (that is optional) and the packaging (JAR by default) are not commonly specified. So the common format in the dependency declaration is rather : groupId:artifactId:version.
Here is an example of dependency declared in the <build><dependencies> part :
<build>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.14.Final</version>
</dependency>
<dependencies>
</build>
Dependency doesn't have a phase binding as plugins to address the "when" question.
But it has a counterpart : the scope.
Indeed declared dependencies are usable by the application at a specific time according to the scope we defined for these.
The scope is a central concept about how a dependency will be visible for the project.
The default scope is compile. That is the most commonly needed scope (convention over configuration again).
The compile scope means that the dependency is available in all classpaths of a project.
The scope defines in which classpaths the dependency should be added.
For example do we need it at compile and runtime, or only for tests compilation and execution ?
For example we previously defined Hibernate as a compile dependency as we need it everywhere : source compilation, test compilation, runtime and so for....
But we don't want that testing libraries may be packaged in the application or referenced in the source code. So we specify the test scope for them :
<build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
<dependencies>
</build>
One line answer - basic understanding
Plugin is a tool you use at the execution of your maven build
Dependency means kind of any library which you will use in your code
If you're coming from a front-end background like me, and are familiar with Grunt and npm, think of it like this:
First you would run, say, npm install grunt-contrib-copy --save-dev. This is like maven's <dependency></dependency>. It downloads the files needed to execute a build task.
Then you would configure the task in Gruntfile.js
copy: {
main: {
src: 'src/*',
dest: 'dest/',
},
}
This is like maven's <plugin>/<plugin>. You are telling the build tool what to do with the code downloaded by npm/<dependency></dependency>.
Of course this is not an exact analogy, but close enough to help wrap your head around it.
Plug-ins are used for adding functionalities to Maven itself (like adding eclipse support or SpringBoot support to Maven etc.). Dependencies are needed by your source code to pass any Maven phase (compile or test for example). In case of JUnit since the test code is basically part of your code base and you call JUnit specific commands inside test suites and those commands are not provided by Java SDK therefore JUnit must be present at the time Maven is in the test phase and this is handled by mentioning JUnit as a dependency in your pom.xml file.
In simple words:
Plugins are used to add some additonal features to the software/tools(like Maven). Maven will use the added plugins at the time of building when we use the build command.
Dependecies are used to add some addtional code to your source code, so a dependency will make some extra code (like Classes in Java) in the form of library available for your source code.
Maven at its heart is a plugin execution framework -- as per formal and standard compact definition. To make it more clear, the commands you use like maven-install/clean/compile/build etc for creating/executing jars, which we sometimes manually run too. So, the things which you want to run (or configure or execute) you basically put them in dependency tag of mavens pom and the answer so as to who will run these dependencies (required for environment setup) be the plugins.
javac (compiler) dependency.java (dependency)
A plugin is an extension to Maven, something used to produce your artifact (maven-jar-plugin for an example, is used to, you guess it, make a jar out of your compiled classes and resources).
A dependency is a library that is needed by the application you are building, at compile and/or test and/or runtime time.

soapUI and JUnit dependency issue

I'm trying to use soapUI integrated to JUnit. I've tried to add the dependencies as mentioned here but it doesn't work. Some classes are not found.
In this post, it is proposed to add the soapui/lib directory to the classpath but this is not really a good practice with Maven.
Do you know which dependency(ies) to add to my project in order to integrate soapUI to JUnit?
Thanks
Depending on what you're trying to do with SoapUI, you may be able to use its Maven plugin, rather than try to integrate it with JUnit: http://www.soapui.org/Test-Automation/maven-2x.html. You can use this to e.g. start a SoapUI mock server, run integration tests that call a web service, then stop the mock server upon completion of the tests. See also the Failsafe plugin if you want to do this.
Failing that, you could add the Maven plugin to your test classpath. This should also pull in all of the dependencies required to run SoapUI itself:
<dependencies>
<dependency>
<groupId>eviware</groupId>
<artifactId>maven-soapui-plugin</artifactId>
<version>4.5.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>eviware</id>
<url>http://www.eviware.com/repository/maven2/</url>
</repository>
</repositories>
You need to create an ext folder under your project and add your dependencies there. This is the directory SoapUI runner will look into, for all your external dependencies.

Resources