This is an automated email from the ASF dual-hosted git repository.

mmartell pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode-native.git


The following commit(s) were added to refs/heads/develop by this push:
     new 620479a  GEODE-9600: Add Cluster Support to NetCore Test Framework 
(#880)
620479a is described below

commit 620479a5069a7c97956cdf46f2b0f69384ff6b94
Author: Michael Martell <mmart...@pivotal.io>
AuthorDate: Tue Oct 12 08:44:25 2021 -0700

    GEODE-9600: Add Cluster Support to NetCore Test Framework (#880)
    
    * Add cluster support to netcore-integration-test and netcore-session 
integration-test
    * Add top level solution for netcore
    * Add programmatic cluster files in shared folder for use by both test 
projects
    * Address Rat check issue: Add using statement to new Process
    * Remove gfsh based cluster scripts, now supported in cluster.cs, etc.
    * Update refs to Cluster.cs, etc. in project files
    * cmake configure Config.cs.in so environment vars are not required
    * Remove old netcore solution file
    * Cleanup per review: Geode .Net Core, not .net Core
---
 netcore/CMakeLists.txt                             |   1 +
 netcore/geode-dotnet-core.sln                      |  56 ---
 netcore/netcore-integration-test/CMakeLists.txt    |  27 --
 .../netcore-integration-test/CacheFactoryTest.cs   |  12 +-
 netcore/netcore-integration-test/CacheTest.cs      |   4 +-
 .../NetCoreCollectionFixture.cs                    |   2 +-
 netcore/netcore-integration-test/ObjectLeakTest.cs |   4 +-
 .../netcore-integration-test/PoolFactoryTest.cs    |   4 +-
 .../netcore-integration-test/PoolManagerTest.cs    |   4 +-
 .../netcore-integration-test/RegionFactoryTest.cs  |  60 ++-
 .../netcore-integration-test.csproj                |   9 +
 .../CMakeLists.txt                                 |  27 --
 .../SessionStateIntegrationTests.cs                | 336 ++++++++------
 .../netcore-session-integration-test.csproj        |   9 +
 netcore/netcore.sln                                |  49 ++
 netcore/{ => shared}/CMakeLists.txt                |  15 +-
 netcore/shared/Cluster.cs                          | 300 +++++++++++++
 .../Config.cs.in}                                  |  39 +-
 .../Framework.cs}                                  |  33 +-
 netcore/shared/Gfsh.cs                             | 493 +++++++++++++++++++++
 netcore/shared/GfshExecute.cs                      | 201 +++++++++
 netcore/shared/TestBase.cs                         |  55 +++
 22 files changed, 1428 insertions(+), 312 deletions(-)

diff --git a/netcore/CMakeLists.txt b/netcore/CMakeLists.txt
index b5c3536..0caa268 100644
--- a/netcore/CMakeLists.txt
+++ b/netcore/CMakeLists.txt
@@ -24,5 +24,6 @@ if(DOTNET AND INCLUDE_DOTNET_CORE)
   add_subdirectory(netcore-integration-test)
   add_subdirectory(netcore-session-integration-test)
   add_subdirectory(utility)
+  add_subdirectory(shared)
 endif()
 
