Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add direct unit tests for working with 32bit and 64bit processes. #37

Merged
merged 10 commits into from
Apr 19, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<forkMode>never</forkMode>
</configuration>
<version>2.19.1</version>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beware of SUREFIRE-1226

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will add on-demand

</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
Expand Down
14 changes: 14 additions & 0 deletions src/test/java/org/jvnet/winp/NativeAPITest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.jvnet.winp;

import java.io.IOException;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import org.hamcrest.core.StringContains;
import org.junit.Assert;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeThat;
Expand Down Expand Up @@ -103,6 +105,18 @@ public void testKill() throws Exception {
wp.killRecursively();
}

@Test
public void shouldFailForNonExistentProcess() {
int nonExistentPid = Integer.MAX_VALUE;
try {
new WinProcess(nonExistentPid).getCommandLine();
} catch(WinpException ex) {
assertThat(ex.getMessage(), containsString("Failed to open process"));
return;
}
Assert.fail("Expected WinpException due to the non-existent process");
}

/**
* Starts notepad process with the TEST environment variable.
* Notepad process may be either 64bit or 32bit depending on the OS Platform.
Expand Down
39 changes: 13 additions & 26 deletions src/test/java/org/jvnet/winp/PlatformSpecificProcessTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Assert;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand All @@ -37,6 +37,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.jvnet.winp.util.ExecutablePlatform;
import org.jvnet.winp.util.ProcessSpawningTest;
import static org.jvnet.winp.util.ProcessSpawningTest.isAlive;
import org.jvnet.winp.util.TestHelper;
Expand Down Expand Up @@ -64,7 +65,7 @@ public void verifyTargetPlatform() {
TestHelper.assumeIs64BitHost();
}

File exec = getExecutable();
File exec = getTestAppExecutable(executablePlatform);
System.out.println("Target executable: " + exec.getAbsolutePath());
Assert.assertTrue("Cannot locate the required executable: " + exec.getAbsolutePath(), exec.exists());
}
Expand Down Expand Up @@ -96,7 +97,9 @@ public void getCommandLine_shouldNotFailIfTheProcessIsDead() throws Exception {
try {
new WinProcess(p).getCommandLine();
} catch (WinpException ex) {
assertThat(ex.getMessage(), containsString("error=299 at envvar-cmdline"));
assertThat(ex.getMessage(), allOf(
containsString("Failed to read " + getExpectedPEBName(false)),
containsString("error=299 at envvar-cmdline")));
return;
}

Expand All @@ -113,42 +116,26 @@ public void getEnvironmentVariables_shouldFailIfTheProcessIsDead() throws Except
try {
new WinProcess(p).getEnvironmentVariables();
} catch (WinpException ex) {
assertThat(ex.getMessage(), containsString("error=299 at envvar-cmdline"));
assertThat(ex.getMessage(), allOf(
containsString("Failed to read " + getExpectedPEBName(false)),
containsString("error=299 at envvar-cmdline")));
return;
}

Assert.fail("Expected WinpException since the process is killed");
}

private Process spawnTestApp() throws IOException, InterruptedException {
return spawnProcess(getExecutable().getAbsolutePath());
return spawnProcess(getTestAppExecutable(executablePlatform).getAbsolutePath());
}

private File getExecutable() {
final String executable;
switch (executablePlatform) {
case X64:
executable = "native_test/testapp/x64/Release/testapp.exe";
break;
case X86:
executable = "native_test/testapp/Win32/Release/testapp.exe";
break;
default:
Assert.fail("Unsupported platform: " + executablePlatform);
throw new IllegalStateException();
}
return new File(executable);
private String getExpectedPEBName(boolean processIsRunning) {
// We cannot read Wow64 Process info from the terminated process, hence PEB32 structure won't be discovered
return (executablePlatform == ExecutablePlatform.X86 && processIsRunning) ? "PEB32" : "PEB";
}


@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { {ExecutablePlatform.X64}, {ExecutablePlatform.X86}});
}

public enum ExecutablePlatform {
X64,
X86;
//TODO: Add support of ARM?
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.winp.profiling;

import java.io.File;
import org.junit.Test;
import org.jvnet.winp.WinProcess;
import org.jvnet.winp.util.ExecutablePlatform;
import org.jvnet.winp.util.ProcessSpawningTest;

/**
* Runs profiling for a single 32bit application.
* @author Oleg Nenashev
*/
public class ProfileSingleEnvVars_32bit extends ProcessSpawningTest {

@Test
public void doProfile() throws Exception {
File executable = getTestAppExecutable(ExecutablePlatform.X86);
Process proc = spawnProcess(true, false, executable.getAbsolutePath());
WinProcess wp = new WinProcess(proc);
wp.getEnvironmentVariables();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.winp.profiling;

import java.io.File;
import org.junit.Before;
import org.junit.Test;
import org.jvnet.winp.WinProcess;
import org.jvnet.winp.util.ExecutablePlatform;
import org.jvnet.winp.util.ProcessSpawningTest;
import org.jvnet.winp.util.TestHelper;

/**
* Runs profiling for a single 64bit application.
* @author Oleg Nenashev
*/
public class ProfileSingleEnvVars_64bit extends ProcessSpawningTest {

@Before
public void assumeIs64Bit() {
TestHelper.assumeIs64BitHost();
}

@Test
public void doProfile() throws Exception {
File executable = getTestAppExecutable(ExecutablePlatform.X64);
Process proc = spawnProcess(false, false, executable.getAbsolutePath());
WinProcess wp = new WinProcess(proc);
wp.getEnvironmentVariables();
killSpawnedProcess();
}

}
34 changes: 34 additions & 0 deletions src/test/java/org/jvnet/winp/util/ExecutablePlatform.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.winp.util;

/**
*
* @author Oleg Nenashev
*/
public enum ExecutablePlatform {
X64,
X86;
//TODO: Add support of ARM?
}
53 changes: 38 additions & 15 deletions src/test/java/org/jvnet/winp/util/ProcessSpawningTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
*/
package org.jvnet.winp.util;

import java.io.File;
import java.io.IOException;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import static org.hamcrest.CoreMatchers.containsString;
import org.junit.After;
import org.junit.Assert;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
Expand All @@ -50,31 +52,36 @@ public void killSpawnedProcess() {
//TODO: destroyForcibly() in Java8
spawnedProcess.destroy();
}

spawnedProcess = null;
}

/**
* Spawns test process, which is guaranteed to be a 32-bit one.
*/
private Process spawnTestApp32() throws AssertionError, InterruptedException, IOException {
return spawnProcess("C:\\Users\\Oleg\\Documents\\jenkins\\windows\\winp\\native\\Release\\testapp32.exe");

protected Process spawnProcess(String ... command) throws AssertionError, InterruptedException, IOException {
return spawnProcess(true, true, command);
}

public Process spawnProcess(String ... command) throws AssertionError, InterruptedException, IOException {
public Process spawnProcess(boolean delayAfterCreate, boolean spotcheckProcess, String ... command) throws AssertionError, InterruptedException, IOException {
assertTrue("Command is undefined", command.length >= 1);
assertNull("Test implementation error: The process has been already spawned", spawnedProcess);

ProcessBuilder pb = new ProcessBuilder(command);
pb.environment().put("TEST", "foobar");
spawnedProcess = pb.start();
Thread.sleep(100); // Try to give the process a little time to start or getting the command line fails randomly


if (delayAfterCreate) {
Thread.sleep(100); // Try to give the process a little time to start or getting the command line fails randomly
}

// Asserts the process status
WinProcess wp = new WinProcess(spawnedProcess);
System.out.println("pid=" + wp.getPid());
assertThat("Failed to determine the command line of the running process",
wp.getCommandLine(), containsString(command[0]));
assertTrue("Failed to read Environment Variables, no PATH discovered",
wp.getEnvironmentVariables().containsKey("PATH"));
if (spotcheckProcess) {
WinProcess wp = new WinProcess(spawnedProcess);
System.out.println("pid=" + wp.getPid());
assertThat("Failed to determine the command line of the running process",
wp.getCommandLine(), containsString(command[0]));
assertTrue("Failed to read Environment Variables, no PATH discovered",
wp.getEnvironmentVariables().containsKey("PATH"));
}

return spawnedProcess;
}

Expand All @@ -87,5 +94,21 @@ public static boolean isAlive(@Nonnull Process proc) {
return true;
}
}

protected static File getTestAppExecutable(ExecutablePlatform executablePlatform) {
final String executable;
switch (executablePlatform) {
case X64:
executable = "native_test/testapp/x64/Release/testapp.exe";
break;
case X86:
executable = "native_test/testapp/Win32/Release/testapp.exe";
break;
default:
Assert.fail("Unsupported platform: " + executablePlatform);
throw new IllegalStateException();
}
return new File(executable);
}

}