I'm trying to run my unit tests through mpirun using ant. I have specified the task as:
<target name="unitTest" depends="buildUnitTest">
<mkdir dir="reports"/>
<junit fork="yes" jvm="mpirun java" printsummary="yes" haltonfailure="yes">
<classpath>
<pathelement location="./bin"/>
<pathelement location="/usr/share/java/junit4.jar"/>
</classpath>
<jvmarg value="-DDIM=3"/>
<jvmarg value="-ea"/>
<formatter type="plain"/>
<batchtest todir="reports">
<fileset dir="test">
<include name="haparanda/utils/*Test.java"/>
<include name="haparanda/iterators/*Test.java"/>
<exclude name="haparanda/iterators/FieldIteratorTest.java"/>
<include name="haparanda/grid/*Test.java"/>
</fileset>
</batchtest>
</junit>
</target>
Running eg:
mpirun java -ea -DDIM=3 -cp ./bin:/usr/share/java/junit4.jar org.junit.runner.JUnitCore haparanda.grid.ComputationalComposedBlockTest
from command line works fine. However, when I run:
ant unitTest
I get the following error:
BUILD FAILED
.../build.xml:28: Process fork failed.
Running ant with the verbose flag I get told that I got an IOException with the error message:
Cannot run program "mpirun java": error=2, No such file or directory
This is the case also when I specify the full path to mpirun and Java:
<junit fork="yes" jvm="/home/malin/bin/openmpi/bin/mpirun /usr/bin/java" printsummary="yes" haltonfailure="yes">
gives me:
.../build.xml:28: Process fork failed.
at ...
Caused by: java.io.IOException: Cannot run program "/home/malin/bin/openmpi/bin/mpirun /usr/bin/java": error=2, No such file or directory
How can i make this work?
This question is quite old and seems to have been successfully addressed in the comments by Gilles Gouaillardet. In the academic setting I am working in, I also attempted to use Junit with Java and MPI. I was unable to successfully use the trick proposed by Gilles Gouaillardet and I ended up with a quite different solution.
Custom Junit4 runner - general idea
An other way of running Junit tests with MPI consists in implementing a custom Junit runner.
In this custom Junit runner, instead of calling the Test methods "directly", you can launch your custom command using a ProcessLauncher. In my implementation, I made every MPI process use the normal Junit4 runtime to run the test methods. However, instead of using the normal RunNotifier of the Junit runtime, the MPI processes use my custom RunNotifier which writes the calls it receives to a file. A file with the calls of
Back in my custom runner, once the mpirun processes have finished, I aggregate the results of each test method of each MPI process and transmit those to the normal RunNotifier.
Benefits
With this system, you are staying within the "normal" Junit4 framework. In my case I was trying to run Junit tests from Maven. I can also integrate the test results with the Eclipse Junit view successfully (this required a few tricks that are not shown in the code excerpt below).
Here is a capture of my Eclipse environment after running the tests (the class names are slightly different than those presented in the excerpts below due to some additional complications for my particular environment).
Some selected code details
Only the most important parts of the custom MpiRunner and MpiTestLauncher are shown. Imports, try/catch structures and numerous details have been removed. I will eventually make the whole code available on GitHub but it isn't quite ready yet.
/** A test class using the custom "MpiRunner" */
#RunWith(MpiRunner.class)
public class TestUsingMpi {
#Test
public void test() {
assertTrue("Should run with multiple processes", MPI.COMM_WORLD.Size() > 1);
}
}
/** Curstom Junit4 Runner */
public class MpiRunner extends Runner {
// some methods skipped, try/catch blocks have been removed
#Override
public void run(RunNotifier notifier) {
// Build the command
final ArrayList<String> command = new ArrayList<>();
command.add("mpirun");
command.add("-np");
command.add(String.valueOf(processCount));
command.add("java");
// Classpath, UserDirectory, JavaLibraryPath ...
command.add("MpiTestLauncher "); // Class with main
command.add(testClass.getCanonicalName()); // Class under test as argument
ProcessBuilder pb = new ProcessBuilder(command);
File mpirunOutFile = new File("MpirunCommandOutput.txt");
pb.redirectOutput(Redirect.appendTo(mpirunOutFile));
pb.redirectError(Redirect.appendTo(mpirunOutFile));
Process p = pb.start(); // Launch the mpirun command
p.waitFor(); // Wait for termination
// Parse the notifications of each MPI process
for (int i = o; i < NbProcesses; i++) {
List<Notification> mpiRankNotifs = parse(i);
//Re-run those notifications on the parameter "notifier" of this method
for (Notification n : notifications) {
//Reconstitute the method call made in the mpi process
Class<?> paramClass = n.parameters[0].getClass();
Method m = RunNotifier.class.getDeclaredMethod(n.method, paramClass);
m.invoke(notifier, n.parameters);
}
}
}
}
/** Main class of the Mpirun java processes */
public class MpiTestLauncher {
public static void main(String[] args) throws Exception {
MPI.Init(args);
commRank = MPI.COMM_WORLD.Rank();
commSize = MPI.COMM_WORLD.Size();
Class<?> testClass = Class.forName(args[0]); // Class that contains the tests
String notificationFileName = testClass.getCanonicalName() + "_" +
commRank;
File f = new File(notificationFileName);
CustomNotifier notifier = new MpiApgasRunNotifier(f);
BlockJUnit4ClassRunner junitDefaultRunner = new BlockJUnit4ClassRunner(testClass);
junitDefaultRunner.run(notifier);
notifier.close(); //Flushes the underlying buffer
MPI.Finalize();
}
}
Related
I know this is "common" error but I am trying to make a JUnit5 Android Room test working.
I found out that JUnit5 does not support the instrumentation test (or google does not support JUnit 5 I should say) but I discovered that https://github.com/mannodermaus/android-junit5 is supposed to help me.
I modified my graddle to have the plugin added in my module and the classpath at the top of the project.
classpath("de.mannodermaus.gradle.plugins:android-junit5:1.7.1.1")
id("kotlin-android")
I also added the specific dependencies from it
androidTestImplementation("de.mannodermaus.junit5:android-test-core:1.2.2")
androidTestRuntimeOnly("de.mannodermaus.junit5:android-test-runner:1.2.2")
And in the android defaultConfig of my module I added
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArgument("runnerBuilder", "de.mannodermaus.junit5.AndroidJUnit5Builder")
The graddle builds fine but the issue is when I run my simple test
class DbTest
{
private lateinit var myDao : MyDao
#BeforeEach
fun init()
{
val context : Context = ApplicationProvider.getApplicationContext();
val db = Room.inMemoryDatabaseBuilder(
context,
ConfigDatabase::class.java).build()
tcdDao = db.getMyDao()
}
[...]
}
The error occurs when I get the context :
No instrumentation registered! Must run under a registering instrumentation.
I want to specify that I cannot use JUnit4.
Am I missing something ? Can I actually test my database with JUnit5 ? Or should I use another solution ?
I'm working at a middleware for aspnetcore2.0 where I want to execute some razor view.
Actually I need a error handling middleware which would show nice pages from razor views. I know that it's possible to do with UseStatusCodePagesWithReExecute based on status codes. But I need a more general approach - handle an exception in my middleware to delegate (in some cases) it to an error view.
I realized that DeveloperExceptionPageMiddleware does something similar to what I need. But I can't understand how it works even after digging into its sources.
Here is the place where that middleware returns a view - https://github.com/aspnet/Diagnostics/blob/dev/src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs#L206
But I can't understand what kind of view it is. It's nor a razor page (as it has no #page directive) neither an mvc view (but i'm not sure).
In the project there're two files for that view: ErrorPage.cshtml and ErrorPage.Designer.cs. How that Designer.cs was created? It looks like a generated file. But thanks to it there's a normal class in the project (ErrorPage) which can be used explicitly. It inherits Microsoft.Extensions.RazorViews.BaseView class from Microsoft.Extensions.RazorViews.Sources package.
So the middleware just execute that view:
var errorPage = new ErrorPage(model);
return errorPage.ExecuteAsync(context);
How can it be achieved in my project?
UPDATE [2018.06]: Please note that the post was written for .NET Core 2.0 times, there're breaking changes for RazorEngine in .NET Core 2.1.
It turned out that it's pretty easy to do.
Aspnet prjoect has an internal tool called RazorPageGenerator (see https://github.com/aspnet/Razor/tree/dev/src/RazorPageGenerator) which can be used to compile views. After compilation with this tool we'll get normal classes which can be used in middlewares.
But before we need to get RazorPageGenerator and slightly customize it.
1.Create a new console project
dotnet new console -o MyRazorGenerator
2.put NuGet.config inside this folder
<configuration>
<config>
<add key="globalPackagesFolder" value="./packages" />
</config>
<packageSources>
<add key="aspnetcore-dev" value="https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json " />
</packageSources>
</configuration>
3.Add the following in csprj (as dotnet add package doesn't support installing pre-prelease packages)
<ItemGroup>
<PackageReference Include="RazorPageGenerator" Version="2.1.0-*" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.Extensions" Version="2.1.0-*" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="2.1.0-*" />
</ItemGroup>
4.restore dotnet restore to check you got RazorPageGenerator
5.add into Program.cs:
public static int Main(string[] args)
{
if (args == null || args.Length < 1)
{
Console.WriteLine("Invalid argument(s).");
return 1;
}
var rootNamespace = args[0];
var targetProjectDirectory = args.Length > 1 ? args[1] : Directory.GetCurrentDirectory();
var razorEngine = RazorPageGenerator.Program.CreateRazorEngine(rootNamespace, builder => {
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
});
var results = RazorPageGenerator.Program.MainCore(razorEngine, targetProjectDirectory);
foreach (var result in results)
{
File.WriteAllText(result.FilePath, result.GeneratedCode);
}
Console.WriteLine();
Console.WriteLine($"{results.Count} files successfully generated.");
Console.WriteLine();
return 0;
}
6.Now we have our own generator and can compile views
7.Create a Razor View (.cshtml)
8.run our generator to compile view:
dotnet run --project .\MyRazorPageGenerator\MyRazorPageGenerator.csproj Croc.XFW3.Web .\Middleware
here I assume that the view is inside Middleware\Views folder.
9.Generator creates a file like ErrorPage.Designer.cs (if view was ErrorPage.cshtml) which we can use:
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
if (context.Response.StatusCode == StatusCodes.Status404NotFound)
{
var statusCodeFeature = context.Features.Get<IStatusCodePagesFeature>();
if (statusCodeFeature == null || !statusCodeFeature.Enabled)
{
if (!context.Response.HasStarted)
{
var view = new ErrorPage(new ErrorPageModel());
await view.ExecuteAsync(context);
}
}
}
}
}
Here we're returning our view in case of 404 error and absense of StatusCodePagesMiddleware. Can be useful for embedded UI in libs.
The generated code uses staff which should be added into your project. To get it we need to acquire nuget package Microsoft.Extensions.RazorViews.Sources. Again it’s not on nuget.org so we need to install it from https://dotnet.myget.org/feed/aspnetcore-dev/package/nuget/Microsoft.Extensions.RazorViews.Sources.
I use Cucumber for jUnit runner to run BDD tests like this:
#RunWith(Cucumber.class)
#CucumberOptions(
format = {"pretty", "json:target/cucumber.json"},
glue = {"com.company.bdd.steps"},
features = {"classpath:bdd-scenarios"},
tags = {"~#skip"}
)
public class CucumberTests {
}
I would like to have beautiful HTML reports from https://github.com/damianszczepanik/cucumber-reporting
And i made jUnit #AfterClass method:
#AfterClass
public static void buildReport() throws Exception {
List<String> srcReportJson = Collections.singletonList("target/cucumber.json");
Configuration configuration = new Configuration(new File("target"), "AEOS BDD Integration Tests");
new ReportBuilder(srcReportJson, configuration).generateReports();
}
The problem is that cucumber.json is empty when #AfterClass method executes. Hence i can't build pretty HTML report.
Is there any hook which i can use to execute some code after cucumber json report is already built?
PS: Cucumber v.1.1.8 is used and Java 1.7 so i was not able to try ExtendedCucumberRunner
Have you considered adding shutdown hook? Here is an example on how to add one. Code in run() method supposed to be executed before JVM shuts down.
You can take a look at custom formatter of cucumber:
Thank you for your suggestions but I just decided to use already existing Maven plugin and execute it's goal right after test goal.
wjpowell posted this suggestion in the cucumber-jvm issues:
"You don't need to do this in cucumber. Use the #beforeclass and #afterclass annotation from within the JUnit test used to run the cucumber tests. This has the benefit of running only for the features specified by the paths or tags options.
#RunWith(Cucumber.class)
#Cucumber.Options(format = {"html:target/cucumber-html-report", "json-pretty:target/cucumber-json-report.json"})
public class RunCukesTest {
#BeforeClass
public static void setup() {
System.out.println("Ran the before");
}
#AfterClass
public static void teardown() {
System.out.println("Ran the after");
}
}
"
I'm currently creation JUnit test for a play application. The problem comes when I try to use FakeApplication. I create one in JUnit test but when a test uses the fakeApplication instance, then I got this:
[error] Test controllers.MyClassTest.getMyProperty failed: play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [default]]
Here's my Java code in the JUnit test class:
...
#BeforeClass
public static void startFakeApplication() {
Map<String, String> settings = new HashMap<String, String>();
settings.put("db.default.url", "jdbc:mysql://myhost/releaseDB?characterEncoding=UTF-8");
settings.put("db.default.driver", "com.mysql.jdbc.Driver");
settings.put("db.default.user", "release");
settings.put("db.default.password", "release");
settings.put("db.default.jndiName", "DefaultDS");
Helpers.start(fakeApplication);
}
...
Then my method to test (notice the dummy run so nothing should cause any trouble):
...
public void getMyProperty() {
Helpers.running (fakeApplication, new Runnable() {
public void run() {
}
});
}
...
I think the problem is a database connection issue, and of course when running play in run mode, everything is fine. If I don't use FakeApplication then it's fine also but I need it.
All the database information in startFakeApplication method are coming from conf/application.conf so they're right.
What is strange is that I also have this line in the output screen when running test:
[info] play - datasource [jdbc:mysql://myhost/releaseDB?characterEncoding=UTF-8] bound to JNDI as DefaultDS
Did I missed something important here ?
Thx
Are you passing your settings map to fakeApplication somewhere? Something like:
FakeApplication fakeApplication = fakeApplication(settings);
An alternative option is to have a separate application-test.conf file and include the following in your build.sbt file:
javaOptions in Test ++= Seq(
"-Dconfig.file=conf/application-test.conf"
)
My framework Acolyte provides a JDBC driver & tools, designed for such purposes (mock up, testing, ...): http://acolyte.eu.org
It's used already in some open source projects (Anorm, Youtube Vitess, ...), either in vanilla Java, or using its Scala DSL.
val jdbcUrl = "jdbc:acolyte:anything-you-want?handler=my-unique-id"
val handler = handleStatement.withQueryDetection(...).
withQueryHandler(/* which result for which query */).
withUpdateHandler(/* which result for which update */).
// Register prepared handler with expected ID 'my-unique-id'
acolyte.Driver.register("my-unique-id", handler);
// then ...
Connection con = DriverManager.getConnection(jdbcUrl);
// ... Connection |con| is managed through |handler|
// Or pass the JDBC url to Play config
I have written a custom JUnit runner that I want to become part of an eclipse plugin that will launch tests using this runner without having to apply the #RunWith annotation to the class. I have managed to get an additional item under the 'Run As' context menu, using the org.eclipse.debug.ui.launchShortcuts extension point. However, I am not sure how to invoke the test using my custom runner.
So I figured out a way to do what I wanted. However, it does seem a bit hacky. But, I thought that I would post the answer here in case someone else runs into the same problem.
First you have to register a junit kind like this:
<extension point="org.eclipse.jdt.junit.internal_testKinds">
<kind
id="my.junit.kind"
displayName="Your Kind Name"
finderClass="org.eclipse.jdt.internal.junit.launcher.JUnit4TestFinder"
loaderPluginId="org.eclipse.jdt.junit4.runtime"
loaderClass="your.test.loader.MyLoaderClass">
<runtimeClasspathEntry pluginId="org.eclipse.jdt.junit4.runtime" />
<runtimeClasspathEntry pluginId="org.eclipse.jdt.junit.core" />
<runtimeClasspathEntry pluginId="org.eclipse.jdt.junit.runtime"/>
</kind>
</extension>
In the xml you have to specify a custom implementation of org.eclipse.jdt.internal.junit.runner.ITestLoaderwhich in turn returns an implementation of org.eclipse.jdt.internal.junit.runner.ITestReference. The core part is the implementation of ITestReference, because this is where you create an instance of your custom JUnit runner.
public class MyTestReference extends JUnit4TestReference
{
public MyTestReference(final Class<?> p_clazz, String[] p_failureNames)
{
super(new Request()
{
#Override
public Runner getRunner()
{
return new MyCustomRunner(p_clazz);
}
}, p_failureNames);
}
...
}
Then finally you have to link this with a launch shortcut that sets the kind appropriately
public class MyJunitLaunchShortcut extends JUnitLaunchShortcut
{
#Override
protected ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement p_element) throws CoreException
{
ILaunchConfigurationWorkingCopy config = super.createLaunchConfiguration(p_element);
config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, "my.junit.kind");
return config;
}
}
This does use a bunch of internal classes, so there is probably a better way. But this seems to work.