Browse Source

Packaging: Add vagrant tests for windows service (#33729)

This commit adds tests using the vagrant windows image for the windows
service manager script.
Ryan Ernst 6 years ago
parent
commit
9ef54203d7

+ 7 - 1
distribution/src/bin/elasticsearch-service.bat

@@ -34,6 +34,7 @@ if /i %SERVICE_CMD% == start goto doStart
 if /i %SERVICE_CMD% == stop goto doStop
 if /i %SERVICE_CMD% == manager goto doManagment
 echo Unknown option "%SERVICE_CMD%"
+exit /B 1
 
 :displayUsage
 echo.
@@ -44,6 +45,7 @@ goto:eof
 "%EXECUTABLE%" //ES//%SERVICE_ID% %LOG_OPTS%
 if not errorlevel 1 goto started
 echo Failed starting '%SERVICE_ID%' service
+exit /B 1
 goto:eof
 :started
 echo The service '%SERVICE_ID%' has been started
@@ -53,16 +55,18 @@ goto:eof
 "%EXECUTABLE%" //SS//%SERVICE_ID% %LOG_OPTS%
 if not errorlevel 1 goto stopped
 echo Failed stopping '%SERVICE_ID%' service
+exit /B 1
 goto:eof
 :stopped
 echo The service '%SERVICE_ID%' has been stopped
 goto:eof
 
 :doManagment
-set EXECUTABLE_MGR=%ES_HOME%\bin\elasticsearch-service-mgr.exe
+set EXECUTABLE_MGR=%ES_HOME%\bin\elasticsearch-service-mgr
 "%EXECUTABLE_MGR%" //ES//%SERVICE_ID%
 if not errorlevel 1 goto managed
 echo Failed starting service manager for '%SERVICE_ID%'
+exit /B 1
 goto:eof
 :managed
 echo Successfully started service manager for '%SERVICE_ID%'.
@@ -73,6 +77,7 @@ rem Remove the service
 "%EXECUTABLE%" //DS//%SERVICE_ID% %LOG_OPTS%
 if not errorlevel 1 goto removed
 echo Failed removing '%SERVICE_ID%' service
+exit /B 1
 goto:eof
 :removed
 echo The service '%SERVICE_ID%' has been removed
@@ -177,6 +182,7 @@ if not "%SERVICE_USERNAME%" == "" (
 
 if not errorlevel 1 goto installed
 echo Failed installing '%SERVICE_ID%' service
+exit /B 1
 goto:eof
 
 :installed

+ 11 - 10
qa/vagrant/src/main/java/org/elasticsearch/packaging/PackagingTests.java

@@ -19,20 +19,20 @@
 
 package org.elasticsearch.packaging;
 
-import org.elasticsearch.packaging.test.DefaultDebPreservationTests;
 import org.elasticsearch.packaging.test.DefaultDebBasicTests;
-import org.elasticsearch.packaging.test.DefaultRpmPreservationTests;
+import org.elasticsearch.packaging.test.DefaultDebPreservationTests;
 import org.elasticsearch.packaging.test.DefaultRpmBasicTests;
-import org.elasticsearch.packaging.test.OssDebPreservationTests;
+import org.elasticsearch.packaging.test.DefaultRpmPreservationTests;
+import org.elasticsearch.packaging.test.DefaultTarTests;
+import org.elasticsearch.packaging.test.DefaultWindowsServiceTests;
+import org.elasticsearch.packaging.test.DefaultZipTests;
 import org.elasticsearch.packaging.test.OssDebBasicTests;
-import org.elasticsearch.packaging.test.OssRpmPreservationTests;
+import org.elasticsearch.packaging.test.OssDebPreservationTests;
 import org.elasticsearch.packaging.test.OssRpmBasicTests;
+import org.elasticsearch.packaging.test.OssRpmPreservationTests;
 import org.elasticsearch.packaging.test.OssTarTests;
+import org.elasticsearch.packaging.test.OssWindowsServiceTests;
 import org.elasticsearch.packaging.test.OssZipTests;
-import org.elasticsearch.packaging.test.DefaultTarTests;
-import org.elasticsearch.packaging.test.DefaultZipTests;
-import org.elasticsearch.packaging.test.PackageDependenciesTests;
-
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
@@ -43,7 +43,6 @@ import org.junit.runners.Suite.SuiteClasses;
     OssTarTests.class,
     DefaultZipTests.class,
     OssZipTests.class,
-    PackageDependenciesTests.class,
     DefaultRpmBasicTests.class,
     OssRpmBasicTests.class,
     DefaultDebBasicTests.class,
@@ -51,6 +50,8 @@ import org.junit.runners.Suite.SuiteClasses;
     DefaultDebPreservationTests.class,
     OssDebPreservationTests.class,
     DefaultRpmPreservationTests.class,
-    OssRpmPreservationTests.class
+    OssRpmPreservationTests.class,
+    DefaultWindowsServiceTests.class,
+    OssWindowsServiceTests.class
 })
 public class PackagingTests {}

