changeset 2612:0fe467368288

[PATCH] Windows - more JUnit fixes This patch fixes many JUnit failures on Windows - in fact, the build gets all the way to integration tests now. The thermostat-web-server module is skipped at this time. Future patches will address that, and the failing integration tests. Reviewed-by: sgehwolf Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-February/022257.html, http://icedtea.classpath.org/pipermail/thermostat/2017-March/022343.html
author Simon Tooke <stooke@redhat.com>
date Wed, 08 Mar 2017 09:24:27 -0500
parents bdeeace47db8
children 333a276ee6ac
files agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMainTest.java agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java agent/core/pom.xml agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java agent/ipc/unix-socket/common/src/test/java/com/redhat/thermostat/agent/ipc/unixsocket/common/internal/UnixSocketIPCPropertiesTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java common/core/src/test/java/com/redhat/thermostat/common/cli/BorderedTableRendererTest.java common/portability/Makefile common/portability/pom.xml common/portability/src/main/java/com/redhat/thermostat/common/portability/HostName.java common/portability/src/main/java/com/redhat/thermostat/common/portability/ProcessUserInfo.java common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/PortableNativeLibraryLoader.java common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/linux/UserNameUtilImpl.java common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/macos/MacOSHelperImpl.java common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsHelperImpl.java common/portability/src/main/native/WindowsHelperImpl.c common/portability/src/test/java/com/redhat/thermostat/common/portability/ProcessCheckerTest.java common/portability/src/test/java/com/redhat/thermostat/common/portability/internal/linux/LinuxPortableProcessStatBuilderImplTest.java config/src/main/java/com/redhat/thermostat/shared/config/OS.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/StoragePopulatorCommandTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/BasePopulatorTest.java distribution/assembly/core-assembly-agent-macosx.xml distribution/assembly/core-assembly-agent-windows.xml distribution/assembly/core-assembly-agent.xml distribution/assembly/core-assembly-macosx.xml distribution/assembly/core-assembly-windows.xml distribution/assembly/core-assembly.xml host-cpu/agent/pom.xml host-cpu/agent/src/test/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilderTest.java host-memory/agent/pom.xml host-memory/agent/src/test/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilderTest.java integration-tests/itest-run/pom.xml integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/EnvironmentExecutor.java keyring/src/main/java/com/redhat/thermostat/utils/keyring/internal/Activator.java numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaLinuxCollectorTest.java setup/command/pom.xml setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/CredentialsFileCreator.java setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/CLISetupTest.java setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/PasswordCredentialsReaderTest.java setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/UsernameCredentialsReaderTest.java setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/CredentialFinderTest.java setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/PropertiesWriterTest.java system-backend/pom.xml thermostat-plugin-validator/src/main/java/com/redhat/thermostat/plugin/validator/ValidationErrorsFormatter.java thermostat-plugin-validator/src/main/resources/com/redhat/thermostat/plugin/validator/strings.properties validate-command/command/src/main/resources/com/redhat/thermostat/validate/locale/strings.properties validate-command/command/src/test/java/com/redhat/thermostat/validate/command/internal/ValidateCommandTest.java vm-byteman/byteman-helper/src/test/java/org/jboss/byteman/thermostat/helper/transport/ipc/LocalSocketTransportFactoryTest.java vm-cpu/agent/pom.xml vm-gc/common/src/main/resources/com/redhat/thermostat/vm/gc/common/locale/strings.properties vm-io/agent/pom.xml vm-io/agent/src/test/java/com/redhat/thermostat/vm/io/agent/internal/VmIoStatBuilderTest.java vm-numa/agent/src/main/java/com/redhat/thermostat/vm/numa/agent/internal/Activator.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfigurationTest.java web/server/pom.xml
diffstat 55 files changed, 573 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMainTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMainTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -49,6 +49,7 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -62,7 +63,8 @@
 import com.redhat.thermostat.shared.config.SSLConfiguration;
 
 public class CommandChannelServerMainTest {
-    
+
+    private static final String IGNORED_ROOT = "/";
     private CommandChannelServerImpl server;
     private ClientIPCService ipcService;
     private IPCMessageChannel agentChannel;
@@ -87,7 +89,14 @@
         
         shutdownHandler = mock(ShutdownHookHandler.class);
         sleeper = mock(Sleeper.class);
-        
+
+        if (OS.IS_WINDOWS) {
+            // Command Channel now uses a native DLL for Windows named pipes on Windows
+            // because of this, CommonPathsImpl tries to initialize.
+            System.setProperty("THERMOSTAT_HOME", IGNORED_ROOT);
+            System.setProperty("USER_THERMOSTAT_HOME", IGNORED_ROOT);
+        }
+
         CommandChannelServerMain.setIPCService(ipcService);
         CommandChannelServerMain.setSSLConfigurationParser(parser);
         CommandChannelServerMain.setServerCreator(creator);
@@ -97,6 +106,8 @@
     
     @After
     public void tearDownOnce() {
+        System.clearProperty("THERMOSTAT_HOME");
+        System.clearProperty("USER_THERMOSTAT_HOME");
         System.clearProperty(CommandChannelServerMain.CONFIG_FILE_PROP);
         CommandChannelServerMain.setIPCService(null);
         CommandChannelServerMain.setSSLConfigurationParser(new SSLConfigurationParser());
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -186,7 +186,11 @@
         when(fsUtils.getOwner(scriptPath)).thenReturn(principal);
         delegate.startListening("127.0.0.1", 123);
         
-        verify(ipcService).createServer(IPC_SERVER_NAME, delegate, principal);
+        if (OS.IS_WINDOWS) {
+            verify(ipcService).createServer(IPC_SERVER_NAME, delegate);
+        } else { // Unix and macOS
+            verify(ipcService).createServer(IPC_SERVER_NAME, delegate, principal);
+        }
         verify(processCreator).startProcess(any(ProcessBuilder.class));
     }
     
--- a/agent/core/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/agent/core/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -135,7 +135,31 @@
           </instructions>
         </configuration>
       </plugin>
-      
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <overwrite>true</overwrite>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>../../common/portability/target</directory>
+                  <includes>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -48,6 +48,7 @@
 import java.lang.ProcessBuilder.Redirect;
 import java.util.List;
 
+import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.testutils.TestUtils;
 import org.junit.Before;
 import org.junit.Test;
@@ -93,16 +94,27 @@
         
         // Check process arguments
         List<String> args = builder.command();
-        assertEquals(5, args.size());
+        int expectedArgCount = OS.IS_WINDOWS ? 7 : 5; // account for extra "cmd", "/c" args on Windows
+        assertEquals(expectedArgCount, args.size());
 
-        final String arg0 = TestUtils.convertWinPathToUnixPath(args.get(0));
-        final String arg3 = TestUtils.convertWinPathToUnixPath(args.get(3));
+        if (OS.IS_WINDOWS) {
+            final String arg2 = TestUtils.convertWinPathToUnixPath(args.get(2));
+            final String arg5 = TestUtils.convertWinPathToUnixPath(args.get(5));
 
-        assertEquals("/path/to/thermostat/bin/thermostat-agent-proxy", arg0);
-        assertEquals("9000", args.get(1));
-        assertEquals("Hello", args.get(2));
-        assertEquals("/path/to/ipc/config", arg3);
-        assertEquals(SERVER_NAME, args.get(4));
+            assertEquals("cmd", args.get(0));
+            assertEquals("/C", args.get(1));
+            assertEquals("/path/to/thermostat/bin/thermostat-agent-proxy.cmd", arg2);
+            assertEquals("9000", args.get(3));
+            assertEquals("Hello", args.get(4));
+            assertEquals("/path/to/ipc/config", arg5);
+            assertEquals(SERVER_NAME, args.get(6));
+        } else {
+            assertEquals("/path/to/thermostat/bin/thermostat-agent-proxy", args.get(0));
+            assertEquals("9000", args.get(1));
+            assertEquals("Hello", args.get(2));
+            assertEquals("/path/to/ipc/config", args.get(3));
+            assertEquals(SERVER_NAME, args.get(4));
+        }
         
         // Check cleanup
         verify(proxy).waitFor();
--- a/agent/ipc/unix-socket/common/src/test/java/com/redhat/thermostat/agent/ipc/unixsocket/common/internal/UnixSocketIPCPropertiesTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/agent/ipc/unix-socket/common/src/test/java/com/redhat/thermostat/agent/ipc/unixsocket/common/internal/UnixSocketIPCPropertiesTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -52,7 +52,7 @@
 
 public class UnixSocketIPCPropertiesTest {
     
-    private static final String SOCKET_DIR_PATH = "/path/to/sockets";
+    private static final String SOCKET_DIR_PATH = new File("/path/to/sockets").getAbsolutePath();
     
     private Properties jProps;
     private File propFile;
@@ -84,7 +84,7 @@
         when(jProps.getProperty(UnixSocketIPCProperties.PROP_UNIX_SOCKET_DIR)).thenReturn(null);
         when(pathUtils.getSystemProperty("java.io.tmpdir")).thenReturn("/path/to/tmp");
         UnixSocketIPCProperties props = new UnixSocketIPCProperties(jProps, propFile, pathUtils);
-        assertEquals("/path/to/tmp/thermostat-socks", props.getSocketDirectory().getAbsolutePath());
+        assertEquals(new File("/path/to/tmp/thermostat-socks").getAbsolutePath(), props.getSocketDirectory().getAbsolutePath());
     }
     
     @Test(expected=IOException.class)
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -49,6 +49,7 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -64,7 +65,10 @@
     
     private static final String JMX_URL = "service:jmx:rmi://myHost:1099/blah";
     private static final String IPC_SERVER_NAME = "agent-proxy-8000";
-    
+    private static final String IGNORED_PATH = "/";
+    private static final String THERMOSTAT_HOME_PROP = "THERMOSTAT_HOME";
+    private static final String USER_THERMOSTAT_HOME_PROP = "USER_THERMOSTAT_HOME";
+
     private AgentProxyControlImpl control;
     private ClientIPCService ipcService;
     private IPCMessageChannel channel;
@@ -83,11 +87,21 @@
         channel = mock(IPCMessageChannel.class);
         when(ipcService.connectToServer(IPC_SERVER_NAME)).thenReturn(channel);
         AgentProxy.setIPCService(ipcService);
+
+        if (OS.IS_WINDOWS) {
+            // Agent Proxy now uses a native DLL for Windows named pipes on Windows
+            // because of this, CommonPathsImpl attempts to initialize.
+            // CommonPathsImpl has not defaults for these values
+            System.setProperty(THERMOSTAT_HOME_PROP, IGNORED_PATH);
+            System.setProperty(USER_THERMOSTAT_HOME_PROP, IGNORED_PATH);
+        }
     }
     
     @After
     public void teardown() throws Exception {
         System.clearProperty(AgentProxy.CONFIG_FILE_PROP);
+        System.clearProperty(THERMOSTAT_HOME_PROP);
+        System.clearProperty(USER_THERMOSTAT_HOME_PROP);
         AgentProxy.setControlCreator(new ControlCreator());
         AgentProxy.setIPCService(null);
     }