diff --git a/netcore/geode-dotnet-core.sln b/netcore/geode-dotnet-core.sln
deleted file mode 100644
index 83316b9..0000000
--- a/netcore/geode-dotnet-core.sln
+++ /dev/null
@@ -1,56 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.30001.183
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "netcore", 
"netcore\netcore.csproj", "{09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = 
"netcore-integration-test", 
"netcore-integration-test\netcore-integration-test.csproj", 
"{501DEA7E-8985-42A8-8BC9-C073E1B6DFE0}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Session", "Session", 
"{520C96EC-F929-4365-8D78-CC5785419B62}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "netcore-session", 
"netcore-session\netcore-session.csproj", 
"{B88C58EB-B144-403B-85F7-7A5B45E643E3}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = 
"netcore-session-integration-test", 
"netcore-session-integration-test\netcore-session-integration-test.csproj", 
"{94D2CD59-A5F3-4504-BF01-0A3B95CE12B5}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = 
"asp-netcore-session-sample", 
"asp-netcore-session-sample\asp-netcore-session-sample.csproj", 
"{4E830BC8-D1CA-40AF-9C9C-D15E193C6585}"
-EndProject
-Global
-       GlobalSection(SolutionConfigurationPlatforms) = preSolution
-               Debug|x64 = Debug|x64
-               Release|x64 = Release|x64
-       EndGlobalSection
-       GlobalSection(ProjectConfigurationPlatforms) = postSolution
-               {09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Debug|x64.ActiveCfg = 
Debug|x64
-               {09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Debug|x64.Build.0 = 
Debug|x64
-               {09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Release|x64.ActiveCfg = 
Release|x64
-               {09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Release|x64.Build.0 = 
Release|x64
-               {501DEA7E-8985-42A8-8BC9-C073E1B6DFE0}.Debug|x64.ActiveCfg = 
Debug|x64
-               {501DEA7E-8985-42A8-8BC9-C073E1B6DFE0}.Debug|x64.Build.0 = 
Debug|x64
-               {501DEA7E-8985-42A8-8BC9-C073E1B6DFE0}.Release|x64.ActiveCfg = 
Release|x64
-               {501DEA7E-8985-42A8-8BC9-C073E1B6DFE0}.Release|x64.Build.0 = 
Release|x64
-               {B88C58EB-B144-403B-85F7-7A5B45E643E3}.Debug|x64.ActiveCfg = 
Debug|x64
-               {B88C58EB-B144-403B-85F7-7A5B45E643E3}.Debug|x64.Build.0 = 
Debug|x64
-               {B88C58EB-B144-403B-85F7-7A5B45E643E3}.Release|x64.ActiveCfg = 
Release|x64
-               {B88C58EB-B144-403B-85F7-7A5B45E643E3}.Release|x64.Build.0 = 
Release|x64
-               {94D2CD59-A5F3-4504-BF01-0A3B95CE12B5}.Debug|x64.ActiveCfg = 
Debug|x64
-               {94D2CD59-A5F3-4504-BF01-0A3B95CE12B5}.Debug|x64.Build.0 = 
Debug|x64
-               {94D2CD59-A5F3-4504-BF01-0A3B95CE12B5}.Release|x64.ActiveCfg = 
Release|x64
-               {94D2CD59-A5F3-4504-BF01-0A3B95CE12B5}.Release|x64.Build.0 = 
Release|x64
-               {4E830BC8-D1CA-40AF-9C9C-D15E193C6585}.Debug|x64.ActiveCfg = 
Debug|x64
-               {4E830BC8-D1CA-40AF-9C9C-D15E193C6585}.Debug|x64.Build.0 = 
Debug|x64
-               {4E830BC8-D1CA-40AF-9C9C-D15E193C6585}.Release|x64.ActiveCfg = 
Release|x64
-               {4E830BC8-D1CA-40AF-9C9C-D15E193C6585}.Release|x64.Build.0 = 
Release|x64
-       EndGlobalSection
-       GlobalSection(SolutionProperties) = preSolution
-               HideSolutionNode = FALSE
-       EndGlobalSection
-       GlobalSection(NestedProjects) = preSolution
-               {B88C58EB-B144-403B-85F7-7A5B45E643E3} = 
{520C96EC-F929-4365-8D78-CC5785419B62}
-               {94D2CD59-A5F3-4504-BF01-0A3B95CE12B5} = 
{520C96EC-F929-4365-8D78-CC5785419B62}
-               {4E830BC8-D1CA-40AF-9C9C-D15E193C6585} = 
{520C96EC-F929-4365-8D78-CC5785419B62}
-       EndGlobalSection
-       GlobalSection(ExtensibilityGlobals) = postSolution
-               SolutionGuid = {B30A49F0-1C96-4D6C-A222-0088B1D7FBBE}
-       EndGlobalSection
-EndGlobal
diff --git a/netcore/netcore-integration-test/CMakeLists.txt 
b/netcore/netcore-integration-test/CMakeLists.txt
index 6756bcf..3b9c863 100644
--- a/netcore/netcore-integration-test/CMakeLists.txt
+++ b/netcore/netcore-integration-test/CMakeLists.txt
@@ -24,34 +24,7 @@ enable_testing()
 set(AUTH_OPTS "--J=-Dgemfire.security-username=server 
--J=-Dgemfire.security-password=server 
--classpath=$<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/../utility/netcore-utility.jar>")
 set(AUTH_LOCATOR_OPTS "${AUTH_OPTS} 
--J=-Dgemfire.security-manager=javaobject.SimpleSecurityManager")
 
-add_test(NAME startclusters COMMAND ${Geode_gfsh_EXECUTABLE}
-         -e "start locator --name=locator --port=10334 
--http-service-port=6060 --J=-Dgemfire.jmx-manager-port=1099"
-         -e "start server --name=server --server-port=0"
-         -e "create region --name=exampleRegion --type=PARTITION"
-         -e "create region --name=geodeSessionState --type=PARTITION"
-         -e "disconnect"
-         -e "start locator --name=auth_locator ${AUTH_LOCATOR_OPTS} 
--port=10335 --http-service-port=7070 --J=-Dgemfire.jmx-manager-port=2099"
-         -e "connect --locator=localhost[10335] --user=server 
--password=server"
-         -e "start server --name=auth_server ${AUTH_OPTS} --server-port=0"
-         -e "create region --name=authExampleRegion --type=PARTITION"
-         -e "create region --name=authGeodeSessionState --type=PARTITION")
-add_test(NAME stopclusters 
-  COMMAND ${Geode_gfsh_EXECUTABLE}
-     -e "connect --locator=localhost[10335] --user=server --password=server" 
-     -e "stop server --name=auth_server"
-     -e "stop locator --name=auth_locator"
-     -e "connect --locator=localhost[10334]" 
-     -e "stop server --name=server"
-     -e "stop locator --name=locator")
-add_test(NAME remove_dirs
-  COMMAND ${CMAKE_COMMAND} -P 
${CMAKE_CURRENT_SOURCE_DIR}/../cmake/remove_dirs.cmake)
-
 add_test(NAME netcore-test 
   COMMAND dotnet test -c $<CONFIG>
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 
-set_tests_properties(startclusters PROPERTIES FIXTURES_SETUP geode)
-set_tests_properties(netcore-test PROPERTIES FIXTURES_REQUIRED geode)
-set_tests_properties(stopclusters PROPERTIES FIXTURES_CLEANUP geode)
-set_tests_properties(remove_dirs PROPERTIES DEPENDS stopclusters)
-
diff --git a/netcore/netcore-integration-test/CacheFactoryTest.cs 
b/netcore/netcore-integration-test/CacheFactoryTest.cs
index 442c825..18ae8d4 100644
--- a/netcore/netcore-integration-test/CacheFactoryTest.cs
+++ b/netcore/netcore-integration-test/CacheFactoryTest.cs
@@ -16,10 +16,16 @@
  */
 using System;
 using Xunit;
+using Xunit.Abstractions;
+
+namespace Apache.Geode.Client.IntegrationTests
+{
+  [Collection("Geode .Net Core Collection")]
+  public class CacheFactoryTest : TestBase {
+    public CacheFactoryTest(ITestOutputHelper testOutputHelper) : 
base(testOutputHelper)
+    {
+    }
 
-namespace Apache.Geode.Client {
-  [Collection("Geode .net Core Collection")]
-  public class CacheFactoryTest {
     [Fact]
     public void CreateFactoryNotNull() {
       using (var cacheFactory = CacheFactory.Create()) {
diff --git a/netcore/netcore-integration-test/CacheTest.cs 
b/netcore/netcore-integration-test/CacheTest.cs
index d06d2fd..f35d181 100644
--- a/netcore/netcore-integration-test/CacheTest.cs
+++ b/netcore/netcore-integration-test/CacheTest.cs
@@ -18,8 +18,8 @@ using System;
 using System.Net.Cache;
 using Xunit;
 
-namespace Apache.Geode.Client {
-  [Collection("Geode .net Core Collection")]
+namespace Apache.Geode.Client.IntegrationTests {
+  [Collection("Geode .Net Core Collection")]
   public class CacheTest {
     [Fact]
     public void ClientCacheGetPdxReadSerialized() {
diff --git a/netcore/netcore-integration-test/NetCoreCollectionFixture.cs 
b/netcore/netcore-integration-test/NetCoreCollectionFixture.cs
index d30833e..f2cf3ee 100644
--- a/netcore/netcore-integration-test/NetCoreCollectionFixture.cs
+++ b/netcore/netcore-integration-test/NetCoreCollectionFixture.cs
@@ -29,5 +29,5 @@ public class NetCoreCollectionFixture : IDisposable {
   Client client_;
 }
 
-[CollectionDefinition("Geode .net Core Collection")]
+[CollectionDefinition("Geode .Net Core Collection")]
 public class NetCoreCollection : ICollectionFixture<NetCoreCollectionFixture> 
{}
diff --git a/netcore/netcore-integration-test/ObjectLeakTest.cs 
b/netcore/netcore-integration-test/ObjectLeakTest.cs
index c1440f9..c87daee 100644
--- a/netcore/netcore-integration-test/ObjectLeakTest.cs
+++ b/netcore/netcore-integration-test/ObjectLeakTest.cs
@@ -17,8 +17,8 @@
 using System;
 using Xunit;
 
-namespace Apache.Geode.Client {
-  [Collection("Geode .net Core Collection")]
+namespace Apache.Geode.Client.IntegrationTests {
+  [Collection("Geode .Net Core Collection")]
   public class ObjectLeakTest {
     [Fact]
     public void LeakCacheFactoryVerifyThrows() {
diff --git a/netcore/netcore-integration-test/PoolFactoryTest.cs 
b/netcore/netcore-integration-test/PoolFactoryTest.cs
index 668be53..1bbc02b 100644
--- a/netcore/netcore-integration-test/PoolFactoryTest.cs
+++ b/netcore/netcore-integration-test/PoolFactoryTest.cs
@@ -17,8 +17,8 @@
 using System.Net.Cache;
 using Xunit;
 
-namespace Apache.Geode.Client {
-  [Collection("Geode .net Core Collection")]
+namespace Apache.Geode.Client.IntegrationTests {
+  [Collection("Geode .Net Core Collection")]
   public class PoolFactoryTest {
     [Fact]
     public void PoolFactoryAddLocatorAllObjectsNotNull() {
diff --git a/netcore/netcore-integration-test/PoolManagerTest.cs 
b/netcore/netcore-integration-test/PoolManagerTest.cs
index e33f53b..19e3ddd 100644
--- a/netcore/netcore-integration-test/PoolManagerTest.cs
+++ b/netcore/netcore-integration-test/PoolManagerTest.cs
@@ -17,8 +17,8 @@
 using System.Net.Cache;
 using Xunit;
 
-namespace Apache.Geode.Client {
-  [Collection("Geode .net Core Collection")]
+namespace Apache.Geode.Client.IntegrationTests {
+  [Collection("Geode .Net Core Collection")]
   public class PoolManagerTest {
     [Fact]
     public void PoolManagerCreatePoolFactoryAllObjectsNotNull() {
diff --git a/netcore/netcore-integration-test/RegionFactoryTest.cs 
b/netcore/netcore-integration-test/RegionFactoryTest.cs
index 970109f..9f0e6d9 100644
--- a/netcore/netcore-integration-test/RegionFactoryTest.cs
+++ b/netcore/netcore-integration-test/RegionFactoryTest.cs
@@ -18,8 +18,9 @@ using System;
 using System.Collections.Generic;
 using System.Net.Cache;
 using Xunit;
+using Xunit.Abstractions;
 
-namespace Apache.Geode.Client {
+namespace Apache.Geode.Client.IntegrationTests {
   public class SimpleAuthInitialize : IAuthInitialize {
     public Dictionary<string, string> GetCredentials() {
       Console.WriteLine("SimpleAuthInitialize::GetCredentials called");
@@ -34,8 +35,13 @@ namespace Apache.Geode.Client {
     }
   }
 
-  [Collection("Geode .net Core Collection")]
-  public class RegionFactoryTest {
+  [Collection("Geode .Net Core Collection")]
+  public class RegionFactoryTest : TestBase
+  {
+    public RegionFactoryTest(ITestOutputHelper testOutputHelper) : 
base(testOutputHelper)
+    {
+    }
+
     private const string Username1 = "rtimmons";
     private const string Username2 = "scharles";
 
@@ -82,25 +88,53 @@ namespace Apache.Geode.Client {
 
     [Fact]
     public void RegionFactoryCreateProxyRegionStringPutGet() {
-      using var cacheFactory = CacheFactory.Create()
-                                   .SetProperty("log-level", "debug")
-                                   .SetProperty("log-file", 
"geode_native.log");
-      using var cache = cacheFactory.CreateCache();
-
-      createPool(cache, 10334);
-      CreateRegionAndDoWork(cache, "exampleRegion", RegionShortcut.Proxy);
+      using (var cluster = new Cluster(output, CreateTestCaseDirectoryName(), 
1, 1))
+      {
+        Assert.True(cluster.Start());
+        Assert.Equal(0, cluster.Gfsh
+            .create()
+            .region()
+            .withName("exampleRegion")
+            .withType("PARTITION")
+            .execute());
+
+        using var cacheFactory = CacheFactory.Create()
+                                     .SetProperty("log-level", "debug")
+                                     .SetProperty("log-file", 
"geode_native.log");
+        using var cache = cacheFactory.CreateCache();
+
+        using var pool = cluster.ApplyLocators(cache.PoolFactory)
+                    .CreatePool("myPool");
+
+        //int port = cluster.
+        //createPool(cache, 10334);
+        CreateRegionAndDoWork(cache, "exampleRegion", RegionShortcut.Proxy);
+      }
     }
 
     [Fact]
     public void RegionFactoryCreateRegionStringPutGetWithAuthentication() {
-      using var cacheFactory = CacheFactory.Create()
+      using (var cluster = new Cluster(output, CreateTestCaseDirectoryName(), 
1, 1))
+      {
+        Assert.True(cluster.Start());
+        Assert.Equal(0, cluster.Gfsh
+            .create()
+            .region()
+            .withName("authExampleRegion")
+            .withType("PARTITION")
+            .execute());
+
+        using var cacheFactory = CacheFactory.Create()
                                    .SetProperty("log-level", "debug")
                                    .SetProperty("log-file", 
"geode_native_with_auth.log");
       cacheFactory.AuthInitialize = new SimpleAuthInitialize();
       using var cache = cacheFactory.CreateCache();
 
-      createPool(cache, 10335);
-      CreateRegionAndDoWork(cache, "authExampleRegion", 
RegionShortcut.CachingProxy);
+      using var pool = cluster.ApplyLocators(cache.PoolFactory)
+                    .CreatePool("myPool");
+
+        CreateRegionAndDoWork(cache, "authExampleRegion", 
RegionShortcut.CachingProxy);
+      }
     }
   }
 }
diff --git a/netcore/netcore-integration-test/netcore-integration-test.csproj 
b/netcore/netcore-integration-test/netcore-integration-test.csproj
index 01fc77c..ac8be9a 100644
--- a/netcore/netcore-integration-test/netcore-integration-test.csproj
+++ b/netcore/netcore-integration-test/netcore-integration-test.csproj
@@ -8,6 +8,15 @@
   </PropertyGroup>
 
   <ItemGroup>
+       <Compile Include="..\shared\Config.cs" Link="Config.cs" />
+       <Compile Include="..\shared\Cluster.cs" Link="Cluster.cs" />
+       <Compile Include="..\shared\Gfsh.cs" Link="Gfsh.cs" />
+       <Compile Include="..\shared\Framework.cs" Link="Framework.cs" />
+       <Compile Include="..\shared\GfshExecute.cs" Link="GfshExecute.cs" />
+       <Compile Include="..\shared\TestBase.cs" Link="TestBase.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
       <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
       <PackageReference Include="xunit" Version="2.4.1" />
       <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
diff --git a/netcore/netcore-session-integration-test/CMakeLists.txt 
b/netcore/netcore-session-integration-test/CMakeLists.txt
index 0b5e905..365cbe0 100644
--- a/netcore/netcore-session-integration-test/CMakeLists.txt
+++ b/netcore/netcore-session-integration-test/CMakeLists.txt
@@ -21,33 +21,6 @@ add_custom_target(netcore-session-integration-test ALL
 
 enable_testing()
 
-add_test(NAME startclusters COMMAND ${Geode_gfsh_EXECUTABLE}
-         -e "start locator --name=locator --port=10334 
--http-service-port=6060 --J=-Dgemfire.jmx-manager-port=1099"
-         -e "start server --name=server --server-port=0"
-         -e "create region --name=exampleRegion --type=PARTITION"
-         -e "create region --name=geodeSessionState --type=PARTITION"
-         -e "disconnect"
-         -e "start locator --name=auth_locator ${AUTH_LOCATOR_OPTS} 
--port=10335 --http-service-port=7070 --J=-Dgemfire.jmx-manager-port=2099"
-         -e "connect --locator=localhost[10335] --user=server 
--password=server"
-         -e "start server --name=auth_server ${AUTH_OPTS} --server-port=0"
-         -e "create region --name=authExampleRegion --type=PARTITION"
-         -e "create region --name=authGeodeSessionState --type=PARTITION")
-add_test(NAME stopclusters 
-  COMMAND ${Geode_gfsh_EXECUTABLE}
-     -e "connect --locator=localhost[10335] --user=server --password=server" 
-     -e "stop server --name=auth_server"
-     -e "stop locator --name=auth_locator"
-     -e "connect --locator=localhost[10334]" 
-     -e "stop server --name=server"
-     -e "stop locator --name=locator")
-add_test(NAME remove_dirs
-  COMMAND ${CMAKE_COMMAND} -P 
${CMAKE_CURRENT_SOURCE_DIR}/../cmake/remove_dirs.cmake)
-
 add_test(NAME netcore-session-test 
   COMMAND dotnet test -c $<CONFIG>
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-
-set_tests_properties(startclusters PROPERTIES FIXTURES_SETUP geode)
-set_tests_properties(netcore-session-test PROPERTIES FIXTURES_REQUIRED geode)
-set_tests_properties(stopclusters PROPERTIES FIXTURES_CLEANUP geode)
-set_tests_properties(remove_dirs PROPERTIES DEPENDS stopclusters)
diff --git 
a/netcore/netcore-session-integration-test/SessionStateIntegrationTests.cs 
b/netcore/netcore-session-integration-test/SessionStateIntegrationTests.cs
index d34002c..6930c7e 100644
--- a/netcore/netcore-session-integration-test/SessionStateIntegrationTests.cs
+++ b/netcore/netcore-session-integration-test/SessionStateIntegrationTests.cs
@@ -16,160 +16,226 @@
  */
 using System;
 using System.Text;
-using Xunit;
-using Apache.Geode.Client;
 using System.Linq;
 using Microsoft.Extensions.Caching.Distributed;
 using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+using Apache.Geode.Client.IntegrationTests;
 
 namespace Apache.Geode.Session.IntegrationTests {
-  public class SessionStateIntegrationTests {
+  [Collection("Geode .Net Core Collection")]
+  public class SessionStateIntegrationTests : TestBase {
 
-    [Fact]
-    public void SetGet() {
-      var ssCacheOptions = new GeodeSessionStateCacheOptions();
-      ssCacheOptions.Host = "localhost";
-      ssCacheOptions.Port = 10334;
-      ssCacheOptions.RegionName = "exampleRegion";
-
-      using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
-
-      var options = new DistributedCacheEntryOptions();
-      var localTime = DateTime.Now.AddDays(1);
-      var dateAndOffset =
-          new DateTimeOffset(localTime, 
TimeZoneInfo.Local.GetUtcOffset(localTime));
-      options.AbsoluteExpiration = dateAndOffset;
-      var testValue = new byte[] { 1, 2, 3, 4, 5 };
-      ssCache.Set("testKey", testValue, options);
-      var value = ssCache.Get("testKey");
-      Assert.True(testValue.SequenceEqual(value));
+    public SessionStateIntegrationTests(ITestOutputHelper testOutputHelper) : 
base(testOutputHelper)
+    {
     }
 
     [Fact]
-    public void Refresh() {
-      var ssCacheOptions = new GeodeSessionStateCacheOptions();
-      ssCacheOptions.Host = "localhost";
-      ssCacheOptions.Port = 10334;
-      ssCacheOptions.RegionName = "exampleRegion";
-
-      using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
-
-      var options = new DistributedCacheEntryOptions();
-      var numSeconds = 20;
-      options.SlidingExpiration = new TimeSpan(0, 0, numSeconds);
-      var testValue = new byte[] { 1, 2, 3, 4, 5 };
-
-      // Set a value
-      ssCache.Set("testKey", testValue, options);
-
-      // Wait half a timeout then refresh
-      System.Threading.Thread.Sleep(numSeconds / 2 * 1000);
-      ssCache.Refresh("testKey");
-
-      // Wait beyond the original expiration
-      System.Threading.Thread.Sleep(numSeconds / 2 * 1000 + 1);
+    public void SetGet()
+    {
+      using (var cluster = new Cluster(output, CreateTestCaseDirectoryName(), 
1, 1))
+      {
+        Assert.True(cluster.Start());
+        Assert.Equal(0, cluster.Gfsh
+            .create()
+            .region()
+            .withName("exampleRegion")
+            .withType("PARTITION")
+            .execute());
+
+        var ssCacheOptions = new GeodeSessionStateCacheOptions();
+        ssCacheOptions.Host = "localhost";
+        ssCacheOptions.Port = cluster.Locators[0].Address.port;
+        ssCacheOptions.RegionName = "exampleRegion";
+
+        using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
+
+        var options = new DistributedCacheEntryOptions();
+        var localTime = DateTime.Now.AddDays(1);
+        var dateAndOffset =
+            new DateTimeOffset(localTime, 
TimeZoneInfo.Local.GetUtcOffset(localTime));
+        options.AbsoluteExpiration = dateAndOffset;
+        var testValue = new byte[] { 1, 2, 3, 4, 5 };
+        ssCache.Set("testKey", testValue, options);
+        var value = ssCache.Get("testKey");
+        Assert.True(testValue.SequenceEqual(value));
+      }
+    }
 
-      // Ensure it's not expired
-      var value = ssCache.Get("testKey");
-      Assert.True(testValue.SequenceEqual(value));
+    [Fact]
+    public void Refresh()
+    {
+      using (var cluster = new Cluster(output, CreateTestCaseDirectoryName(), 
1, 1))
+      {
+        Assert.True(cluster.Start());
+        Assert.Equal(0, cluster.Gfsh
+            .create()
+            .region()
+            .withName("exampleRegion")
+            .withType("PARTITION")
+            .execute());
+
+        var ssCacheOptions = new GeodeSessionStateCacheOptions();
+        ssCacheOptions.Host = "localhost";
+        ssCacheOptions.Port = cluster.Locators[0].Address.port;
+        ssCacheOptions.RegionName = "exampleRegion";
+
+        using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
+
+        var options = new DistributedCacheEntryOptions();
+        var numSeconds = 20;
+        options.SlidingExpiration = new TimeSpan(0, 0, numSeconds);
+        var testValue = new byte[] { 1, 2, 3, 4, 5 };
+
+        // Set a value
+        ssCache.Set("testKey", testValue, options);
+
+        // Wait half a timeout then refresh
+        System.Threading.Thread.Sleep(numSeconds / 2 * 1000);
+        ssCache.Refresh("testKey");
+
+        // Wait beyond the original expiration
+        System.Threading.Thread.Sleep(numSeconds / 2 * 1000 + 1);
+
+        // Ensure it's not expired
+        var value = ssCache.Get("testKey");
+        Assert.True(testValue.SequenceEqual(value));
+      }
     }
 
     [Fact]
-    public void SetWithAbsoluteExpiration() {
-      var ssCacheOptions = new GeodeSessionStateCacheOptions();
-      ssCacheOptions.Host = "localhost";
-      ssCacheOptions.Port = 10334;
-      ssCacheOptions.RegionName = "exampleRegion";
-
-      using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
-
-      var options = new DistributedCacheEntryOptions();
-      options.AbsoluteExpiration = DateTime.Now.AddSeconds(5);
-      ssCache.Set("testKey", Encoding.UTF8.GetBytes("testValue"), options);
-      System.Threading.Thread.Sleep(6000);
-      var value = ssCache.Get("testKey");
-      Assert.Null(value);
+    public void SetWithAbsoluteExpiration()
+    {
+      using (var cluster = new Cluster(output, CreateTestCaseDirectoryName(), 
1, 1))
+      {
+        Assert.True(cluster.Start());
+        Assert.Equal(0, cluster.Gfsh
+            .create()
+            .region()
+            .withName("exampleRegion")
+            .withType("PARTITION")
+            .execute());
+
+        var ssCacheOptions = new GeodeSessionStateCacheOptions();
+        ssCacheOptions.Host = "localhost";
+        ssCacheOptions.Port = cluster.Locators[0].Address.port;
+        ssCacheOptions.RegionName = "exampleRegion";
+
+        using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
+
+        var options = new DistributedCacheEntryOptions();
+        options.AbsoluteExpiration = DateTime.Now.AddSeconds(5);
+        ssCache.Set("testKey", Encoding.UTF8.GetBytes("testValue"), options);
+        System.Threading.Thread.Sleep(6000);
+        var value = ssCache.Get("testKey");
+        Assert.Null(value);
+      }
     }
 
     [Fact]
-    public void Remove() {
-      var ssCacheOptions = new GeodeSessionStateCacheOptions();
-      ssCacheOptions.Host = "localhost";
-      ssCacheOptions.Port = 10334;
-      ssCacheOptions.RegionName = "exampleRegion";
-
-      using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
-
-      var options = new DistributedCacheEntryOptions();
-      var localTime = DateTime.Now.AddDays(1);
-      var dateAndOffset =
-          new DateTimeOffset(localTime, 
TimeZoneInfo.Local.GetUtcOffset(localTime));
-      options.AbsoluteExpiration = dateAndOffset;
-      var testValue = new byte[] { 1, 2, 3, 4, 5 };
-      ssCache.Set("testKey", testValue, options);
-      var value = ssCache.Get("testKey");
-
-      ssCache.Remove("testKey");
-      value = ssCache.Get("testKey");
-      Assert.Null(value);
+    public void Remove()
+    {
+      using (var cluster = new Cluster(output, CreateTestCaseDirectoryName(), 
1, 1))
+      {
+        Assert.True(cluster.Start());
+        Assert.Equal(0, cluster.Gfsh
+            .create()
+            .region()
+            .withName("exampleRegion")
+            .withType("PARTITION")
+            .execute());
+
+        var ssCacheOptions = new GeodeSessionStateCacheOptions();
+        ssCacheOptions.Host = "localhost";
+        ssCacheOptions.Port = cluster.Locators[0].Address.port;
+        ssCacheOptions.RegionName = "exampleRegion";
+
+        using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
+
+        var options = new DistributedCacheEntryOptions();
+        var localTime = DateTime.Now.AddDays(1);
+        var dateAndOffset =
+            new DateTimeOffset(localTime, 
TimeZoneInfo.Local.GetUtcOffset(localTime));
+        options.AbsoluteExpiration = dateAndOffset;
+        var testValue = new byte[] { 1, 2, 3, 4, 5 };
+        ssCache.Set("testKey", testValue, options);
+        var value = ssCache.Get("testKey");
+
+        ssCache.Remove("testKey");
+        value = ssCache.Get("testKey");
+        Assert.Null(value);
+      }
     }
 
     [Fact]
-    public void SetGetRemoveAsync() {
-      var ssCacheOptions = new GeodeSessionStateCacheOptions();
-      ssCacheOptions.Host = "localhost";
-      ssCacheOptions.Port = 10334;
-      ssCacheOptions.RegionName = "exampleRegion";
-
-      using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
-
-      var options = new DistributedCacheEntryOptions();
-      var localTime = DateTime.Now.AddDays(1);
-      var dateAndOffset =
-          new DateTimeOffset(localTime, 
TimeZoneInfo.Local.GetUtcOffset(localTime));
-      options.AbsoluteExpiration = dateAndOffset;
-
-      var testValue1 = new byte[] { 1, 2, 3, 4, 5 };
-      var testValue2 = new byte[] { 11, 12, 13, 14, 15 };
-      var testValue3 = new byte[] { 21, 22, 23, 24, 25 };
-      var testValue4 = new byte[] { 31, 32, 33, 34, 35 };
-      var testValue5 = new byte[] { 41, 42, 43, 44, 45 };
-
-      var set1 = ssCache.SetAsync("testKey1", testValue1, options);
-      var set2 = ssCache.SetAsync("testKey2", testValue2, options);
-      var set3 = ssCache.SetAsync("testKey3", testValue3, options);
-      var set4 = ssCache.SetAsync("testKey4", testValue4, options);
-      var set5 = ssCache.SetAsync("testKey5", testValue5, options);
-
-      Task.WaitAll(set1, set2, set3, set4, set5);
-
-      var value1 = ssCache.GetAsync("testKey1");
-      var value2 = ssCache.GetAsync("testKey2");
-      var value3 = ssCache.GetAsync("testKey3");
-      var value4 = ssCache.GetAsync("testKey4");
-      var value5 = ssCache.GetAsync("testKey5");
-
-      Task.WaitAll(value1, value2, value3, value4, value5);
-
-      Assert.True(testValue1.SequenceEqual(value1.Result));
-      Assert.True(testValue2.SequenceEqual(value2.Result));
-      Assert.True(testValue3.SequenceEqual(value3.Result));
-      Assert.True(testValue4.SequenceEqual(value4.Result));
-      Assert.True(testValue5.SequenceEqual(value5.Result));
-
-      var rm1 = ssCache.RemoveAsync("testKey1");
-      var rm2 = ssCache.RemoveAsync("testKey2");
-      var rm3 = ssCache.RemoveAsync("testKey3");
-      var rm4 = ssCache.RemoveAsync("testKey4");
-      var rm5 = ssCache.RemoveAsync("testKey5");
-
-      Task.WaitAll(rm1, rm2, rm3, rm4, rm5);
-
-      Assert.Null(ssCache.Get("testKey1"));
-      Assert.Null(ssCache.Get("testKey2"));
-      Assert.Null(ssCache.Get("testKey3"));
-      Assert.Null(ssCache.Get("testKey4"));
-      Assert.Null(ssCache.Get("testKey5"));
+    public void SetGetRemoveAsync()
+    {
+      using (var cluster = new Cluster(output, CreateTestCaseDirectoryName(), 
1, 1))
+      {
+        Assert.True(cluster.Start());
+        Assert.Equal(0, cluster.Gfsh
+            .create()
+            .region()
+            .withName("exampleRegion")
+            .withType("PARTITION")
+            .execute());
+
+        var ssCacheOptions = new GeodeSessionStateCacheOptions();
+        ssCacheOptions.Host = "localhost";
+        ssCacheOptions.Port = cluster.Locators[0].Address.port;
+        ssCacheOptions.RegionName = "exampleRegion";
+
+        using var ssCache = new GeodeSessionStateCache(ssCacheOptions);
+
+        var options = new DistributedCacheEntryOptions();
+        var localTime = DateTime.Now.AddDays(1);
+        var dateAndOffset =
+            new DateTimeOffset(localTime, 
TimeZoneInfo.Local.GetUtcOffset(localTime));
+        options.AbsoluteExpiration = dateAndOffset;
+
+        var testValue1 = new byte[] { 1, 2, 3, 4, 5 };
+        var testValue2 = new byte[] { 11, 12, 13, 14, 15 };
+        var testValue3 = new byte[] { 21, 22, 23, 24, 25 };
+        var testValue4 = new byte[] { 31, 32, 33, 34, 35 };
+        var testValue5 = new byte[] { 41, 42, 43, 44, 45 };
+
+        var set1 = ssCache.SetAsync("testKey1", testValue1, options);
+        var set2 = ssCache.SetAsync("testKey2", testValue2, options);
+        var set3 = ssCache.SetAsync("testKey3", testValue3, options);
+        var set4 = ssCache.SetAsync("testKey4", testValue4, options);
+        var set5 = ssCache.SetAsync("testKey5", testValue5, options);
+
+        Task.WaitAll(set1, set2, set3, set4, set5);
+
+        var value1 = ssCache.GetAsync("testKey1");
+        var value2 = ssCache.GetAsync("testKey2");
+        var value3 = ssCache.GetAsync("testKey3");
+        var value4 = ssCache.GetAsync("testKey4");
+        var value5 = ssCache.GetAsync("testKey5");
+
+        Task.WaitAll(value1, value2, value3, value4, value5);
+
+        Assert.True(testValue1.SequenceEqual(value1.Result));
+        Assert.True(testValue2.SequenceEqual(value2.Result));
+        Assert.True(testValue3.SequenceEqual(value3.Result));
+        Assert.True(testValue4.SequenceEqual(value4.Result));
+        Assert.True(testValue5.SequenceEqual(value5.Result));
+
+        var rm1 = ssCache.RemoveAsync("testKey1");
+        var rm2 = ssCache.RemoveAsync("testKey2");
+        var rm3 = ssCache.RemoveAsync("testKey3");
+        var rm4 = ssCache.RemoveAsync("testKey4");
+        var rm5 = ssCache.RemoveAsync("testKey5");
+
+        Task.WaitAll(rm1, rm2, rm3, rm4, rm5);
+
+        Assert.Null(ssCache.Get("testKey1"));
+        Assert.Null(ssCache.Get("testKey2"));
+        Assert.Null(ssCache.Get("testKey3"));
+        Assert.Null(ssCache.Get("testKey4"));
+        Assert.Null(ssCache.Get("testKey5"));
+      }
     }
   }
 }
diff --git 
a/netcore/netcore-session-integration-test/netcore-session-integration-test.csproj
 
b/netcore/netcore-session-integration-test/netcore-session-integration-test.csproj
index e8a76d7..301d1b9 100644
--- 
a/netcore/netcore-session-integration-test/netcore-session-integration-test.csproj
+++ 
b/netcore/netcore-session-integration-test/netcore-session-integration-test.csproj
@@ -8,6 +8,15 @@
   </PropertyGroup>
 
   <ItemGroup>
+       <Compile Include="..\shared\Config.cs" Link="Config.cs" />
+       <Compile Include="..\shared\Cluster.cs" Link="Cluster.cs" />
+       <Compile Include="..\shared\Gfsh.cs" Link="Gfsh.cs" />
+       <Compile Include="..\shared\Framework.cs" Link="Framework.cs" />
+       <Compile Include="..\shared\GfshExecute.cs" Link="GfshExecute.cs" />
+       <Compile Include="..\shared\TestBase.cs" Link="TestBase.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
        <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
diff --git a/netcore/netcore.sln b/netcore/netcore.sln
new file mode 100644
index 0000000..f4249d3
--- /dev/null
+++ b/netcore/netcore.sln
@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31702.278
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "netcore-lib", 
"netcore-lib\netcore-lib.csproj", "{27274EF5-E606-4D98-98C0-8214B80FC267}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = 
"netcore-integration-test", 
"netcore-integration-test\netcore-integration-test.csproj", 
"{1FB30EB0-1121-4E9D-AAB9-6ABF88378219}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = 
"asp-netcore-session-sample", 
"asp-netcore-session-sample\asp-netcore-session-sample.csproj", 
"{94BC7C9E-1967-4E87-983A-FECD32F7DDE2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "netcore-session", 
"netcore-session\netcore-session.csproj", 
"{72C7BDE7-F933-464A-A5E7-F024D73CD8F1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = 
"netcore-session-integration-test", 
"netcore-session-integration-test\netcore-session-integration-test.csproj", 
"{8C06FA0E-A460-442B-978D-C0195259893F}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|x64 = Debug|x64
+               RelWithDebInfo|x64 = RelWithDebInfo|x64
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {27274EF5-E606-4D98-98C0-8214B80FC267}.Debug|x64.ActiveCfg = 
Debug|x64
+               {27274EF5-E606-4D98-98C0-8214B80FC267}.Debug|x64.Build.0 = 
Debug|x64
+               
{27274EF5-E606-4D98-98C0-8214B80FC267}.RelWithDebInfo|x64.ActiveCfg = 
RelWithDebInfo|x64
+               
{27274EF5-E606-4D98-98C0-8214B80FC267}.RelWithDebInfo|x64.Build.0 = 
RelWithDebInfo|x64
+               {1FB30EB0-1121-4E9D-AAB9-6ABF88378219}.Debug|x64.ActiveCfg = 
Debug|x64
+               {1FB30EB0-1121-4E9D-AAB9-6ABF88378219}.Debug|x64.Build.0 = 
Debug|x64
+               
{1FB30EB0-1121-4E9D-AAB9-6ABF88378219}.RelWithDebInfo|x64.ActiveCfg = 
RelWithDebInfo|x64
+               
{1FB30EB0-1121-4E9D-AAB9-6ABF88378219}.RelWithDebInfo|x64.Build.0 = 
RelWithDebInfo|x64
+               {94BC7C9E-1967-4E87-983A-FECD32F7DDE2}.Debug|x64.ActiveCfg = 
Debug|x64
+               {94BC7C9E-1967-4E87-983A-FECD32F7DDE2}.Debug|x64.Build.0 = 
Debug|x64
+               
{94BC7C9E-1967-4E87-983A-FECD32F7DDE2}.RelWithDebInfo|x64.ActiveCfg = 
RelWithDebInfo|x64
+               
{94BC7C9E-1967-4E87-983A-FECD32F7DDE2}.RelWithDebInfo|x64.Build.0 = 
RelWithDebInfo|x64
+               {72C7BDE7-F933-464A-A5E7-F024D73CD8F1}.Debug|x64.ActiveCfg = 
Debug|x64
+               {72C7BDE7-F933-464A-A5E7-F024D73CD8F1}.Debug|x64.Build.0 = 
Debug|x64
+               
{72C7BDE7-F933-464A-A5E7-F024D73CD8F1}.RelWithDebInfo|x64.ActiveCfg = 
RelWithDebInfo|x64
+               
{72C7BDE7-F933-464A-A5E7-F024D73CD8F1}.RelWithDebInfo|x64.Build.0 = 
RelWithDebInfo|x64
+               {8C06FA0E-A460-442B-978D-C0195259893F}.Debug|x64.ActiveCfg = 
Debug|x64
+               {8C06FA0E-A460-442B-978D-C0195259893F}.Debug|x64.Build.0 = 
Debug|x64
+               
{8C06FA0E-A460-442B-978D-C0195259893F}.RelWithDebInfo|x64.ActiveCfg = 
RelWithDebInfo|x64
+               
{8C06FA0E-A460-442B-978D-C0195259893F}.RelWithDebInfo|x64.Build.0 = 
RelWithDebInfo|x64
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {1C2B71F0-E68A-43D1-9AA1-6A1CEE82C993}
+       EndGlobalSection
+EndGlobal
diff --git a/netcore/CMakeLists.txt b/netcore/shared/CMakeLists.txt
similarity index 68%
copy from netcore/CMakeLists.txt
copy to netcore/shared/CMakeLists.txt
index b5c3536..c9e0ed5 100644
--- a/netcore/CMakeLists.txt
+++ b/netcore/shared/CMakeLists.txt
@@ -12,17 +12,6 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-project(netcore LANGUAGES NONE)
-
-option(INCLUDE_DOTNET_CORE "Build .NET Core client." ON)
-
-find_program(DOTNET dotnet)
-
-if(DOTNET AND INCLUDE_DOTNET_CORE)
-  add_subdirectory(netcore-lib)
-  add_subdirectory(netcore-session)
-  add_subdirectory(netcore-integration-test)
-  add_subdirectory(netcore-session-integration-test)
-  add_subdirectory(utility)
-endif()
+project(netcore-shared LANGUAGES NONE)
 
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cs.in 
${CMAKE_CURRENT_SOURCE_DIR}/Config.cs)
diff --git a/netcore/shared/Cluster.cs b/netcore/shared/Cluster.cs
new file mode 100644
index 0000000..c3d0004
--- /dev/null
+++ b/netcore/shared/Cluster.cs
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Xunit.Abstractions;
+
+namespace Apache.Geode.Client.IntegrationTests
+{
+    public class Cluster : IDisposable
+    {
+        private int locatorCount_;
+        private int serverCount_;
+        private bool started_;
+        private List<Locator> locators_;
+        private string name_;
+        internal int jmxManagerPort = Framework.FreeTcpPort();
+        internal string keyStore_ = Config.SslServerKeyPath + 
"/server_keystore_chained.jks";
+        internal string keyStorePassword_ = "apachegeode";
+        internal string trustStore_ = Config.SslServerKeyPath + 
"/server_truststore_chained_root.jks";
+        internal string trustStorePassword_ = "apachegeode";
+
+        public Gfsh Gfsh { get; private set; }
+
+        public bool UseSSL { get; set; }
+
+        public List<Locator> Locators
+        {
+          get { return locators_; }
+        }
+
+    internal PoolFactory ApplyLocators(PoolFactory poolFactory)
+        {
+            foreach (var locator in locators_)
+            {
+                poolFactory.AddLocator(locator.Address.address, 
locator.Address.port);
+            }
+            return poolFactory;
+        }
+
+        public Cluster(ITestOutputHelper output, string name, int 
locatorCount, int serverCount)
+        {
+            started_ = false;
+            Gfsh = new GfshExecute(output);
+            UseSSL = false;
+            name_ = name;
+            locatorCount_ = locatorCount;
+            serverCount_ = serverCount;
+            locators_ = new List<Locator>();
+        }
+
+        private bool StartLocators()
+        {
+            var success = true;
+
+            for (var i = 0; i < locatorCount_; i++)
+            {
+                var locator = new Locator(this, new List<Locator>(),
+                    name_ + "/locator/" + i.ToString());
+                locators_.Add(locator);
+                success = (locator.Start() == 0);
+            }
+            return success;
+        }
+
+        private bool StartServers()
+        {
+            var success = true;
+
+            for (var i = 0; i < serverCount_; i++)
+            {
+                var server = new Server(this, locators_,
+                    name_ + "/server/" + i.ToString());
+                var localResult = server.Start();
+                if (localResult != 0)
+                {
+                    success = false;
+                }
+            }
+            return success;
+        }
+
+        private void RemoveClusterDirectory()
+        {
+            if (Directory.Exists(name_))
+            {
+                Directory.Delete(name_, true);
+            }
+        }
+
+        public bool Start()
+        {
+            if (!started_)
+            {
+                RemoveClusterDirectory();
+                var locatorSuccess = StartLocators();
+                var serverSuccess = StartServers();
+                started_ = (locatorSuccess && serverSuccess);
+            }
+            return (started_);
+        }
+
+        public void Dispose()
+        {
+            if (started_)
+            {
+                this.Gfsh
+                    .shutdown()
+                    .withIncludeLocators(true)
+                    .execute();
+            }
+        }
+
+        public IGeodeCache CreateCache(IDictionary<string, string> properties)
+        {
+            var cacheFactory = new CacheFactory();
+
+            cacheFactory
+                .SetProperty("log-level", "none")
+                .SetProperty("statistic-sampling-enabled", "false");
+
+            foreach (var pair in properties)
+            {
+                cacheFactory.SetProperty(pair.Key, pair.Value);
+            }
+
+            var cache = cacheFactory.CreateCache();
+
+            ApplyLocators(cache.PoolFactory).CreatePool("default");
+
+            return cache;
+        }
+
+        public IGeodeCache CreateCache()
+        {
+            return CreateCache(new Dictionary<string, string>());
+        }
+
+    }
+
+    public struct Address
+    {
+        public string address;
+        public int port;
+    }
+
+    public class Locator
+    {
+        private Cluster cluster_;
+        private string name_;
+        private List<Locator> locators_;
+        private bool started_;
+
+        public Locator(Cluster cluster, List<Locator> locators, string name)
+        {
+            cluster_ = cluster;
+            locators_ = locators;
+            name_ = name;
+            var address = new Address();
+            address.address = "localhost";
+            address.port = Framework.FreeTcpPort();
+            Address = address;
+        }
+
+        public Address Address { get; private set; }
+
+        public int Start()
+        {
+            var result = -1;
+            if (!started_)
+            {
+                var locator = cluster_.Gfsh
+                    .start()
+                    .locator()
+                    .withDir(name_)
+                    .withName(name_.Replace('/', '_'))
+                    .withBindAddress(Address.address)
+                    .withPort(Address.port)
+                    .withMaxHeap("256m")
+                    .withJmxManagerPort(cluster_.jmxManagerPort)
+                    .withJmxManagerStart(true)
+                    .withHttpServicePort(0);
+                if (cluster_.UseSSL)
+                {
+                   locator
+                        .withConnect(false)
+                        .withSslEnableComponents("all")
+                        .withSslKeyStore(cluster_.keyStore_)
+                        .withSslKeyStorePassword(cluster_.keyStorePassword_)
+                        .withSslTrustStore(cluster_.trustStore_)
+                        
.withSslTrustStorePassword(cluster_.trustStorePassword_);
+                }
+                result = locator.execute();
+
+                if (cluster_.UseSSL)
+                {
+                    cluster_.Gfsh.connect()
+                        .withJmxManager(Address.address, 
cluster_.jmxManagerPort)
+                        .withUseSsl(true)
+                        .withKeyStore(cluster_.keyStore_)
+                        .withKeyStorePassword(cluster_.keyStorePassword_)
+                        .withTrustStore(cluster_.trustStore_)
+                        .withTrustStorePassword(cluster_.trustStorePassword_)
+                        .execute();
+                }
+
+                started_ = true;
+
+            }
+            return result;
+        }
+
+        public int Stop()
+        {
+            var result = cluster_.Gfsh
+                .stop()
+                .locator()
+                .withDir(name_)
+                .execute();
+            started_ = false;
+            return result;
+        }
+    }
+
+    public class Server
+    {
+        private Cluster cluster_;
+        private string name_;
+        private List<Locator> locators_;
+        private bool started_;
+
+        public Server(Cluster cluster, List<Locator> locators, string name)
+        {
+            cluster_ = cluster;
+            locators_ = locators;
+            name_ = name;
+            var address = new Address();
+            address.address = "localhost";
+            address.port = 0;
+            Address = address;
+        }
+
+        public Address Address { get; private set; }
+
+        public int Start()
+        {
+            var result = -1;
+            if (!started_)
+            {
+                var server = cluster_.Gfsh
+                    .start()
+                    .server()
+                    .withDir(name_)
+                    .withName(name_.Replace('/', '_'))
+                    .withBindAddress(Address.address)
+                    .withPort(Address.port)
+                    .withMaxHeap("1g");
+                if (cluster_.UseSSL)
+                {
+                    server
+                        .withSslEnableComponents("all")
+                        .withSslKeyStore(cluster_.keyStore_)
+                        .withSslKeyStorePassword(cluster_.keyStorePassword_)
+                        .withSslTrustStore(cluster_.trustStore_)
+                        
.withSslTrustStorePassword(cluster_.trustStorePassword_);
+
+                }
+                result = server.execute();
+                started_ = true;
+            }
+            return result;
+        }
+
+        public int Stop()
+        {
+            var result = cluster_.Gfsh
+                .stop()
+                .server()
+                .withDir(name_)
+                .execute();
+            started_ = false;
+            return result;
+        }
+    }
+}
diff --git a/netcore/netcore-integration-test/NetCoreCollectionFixture.cs 
b/netcore/shared/Config.cs.in
similarity index 57%
copy from netcore/netcore-integration-test/NetCoreCollectionFixture.cs
copy to netcore/shared/Config.cs.in
index d30833e..4111ec2 100644
--- a/netcore/netcore-integration-test/NetCoreCollectionFixture.cs
+++ b/netcore/shared/Config.cs.in
@@ -1,4 +1,4 @@
-/*
+/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -14,20 +14,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-using System;
-using Apache.Geode.Client;
-using Xunit;
 
-public class NetCoreCollectionFixture : IDisposable {
-  public NetCoreCollectionFixture() {
-    client_ = new Client();
+// GENERATED FROM Config.cs.in DO NOT EDIT Config.cs
+
+public class Config
+{
+  public static string GeodeGfsh
+  {
+    get { return @"@Geode_gfsh_EXECUTABLE@"; }
   }
-  public void Dispose() {
-    client_.Dispose();
+
+  public static string JavaobjectJarPath
+  {
+    get { return @"@JAVAOBJECT_JAR_PATH@"; }
   }
 
-  Client client_;
-}
+  public static string SslServerKeyPath
+  {
+       get { return @"@CMAKE_CURRENT_SOURCE_DIR@/../../ssl_keys/server_keys"; }
+  }
 
-[CollectionDefinition("Geode .net Core Collection")]
-public class NetCoreCollection : ICollectionFixture<NetCoreCollectionFixture> 
{}
+  public static string SslClientKeyPath
+  {
+       get { return @"@CMAKE_CURRENT_SOURCE_DIR@/../../ssl_keys/client_keys"; }
+  }
+
+  public static string SniConfigPath
+  {
+       get { return @"@CMAKE_CURRENT_SOURCE_DIR@/../../sni-test-config"; }
+  }
+}
diff --git a/netcore/netcore-integration-test/NetCoreCollectionFixture.cs 
b/netcore/shared/Framework.cs
similarity index 65%
copy from netcore/netcore-integration-test/NetCoreCollectionFixture.cs
copy to netcore/shared/Framework.cs
index d30833e..d005c07 100644
--- a/netcore/netcore-integration-test/NetCoreCollectionFixture.cs
+++ b/netcore/shared/Framework.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -14,20 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-using System;
-using Apache.Geode.Client;
-using Xunit;
 
-public class NetCoreCollectionFixture : IDisposable {
-  public NetCoreCollectionFixture() {
-    client_ = new Client();
-  }
-  public void Dispose() {
-    client_.Dispose();
-  }
+using System.Net;
+using System.Net.Sockets;
 
-  Client client_;
-}
-
-[CollectionDefinition("Geode .net Core Collection")]
-public class NetCoreCollection : ICollectionFixture<NetCoreCollectionFixture> 
{}
+namespace Apache.Geode.Client.IntegrationTests
+{
+    public abstract class Framework
+    {
+        public static int FreeTcpPort()
+        {
+            var tcpListner = new TcpListener(IPAddress.Loopback, 0);
+            tcpListner.Start();
+            var port = ((IPEndPoint)tcpListner.LocalEndpoint).Port;
+            tcpListner.Stop();
+            return port;
+        }
+    }
+}
\ No newline at end of file
diff --git a/netcore/shared/Gfsh.cs b/netcore/shared/Gfsh.cs
new file mode 100644
index 0000000..14ba81b
--- /dev/null
+++ b/netcore/shared/Gfsh.cs
@@ -0,0 +1,493 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Net;
+using System.Net.Sockets;
+
+namespace Apache.Geode.Client.IntegrationTests
+{
+    public abstract class Gfsh 
+    {
+
+        //TODO: Understand what C++ Command class is doing.  Why is it a 
template,
+        //when the only <T> class we're passing is void?  How can you call a 
ctor
+        //or a (non-existent?) 'parse' function on void?  So many questions...
+        public class Command
+        {
+            public Command(Gfsh gfsh, string command)
+            {
+                gfsh_ = gfsh;
+                command_ = command;
+            }
+
+            public int execute()
+            {
+                return gfsh_.execute(command_);
+            }
+
+            public override string ToString()
+            {
+                return command_;
+            }
+
+            protected Gfsh gfsh_;
+            protected string command_;
+        }
+
+        public class Start
+        {
+            public Start(Gfsh gfsh)
+            {
+                gfsh_ = gfsh;
+            }
+
+            public class Server : Command
+            {
+                public Server(Gfsh gfsh) : base(gfsh, "start server")
+                {
+                    gfsh_ = gfsh;
+                }
+
+                public Server withName(string name)
+                {
+                    command_ += " --name=" + name;
+                    return this;
+                }
+
+                public Server withDir(string dir)
+                {
+                    command_ += " --dir=" + dir;
+                    return this;
+                }
+
+                public Server withBindAddress(string bindAddress)
+                {
+                    command_ += " --bind-address=" + bindAddress;
+                    return this;
+                }
+
+                public Server withPort(int port)
+                {
+                    command_ += " --server-port=" + port.ToString();
+                    return this;
+                }
+
+                public Server withLocators(string locators)
+                {
+                    command_ += " --locators=" + locators;
+                    return this;
+                }
+
+                public Server withLogLevel(string logLevel)
+                {
+                    command_ += " --log-level=" + logLevel;
+                    return this;
+                }
+
+                public Server withMaxHeap(string maxHeap)
+                {
+                    command_ += " --max-heap=" + maxHeap;
+                    return this;
+                }
+
+               public Server withSslKeyStore(string keyStore)
+                {
+                    command_ += " --J=-Dgemfire.ssl-keystore=" + keyStore;
+                    return this;
+                }
+
+                public Server withSslKeyStorePassword(string keyStorePassword)
+                {
+                    command_ += " --J=-Dgemfire.ssl-keystore-password=" + 
keyStorePassword;
+                    return this;
+                }
+
+                public Server withSslTrustStore(string trustStore)
+                {
+                    command_ += " --J=-Dgemfire.ssl-truststore=" + trustStore;
+                    return this;
+                }
+
+                public Server withSslTrustStorePassword(string 
trustStorePassword)
+                {
+                    command_ += " --J=-Dgemfire.ssl-truststore-password=" + 
trustStorePassword;
+                    return this;
+                }
+
+                public Server withSslEnableComponents(string components)
+                {
+                    command_ += " --J=-Dgemfire.ssl-enabled-components=" + 
components;
+                    return this;
+                }
+            }
+
+            public Server server()
+            {
+                return new Server(gfsh_);
+            }
+
+            public class Locator : Command
+            {
+                public Locator(Gfsh gfsh) : base(gfsh, "start locator")
+                {
+                }
+
+                public Locator withName(string name)
+                {
+                    command_ += " --name=" + name;
+                    return this;
+                }
+
+                public Locator withDir(string dir)
+                {
+                    command_ += " --dir=" + dir;
+                    return this;
+                }
+
+                public Locator withBindAddress(string bindAddress)
+                {
+                    command_ += " --bind-address=" + bindAddress;
+                    return this;
+                }
+
+                public Locator withPort(int port)
+                {
+                    command_ += " --port=" + port;
+                    return this;
+                }
+
+                public Locator withJmxManagerPort(int jmxManagerPort)
+                {
+                    command_ += " --J=-Dgemfire.jmx-manager-port=" + 
jmxManagerPort;
+                    return this;
+                }
+
+                public Locator withJmxManagerStart(bool start)
+                {
+                    command_ += " --J=-Dgemfire.jmx-manager-start=" + (start ? 
"true" : "false");
+                    return this;
+                }
+                
+                public Locator withHttpServicePort(int httpServicePort)
+                {
+                    command_ += " --http-service-port=" + httpServicePort;
+                    return this;
+                }
+
+                public Locator withLogLevel(string logLevel)
+                {
+                    command_ += " --log-level=" + logLevel;
+                    return this;
+                }
+
+                public Locator withMaxHeap(string maxHeap)
+                {
+                    command_ += " --max-heap=" + maxHeap;
+                    return this;
+                }
+
+                public Locator withConnect(bool connect)
+                {
+                    command_ += " --connect=";
+                    command_ += connect ? "true" : "false";
+                    return this;
+                }
+
+                public Locator withSslKeyStore(string keyStore)
+                {
+                    command_ += " --J=-Dgemfire.ssl-keystore=" + keyStore;
+                    return this;
+                }
+
+                public Locator withSslKeyStorePassword(string keyStorePassword)
+                {
+                    command_ += " --J=-Dgemfire.ssl-keystore-password=" + 
keyStorePassword;
+                    return this;
+                }
+
+                public Locator withSslTrustStore(string trustStore)
+                {
+                    command_ += " --J=-Dgemfire.ssl-truststore=" + trustStore;
+                    return this;
+                }
+
+                public Locator withSslTrustStorePassword(string 
trustStorePassword)
+                {
+                    command_ += " --J=-Dgemfire.ssl-truststore-password=" + 
trustStorePassword;
+                    return this;
+                }
+
+                public Locator withSslEnableComponents(string components)
+                {
+                    command_ += " --J=-Dgemfire.ssl-enabled-components=" + 
components;
+                    return this;
+                }
+            }
+
+            public Locator locator()
+            {
+                return new Locator(gfsh_);
+            }
+
+            private Gfsh gfsh_;
+        }
+
+        public Start start()
+        {
+            return new Start(this);
+        }
+
+        public class Stop
+        {
+            public Stop(Gfsh gfsh)
+            {
+                gfsh_ = gfsh;
+            }
+
+            public class Locator : Command
+            {
+                public Locator(Gfsh gfsh) : base(gfsh, "stop locator")
+                {
+                }
+
+                public Locator withName(string name)
+                {
+                    command_ += " --name=" + name;
+                    return this;
+                }
+
+                public Locator withDir(string dir)
+                {
+                    command_ += " --dir=" + dir;
+                    return this;
+                }
+            }
+
+            public Locator locator()
+            {
+                return new Locator(gfsh_);
+            }
+
+            public class Server : Command
+            {
+                public Server(Gfsh gfsh) : base(gfsh, "stop server")
+                {
+                }
+
+                public Server withName(string name)
+                {
+                    command_ += " --name=" + name;
+                    return this;
+                }
+
+                public Server withDir(string dir)
+                {
+                    command_ += " --dir=" + dir;
+                    return this;
+                }
+            }
+            public Server server()
+            {
+                return new Server(gfsh_);
+            }
+
+            private Gfsh gfsh_;
+        }
+
+        public Stop stop()
+        {
+            return new Stop(this);
+        }
+
+        public class Create
+        {
+            public Create(Gfsh gfsh)
+            {
+                gfsh_ = gfsh;
+            }
+
+            public class Region : Command
+            {
+                public Region(Gfsh gfsh) : base(gfsh, "create region") { }
+
+                public Region withName(string name)
+                {
+                    command_ += " --name=" + name;
+                    return this;
+                }
+
+                public Region withType(string type)
+                {
+                    command_ += " --type=" + type;
+                    return this;
+                }
+            }
+
+            public Region region()
+            {
+                return new Region(gfsh_);
+            }
+
+            private Gfsh gfsh_;
+        }
+        public Create create()
+        {
+            return new Create(this);
+        }
+
+        public class Shutdown : Command
+        {
+            public Shutdown(Gfsh gfsh) : base(gfsh, "shutdown") { }
+
+            public Shutdown withIncludeLocators(bool includeLocators)
+            {
+                command_ += " --include-locators=";
+                command_ += includeLocators ? "true" : "false";
+                return this;
+            }
+        }
+
+        public Shutdown shutdown()
+        {
+            return new Shutdown(this);
+        }
+
+        public class Connect : Command
+        {
+            public Connect(Gfsh gfsh) : base(gfsh, "connect") { }
+
+            public Connect withJmxManager(string jmxManagerAddress, int 
jmxManagerPort)
+            {
+                command_ += " --jmx-manager=" + jmxManagerAddress + "[" + 
jmxManagerPort.ToString() + "]";
+                return this;
+            }
+
+            public Connect withUseSsl(bool enable)
+            {
+                command_ += " --use-ssl=" + (enable ? "true" : "false");
+                return this;
+            }
+
+            public Connect withKeyStore(string keyStore)
+            {
+                command_ += " --key-store=" + keyStore;
+                return this;
+            }
+
+            public Connect withKeyStorePassword(string keyStorePassword)
+            {
+                command_ += " --key-store-password=" + keyStorePassword;
+                return this;
+            }
+
+            public Connect withTrustStore(string trustStore)
+            {
+                command_ += " --trust-store=" + trustStore;
+                return this;
+            }
+
+            public Connect withTrustStorePassword(string trustStorePassword)
+            {
+                command_ += " --trust-store-password=" + trustStorePassword;
+                return this;
+            }
+        }
+
+        public Connect connect()
+        {
+            return new Connect(this);
+        }
+
+        public class ConfigurePdx : Command
+        {
+            public ConfigurePdx(Gfsh gfsh) : base(gfsh, "configure pdx") { }
+
+            public ConfigurePdx withReadSerialized(bool readSerialized)
+            {
+                command_ += " --read-serialized=";
+                command_ += readSerialized ? "true" : "false";
+                return this;
+            }
+        }
+
+        public ConfigurePdx configurePdx()
+        {
+            return new ConfigurePdx(this);
+        }
+
+        public class Deploy : Command
+        {
+            public Deploy(Gfsh gfsh) : base(gfsh, "deploy") { }
+
+            public Deploy withJar(string fullPathToJar)
+            {
+                command_ += " --jar=" + fullPathToJar;
+                return this;
+            }
+
+            public Deploy withDir(string fullPathToDir)
+            {
+                command_ += " --dir=" + fullPathToDir;
+                return this;
+            }
+
+            public Deploy withGroup(string groupName)
+            {
+                command_ += " --group=" + groupName;
+                return this;
+            }
+        }
+
+        public Deploy deploy()
+        {
+            return new Deploy(this);
+        }
+
+        public class ExecuteFunction : Command
+        {
+            public ExecuteFunction(Gfsh gfsh) : base(gfsh, "execute function") 
{ }
+
+            public ExecuteFunction withId(string functionId)
+            {
+                command_ += " --id=" + functionId;
+                return this;
+            }
+
+            public ExecuteFunction withMember(string memberName)
+            {
+                command_ += " --member=" + memberName;
+                return this;
+            }
+        }
+
+        public ExecuteFunction executeFunction()
+        {
+            return new ExecuteFunction(this);
+        }
+
+        private static int FreeTcpPort()
+        {
+            var tcpListner = new TcpListener(IPAddress.Loopback, 0);
+            tcpListner.Start();
+            var port = ((IPEndPoint)tcpListner.LocalEndpoint).Port;
+            tcpListner.Stop();
+            return port;
+        }
+
+        public abstract int execute(string cmd);
+    }
+}
diff --git a/netcore/shared/GfshExecute.cs b/netcore/shared/GfshExecute.cs
new file mode 100644
index 0000000..6171783
--- /dev/null
+++ b/netcore/shared/GfshExecute.cs
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using System.Collections.Generic;
+using Xunit.Abstractions;
+
+namespace Apache.Geode.Client.IntegrationTests
+{
+    public class GfshExecute : Gfsh
+    {
+        private String connectionCommand_ = null;
+        private ITestOutputHelper output;
+
+        public GfshExecute(ITestOutputHelper output)
+        {
+            this.output = output;
+        }
+
+        private void ExtractConnectionCommand(String command)
+        {
+            if (command.StartsWith("connect"))
+            {
+                connectionCommand_ = command;
+            }
+            else if (command.StartsWith("start locator"))
+            {
+                if (command.Contains("--connect=false"))
+                {
+                    return;
+                }
+
+                var jmxManagerHost = "localhost";
+                var jmxManagerPort = "1099";
+
+                var jmxManagerHostRegex = new 
Regex(@"\bbind-address=([^\s])\b");
+                var jmxManagerHostMatch = jmxManagerHostRegex.Match(command);
+
+                if (jmxManagerHostMatch.Success)
+                {
+                    jmxManagerHost = jmxManagerHostMatch.Groups[1].Value;
+                }
+
+                var jmxManagerPortRegex = new 
Regex(@"\bjmx-manager-port=(\d+)\b");
+                var jmxManagerPortMatch = jmxManagerPortRegex.Match(command);
+                if (jmxManagerPortMatch.Success)
+                {
+                    jmxManagerPort = jmxManagerPortMatch.Groups[1].Value;
+                }
+
+                connectionCommand_ = new 
Connect(this).withJmxManager(jmxManagerHost, 
int.Parse(jmxManagerPort)).ToString();
+            }
+
+        }
+
+        public override int execute(string cmd)
+        {
+
+            var commands = new List<string>();
+
+            if (null != connectionCommand_)
+            {
+                commands.Add("-e");
+                commands.Add(connectionCommand_);
+            }
+
+            commands.Add("-e");
+            commands.Add(cmd);
+
+            // TODO escape commands
+            var fullCmd = "\"" + string.Join("\" \"", commands) + "\"";
+
+            using var gfsh = new Process
+            {
+                StartInfo =
+                {
+                    FileName = Config.GeodeGfsh,
+                    Arguments = fullCmd,
+                    WindowStyle = ProcessWindowStyle.Hidden,
+                    UseShellExecute = false,
+                    RedirectStandardOutput = true,
+                    RedirectStandardError = true,
+                    CreateNoWindow = false
+                }
+            };
+
+            gfsh.OutputDataReceived += (sender, args) =>
+            {
+                if (args.Data != null)
+                {
+                    WriteLine("GfshExecute: " + args.Data);
+                }
+            };
+
+            gfsh.ErrorDataReceived += (sender, args) =>
+            {
+                if (args.Data != null)
+                {
+                    WriteLine("GfshExecute: ERROR: " + args.Data);
+                }
+            };
+
+            gfsh.Start();
+            gfsh.BeginOutputReadLine();
+            gfsh.BeginErrorReadLine();
+            if (gfsh.WaitForExit(60000))
+            {
+                WriteLine("GeodeServer Start: gfsh.HasExited = {0}, 
gfsh.ExitCode = {1}",
+                    gfsh.HasExited,
+                    gfsh.ExitCode);
+            }
+            else
+            {
+                WriteLine("GeodeServer Start: gfsh failed to exit, force 
killing.");
+                KillAndIgnore(gfsh);
+            }
+            CancelErrorReadAndIgnore(gfsh);
+            CancelOutputReadAndIgnore(gfsh);
+
+            ExtractConnectionCommand(cmd);
+
+            return gfsh.ExitCode;
+        }
+
+        private static void CancelOutputReadAndIgnore(Process gfsh)
+        {
+            try
+            {
+                gfsh.CancelOutputRead();
+            }
+            catch
+            {
+                // ignored
+            }
+        }
+
+        private static void CancelErrorReadAndIgnore(Process gfsh)
+        {
+            try
+            {
+                gfsh.CancelErrorRead();
+            }
+            catch
+            {
+                // ignored
+            }
+        }
+
+        private static void KillAndIgnore(Process gfsh)
+        {
+            try
+            {
+                gfsh.Kill();
+            }
+            catch
+            {
+                // ignored
+            }
+        }
+
+        private void WriteLine(string format, params object[] args)
+        {
+            if (null == output)
+            {
+                Debug.WriteLine(format, args);
+            }
+            else
+            {
+                output.WriteLine(format, args);
+            }
+        }
+
+        private void WriteLine(string message)
+        {
+            if (null == output)
+            {
+                Debug.WriteLine(message);
+            }
+            else
+            {
+                output.WriteLine(message);
+            }
+        }
+    }
+}
diff --git a/netcore/shared/TestBase.cs b/netcore/shared/TestBase.cs
new file mode 100644
index 0000000..20c8875
--- /dev/null
+++ b/netcore/shared/TestBase.cs
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.IO;
+using System.Reflection;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Apache.Geode.Client.IntegrationTests {
+    [Trait("Category", "Integration")]
+    public class TestBase
+    {
+        protected ITest currentTest;
+        protected ITestOutputHelper output;
+
+        public TestBase(ITestOutputHelper testOutputHelper)
+        {
+            var helper = (TestOutputHelper)testOutputHelper;
+
+            ITest test = (ITest)helper.GetType().GetField("test", 
BindingFlags.NonPublic | BindingFlags.Instance)
+                                      .GetValue(helper);
+
+            currentTest = test;
+            output = testOutputHelper;
+        }
+
+        public void CleanTestCaseDirectory(string directory)
+        {
+            if (Directory.Exists(directory))
+            {
+                Directory.Delete(directory, true);
+            }
+        }
+
+        public string CreateTestCaseDirectoryName()
+        {
+            return currentTest.TestCase.TestMethod.Method.Name;
+        }
+    }
+}

Reply via email to