+ 2 - 26
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/ArchiveTestCase.java

@@ -22,15 +22,12 @@ package org.elasticsearch.packaging.test;
 import com.carrotsearch.randomizedtesting.annotations.TestCaseOrdering;
 import org.apache.http.client.fluent.Request;
 import org.elasticsearch.packaging.util.Archives;
+import org.elasticsearch.packaging.util.Distribution;
+import org.elasticsearch.packaging.util.Installation;
 import org.elasticsearch.packaging.util.Platforms;
 import org.elasticsearch.packaging.util.ServerUtils;
 import org.elasticsearch.packaging.util.Shell;
 import org.elasticsearch.packaging.util.Shell.Result;
-import org.junit.Before;
-import org.junit.BeforeClass;
-
-import org.elasticsearch.packaging.util.Distribution;
-import org.elasticsearch.packaging.util.Installation;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -40,7 +37,6 @@ import java.util.stream.Stream;
 
 import static java.util.stream.Collectors.joining;
 import static org.elasticsearch.packaging.util.Archives.ARCHIVE_OWNER;
-import static org.elasticsearch.packaging.util.Cleanup.cleanEverything;
 import static org.elasticsearch.packaging.util.Archives.installArchive;
 import static org.elasticsearch.packaging.util.Archives.verifyArchiveInstallation;
 import static org.elasticsearch.packaging.util.FileMatcher.Fileness.File;