--- a/common/core/src/test/java/com/redhat/thermostat/common/cli/BorderedTableRendererTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/cli/BorderedTableRendererTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -69,7 +69,7 @@
         assertEquals("+-----+-----+-----+\n" +
                 "| Foo | Bar | Baz |\n" +
                 "+-----+-----+-----+\n" +
-                "+-----+-----+-----+\n", new String(out.toByteArray()));
+                "+-----+-----+-----+\n", new String(out.toByteArray()).replace("\r", ""));
     }
 
     @Test
@@ -85,7 +85,7 @@
                 "| hello      | fluff            | world    |\n" +
                 "| looooooong | f1               | foobar   |\n" +
                 "| f2         | shoooooooooooort | poo      |\n" +
-                "+------------+------------------+----------+\n", new String(out.toByteArray()));
+                "+------------+------------------+----------+\n", new String(out.toByteArray()).replace("\r", ""));
     }
 
     @Test
@@ -101,7 +101,7 @@
                 "| hello      | fluff            | world    |\n" +
                 "| looooooong | f1               | foobar   |\n" +
                 "| f2         | shoooooooooooort | poo      |\n" +
-                "+------------+------------------+----------+\n", new String(out.toByteArray()));
+                "+------------+------------------+----------+\n", new String(out.toByteArray()).replace("\r", ""));
         btr.printLine("newwwwwwwwwwww", "line", "added");
         btr.render(out = new ByteArrayOutputStream());
         assertEquals("+----------------+------------------+----------+\n" +
@@ -111,6 +111,6 @@
                 "| looooooong     | f1               | foobar   |\n" +
                 "| f2             | shoooooooooooort | poo      |\n" +
                 "| newwwwwwwwwwww | line             | added    |\n" +
-                "+----------------+------------------+----------+\n", new String(out.toByteArray()));
+                "+----------------+------------------+----------+\n", new String(out.toByteArray()).replace("\r", ""));
     }
 }
\ No newline at end of file
--- a/common/portability/Makefile	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/Makefile	Wed Mar 08 09:24:27 2017 -0500
@@ -6,6 +6,7 @@
 
 CLASSPATH  = target/classes/
 TARGET_DIR = target
+EXECUTABLE = $(SO_PREFIX)thermostat-common-portability$(SO_SUFFIX)
 
 ifeq ($(JNI_PLATFORM),win32)
     JNI_PLATFORM = win32
@@ -32,40 +33,34 @@
 HOSTNAME_SOURCES    = src/main/native/HostName.c
 HOSTNAME_TARGET     = $(TARGET_DIR)/HostName.c
 HOSTNAME_OBJECTS    = $(HOSTNAME_TARGET:.c=.o)
-HOSTNAME_EXECUTABLE = $(SO_PREFIX)HostNameWrapper$(SO_SUFFIX)
 
 USERNAME_SOURCES    = src/main/native/UserNameUtilImpl.c
 USERNAME_TARGET     = $(TARGET_DIR)/UserNameUtilImpl.c
 USERNAME_OBJECTS    = $(USERNAME_TARGET:.c=.o)
-USERNAME_EXECUTABLE = $(SO_PREFIX)UserNameUtilWrapper$(SO_SUFFIX)
 
 ifeq ($(JNI_PLATFORM),win32)
 HELPER_SOURCES    = src/main/native/WindowsHelperImpl.c
 HELPER_TARGET     = $(TARGET_DIR)/WindowsHelperImpl.c
 HELPER_OBJECTS    = $(HELPER_TARGET:.c=.o)
-HELPER_EXECUTABLE = $(SO_PREFIX)WindowsHelperWrapper$(SO_SUFFIX)
 endif
 
 ifeq ($(JNI_PLATFORM),darwin)
 HELPER_SOURCES    = src/main/native/MacOSHelperImpl.c
 HELPER_TARGET     = $(TARGET_DIR)/MacOSHelperImpl.c
 HELPER_OBJECTS    = $(HELPER_TARGET:.c=.o)
-HELPER_EXECUTABLE = $(SO_PREFIX)MacOSHelperWrapper$(SO_SUFFIX)
 endif
 
-EXECUTABLES          = $(HOSTNAME_EXECUTABLE) $(USERNAME_EXECUTABLE)
+EXECUTABLES          = $(EXECUTABLE)
 
 .PHONY:UserNameUtilImpl
 JNI_LIST = com.redhat.thermostat.common.portability.HostName com.redhat.thermostat.common.portability.internal.linux.UserNameUtilImpl
 
 ifeq ($(JNI_PLATFORM),win32)
-    EXECUTABLES  += $(HELPER_EXECUTABLE)
     JNI_LIST     +=  com.redhat.thermostat.common.portability.internal.windows.WindowsHelperImpl
     HELPER_LIBS  += -l psapi -l Netapi32
 endif
 
 ifeq ($(JNI_PLATFORM),darwin)
-    EXECUTABLES  += $(HELPER_EXECUTABLE)
     JNI_LIST     +=  com.redhat.thermostat.common.portability.internal.macos.MacOSHelperImpl
 endif
 
@@ -82,14 +77,9 @@
 	$(COPY) $(HELPER_SOURCES) $(HELPER_TARGET)
 endif
 
