Skip to content

Commit

Permalink
Test native, generic, update, restore, unexpected error
Browse files Browse the repository at this point in the history
  • Loading branch information
theotherp committed Mar 25, 2024
1 parent 520e2b0 commit ca807b4
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 25 deletions.
Expand Up @@ -46,8 +46,8 @@ public class SystemControl {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;

public void exitWithReturnCode(final int returnCode) {
if (Boolean.parseBoolean(environment.getProperty("hydradontshutdown", "false"))) {
public void exitWithReturnCode(final int returnCode, boolean forceShutdown) {
if (Boolean.parseBoolean(environment.getProperty("hydradontshutdown", "false")) && !forceShutdown) {
logger.warn("Not shutting down because property hydradontshutdown is set");
return;
}
Expand All @@ -70,4 +70,8 @@ public void exitWithReturnCode(final int returnCode) {
}
}).start();
}

public void exitWithReturnCode(final int returnCode) {
exitWithReturnCode(returnCode, false);
}
}
Expand Up @@ -26,6 +26,7 @@
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
Expand All @@ -40,18 +41,12 @@ public class SystemControlWeb {

@Secured({"ROLE_ADMIN"})
@RequestMapping(value = "/internalapi/control/shutdown", method = RequestMethod.GET)
public GenericResponse shutdown() throws Exception {
return doShutdown();
}

@NotNull
private GenericResponse doShutdown() {
public GenericResponse shutdown(@RequestParam(required = false) Integer returnCode, @RequestParam(required = false) Boolean forceShutdown) throws Exception {
logger.info("Shutting down due to external request");
systemControl.exitWithReturnCode(SystemControl.SHUTDOWN_RETURN_CODE);
systemControl.exitWithReturnCode(returnCode == null ? SystemControl.SHUTDOWN_RETURN_CODE : returnCode, forceShutdown != null && forceShutdown);
return GenericResponse.ok();
}


@Secured({"ROLE_ADMIN"})
@RequestMapping(value = "/internalapi/control/restart", method = RequestMethod.GET)
public GenericResponse restart() throws Exception {
Expand Down
9 changes: 7 additions & 2 deletions other/gowrapper/base/base.go
Expand Up @@ -135,8 +135,10 @@ func determineReleaseType() ReleaseType {
if _, err := os.Stat(filepath.Join(basePath, "core.exe")); err == nil {
Fatal("lib folder and core found. Either delete the executable to use the generic release type (using java and ignoring the executable) or delete the lib folder to use the executable and not require java")
}
Logf(logrus.InfoLevel, "Release type GENERIC detected")
return GENERIC
} else if _, err := os.Stat(filepath.Join(basePath, "core.exe")); err == nil {
Logf(logrus.InfoLevel, "Release type NATIVE detected")
return NATIVE
} else {
Fatal("Unable to determine the release type. Neither lib folder nor core found")
Expand Down Expand Up @@ -509,7 +511,7 @@ func runMainProcess(executable string, arguments []string) int {
if !*argsQuiet {
println(line)
}
handleProcessUriInLogLine(line)
checkLogLine(line)
consoleLines = append(consoleLines, line)
if len(consoleLines) > 250 {
consoleLines = consoleLines[1:]
Expand All @@ -536,7 +538,7 @@ func runMainProcess(executable string, arguments []string) int {
return 0
}

func handleProcessUriInLogLine(line string) {
func checkLogLine(line string) {
markerLine := "You can access NZBHydra 2 in your browser via "
if strings.Contains(line, markerLine) {
Uri = strings.TrimSpace(line[strings.Index(line, markerLine)+len(markerLine):])
Expand All @@ -547,6 +549,9 @@ func handleProcessUriInLogLine(line string) {
urlToOpen := strings.TrimSpace(line[strings.Index(line, markerLine)+len(markerLine):])
OpenBrowser(urlToOpen)
}
if strings.Contains(line, "Started NzbHydra in") {
Log(logrus.InfoLevel, "Main process has started successfully")
}
}

func OpenBrowser(urlToOpen string) {
Expand Down
192 changes: 179 additions & 13 deletions other/gowrapper/base/base_test.go
@@ -1,42 +1,173 @@
package base

import (
"bufio"
"fmt"
"github.com/stretchr/testify/assert"
"net/http"
"os"
"strings"
"sync"
"testing"
"time"
)

type Predicate func(error error, response *http.Response) bool

var reachedLineNumber int

//goland:noinspection GoUnhandledErrorResult
func TestSimpleShutdown(t *testing.T) {
func TestNative(t *testing.T) {
var wg sync.WaitGroup
dir := "d:\\NZBHydra\\nzbhydra2\\gowrappertest\\automated\\mainfolder\\"
os.RemoveAll(dir)
os.Create(dir)
Unzip("d:\\NZBHydra\\nzbhydra2\\gowrappertest\\automated\\sources\\nzbhydra2-5.3.10-windows-withData.zip", dir)
os.Chdir(dir)
Uri = "http://127.0.0.1:5076/"
var exitCode int
prepareAndRun(&wg, "native")

wg.Add(1)
go func() {
defer wg.Done()
isNative, _ := wrapperLogContainsString("Release type NATIVE detected")
assert.True(t, isNative, "Process does not use native binary")

started, _ := wrapperLogContainsString("Main process has started successfully")
assert.True(t, started, "Process has not started")

shutdownWithCode(0)

shutdown, _ := wrapperLogContainsString("NZBHydra main process has stopped for shutdown")
assert.True(t, shutdown, "Process has not shut down")
}()
wg.Wait()
}

//goland:noinspection GoUnhandledErrorResult
func TestGeneric(t *testing.T) {
var wg sync.WaitGroup
prepareAndRun(&wg, "generic")

wg.Add(1)
go runCode(&wg, &exitCode)
go func() {
defer wg.Done()
isGeneric, _ := wrapperLogContainsString("Release type GENERIC detected")
assert.True(t, isGeneric, "Process does not use jar file")

started, _ := wrapperLogContainsString("Main process has started successfully")
assert.True(t, started, "Process has not started")

shutdownWithCode(0)

shutdown, _ := wrapperLogContainsString("NZBHydra main process has stopped for shutdown")
assert.True(t, shutdown, "Process has not shut down")
}()
wg.Wait()
}

//goland:noinspection GoUnhandledErrorResult
func TestUpdate(t *testing.T) {
var wg sync.WaitGroup
prepareAndRun(&wg, "native")

wg.Add(1)
go func() {
defer wg.Done()
waitForServerUp()

shutdownWithCode(11)
updated, _ := wrapperLogContainsString("Update successful")
assert.True(t, updated, "Process was not updated")

restarted, _ := wrapperLogContainsString("Main process has started successfully")
assert.True(t, restarted, "Process has not restarted after update")

shutdownWithCode(0)
shutdown, _ := wrapperLogContainsString("NZBHydra main process has stopped for shutdown")
assert.True(t, shutdown, "Process has not shut down")
waitForServerDown(t)
}()
wg.Wait()
}

//goland:noinspection GoUnhandledErrorResult
func TestRestore(t *testing.T) {
var wg sync.WaitGroup
prepareAndRun(&wg, "native")

wg.Add(1)
go func() {
defer wg.Done()
getWaiting(Uri, func(error error, response *http.Response) bool { return response != nil && response.StatusCode == 200 })
getWaiting(Uri+"internalapi/control/shutdown?internalApiKey="+GetInternalApiKey(), func(error error, response *http.Response) bool { return error != nil })
wasShutdown := getWaiting(Uri, func(error error, response *http.Response) bool { return error != nil })
assert.True(t, wasShutdown, "Server was not shut down")
waitForServerUp()

shutdownWithCode(33)
restored, _ := wrapperLogContainsString("Moved all files from restore folder")
assert.True(t, restored, "Process has not restored")

restarted, _ := wrapperLogContainsString("Main process has started successfully")
assert.True(t, restarted, "Process has not restarted after restore")

shutdownWithCode(0)
shutdown, _ := wrapperLogContainsString("NZBHydra main process has stopped for shutdown")
assert.True(t, shutdown, "Process has not shut down")
waitForServerDown(t)
}()
wg.Wait()
}

func TestHandleUnexpectedError(t *testing.T) {
var wg sync.WaitGroup
_ = os.Setenv("nzbhydra_devMode", "true")
prepareAndRun(&wg, "native")

wg.Add(1)
go func() {
defer wg.Done()
waitForServerUp()
started, _ := wrapperLogContainsString("Main process has started successfully")
assert.True(t, started, "Process has not started")

url := fmt.Sprintf("%sdev/crash?internalApiKey=%s", Uri, GetInternalApiKey())
_, _ = ExecuteGetRequest(url)

handled, _ := wrapperLogContainsString("Main process shut down unexpectedly.")
assert.True(t, handled, "Process has not handled unexpected error")
handled, _ = wrapperLogContainsString("The last 250 lines from output")
assert.True(t, handled, "Process has not handled unexpected error")

restarted, _ := wrapperLogContainsString("Main process has started successfully")
assert.True(t, restarted, "Process has not restarted after crash")

shutdownWithCode(0)
shutdown, _ := wrapperLogContainsString("NZBHydra main process has stopped for shutdown")
assert.True(t, shutdown, "Process has not shut down")
waitForServerDown(t)
}()
wg.Wait()
}

func shutdownWithCode(code int) bool {
url := fmt.Sprintf("%sinternalapi/control/shutdown?returnCode=%d&internalApiKey=%s", Uri, code, GetInternalApiKey())
return getWaiting(url, func(error error, response *http.Response) bool { return error != nil })
}

func waitForServerDown(t *testing.T) {
wasShutdown := getWaiting(Uri, func(error error, response *http.Response) bool { return error != nil })
assert.True(t, wasShutdown, "Server was not shut down")
}

func waitForServerUp() bool {
return getWaiting(Uri, func(error error, response *http.Response) bool { return response != nil && response.StatusCode == 200 })
}

func prepareAndRun(wg *sync.WaitGroup, testType string) {
reachedLineNumber = 0
dir := "d:\\NZBHydra\\nzbhydra2\\gowrappertest\\automated\\mainfolder\\"
os.RemoveAll(dir)
os.Create(dir)
Unzip(fmt.Sprintf("d:\\NZBHydra\\nzbhydra2\\gowrappertest\\automated\\sources\\nzbhydra2-5.3.10-%s-testSource.zip", testType), dir)
os.Chdir(dir)
Uri = "http://127.0.0.1:5076/"
var exitCode int
wg.Add(1)
go runCode(wg, &exitCode)
}

func getWaiting(url string, predicate Predicate) bool {
beganAt := time.Now()
for {
Expand All @@ -60,3 +191,38 @@ func runCode(wg *sync.WaitGroup, exitCode *int) {
}
Entrypoint(false, false)
}

func wrapperLogContainsString(searchString string) (bool, error) {
beganAt := time.Now()
for {
if beganAt.Add(time.Second * 10).Before(time.Now()) {
return false, nil
}
file, err := os.Open("d:\\NZBHydra\\nzbhydra2\\gowrappertest\\automated\\mainfolder\\data\\logs\\wrapper.log")
if err != nil {
//Assume file does not exist yet
continue
}

scanner := bufio.NewScanner(file)
lineNumber := 0
for scanner.Scan() {
lineNumber++
//Do not read the same line again
if lineNumber < reachedLineNumber {
continue
}
if strings.Contains(scanner.Text(), searchString) {
_ = file.Close()
reachedLineNumber = lineNumber
return true, nil
}
}
_ = file.Close()
if err := scanner.Err(); err != nil {
return false, err
}

time.Sleep(time.Millisecond * 500)
}
}

0 comments on commit ca807b4

Please sign in to comment.