@@ -55,12 +51,8 @@ import static org.elasticsearch.packaging.util.ServerUtils.makeRequest;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.isEmptyString;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeThat;
-import static org.junit.Assume.assumeTrue;
 
 /**
  * Tests that apply to the archive distributions (tar, zip). To add a case for a distribution, subclass and
@@ -69,22 +61,6 @@ import static org.junit.Assume.assumeTrue;
 @TestCaseOrdering(TestCaseOrdering.AlphabeticOrder.class)
 public abstract class ArchiveTestCase extends PackagingTestCase {
 
-    private static Installation installation;
-
-    /** The {@link Distribution} that should be tested in this case */
-    protected abstract Distribution distribution();
-
-    @BeforeClass
-    public static void cleanup() {
-        installation = null;
-        cleanEverything();
-    }
-
-    @Before
-    public void onlyCompatibleDistributions() {
-        assumeTrue("only compatible distributions", distribution().packaging.compatible);
-    }
-
     public void test10Install() {
         installation = installArchive(distribution());
         verifyArchiveInstallation(installation, distribution());

+ 30 - 0
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/DefaultWindowsServiceTests.java

@@ -0,0 +1,30 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.
+ */
+
+package org.elasticsearch.packaging.test;
+
+import org.elasticsearch.packaging.util.Distribution;
+
+public class DefaultWindowsServiceTests extends WindowsServiceTestCase {
+
+    @Override
+    protected Distribution distribution() {
+        return Distribution.DEFAULT_ZIP;
+    }
+}

+ 25 - 0
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/OssDebBasicTests.java

@@ -19,7 +19,17 @@
 
 package org.elasticsearch.packaging.test;
 
+import junit.framework.TestCase;
 import org.elasticsearch.packaging.util.Distribution;
+import org.elasticsearch.packaging.util.Platforms;
+import org.elasticsearch.packaging.util.Shell;
+
+import java.util.regex.Pattern;
+
+import static org.elasticsearch.packaging.util.Distribution.DEFAULT_DEB;
+import static org.elasticsearch.packaging.util.Distribution.OSS_DEB;
+import static org.elasticsearch.packaging.util.FileUtils.getDistributionFile;
+import static org.junit.Assume.assumeTrue;
 
 public class OssDebBasicTests extends PackageTestCase {
 
@@ -27,4 +37,19 @@ public class OssDebBasicTests extends PackageTestCase {
     protected Distribution distribution() {
         return Distribution.OSS_DEB;
     }
+
+    public void test11DebDependencies() {
+        assumeTrue(Platforms.isDPKG());
+
+        final Shell sh = new Shell();
+
+        final Shell.Result defaultResult = sh.run("dpkg -I " + getDistributionFile(DEFAULT_DEB));
+        final Shell.Result ossResult = sh.run("dpkg -I " + getDistributionFile(OSS_DEB));
+
+        TestCase.assertTrue(Pattern.compile("(?m)^ Depends:.*bash.*").matcher(defaultResult.stdout).find());
+        TestCase.assertTrue(Pattern.compile("(?m)^ Depends:.*bash.*").matcher(ossResult.stdout).find());
+
+        TestCase.assertTrue(Pattern.compile("(?m)^ Conflicts: elasticsearch-oss$").matcher(defaultResult.stdout).find());
+        TestCase.assertTrue(Pattern.compile("(?m)^ Conflicts: elasticsearch$").matcher(ossResult.stdout).find());
+    }
 }

+ 28 - 0
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/OssRpmBasicTests.java

@@ -19,7 +19,17 @@
 
 package org.elasticsearch.packaging.test;
 
+import junit.framework.TestCase;
 import org.elasticsearch.packaging.util.Distribution;
+import org.elasticsearch.packaging.util.Platforms;
+import org.elasticsearch.packaging.util.Shell;
+
+import java.util.regex.Pattern;
+
+import static org.elasticsearch.packaging.util.Distribution.DEFAULT_RPM;
+import static org.elasticsearch.packaging.util.Distribution.OSS_RPM;
+import static org.elasticsearch.packaging.util.FileUtils.getDistributionFile;
+import static org.junit.Assume.assumeTrue;
 
 public class OssRpmBasicTests extends PackageTestCase {
 
@@ -27,4 +37,22 @@ public class OssRpmBasicTests extends PackageTestCase {
     protected Distribution distribution() {
         return Distribution.OSS_RPM;
     }
+
+    public void test11RpmDependencies() {
+        assumeTrue(Platforms.isRPM());
+
+        final Shell sh = new Shell();
+
+        final Shell.Result defaultDeps = sh.run("rpm -qpR " + getDistributionFile(DEFAULT_RPM));
+        final Shell.Result ossDeps = sh.run("rpm -qpR " + getDistributionFile(OSS_RPM));
+
+        TestCase.assertTrue(Pattern.compile("(?m)^/bin/bash\\s*$").matcher(defaultDeps.stdout).find());
+        TestCase.assertTrue(Pattern.compile("(?m)^/bin/bash\\s*$").matcher(ossDeps.stdout).find());
+
+        final Shell.Result defaultConflicts = sh.run("rpm -qp --conflicts " + getDistributionFile(DEFAULT_RPM));
+        final Shell.Result ossConflicts = sh.run("rpm -qp --conflicts " + getDistributionFile(OSS_RPM));
+
+        TestCase.assertTrue(Pattern.compile("(?m)^elasticsearch-oss\\s*$").matcher(defaultConflicts.stdout).find());
+        TestCase.assertTrue(Pattern.compile("(?m)^elasticsearch\\s*$").matcher(ossConflicts.stdout).find());
+    }
 }

+ 30 - 0
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/OssWindowsServiceTests.java

@@ -0,0 +1,30 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.
+ */
+
+package org.elasticsearch.packaging.test;
+
+import org.elasticsearch.packaging.util.Distribution;
+
+public class OssWindowsServiceTests extends WindowsServiceTestCase {
+
+    @Override
+    protected Distribution distribution() {
+        return Distribution.OSS_ZIP;
+    }
+}

+ 0 - 73
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/PackageDependenciesTests.java

@@ -1,73 +0,0 @@
-/*
- * Licensed to Elasticsearch under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch 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.
- */
-
-package org.elasticsearch.packaging.test;
-
-import org.elasticsearch.packaging.util.Platforms;
-import org.elasticsearch.packaging.util.Shell;
-import org.elasticsearch.packaging.util.Shell.Result;
-
-import java.util.regex.Pattern;
-
-import static junit.framework.TestCase.assertTrue;
-import static org.elasticsearch.packaging.util.Distribution.DEFAULT_DEB;
-import static org.elasticsearch.packaging.util.Distribution.DEFAULT_RPM;
-import static org.elasticsearch.packaging.util.Distribution.OSS_DEB;
-import static org.elasticsearch.packaging.util.Distribution.OSS_RPM;
-import static org.elasticsearch.packaging.util.FileUtils.getDistributionFile;
-import static org.junit.Assume.assumeTrue;
-
-/**
- * Tests that linux packages correctly declare their dependencies and their conflicts
- */
-public class PackageDependenciesTests extends PackagingTestCase {
-
-    public void testDebDependencies() {
-        assumeTrue(Platforms.isDPKG());
-
-        final Shell sh = new Shell();
-
-        final Result defaultResult = sh.run("dpkg -I " + getDistributionFile(DEFAULT_DEB));
-        final Result ossResult = sh.run("dpkg -I " + getDistributionFile(OSS_DEB));
-
-        assertTrue(Pattern.compile("(?m)^ Depends:.*bash.*").matcher(defaultResult.stdout).find());
-        assertTrue(Pattern.compile("(?m)^ Depends:.*bash.*").matcher(ossResult.stdout).find());
-
-        assertTrue(Pattern.compile("(?m)^ Conflicts: elasticsearch-oss$").matcher(defaultResult.stdout).find());
-        assertTrue(Pattern.compile("(?m)^ Conflicts: elasticsearch$").matcher(ossResult.stdout).find());
-    }
-
-    public void testRpmDependencies() {
-        assumeTrue(Platforms.isRPM());
-
-        final Shell sh = new Shell();
-
-        final Result defaultDeps = sh.run("rpm -qpR " + getDistributionFile(DEFAULT_RPM));
-        final Result ossDeps = sh.run("rpm -qpR " + getDistributionFile(OSS_RPM));
-
-        assertTrue(Pattern.compile("(?m)^/bin/bash\\s*$").matcher(defaultDeps.stdout).find());
-        assertTrue(Pattern.compile("(?m)^/bin/bash\\s*$").matcher(ossDeps.stdout).find());
-
-        final Result defaultConflicts = sh.run("rpm -qp --conflicts " + getDistributionFile(DEFAULT_RPM));
-        final Result ossConflicts = sh.run("rpm -qp --conflicts " + getDistributionFile(OSS_RPM));
-
-        assertTrue(Pattern.compile("(?m)^elasticsearch-oss\\s*$").matcher(defaultConflicts.stdout).find());
-        assertTrue(Pattern.compile("(?m)^elasticsearch\\s*$").matcher(ossConflicts.stdout).find());
-    }
-}

+ 0 - 19
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/PackageTestCase.java

@@ -20,13 +20,9 @@
 package org.elasticsearch.packaging.test;
 
 import com.carrotsearch.randomizedtesting.annotations.TestCaseOrdering;
-import org.elasticsearch.packaging.util.Distribution;
-import org.elasticsearch.packaging.util.Installation;
 import org.elasticsearch.packaging.util.Shell;
-
 import org.elasticsearch.packaging.util.Shell.Result;
 import org.junit.Before;
-import org.junit.BeforeClass;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -35,7 +31,6 @@ import java.nio.file.Paths;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static org.elasticsearch.packaging.util.Cleanup.cleanEverything;
 import static org.elasticsearch.packaging.util.FileUtils.assertPathsDontExist;
 import static org.elasticsearch.packaging.util.FileUtils.mv;
 import static org.elasticsearch.packaging.util.Packages.SYSTEMD_SERVICE;
@@ -49,31 +44,17 @@ import static org.elasticsearch.packaging.util.Packages.verifyPackageInstallatio
 import static org.elasticsearch.packaging.util.Platforms.getOsRelease;
 import static org.elasticsearch.packaging.util.Platforms.isSystemd;
 import static org.elasticsearch.packaging.util.ServerUtils.runElasticsearchTests;
-
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.isEmptyString;
-
 import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assume.assumeThat;
 import static org.junit.Assume.assumeTrue;
 
 @TestCaseOrdering(TestCaseOrdering.AlphabeticOrder.class)
 public abstract class PackageTestCase extends PackagingTestCase {
 
-    private static Installation installation;
-
-    protected abstract Distribution distribution();
-
-    @BeforeClass
-    public static void cleanup() {
-        installation = null;
-        cleanEverything();
-    }
-
     @Before
     public void onlyCompatibleDistributions() {
         assumeTrue("only compatible distributions", distribution().packaging.compatible);

+ 25 - 2
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/PackagingTestCase.java

@@ -21,23 +21,32 @@ package org.elasticsearch.packaging.test;
 
 import com.carrotsearch.randomizedtesting.JUnit3MethodProvider;
 import com.carrotsearch.randomizedtesting.RandomizedRunner;
+import com.carrotsearch.randomizedtesting.annotations.TestCaseOrdering;
 import com.carrotsearch.randomizedtesting.annotations.TestMethodProviders;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.elasticsearch.packaging.util.Distribution;
+import org.elasticsearch.packaging.util.Installation;
+import org.junit.Assert;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
+import static org.elasticsearch.packaging.util.Cleanup.cleanEverything;
+import static org.junit.Assume.assumeTrue;
+
 @RunWith(RandomizedRunner.class)
 @TestMethodProviders({
     JUnit3MethodProvider.class
 })
+@TestCaseOrdering(TestCaseOrdering.AlphabeticOrder.class)
 /**
  * Class that all packaging test cases should inherit from. This makes working with the packaging tests more similar to what we're
  * familiar with from {@link org.elasticsearch.test.ESTestCase} without having to apply its behavior that's not relevant here
  */
-public abstract class PackagingTestCase {
+public abstract class PackagingTestCase extends Assert {
 
     protected final Log logger = LogFactory.getLog(getClass());
 
@@ -45,7 +54,21 @@ public abstract class PackagingTestCase {
     public final TestName testNameRule = new TestName();
 
     @Before
-    public void logTestNameBefore() {
+    public void setup() {
+        assumeTrue("only compatible distributions", distribution().packaging.compatible);
         logger.info("[" + testNameRule.getMethodName() + "]: before test");
     }
+
+    protected static Installation installation;
+
+    @BeforeClass
+    public static void cleanup() {
+        installation = null;
+        cleanEverything();
+    }
+
+    /** The {@link Distribution} that should be tested in this case */
+    protected abstract Distribution distribution();
+
+
 }

+ 253 - 0
qa/vagrant/src/main/java/org/elasticsearch/packaging/test/WindowsServiceTestCase.java

@@ -0,0 +1,253 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.
+ */
+
+package org.elasticsearch.packaging.test;
+
+import junit.framework.TestCase;
+import org.elasticsearch.packaging.util.FileUtils;
+import org.elasticsearch.packaging.util.Platforms;
+import org.elasticsearch.packaging.util.ServerUtils;
+import org.elasticsearch.packaging.util.Shell;
+import org.elasticsearch.packaging.util.Shell.Result;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import static com.carrotsearch.randomizedtesting.RandomizedTest.assumeTrue;
+import static java.util.stream.Collectors.joining;
+import static org.elasticsearch.packaging.util.Archives.installArchive;
+import static org.elasticsearch.packaging.util.Archives.verifyArchiveInstallation;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+
+public abstract class WindowsServiceTestCase extends PackagingTestCase {
+
+    private static final String DEFAULT_ID = "elasticsearch-service-x64";
+    private static final String DEFAULT_DISPLAY_NAME = "Elasticsearch " + FileUtils.getCurrentVersion() + " (elasticsearch-service-x64)";
+    private static String serviceScript;
+
+    private Shell sh;
+
+    @Before
+    public void createShell() {
+        sh = new Shell();
+    }
+
+    @BeforeClass
+    public static void ensureWindows() {
+        assumeTrue(Platforms.WINDOWS);
+    }
+
+    @After
+    public void uninstallService() {
+        sh.runIgnoreExitCode(serviceScript + " remove");
+    }
+
+    private Result runWithoutJava(String script) {
+        // on windows, removing java from PATH and removing JAVA_HOME is less involved than changing the permissions of the java
+        // executable. we also don't check permissions in the windows scripts anyway
+        final String originalPath = sh.run("$Env:PATH").stdout.trim();
+        final String newPath = Arrays.stream(originalPath.split(";"))
+            .filter(path -> path.contains("Java") == false)
+            .collect(joining(";"));
+
+        // note the lack of a $ when clearing the JAVA_HOME env variable - with a $ it deletes the java home directory
+        // https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/providers/environment-provider?view=powershell-6
+        //
+        // this won't persist to another session so we don't have to reset anything
+        return sh.runIgnoreExitCode(
+            "$Env:PATH = '" + newPath + "'; " +
+                "Remove-Item Env:JAVA_HOME; " +
+                script
+        );
+    }
+
+    private void assertService(String id, String status, String displayName) {
+        Result result = sh.run("Get-Service " + id + " | Format-List -Property Name, Status, DisplayName");
+        assertThat(result.stdout, containsString("Name        : " + id));
+        assertThat(result.stdout, containsString("Status      : " + status));
+        assertThat(result.stdout, containsString("DisplayName : " + displayName));
+    }
+
+    // runs the service command, dumping all log files on failure
+    private void assertCommand(String script) {
+        Result result = sh.runIgnoreExitCode(script);
+        if (result.exitCode != 0) {
+            logger.error("---- Failed to run script: " + script);
+            logger.error(result);
+            logger.error("Dumping log files\n");
+            Result logs = sh.run("$files = Get-ChildItem \"" + installation.logs + "\\elasticsearch.log\"; " +
+                "Write-Output $files; " +
+                "foreach ($file in $files) {" +
+                    "Write-Output \"$file\"; " +
+                    "Get-Content \"$file\" " +
+                "}");
+            logger.error(logs.stdout);
+            fail();
+        } else {
+            logger.info("\nscript: " + script + "\nstdout: " + result.stdout + "\nstderr: " + result.stderr);
+        }
+    }
+
+    public void test10InstallArchive() {
+        installation = installArchive(distribution());
+        verifyArchiveInstallation(installation, distribution());
+        serviceScript = installation.bin("elasticsearch-service.bat").toString();
+    }
+
+    public void test11InstallServiceExeMissing() throws IOException {
+        Path serviceExe = installation.bin("elasticsearch-service-x64.exe");
+        Path tmpServiceExe = serviceExe.getParent().resolve(serviceExe.getFileName() + ".tmp");
+        Files.move(serviceExe, tmpServiceExe);
+        Result result =  sh.runIgnoreExitCode(serviceScript + " install");
+        assertThat(result.exitCode, equalTo(1));
+        assertThat(result.stdout, containsString("elasticsearch-service-x64.exe was not found..."));
+        Files.move(tmpServiceExe, serviceExe);
+    }
+
+    public void test12InstallService() {
+        sh.run(serviceScript + " install");
+        assertService(DEFAULT_ID, "Stopped", DEFAULT_DISPLAY_NAME);
+        sh.run(serviceScript + " remove");
+    }
+
+    public void test13InstallMissingJava() throws IOException {
+        Result result = runWithoutJava(serviceScript + " install");
+        assertThat(result.exitCode, equalTo(1));
+        assertThat(result.stderr, containsString("could not find java; set JAVA_HOME or ensure java is in PATH"));
+    }
+
+    public void test14RemoveNotInstalled() {
+        Result result = sh.runIgnoreExitCode(serviceScript + " remove");
+        assertThat(result.stdout, result.exitCode, equalTo(1));
+        assertThat(result.stdout, containsString("Failed removing '" + DEFAULT_ID + "' service"));
+    }
+
+    public void test20CustomizeServiceId() {
+        String serviceId = "my-es-service";
+        String displayName = DEFAULT_DISPLAY_NAME.replace(DEFAULT_ID, serviceId);
+        sh.getEnv().put("SERVICE_ID", serviceId);
+        sh.run(serviceScript + " install");
+        assertService(serviceId, "Stopped", displayName);
+        sh.run(serviceScript + " remove");
+    }
+
+    public void test21CustomizeServiceDisplayName() {
+        String displayName = "my es service display name";
+        sh.getEnv().put("SERVICE_DISPLAY_NAME", displayName);
+        sh.run(serviceScript + " install");
+        assertService(DEFAULT_ID, "Stopped", displayName);
+        sh.run(serviceScript + " remove");
+    }
+
+    // NOTE: service description is not attainable through any powershell api, so checking it is not possible...
+
+    public void test30StartStop() throws IOException {
+        sh.run(serviceScript + " install");
+        assertCommand(serviceScript + " start");
+        ServerUtils.waitForElasticsearch();
+        ServerUtils.runElasticsearchTests();
+
+        assertCommand(serviceScript + " stop");
+        assertService(DEFAULT_ID, "Stopped", DEFAULT_DISPLAY_NAME);
+        // the process is stopped async, and can become a zombie process, so we poll for the process actually being gone
+        assertCommand("$p = Get-Service -Name \"elasticsearch-service-x64\" -ErrorAction SilentlyContinue;" +
+            "$i = 0;" +
+            "do {" +
+              "$p = Get-Process -Name \"elasticsearch-service-x64\" -ErrorAction SilentlyContinue;" +
+              "echo \"$p\";" +
+              "if ($p -eq $Null) {" +
+              "  Write-Host \"exited after $i seconds\";" +
+              "  exit 0;" +
+              "}" +
+              "Start-Sleep -Seconds 1;" +
+              "$i += 1;" +
+            "} while ($i -lt 300);" +
+            "exit 9;");
+
+        assertCommand(serviceScript + " remove");
+        assertCommand("$p = Get-Service -Name \"elasticsearch-service-x64\" -ErrorAction SilentlyContinue;" +
+            "echo \"$p\";" +
+            "if ($p -eq $Null) {" +
+            "  exit 0;" +
+            "} else {" +
+            "  exit 1;" +
+            "}");
+    }
+
+    public void test31StartNotInstalled() throws IOException {
+        Result result = sh.runIgnoreExitCode(serviceScript + " start");
+        assertThat(result.stdout, result.exitCode, equalTo(1));
+        assertThat(result.stdout, containsString("Failed starting '" + DEFAULT_ID + "' service"));
+    }
+
+    public void test32StopNotStarted() throws IOException {
+        sh.run(serviceScript + " install");
+        Result result = sh.run(serviceScript + " stop"); // stop is ok when not started
+        assertThat(result.stdout, containsString("The service '" + DEFAULT_ID + "' has been stopped"));
+    }
+
+    /*
+    // TODO: need to make JAVA_HOME resolve at install time for this to work
+    // see https://github.com/elastic/elasticsearch/issues/23097
+    public void test33JavaChanged() throws IOException {
+        sh.run(serviceScript + " install");
+        runWithoutJava(serviceScript + "start");
+        ServerUtils.waitForElasticsearch();
+        sh.run(serviceScript + " stop");
+        sh.runIgnoreExitCode("Wait-Process -Name \"elasticsearch-service-x64\" -Timeout 10");
+        sh.run(serviceScript + " remove");
+    }*/
+
+    public void test60Manager() throws IOException {
+        Path serviceMgr = installation.bin("elasticsearch-service-mgr.exe");
+        Path tmpServiceMgr = serviceMgr.getParent().resolve(serviceMgr.getFileName() + ".tmp");
+        Files.move(serviceMgr, tmpServiceMgr);
+        Path fakeServiceMgr = serviceMgr.getParent().resolve("elasticsearch-service-mgr.bat");
+        Files.write(fakeServiceMgr, Arrays.asList("echo \"Fake Service Manager GUI\""));
+        Shell sh = new Shell();
+        Result result =  sh.run(serviceScript + " manager");
+        assertThat(result.stdout, containsString("Fake Service Manager GUI"));
+
+        // check failure too
+        Files.write(fakeServiceMgr, Arrays.asList("echo \"Fake Service Manager GUI Failure\"", "exit 1"));
+        result =  sh.runIgnoreExitCode(serviceScript + " manager");
+        TestCase.assertEquals(1, result.exitCode);
+        TestCase.assertTrue(result.stdout, result.stdout.contains("Fake Service Manager GUI Failure"));
+        Files.move(tmpServiceMgr, serviceMgr);
+    }
+
+    public void test70UnknownCommand() {
+        Result result = sh.runIgnoreExitCode(serviceScript + " bogus");
+        assertThat(result.exitCode, equalTo(1));
+        assertThat(result.stdout, containsString("Unknown option \"bogus\""));
+    }
+
+    // TODO:
+    // custom SERVICE_USERNAME/SERVICE_PASSWORD
+    // custom SERVICE_LOG_DIR
+    // custom LOG_OPTS (looks like it currently conflicts with setting custom log dir)
+    // install and run with java opts
+    // install and run java opts Xmx/s (each data size type)
+}