-$(HOSTNAME_EXECUTABLE): $(HOSTNAME_OBJECTS)
-	$(CC) $(MYLDFLAGS) $(LDFLAGS) $(HOSTNAME_OBJECTS) $(PLATFORM_LIBS) -o $(TARGET_DIR)/$@
+$(EXECUTABLE): $(HOSTNAME_OBJECTS) $(USERNAME_OBJECTS) $(HELPER_OBJECTS)
+	$(CC) $(MYLDFLAGS) $(LDFLAGS) $(HOSTNAME_OBJECTS) $(USERNAME_OBJECTS) $(HELPER_OBJECTS) $(PLATFORM_LIBS) $(HELPER_LIBS) -o $(TARGET_DIR)/$@
 
-$(USERNAME_EXECUTABLE): $(USERNAME_OBJECTS)
-	$(CC) $(MYLDFLAGS) $(LDFLAGS) $(USERNAME_OBJECTS) $(PLATFORM_LIBS) -o $(TARGET_DIR)/$@
-
-$(HELPER_EXECUTABLE): $(HELPER_OBJECTS)
-	$(CC) $(MYLDFLAGS) $(LDFLAGS) $(HELPER_OBJECTS) $(PLATFORM_LIBS) $(HELPER_LIBS) -o $(TARGET_DIR)/$@
 
 .c.o:
 	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
@@ -98,14 +88,12 @@
 	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
 
 clean-lib:
-	rm -f $(TARGET_DIR)/$(HOSTNAME_EXECUTABLE)
-	rm -f $(TARGET_DIR)/$(USERNAME_EXECUTABLE)
-	rm -f $(TARGET_DIR)/$(HELPER_EXECUTABLE)
+	rm -f $(TARGET_DIR)/$(EXECUTABLE)
 
 clean-obj:
-	rm -f $(HOSTNAME_OBJECTS) $(HOSTNAME_TARGET)
-	rm -f $(USERNAME_OBJECTS) $(USERNAME_TARGET)
-	rm -f $(HELPER_OBJECTS) $(HELPER_TARGET)
+	rm -f $(HOSTNAME_OBJECTS)
+	rm -f $(USERNAME_OBJECTS)
+	rm -f $(HELPER_OBJECTS)
 
 clean: clean-obj clean-lib
 
--- a/common/portability/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -161,6 +161,28 @@
             </plugin>
 
             <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <phase>test-compile</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</file>
+                                    <classifier>shared-library</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <configuration>
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/HostName.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/HostName.java	Wed Mar 08 09:24:27 2017 -0500
@@ -36,18 +36,13 @@
 
 package com.redhat.thermostat.common.portability;
 
-import com.redhat.thermostat.shared.config.NativeLibraryResolver;
+import com.redhat.thermostat.common.portability.internal.PortableNativeLibraryLoader;
 
 /**
  * Finds the current host name without doing a DNS lookup
  */
-public class HostName {
+public class HostName extends PortableNativeLibraryLoader {
 
-    static {
-        String lib = NativeLibraryResolver.getAbsoluteLibraryPath("HostNameWrapper");
-        System.load(lib);
-    }
-    
     public static String getLocalHostName() {
         return getHostName();
     }
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/ProcessUserInfo.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/ProcessUserInfo.java	Wed Mar 08 09:24:27 2017 -0500
@@ -70,14 +70,11 @@
         final ProcessUserInfoBuilder builder;
         if (OS.IS_LINUX) {
             builder = new LinuxProcessUserInfoBuilderImpl(source, userNameUtil);
-        }
-        else if (OS.IS_WINDOWS) {
+        } else if (OS.IS_WINDOWS) {
             builder = new WindowsUserInfoBuilderImpl();
-        }
-        else if (OS.IS_MACOS) {
+        } else if (OS.IS_MACOS) {
             builder = new MacOSUserInfoBuilderImpl();
-        }
-        else {
+        } else {
             throw new UnimplementedError("ProcessUserInfo");
         }
         return builder;
@@ -87,11 +84,9 @@
         final ProcessUserInfoBuilder builder;
         if (OS.IS_LINUX) {
             builder = new LinuxProcessUserInfoBuilderImpl();
-        }
-        else if (OS.IS_WINDOWS) {
+        } else if (OS.IS_WINDOWS) {
             builder = new WindowsUserInfoBuilderImpl();
-        }
-        else {
+        } else {
             builder = new MacOSUserInfoBuilderImpl();
         }
         return builder;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/PortableNativeLibraryLoader.java	Wed Mar 08 09:24:27 2017 -0500
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.portability.internal;
+
+import com.redhat.thermostat.shared.config.NativeLibraryResolver;
+import java.util.logging.Logger;
+
+public class PortableNativeLibraryLoader {
+
+    private static boolean nativeLibraryLoaded;
+
+    protected static boolean isNativeLibraryLoaded() {
+        return nativeLibraryLoaded;
+    }
+
+    static {
+        final String libfn = NativeLibraryResolver.getAbsoluteLibraryPath("thermostat-common-portability");
+        try {
+            System.load(libfn);
+            nativeLibraryLoaded = true;
+        } catch (UnsatisfiedLinkError e) {
+            nativeLibraryLoaded = false;
+            Logger logger = Logger.getLogger(PortableNativeLibraryLoader.class.getName());
+            logger.warning("Could not load thermostat-common-portability library:" + libfn);
+        }
+    }
+}
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/linux/UserNameUtilImpl.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/linux/UserNameUtilImpl.java	Wed Mar 08 09:24:27 2017 -0500
@@ -40,14 +40,9 @@
 
 import com.redhat.thermostat.common.portability.UserNameLookupException;
 import com.redhat.thermostat.common.portability.UserNameUtil;
-import com.redhat.thermostat.shared.config.NativeLibraryResolver;
+import com.redhat.thermostat.common.portability.internal.PortableNativeLibraryLoader;
 
-public class UserNameUtilImpl implements UserNameUtil {
-    
-    static {
-        String lib = NativeLibraryResolver.getAbsoluteLibraryPath("UserNameUtilWrapper");
-        System.load(lib);
-    }
+public class UserNameUtilImpl extends PortableNativeLibraryLoader implements UserNameUtil {
     
     public String getUserName(long uid) throws UserNameLookupException {
         String username = null;
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/macos/MacOSHelperImpl.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/macos/MacOSHelperImpl.java	Wed Mar 08 09:24:27 2017 -0500
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.common.portability.internal.macos;
 
+import com.redhat.thermostat.common.portability.internal.PortableNativeLibraryLoader;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.NativeLibraryResolver;
 import com.redhat.thermostat.shared.config.OS;
@@ -48,7 +49,7 @@
 /**
  * Utility class to access Windows native code
  */
-public class MacOSHelperImpl {
+public class MacOSHelperImpl extends PortableNativeLibraryLoader {
 
     private static final Logger logger = LoggingUtils.getLogger(MacOSHelperImpl.class);
 
@@ -57,20 +58,8 @@
     public static MacOSHelperImpl INSTANCE;
 
     static {
-        if (OS.IS_MACOS) {
-            String lib = NativeLibraryResolver.getAbsoluteLibraryPath("MacOSHelperWrapper");
-            try {
-                System.load(lib);
-                INSTANCE = new MacOSHelperImpl();
-                pagesize = (int)getLongSysctl0("vm.pagesize");
-            } catch (UnsatisfiedLinkError e) {
-                logger.severe("Could not load MacOSHelperWrapper DLL:" + lib);
-                INSTANCE = null;
-                // do not throw here, because you'll get a NoClassDefFound thrown when running other tests that Mock this class
-            }
-        } else {
-            INSTANCE = null;
-        }
+        INSTANCE = OS.IS_MACOS && isNativeLibraryLoaded() ? new MacOSHelperImpl() : null;
+        pagesize = INSTANCE != null ? (int)getLongSysctl0("vm.pagesize") : 0;
     }
 
     private MacOSHelperImpl() {
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsHelperImpl.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsHelperImpl.java	Wed Mar 08 09:24:27 2017 -0500
@@ -36,22 +36,18 @@
 
 package com.redhat.thermostat.common.portability.internal.windows;
 
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.NativeLibraryResolver;
+import com.redhat.thermostat.common.portability.internal.PortableNativeLibraryLoader;
 import com.redhat.thermostat.shared.config.OS;
 
 import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.logging.Logger;
 
 /**
  * Utility class to access Windows native code
  */
-public class WindowsHelperImpl {
-
-    private static final Logger logger = LoggingUtils.getLogger(WindowsHelperImpl.class);
+public class WindowsHelperImpl extends PortableNativeLibraryLoader {
 
     public static WindowsHelperImpl INSTANCE;
 
@@ -83,19 +79,7 @@
      */
 
     static {
-        if (OS.IS_WINDOWS) {
-            String lib = NativeLibraryResolver.getAbsoluteLibraryPath("WindowsHelperWrapper");
-            try {
-                System.load(lib);
-                INSTANCE = new WindowsHelperImpl();
-            } catch (UnsatisfiedLinkError e) {
-                logger.severe("Could not load WindowsHelperImpl DLL:" + lib);
-                INSTANCE = null;
-                // do not throw here, because you'll get a NoClassDefFound thrown when running other tests that Mock this class
-            }
-        } else {
-            INSTANCE = null;
-        }
+        INSTANCE = OS.IS_WINDOWS && isNativeLibraryLoaded() ? new WindowsHelperImpl() : null;
     }
 
     private WindowsHelperImpl() {
@@ -275,6 +259,10 @@
         return info;
     }
 
+    public int getLastError() {
+        return getLastError0();
+    }
+
     public long getProcessHandle(int pid) {
         return getProcessHandle0(pid);
     }
@@ -302,6 +290,8 @@
     private static native int getCPUCount0();
     private static native long queryPerformanceFrequency0();
 
+    private static native int getLastError0();
+
     private static native String getProcessSID0(int pid);
     private static native String getUserName0(int pid, boolean prependDomain);
     private static native Object getEnvironment0(long hProcess, int mode); // mode = 0 returns DirectByteBuffer, 1 = String cwd, 2 = String execuatable, 3 = String command line
--- a/common/portability/src/main/native/WindowsHelperImpl.c	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/main/native/WindowsHelperImpl.c	Wed Mar 08 09:24:27 2017 -0500
@@ -152,6 +152,12 @@
     return TRUE;
 }
 
+JNIEXPORT jint JNICALL Java_com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl_getLastError0
+  (JNIEnv *env, jclass winHelperClass)
+{
+    return GetLastError();
+}
+
 /*
  * Class:     com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl
  * Method:    getCPUString0
@@ -159,6 +165,7 @@
  */
 JNIEXPORT jstring JNICALL Java_com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl_getCPUString0
   (JNIEnv *env, jclass winHelperClass) {
+
     // Get extended ids.
     int CPUInfo[4] = {-1};
     __cpuid(CPUInfo, 0x80000000);
@@ -352,7 +359,7 @@
     wchar_t lpDomain[MAX_NAME*2 + 1];  // room for '\' + lpName
     jstring s = NULL;
 
-    if( !LookupAccountSidW(NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType)) {
+    if (!LookupAccountSidW(NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType)) {
         DWORD dwResult = GetLastError();
         if(dwResult == ERROR_NONE_MAPPED) {
             wcscpy(lpName, L"NONE_MAPPED");
@@ -676,6 +683,7 @@
  */
 JNIEXPORT jboolean JNICALL Java_com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl_getProcessInfo0
   (JNIEnv *env, jclass winHelperClass, jint pid, jlongArray array) {
+
     testLength(env, array, 4);
 
     HANDLE hProcess;
@@ -723,6 +731,7 @@
  */
 JNIEXPORT jboolean JNICALL Java_com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl_getProcessIOInfo0
   (JNIEnv *env, jclass winHelperClass, jint pid, jlongArray array) {
+
     testLength(env, array, 6);
 
     HANDLE hProcess;
@@ -753,7 +762,6 @@
     return TRUE;
 }
 
-
 /*
  * Class:     com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl
  * Method:    getProcessHandle0
--- a/common/portability/src/test/java/com/redhat/thermostat/common/portability/ProcessCheckerTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/test/java/com/redhat/thermostat/common/portability/ProcessCheckerTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -37,24 +37,31 @@
 package com.redhat.thermostat.common.portability;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.io.File;
 
+import com.redhat.thermostat.shared.config.OS;
+import org.junit.Assume;
 import org.junit.Test;
 
 public class ProcessCheckerTest {
 
+    // only Linux (and other /proc OS) can test process.exists(pid) like this
+
     private static final int SOME_PID = 80980;
     
     @Test
     public void testProcessExists() {
+        assumeTrue(OS.IS_LINUX);
         basicTest(true);
     }
     
     @Test
     public void testProcessNotExisting() {
+        assumeTrue(OS.IS_LINUX);
         basicTest(false);
     }
     
--- a/common/portability/src/test/java/com/redhat/thermostat/common/portability/internal/linux/LinuxPortableProcessStatBuilderImplTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/common/portability/src/test/java/com/redhat/thermostat/common/portability/internal/linux/LinuxPortableProcessStatBuilderImplTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -38,6 +38,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -47,6 +50,7 @@
 import java.io.StringReader;
 
 import com.redhat.thermostat.common.portability.PortableProcessStat;
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.Test;
 
 import com.redhat.thermostat.common.portability.linux.ProcDataSource;
@@ -57,11 +61,16 @@
     public void testSimpleProcessStatus() {
         ProcDataSource dataSource = new ProcDataSource();
         PortableProcessStat stat = new LinuxPortableProcessStatBuilderImpl(dataSource).build(1);
-        assertNotNull(stat);
+        if (OS.IS_LINUX) {
+            assertNotNull(stat);
+        } else {
+            assertNull(stat);
+        }
     }
 
     @Test
     public void testKnownProcessStatus() throws IOException {
+        assumeTrue(OS.IS_LINUX);
         final int PID = 10363;
         String PROCESS_NAME = "(bash)";
         String STATE = "S";
@@ -102,6 +111,7 @@
 
     @Test
     public void testBadProcessName() throws IOException {
+        assumeTrue(OS.IS_LINUX);
         final int PID = 10363;
         String PROCESS_NAME = "(secretly-bad process sleep 10 20 ) 6)";
         String STATE = "S";
--- a/config/src/main/java/com/redhat/thermostat/shared/config/OS.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/OS.java	Wed Mar 08 09:24:27 2017 -0500
@@ -62,6 +62,11 @@
      */
     public static final boolean IS_MACOS;
 
+    /*
+     * the standandard line ending for this OS
+     */
+    public static final String EOL = System.getProperty("line.separator");
+
     static {
         final String osname = System.getProperty("os.name").toLowerCase();
 
@@ -70,5 +75,7 @@
 
         IS_MACOS = osname.contains("os x") || osname.contains("mac") || osname.contains("darwin");
         IS_LINUX = osname.contains("linux");
+
+
     }
 }
--- a/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/StoragePopulatorCommandTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/StoragePopulatorCommandTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -61,6 +61,7 @@
 
 import com.redhat.thermostat.common.cli.CliCommandOption;
 import com.redhat.thermostat.common.cli.TabCompleter;
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -145,7 +146,7 @@
 
         command.run(ctx);
         String errorString = new String(errorBAOS.toByteArray());
-        assertEquals("Config file \"/foo/bar/config\" does not exist!\n", errorString);
+        assertEquals("Config file \"/foo/bar/config\" does not exist!" + OS.EOL, errorString);
     }
 
     @Test
@@ -164,7 +165,7 @@
 
         command.run(ctx);
         String errorString = new String(errorBAOS.toByteArray());
-        assertEquals("Failed to parse config file.\n", errorString);
+        assertEquals("Failed to parse config file." + OS.EOL, errorString);
     }
 
     @Test
@@ -181,7 +182,7 @@
 
         command.run(ctx);
         String errorString = new String(errorBAOS.toByteArray());
-        assertEquals("No populator for collection \"foo\" found.\n", errorString);
+        assertEquals("No populator for collection \"foo\" found." + OS.EOL, errorString);
     }
 
     @Test
--- a/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/BasePopulatorTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/BasePopulatorTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -43,6 +43,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -100,7 +101,7 @@
         for (int i = 0; i < (expectedCount - 1); i++) {
             expected = expected + ".";
         }
-        expected = expected + "Items have arrived.\n";
+        expected = expected + "Items have arrived." + OS.EOL;
 
         String outputString = new String(outputBAOS.toByteArray());
         assertEquals(expected, outputString);
@@ -116,7 +117,7 @@
 
         populator.reportSubmitted(item, totalCount, console);
 
-        String expectedString  = "Submitted " + totalCount + " " + name + " records to storage.\n";
+        String expectedString  = "Submitted " + totalCount + " " + name + " records to storage." + OS.EOL;
         String outputString = new String(outputBAOS.toByteArray());
         assertEquals(expectedString, outputString);
     }
--- a/distribution/assembly/core-assembly-agent-macosx.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/distribution/assembly/core-assembly-agent-macosx.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -92,9 +92,7 @@
       <outputDirectory>native</outputDirectory>
       <directory>${main.basedir}/common/portability/target</directory>
       <includes>
-        <include>libHostNameWrapper${sharedlib.suffix}</include>
-        <include>libUserNameUtilWrapper${sharedlib.suffix}</include>
-        <include>libMacOSHelperWrapper${sharedlib.suffix}</include>
+        <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include>
       </includes>
     </fileSet>
   </fileSets>
--- a/distribution/assembly/core-assembly-agent-windows.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/distribution/assembly/core-assembly-agent-windows.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -88,9 +88,7 @@
       <outputDirectory>native</outputDirectory>
       <directory>${main.basedir}/common/portability/target</directory>
       <includes>
-        <include>HostNameWrapper${sharedlib.suffix}</include>
-        <include>UserNameUtilWrapper${sharedlib.suffix}</include>
-        <include>WindowsHelperWrapper${sharedlib.suffix}</include>
+        <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include>
       </includes>
     </fileSet>
     <fileSet>
--- a/distribution/assembly/core-assembly-agent.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/distribution/assembly/core-assembly-agent.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -99,8 +99,7 @@
       <outputDirectory>native</outputDirectory>
       <directory>${main.basedir}/common/portability/target</directory>
       <includes>
-        <include>libHostNameWrapper${sharedlib.suffix}</include>
-        <include>libUserNameUtilWrapper${sharedlib.suffix}</include>
+        <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include>
       </includes>
     </fileSet>
   </fileSets>
--- a/distribution/assembly/core-assembly-macosx.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/distribution/assembly/core-assembly-macosx.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -95,9 +95,7 @@
       <outputDirectory>native</outputDirectory>
       <directory>${main.basedir}/common/portability/target</directory>
       <includes>
-        <include>libHostNameWrapper${sharedlib.suffix}</include>
-        <include>libUserNameUtilWrapper${sharedlib.suffix}</include>
-        <include>libMacOSHelperWrapper${sharedlib.suffix}</include>
+        <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include>
       </includes>
     </fileSet>
   </fileSets>
--- a/distribution/assembly/core-assembly-windows.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/distribution/assembly/core-assembly-windows.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -91,9 +91,7 @@
       <outputDirectory>native</outputDirectory>
       <directory>${main.basedir}/common/portability/target</directory>
       <includes>
-        <include>HostNameWrapper${sharedlib.suffix}</include>
-        <include>UserNameUtilWrapper${sharedlib.suffix}</include>
-        <include>WindowsHelperWrapper${sharedlib.suffix}</include>
+        <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include>
       </includes>
     </fileSet>
     <fileSet>
--- a/distribution/assembly/core-assembly.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/distribution/assembly/core-assembly.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -102,8 +102,7 @@
       <outputDirectory>native</outputDirectory>
       <directory>${main.basedir}/common/portability/target</directory>
       <includes>
-        <include>libHostNameWrapper${sharedlib.suffix}</include>
-        <include>libUserNameUtilWrapper${sharedlib.suffix}</include>
+        <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include>
       </includes>
     </fileSet>
     <fileSet>
--- a/host-cpu/agent/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/host-cpu/agent/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -38,14 +38,17 @@
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+
   <parent>
     <artifactId>thermostat-host-cpu</artifactId>
     <groupId>com.redhat.thermostat</groupId>
     <version>1.99.12-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-host-cpu-agent</artifactId>
   <packaging>bundle</packaging>
   <name>Thermostat Host CPU Agent plugin</name>
+
   <build>
     <plugins>
       <plugin>
@@ -66,8 +69,44 @@
           </instructions>
         </configuration>
       </plugin>
+
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <overwrite>true</overwrite>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>../../common/portability/target</directory>
+                  <includes>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <systemPropertyVariables>
+            <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
+
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
@@ -96,6 +135,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-portability</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-host-cpu-common</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/host-cpu/agent/src/test/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilderTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/host-cpu/agent/src/test/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilderTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -47,6 +47,8 @@
 import java.io.IOException;
 import java.io.StringReader;
 
+import com.redhat.thermostat.shared.config.OS;
+import org.junit.Assume;
 import org.junit.Test;
 
 import com.redhat.thermostat.common.portability.linux.ProcDataSource;
@@ -78,6 +80,7 @@
 
     @Test
     public void testBuildCpuStatFromFile() throws IOException {
+        Assume.assumeTrue(OS.IS_LINUX); // only Linux builds from /proc
         long CLOCK1 = 1000;
         long CLOCK2 = 2000;
 
--- a/host-memory/agent/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/host-memory/agent/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -38,14 +38,18 @@
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+
   <parent>
     <artifactId>thermostat-host-memory</artifactId>
     <groupId>com.redhat.thermostat</groupId>
     <version>1.99.12-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-host-memory-agent</artifactId>
   <packaging>bundle</packaging>
+
   <name>Thermostat Host Memory Agent plugin</name>
+
   <build>
     <plugins>
       <plugin>
@@ -66,8 +70,44 @@
           </instructions>
         </configuration>
       </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <overwrite>true</overwrite>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>../../common/portability/target</directory>
+                  <includes>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <!-- the test needs to link to common-portability native libraries -->
+          <systemPropertyVariables>
+            <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
+
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
@@ -96,6 +136,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-portability</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-host-memory-common</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/host-memory/agent/src/test/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilderTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/host-memory/agent/src/test/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilderTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -46,6 +46,8 @@
 import java.io.IOException;
 import java.io.StringReader;
 
+import com.redhat.thermostat.shared.config.OS;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -68,10 +70,13 @@
     public void testSimpleBuild() {
         MemoryStat stat = new MemoryStatBuilder(new ProcDataSource(), writerId).build();
         assertNotNull(stat);
+        assertTrue(stat.getFree() <= stat.getTotal());
+        assertTrue(stat.getSwapFree() <= stat.getSwapTotal());
     }
 
     @Test
     public void testEmptyBuild() throws IOException {
+        Assume.assumeTrue(OS.IS_LINUX);
         String memory = "";
         StringReader memoryReader = new StringReader(memory);
         ProcDataSource dataSource = mock(ProcDataSource.class);
@@ -84,6 +89,7 @@
 
     @Test
     public void testBuild() throws IOException {
+        Assume.assumeTrue(OS.IS_LINUX);
         int i = 1;
         final long TOTAL = i++;
         final long FREE = i++;
--- a/integration-tests/itest-run/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/integration-tests/itest-run/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -162,7 +162,7 @@
     								</goals>
     							</pluginExecutionFilter>
     							<action>
-    								<ignore></ignore>
+    								<ignore/>
     							</action>
     						</pluginExecution>
     					</pluginExecutions>
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/EnvironmentExecutor.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/EnvironmentExecutor.java	Wed Mar 08 09:24:27 2017 -0500
@@ -43,6 +43,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
+import com.redhat.thermostat.shared.config.OS;
 import expectj.Executor;
 
 /**
@@ -86,6 +87,10 @@
     List<String> buildCommmands() {
         List<String> commands = new ArrayList<>(1 + args.length);
         String command = buildScriptPath();
+        if (OS.IS_WINDOWS) {
+            commands.add("cmd.exe");
+            commands.add("/c");
+        }
         commands.add(command);
         commands.addAll(Arrays.asList(args));
         return commands;
--- a/keyring/src/main/java/com/redhat/thermostat/utils/keyring/internal/Activator.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/keyring/src/main/java/com/redhat/thermostat/utils/keyring/internal/Activator.java	Wed Mar 08 09:24:27 2017 -0500
@@ -81,8 +81,7 @@
         } catch (UnsatisfiedLinkError e) {
             if (OS.IS_LINUX) {
                 theKeyring = new DummyKeyringImpl();
-            }
-            else {
+            } else {
                 ServiceTracker<CommonPaths,CommonPaths> pathTracker = new ServiceTracker<CommonPaths,CommonPaths>(context,CommonPaths.class.getName(), null) {
                     @Override
                     public CommonPaths addingService(ServiceReference<CommonPaths> reference) {
--- a/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaLinuxCollectorTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaLinuxCollectorTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -48,7 +48,9 @@
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -160,6 +162,7 @@
 
     @Test
     public void testDefaultDir() {
+        Assume.assumeTrue(OS.IS_LINUX); // tries to access a directory that's only in linux
         NumaLinuxCollectorImpl coll = new NumaLinuxCollectorImpl();
         assertEquals("/sys/devices/system/node", coll.getBaseDir());
     }
--- a/setup/command/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/setup/command/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -71,6 +71,17 @@
           </instructions>
         </configuration>
       </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <!-- the test needs to link to common-portability native libraries -->
+          <systemPropertyVariables>
+            <com.redhat.thermostat.shared.loader.testNativesHome>${root.project.directory}/common/portability/target/</com.redhat.thermostat.shared.loader.testNativesHome>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
   
--- a/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/CredentialsFileCreator.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/CredentialsFileCreator.java	Wed Mar 08 09:24:27 2017 -0500
@@ -62,7 +62,10 @@
                 // on windows, credentials may be globally visible.
                 // PosixFilePermissions don't work on windows (throws exception even!)
                 // the code below doesn't enforce this (but should)
-                final boolean success = file.createNewFile() && file.setReadable(true, true) && file.setWritable(true, true);
+
+                // during JUnit, this can be a mock.  Call the real method
+                final boolean wasCreated = new File(file.toPath().toString()).createNewFile();
+                final boolean setParams = wasCreated && file.setReadable(true, true) && file.setWritable(true, true);
             }
         }
     }
--- a/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/CLISetupTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/CLISetupTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -50,6 +50,7 @@
 import java.io.IOException;
 import java.io.PrintStream;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -195,7 +196,7 @@
         String output = new String(bout.toByteArray());
         assertTrue("Expected client-user in output. Got: " + output, output.contains("client-user"));
         assertTrue("Expected agent-user in output. Got: " + output, output.contains("agent-user"));
-        assertEquals("Both client and agent usernames cannot be 'identical-user'!\n", new String(berr.toByteArray()));
+        assertEquals("Both client and agent usernames cannot be 'identical-user'!" + OS.EOL, new String(berr.toByteArray()));
     }
     
     @Test
--- a/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/PasswordCredentialsReaderTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/PasswordCredentialsReaderTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -78,9 +78,9 @@
         when(console.getInput()).thenReturn(new ByteArrayInputStream(input.getBytes()));
         char[] password = credsReader.readPassword();
         assertEquals("second", new String(password));
-        assertEquals("Passwords did not match!\n", new String(berr.toByteArray()));
+        assertEquals("Passwords did not match!\n", bosToUnixString(berr));
         assertEquals("tell me the password: \nrepeat the password: \ntell me the password: \nrepeat the password: \n",
-                makeNewlinesConsistent(new String(bout.toByteArray())));
+                bosToUnixString(bout));
     }
     
     @Test
@@ -89,9 +89,9 @@
         when(console.getInput()).thenReturn(new ByteArrayInputStream(input.getBytes()));
         char[] password = credsReader.readPassword();
         assertEquals("a", new String(password));
-        assertEquals("Chosen password invalid!\n", makeNewlinesConsistent(new String(berr.toByteArray())));
+        assertEquals("Chosen password invalid!\n", bosToUnixString(berr));
         assertEquals("tell me the password: \nrepeat the password: \ntell me the password: \nrepeat the password: \n",
-                makeNewlinesConsistent(new String(bout.toByteArray())));
+                bosToUnixString(bout));
     }
     
     @Test
@@ -101,7 +101,7 @@
         char[] password = credsReader.readPassword();
         assertArrayEquals(new char[] { 'b', 'a', 'r' }, password);
         assertEquals("Expected no errors", "", new String(berr.toByteArray()));
-        assertEquals("tell me the password: \nrepeat the password: \n", makeNewlinesConsistent(new String(bout.toByteArray())));
+        assertEquals("tell me the password: \nrepeat the password: \n", bosToUnixString(bout));
     }
     
     @Test
@@ -111,7 +111,7 @@
         char[] password = credsReader.readPassword();
         assertArrayEquals(new char[] { 'b', 'a', 'r' }, password);
         assertEquals("Expected no errors", "", new String(berr.toByteArray()));
-        assertEquals("tell me the password: \nrepeat the password: \n", makeNewlinesConsistent(new String(bout.toByteArray())));
+        assertEquals("tell me the password: \nrepeat the password: \n", bosToUnixString(bout));
     }
     
     /*
@@ -175,8 +175,7 @@
         return builder.toString();
     }
 
-    private String makeNewlinesConsistent(String input) {
-        return input.replace("\r\n", "\n");
+    private String bosToUnixString(ByteArrayOutputStream out) {
+        return new String(out.toByteArray()).replace("\r\n", "\n");
     }
-
 }
--- a/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/UsernameCredentialsReaderTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/cli/UsernameCredentialsReaderTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -77,7 +77,7 @@
         String username = credsReader.read();
         assertEquals("foo-user", username);
         assertEquals("Expected no errors", "", new String(berr.toByteArray()));
-        assertEquals("tell me the username: foo-user\n", makeNewlinesConsistent(new String(bout.toByteArray())));
+        assertEquals("tell me the username: foo-user\n", bosToUnixString(bout));
     }
     
     @Test
@@ -86,8 +86,8 @@
         when(console.getInput()).thenReturn(new ByteArrayInputStream(input.getBytes()));
         String username = credsReader.read();
         assertEquals("try-second-time", username);
-        assertEquals("Chosen username '' invalid!\n", new String(berr.toByteArray()));
-        assertEquals("tell me the username: \ntell me the username: try-second-time\n", makeNewlinesConsistent(new String(bout.toByteArray())));
+        assertEquals("Chosen username '' invalid!\n", bosToUnixString(berr));
+        assertEquals("tell me the username: \ntell me the username: try-second-time\n", bosToUnixString(bout));
     }
     
     /*
@@ -125,8 +125,8 @@
         return builder.toString();
     }
 
-    private String makeNewlinesConsistent(String input) {
-        return input.replace("\r\n", "\n");
+    private String bosToUnixString(ByteArrayOutputStream out) {
+        return new String(out.toByteArray()).replace("\r\n", "\n");
     }
 
 }
--- a/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/CredentialFinderTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/CredentialFinderTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -36,10 +36,11 @@
 
 package com.redhat.thermostat.setup.command.internal.model;
 
-import com.redhat.thermostat.setup.command.internal.model.CredentialFinder;
 import com.redhat.thermostat.shared.config.CommonPaths;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -165,8 +166,9 @@
 
     @Test
     public void verifyFileFromUserHomeIsUsedIfSystemHomeIsNotUsableAndFileDoesNotExist() throws IOException {
+        // Windows can't set a directory readonly http://bugs.java.com/view_bug.do?bug_id=6728842
+        Assume.assumeTrue(!OS.IS_WINDOWS);
         systemConfigDir.setReadOnly();
-
         CredentialFinder finder = new CredentialFinder(paths) {
             @Override
             File getConfigurationFile(File directory, String name) {
--- a/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/PropertiesWriterTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/PropertiesWriterTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -46,6 +46,7 @@
 import java.util.Arrays;
 import java.util.Properties;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -82,7 +83,7 @@
         };
         StringBuilder rolesBuilder = new StringBuilder();
         for (int i = 0; i < roles.length - 1; i++) {
-            rolesBuilder.append(roles[i] + ", " + System.getProperty("line.separator"));
+            rolesBuilder.append(roles[i] + ", " + OS.EOL);
         }
         rolesBuilder.append(roles[roles.length - 1]);
         String value = rolesBuilder.toString();
@@ -91,9 +92,12 @@
         propsToStore.setProperty(key, value);
         FileOutputStream roleStream = new FileOutputStream(rolesPropertiesFile.toFile());
         propsToStore.store(new PropertiesWriter(roleStream), null);
+        roleStream.close();
 
         Properties propsToLoad = new Properties();
-        propsToLoad.load(new FileInputStream(rolesPropertiesFile.toFile()));
+        FileInputStream inRoleStream = new FileInputStream(rolesPropertiesFile.toFile());
+        propsToLoad.load(inRoleStream);
+        inRoleStream.close();
         String[] loadedRoles = propsToLoad.getProperty(key).split(",\\s+");
 
         assertTrue(Arrays.asList(roles).containsAll(Arrays.asList(loadedRoles)));
--- a/system-backend/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/system-backend/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -70,6 +70,12 @@
 
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-portability</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-core</artifactId>
       <version>${project.version}</version>
     </dependency>
@@ -122,13 +128,38 @@
         </configuration>
       </plugin>
 
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <overwrite>true</overwrite>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>../common/portability/target</directory>
+                  <includes>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
           <configuration>
-            <!-- FIXME: the test need to link to agent-core native libraries -->
+            <!-- the test needs to link to common-portability native libraries -->
             <systemPropertyVariables>
-              <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}/../../agent/core/target/</com.redhat.thermostat.shared.loader.testNativesHome>
+              <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome>
             </systemPropertyVariables>            
           </configuration>
       </plugin>      
--- a/thermostat-plugin-validator/src/main/java/com/redhat/thermostat/plugin/validator/ValidationErrorsFormatter.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/thermostat-plugin-validator/src/main/java/com/redhat/thermostat/plugin/validator/ValidationErrorsFormatter.java	Wed Mar 08 09:24:27 2017 -0500
@@ -44,6 +44,7 @@
 import java.util.Map;
 
 import com.redhat.thermostat.plugin.validator.internal.LocaleResources;
+import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.shared.locale.Translate;
 
 /**
@@ -60,6 +61,7 @@
     }
 
     private Map<ErrorType,LocaleResources> translateKeys;
+
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
     
     public ValidationErrorsFormatter() {
@@ -80,9 +82,11 @@
     }
     
     private StringBuilder formatError(ValidationIssue ave) {
+
+        final String LS = OS.EOL;
+
         StringBuilder builder = new StringBuilder();
-        
-        String LS = System.getProperty("line.separator");
+
         String firstLine = null;
         String secondLine = null;
         String thirdLine = null;
@@ -113,7 +117,7 @@
                        translateKeys.get(ErrorType.valueOf(ave.getClass().getSimpleName().toUpperCase())),
                        absolutePath, 
                        Integer.toString(ave.getLineNumber()), 
-                       Integer.toString(ave.getColumnNumber())).getContents());
+                       Integer.toString(ave.getColumnNumber())).getContents()).append(LS);
                     
         builder.append(formatMessage(ave.getMessage())).append(LS).append(LS);
         builder.append(firstLine).append(LS);
@@ -131,7 +135,7 @@
         String output = "";
         
         for (int i = 0; i < size; i++) {
-            output=output.concat(arguments[i]);
+            output = output.concat(arguments[i]);
         }
         return output;
     }
--- a/thermostat-plugin-validator/src/main/resources/com/redhat/thermostat/plugin/validator/strings.properties	Mon Mar 06 11:53:28 2017 +0100
+++ b/thermostat-plugin-validator/src/main/resources/com/redhat/thermostat/plugin/validator/strings.properties	Wed Mar 08 09:24:27 2017 -0500
@@ -1,3 +1,3 @@
-VALIDATION_WARNING = Warning in file {0}:{1}.{2}\n
-VALIDATION_ERROR = Error in file {0}:{1}.{2}\n
-VALIDATION_FATAL_ERROR = Fatal error in file {0}:{1}.{2}\n
\ No newline at end of file
+VALIDATION_WARNING = Warning in file {0}:{1}.{2}
+VALIDATION_ERROR = Error in file {0}:{1}.{2}
+VALIDATION_FATAL_ERROR = Fatal error in file {0}:{1}.{2}
\ No newline at end of file
--- a/validate-command/command/src/main/resources/com/redhat/thermostat/validate/locale/strings.properties	Mon Mar 06 11:53:28 2017 +0100
+++ b/validate-command/command/src/main/resources/com/redhat/thermostat/validate/locale/strings.properties	Wed Mar 08 09:24:27 2017 -0500
@@ -1,5 +1,5 @@
-VALIDATION_SUCCESSFUL = Validation successful for file {0}\n
-VALIDATION_FAILED = Validation failed for file {0}\n
+VALIDATION_SUCCESSFUL = Validation successful for file {0}
+VALIDATION_FAILED = Validation failed for file {0}
 
 FILE_NOT_FOUND = File {0} not found. Please check the file name and/or the path
 ONE_ARGUMENT_EXPECTED = One non-option argument expected
\ No newline at end of file
--- a/validate-command/command/src/test/java/com/redhat/thermostat/validate/command/internal/ValidateCommandTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/validate-command/command/src/test/java/com/redhat/thermostat/validate/command/internal/ValidateCommandTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -47,10 +47,9 @@
 import java.io.UnsupportedEncodingException;
 import java.net.URL;
 import java.net.URLDecoder;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
 
+import com.redhat.thermostat.shared.config.OS;
 import org.apache.commons.cli.MissingArgumentException;
 import org.junit.Before;
 import org.junit.Test;
@@ -101,7 +100,7 @@
         cmd.run(ctxt);
         String errorOutput = new String(errorBaos.toByteArray());
         String validateOutput = buildErrorMessage();
-        
+
         assertEquals(validateOutput, errorOutput);
         assertEquals("", new String(outputBaos.toByteArray()));
     }
@@ -114,7 +113,7 @@
 
         cmd.run(ctxt);
         
-        String expected = "Validation successful for file " + fileName + "\n\n";
+        String expected = "Validation successful for file " + fileName + OS.EOL;
         String actual = new String(outputBaos.toByteArray());
         assertEquals(expected, actual);
         
@@ -150,8 +149,8 @@
     }
     
     private String buildErrorMessage() {
-        String LS = System.getProperty("line.separator");
-        StringBuilder builder = new StringBuilder();
+        final String LS = OS.EOL;
+        final StringBuilder builder = new StringBuilder();
         
         
         builder.append("Error in file ").append(fileName).append(":10.60").append(LS);
@@ -186,7 +185,7 @@
         builder.append("      </bundles>").append(LS);
         builder.append("      <dependencies>").append(LS);
         builder.append("                   ^").append(LS).append(LS);
-        builder.append("Validation failed for file ").append(fileName).append(LS).append(LS);
+        builder.append("Validation failed for file ").append(fileName).append(LS);
 
         return builder.toString();
     }
@@ -195,7 +194,8 @@
         try {
             // Spaces are encoded as %20 in URLs. Use URLDecoder.decode() so
             // as to handle cases like that.
-            return URLDecoder.decode(url.getFile(), "UTF-8");
+            final String fn = URLDecoder.decode(url.getFile(), "UTF-8");
+            return OS.IS_UNIX ? fn : fn.replace('/','\\').substring(1); // for Windows, ensure backslash, and get rid of leading '/'
         } catch (UnsupportedEncodingException e) {
             throw new AssertionError("UTF-8 not supported, huh?");
         }
--- a/vm-byteman/byteman-helper/src/test/java/org/jboss/byteman/thermostat/helper/transport/ipc/LocalSocketTransportFactoryTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/vm-byteman/byteman-helper/src/test/java/org/jboss/byteman/thermostat/helper/transport/ipc/LocalSocketTransportFactoryTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -45,12 +45,14 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.File;
+
 public class LocalSocketTransportFactoryTest {
     
     private static final String IPC_SOCKET_NAME = "org.jboss.byteman.thermostat.socketName";
     private static final String IPC_SOCKET_NAME_VALUE = "someSocketName";
     private static final String IPC_CONFIG = "org.jboss.byteman.thermostat.ipcConfig";
-    private static final String IPC_CONFIG_VALUE = "/path/to/ipcConfigFile";
+    private static final String IPC_CONFIG_VALUE = new File("/path/to/ipcConfigFile").getAbsolutePath();
 
     @Before
     public void setup() {
--- a/vm-cpu/agent/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/vm-cpu/agent/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -38,14 +38,18 @@
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+
   <parent>
     <artifactId>thermostat-vm-cpu</artifactId>
     <groupId>com.redhat.thermostat</groupId>
     <version>1.99.12-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-vm-cpu-agent</artifactId>
   <packaging>bundle</packaging>
+
   <name>Thermostat VM CPU Agent plugin</name>
+
   <build>
     <plugins>
       <plugin>
@@ -66,8 +70,44 @@
           </instructions>
         </configuration>
       </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <overwrite>true</overwrite>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>../../common/portability/target</directory>
+                  <includes>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <!-- the test needs to link to common-portability native libraries -->
+          <systemPropertyVariables>
+            <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
+
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
@@ -96,6 +136,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-portability</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-vm-cpu-common</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/vm-gc/common/src/main/resources/com/redhat/thermostat/vm/gc/common/locale/strings.properties	Mon Mar 06 11:53:28 2017 +0100
+++ b/vm-gc/common/src/main/resources/com/redhat/thermostat/vm/gc/common/locale/strings.properties	Wed Mar 08 09:24:27 2017 -0500
@@ -1,4 +1,4 @@
-VALIDATION_FAILED = Validation failed for file {0} : {1}\n
-VALIDATION_WARNING = Warning in file {0}:{1}.{2}\n
-VALIDATION_ERROR = Error in file {0}:{1}.{2}\n
-VALIDATION_FATAL_ERROR = Fatal error in file {0}:{1}.{2}\n
+VALIDATION_FAILED = Validation failed for file {0} : {1}
+VALIDATION_WARNING = Warning in file {0}:{1}.{2}
+VALIDATION_ERROR = Error in file {0}:{1}.{2}
+VALIDATION_FATAL_ERROR = Fatal error in file {0}:{1}.{2}
--- a/vm-io/agent/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/vm-io/agent/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -38,14 +38,17 @@
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+
   <parent>
     <artifactId>thermostat-vm-io</artifactId>
     <groupId>com.redhat.thermostat</groupId>
     <version>1.99.12-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-vm-io-agent</artifactId>
   <packaging>bundle</packaging>
   <name>Thermostat VM IO Agent plugin</name>
+
   <build>
     <plugins>
       <plugin>
@@ -66,8 +69,44 @@
           </instructions>
         </configuration>
       </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <overwrite>true</overwrite>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>../../common/portability/target</directory>
+                  <includes>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <!-- the test needs to link to common-portability native libraries -->
+          <systemPropertyVariables>
+            <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
+
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
@@ -115,5 +154,10 @@
       <version>${project.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-portability</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
 </project>
--- a/vm-io/agent/src/test/java/com/redhat/thermostat/vm/io/agent/internal/VmIoStatBuilderTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/vm-io/agent/src/test/java/com/redhat/thermostat/vm/io/agent/internal/VmIoStatBuilderTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -37,12 +37,14 @@
 package com.redhat.thermostat.vm.io.agent.internal;
 
 import com.redhat.thermostat.common.Clock;
+import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.vm.io.common.VmIoStat;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.mock;
 
@@ -60,7 +62,10 @@
         Clock clock = mock(Clock.class);
         VmIoStatBuilder builder = new VmIoStatBuilderImpl(clock, writerID);
         VmIoStat result = builder.build("vmId", 0);
-        assertNull(result);
+        if (OS.IS_WINDOWS)  // on Windows implementation, pid 0 will return information for the current process
+            assertNotNull(result);
+        else
+            assertNull(result);
     }
 
 }
--- a/vm-numa/agent/src/main/java/com/redhat/thermostat/vm/numa/agent/internal/Activator.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/vm-numa/agent/src/main/java/com/redhat/thermostat/vm/numa/agent/internal/Activator.java	Wed Mar 08 09:24:27 2017 -0500
@@ -45,6 +45,7 @@
 import com.redhat.thermostat.common.Clock;
 import com.redhat.thermostat.common.SystemClock;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.OS;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -85,9 +86,13 @@
                 WriterID writerID = services.get(WriterID.class);
                 Clock clock = new SystemClock();
                 try {
-                    PageSizeProvider pageSizeProvider = new PageSizeProviderImpl();
-                    NumaMapsReaderProvider readerProvider = new NumaMapsReaderProviderImpl();
-                    backend = constructBackend(executor, clock, readerProvider, pageSizeProvider, vmNumaDAO, version, registrar, writerID);
+                    if (OS.IS_LINUX) {
+                        PageSizeProvider pageSizeProvider = new PageSizeProviderImpl();
+                        NumaMapsReaderProvider readerProvider = new NumaMapsReaderProviderImpl();
+                        backend = constructBackend(executor, clock, readerProvider, pageSizeProvider, vmNumaDAO, version, registrar, writerID);
+                    } else {
+                        backend = constructBackend(executor, clock, null, null, vmNumaDAO, version, registrar, writerID);
+                    }
                     reg = context.registerService(Backend.class, backend, null);
                 } catch (IOException e) {
                     logger.log(Level.WARNING, "Unexpected exception retrieving Linux page sizes. NUMA counts will be disabled", e);
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfigurationTest.java	Mon Mar 06 11:53:28 2017 +0100
+++ b/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfigurationTest.java	Wed Mar 08 09:24:27 2017 -0500
@@ -52,7 +52,6 @@
 import com.redhat.thermostat.common.utils.HostPortPair;
 import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration;
 import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration.ConfigKeys;
 
 public class EmbeddedServletContainerConfigurationTest {
@@ -319,7 +318,7 @@
         systemConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "logfile.log");
         EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
         assertTrue("Should have request log config", config.hasRequestLogConfig());
-        assertEquals("/test/userhome/logs/logfile.log", config.getAbsolutePathToRequestLog());
+        assertEquals(new File("/test/userhome/logs/logfile.log").getAbsolutePath(), config.getAbsolutePathToRequestLog());
 
         // user config only
         userConfig = new Properties();
@@ -327,7 +326,7 @@
         userConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "userlogFile.log");
         config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
         assertTrue("Should have request log config", config.hasRequestLogConfig());
-        assertEquals("/test/userhome/logs/userlogFile.log", config.getAbsolutePathToRequestLog());
+        assertEquals(new File("/test/userhome/logs/userlogFile.log").getAbsolutePath(), config.getAbsolutePathToRequestLog());
 
         // user and system config
         userConfig = new Properties();
@@ -337,7 +336,7 @@
         config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
         assertTrue("Should have request log config", config.hasRequestLogConfig());
         assertEquals("User config overrides system config",
-                     "/test/userhome/logs/userlogFile.log",
+                new File("/test/userhome/logs/userlogFile.log").getAbsolutePath(),
                      config.getAbsolutePathToRequestLog());
 
         // no config
@@ -386,6 +385,6 @@
 
         EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, irrelevantForTest, irrelevantForTest);
         String actual = config.getAbsolutePathToJaasConfig();
-        assertEquals(fooThHome + "/thermostat_jaas.conf", actual);
+        assertEquals(new File(fooThHome + "/thermostat_jaas.conf").getAbsolutePath(), actual);
     }
 }
--- a/web/server/pom.xml	Mon Mar 06 11:53:28 2017 +0100
+++ b/web/server/pom.xml	Wed Mar 08 09:24:27 2017 -0500
@@ -50,6 +50,18 @@
 
   <name>Thermostat Web Server</name>
 
+  <profiles>
+    <profile>
+      <id>windows</id>
+      <activation>
+        <os><family>Windows</family></os>
+      </activation>
+      <properties>
+        <maven.test.skip>true</maven.test.skip>
+      </properties>
+    </profile>
+  </profiles>
+
   <dependencies>
   
     <dependency>