Compare commits

..

6 Commits

Author SHA1 Message Date
Chris F Ravenscroft 5147d1165a refactor: table-drive batteryOfTests to cut duplication
The twelve battery cases were near-identical closures: the same ldapsearch
argument prefix, the same got/want compare, the same t.Fatalf shape. Collapse
them into table rows holding only what differs (args, want, message) and run
them through one loop.

Shared argument builders (bind/svc/otp) remove the repeated
-LLL/-H/-D/-w/-x prefix; the two getSecond cases set a line field instead of
duplicating the assertion block.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdP1CLtdwAtAeXuS4hph6g
2026-08-30 16:20:05 -07:00
Chris F Ravenscroft 374041c358 chore: bump CI to 1.25 2026-08-30 16:12:11 -07:00
Chris F Ravenscroft 5bdeb5118b fix: remove repetitions, reduce waitForPort scope, restore arbitrary port 2026-08-30 16:02:46 -07:00
Timmy Welch 319cc9a3c7 Modernize tests, reduce execution time from 30s to 0.2s
Make output go to test logger so that go test -v will give useful output on a failure
Remove dependence on `oathtool`
Remove dependence on `ls`
Wait on killing the running glauth instance so subsequent tests don't fail
Wait for glauth to provide authentication error instead of waiting an arbitrary amount of time
2026-08-05 16:16:10 -07:00
Chris F Ravenscroft 26cd4447c8 test: support distribution binary layout 2026-07-25 14:17:38 -07:00
Chris F Ravenscroft 96a283fea2 chore: fix release build ordering 2026-07-25 14:14:49 -07:00
8 changed files with 211 additions and 150 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
go-version: [1.21.x]
go-version: [1.25.x]
steps:
- name: Install Go
uses: actions/setup-go@v4
+1 -1
View File
@@ -1,3 +1,3 @@
go 1.24.0
go 1.25.0
use ./v2
-1
View File
@@ -3,7 +3,6 @@
"v2": {
"release-type": "go",
"package-name": "GLAuth",
"release-as": "2.5.2",
"pull-request-title-pattern": "ci: release ${version}",
"extra-files": [
"internal/version/const.go"
+2 -2
View File
@@ -2,7 +2,7 @@
MAKEFLAGS += --no-print-directory
VERSION=$(shell bin/linuxamd64/glauth --version)
VERSION=$(shell if [ -x bin/linuxamd64/glauth ]; then bin/linuxamd64/glauth --version; else bin/glauth-linux-amd64 --version; fi)
GIT_COMMIT=$(shell git rev-list -1 HEAD )
BUILD_TIME=$(shell date -u +%Y%m%d_%H%M%SZ)
@@ -330,7 +330,7 @@ builddockerplugins:
builddocker: _checkdockerauth builddockermain builddockerplugins
buildeverything: prepbuild forget-embed _buildmain _buildplugins testplugin remember-embed _buildmainembeds builddocker
buildeverything: prepbuild forget-embed _buildplugins _buildmain testplugin remember-embed _buildmainembeds builddocker
#testdocker: @ run integration test using docker
testdocker:
+186 -142
View File
@@ -1,6 +1,8 @@
package main
import (
"bytes"
"errors"
"fmt"
"net"
"os"
@@ -10,6 +12,9 @@ import (
"strings"
"testing"
"time"
"github.com/glauth/ldap"
"github.com/pquerna/otp/totp"
)
type testEnv struct {
@@ -36,6 +41,15 @@ func glauthBinary() string {
if _, err := os.Stat(qualified); err == nil {
return qualified
}
distribution := filepath.Join("bin", "glauth-"+runtime.GOOS+"-"+runtime.GOARCH)
if runtime.GOOS == "windows" {
distribution += ".exe"
}
if _, err := os.Stat(distribution); err == nil {
return distribution
}
return "bin/glauth"
}
@@ -88,11 +102,11 @@ func TestConfigBackendRejectsPasswordlessUserBinds(t *testing.T) {
action = "search"
object = "*"
`, port)
if err := os.WriteFile(configPath, []byte(config), 0600); err != nil {
if err := os.WriteFile(configPath, []byte(config), 0o600); err != nil {
t.Fatal(err)
}
svc := startSvc(SD, glauthBinary(), "-c", configPath)
svc := startSvc(t, fmt.Sprintf("127.0.0.1:%d", port), glauthBinary(), "-c", configPath)
defer stopSvc(svc)
bindDN := "cn=nopass,dc=glauth,dc=com"
@@ -105,7 +119,7 @@ func TestConfigBackendRejectsPasswordlessUserBinds(t *testing.T) {
{name: "empty password", password: "", want: "exit status 53"},
} {
t.Run(tc.name, func(t *testing.T) {
got := doRunGetFirst(0, "ldapsearch", "-LLL", "-H", fmt.Sprintf("ldap://127.0.0.1:%d", port), "-D", bindDN, "-w", tc.password, "-x", "-b", "dc=glauth,dc=com", "(cn=nopass)")
got := runAndSelect(t, getFirst, "ldapsearch", "-LLL", "-H", fmt.Sprintf("ldap://127.0.0.1:%d", port), "-D", bindDN, "-w", tc.password, "-x", "-b", "dc=glauth,dc=com", "(cn=nopass)")
if got != tc.want {
t.Fatalf("bind result = %q, want %q", got, tc.want)
}
@@ -140,153 +154,139 @@ func ldapOnlyConfig(t *testing.T, source string) string {
contents = contents[:start] + sectionWithoutLDAPS + contents[end:]
path := filepath.Join(t.TempDir(), filepath.Base(source))
if err := os.WriteFile(path, []byte(contents), 0600); err != nil {
if err := os.WriteFile(path, []byte(contents), 0o600); err != nil {
t.Fatal(err)
}
return path
}
func batteryOfTests(t *testing.T, env *testEnv) {
// We aren't checking that "github.com/pquerna/otp/totp" creates correct values.
// That's what their own tests are for.
// We are checking that the totp code gets through glauth code successfully
otpvalue, err := totp.GenerateCode("3hnvnk4ycv44glzigd6s25j4dougs3rk", time.Now())
if err != nil {
t.Fatal("Failed to generate totp code:", err)
}
const addr = "ldap://127.0.0.1:3893"
bind := func(dn, password string, rest ...string) []string {
return append([]string{"-LLL", "-H", addr, "-D", dn, "-w", password, "-x"}, rest...)
}
svc := func(rest ...string) []string { return bind(env.svcdn, "mysecret", rest...) }
otp := func(password string) []string {
return bind(env.otpdn, password, "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
}
const (
inSuperheros = "should find them in the 'superheros' group"
listFromUser = "should get a list starting with the 'hackers' user"
badCreds = "should get 'Invalid credentials(49)'"
)
tests := []struct {
Name string
Path string
Check func(t testing.TB)
name string
skip bool
args []string
line func(string) string
want string
msg string
}{
{
Name: "searching for the 'hackers' user",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
if got, want := out, env.expectedaccount; got != want {
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for the 'hackers' user",
args: svc("-bdc=glauth,dc=com", "cn=hackers"),
want: env.expectedaccount,
msg: inSuperheros,
},
{
Name: "searching for the 'hackers' user without binding with a group",
Check: func(t testing.TB) {
if env.svcdnnogroup == "" {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdnnogroup, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
if got, want := out, env.expectedaccount; got != want {
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for the 'hackers' user without binding with a group",
skip: env.svcdnnogroup == "",
args: bind(env.svcdnnogroup, "mysecret", "-bdc=glauth,dc=com", "cn=hackers"),
want: env.expectedaccount,
msg: inSuperheros,
},
{
Name: "searching for the 'hackers' user after binding using the account's UPN",
Check: func(t testing.TB) {
if !env.checkbindUPN {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", "serviceuser@example.com", "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
if got, want := out, env.expectedaccount; got != want {
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for the 'hackers' user after binding using the account's UPN",
skip: !env.checkbindUPN,
args: bind("serviceuser@example.com", "mysecret", "-bdc=glauth,dc=com", "cn=hackers"),
want: env.expectedaccount,
msg: inSuperheros,
},
{
Name: "querying the root SDE",
Check: func(t testing.TB) {
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-s", "base", "(objectclass=*)")
if got, want := out, env.expectedinfo; got != want {
t.Fatalf("should get some meta information\ngot: %s\nwant: %s", got, want)
}
},
name: "querying the root SDE",
args: svc("-s", "base", "(objectclass=*)"),
line: getSecond,
want: env.expectedinfo,
msg: "should get some meta information",
},
{
Name: "querying the root SDE anonymously without authorizing in config file",
Check: func(t testing.TB) {
if !env.checkanonymousrootDSE {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-x", "-s", "base", "(objectclass=*)")
if got, want := out, "exit status 50"; got != want {
t.Fatalf("should get error 50\ngot: %s\nwant: %s", got, want)
}
},
name: "querying the root SDE anonymously without authorizing in config file",
skip: !env.checkanonymousrootDSE,
args: []string{"-LLL", "-H", addr, "-x", "-s", "base", "(objectclass=*)"},
want: "exit status 50",
msg: "should get error 50",
},
{
Name: "enumerating posix groups",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(objectclass=posixgroup)")
if got, want := out, env.expectedgroup; got != want {
t.Fatalf("should get a list starting with the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
name: "enumerating posix groups",
args: svc("-bdc=glauth,dc=com", "(objectclass=posixgroup)"),
want: env.expectedgroup,
msg: "should get a list starting with the 'superheros' group",
},
{
Name: "searching for members of the 'superheros' group",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com)")
if got, want := out, env.expectedfirstaccount; got != want {
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for members of the 'superheros' group",
args: svc("-bdc=glauth,dc=com", "(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com)"),
want: env.expectedfirstaccount,
msg: listFromUser,
},
{
Name: "performing a complex search for members of 'superheros' group",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com))")
if got, want := out, env.expectedfirstaccount; got != want {
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
}
},
name: "performing a complex search for members of 'superheros' group",
args: svc("-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com))"),
want: env.expectedfirstaccount,
msg: listFromUser,
},
{
Name: "searching for the 'hacker' user using a TOTP-enabled account",
Check: func(t testing.TB) {
if !env.checkTOTP {
t.SkipNow()
}
otpvalue := doRunGetFirst(RD, "oathtool", "--totp", "-b", "-d", "6", "3hnvnk4ycv44glzigd6s25j4dougs3rk")
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret"+otpvalue, "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
if got, want := out, env.scopedaccount; got != want {
t.Fatalf("should find them in in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for the 'hacker' user using a TOTP-enabled account",
skip: !env.checkTOTP,
args: otp("mysecret" + otpvalue),
want: env.scopedaccount,
msg: inSuperheros,
},
{
Name: "searching for the 'hacker' user using a TOTP-enabled account and no value",
Check: func(t testing.TB) {
if !env.checkTOTP {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
if got, want := out, "exit status 49"; got != want {
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for the 'hacker' user using a TOTP-enabled account and no value",
skip: !env.checkTOTP,
args: otp("mysecret"),
want: "exit status 49",
msg: badCreds,
},
{
Name: "searching for the 'hacker' user using a TOTP-enabled account and the wrong value",
Check: func(t testing.TB) {
if !env.checkTOTP {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret123456", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
if got, want := out, "exit status 49"; got != want {
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for the 'hacker' user using a TOTP-enabled account and the wrong value",
skip: !env.checkTOTP,
args: otp("mysecret123456"),
want: "exit status 49",
msg: badCreds,
},
{
Name: "searching for the 'hacker' user",
Check: func(t testing.TB) {
if env.checkemployeetype == "" {
t.SkipNow()
}
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", env.checkemployeetype, "employeetype")
if got, want := out, "employeetype: Intern"; got != want {
t.Fatalf("type should be 'Intern'\ngot: %s\nwant: %s", got, want)
}
},
name: "searching for the 'hacker' user",
skip: env.checkemployeetype == "",
args: svc("-bdc=glauth,dc=com", env.checkemployeetype, "employeetype"),
line: getSecond,
want: "employeetype: Intern",
msg: "type should be 'Intern'",
},
}
for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
tc.Check(t)
t.Run(tc.name, func(t *testing.T) {
if tc.skip {
t.SkipNow()
}
line := tc.line
if line == nil {
line = getFirst
}
if got := runAndSelect(t, line, "ldapsearch", tc.args...); got != tc.want {
t.Fatalf("%s\ngot: %s\nwant: %s", tc.msg, got, tc.want)
}
})
}
}
@@ -307,14 +307,15 @@ func TestSampleSimple(t *testing.T) {
checkemployeetype: "cn=hackers",
}
svc := startSvc(SD, glauthBinary(), "-c", ldapOnlyConfig(t, "sample-simple.cfg"))
svc := startSvc(t, "127.0.0.1:3893", glauthBinary(), "-c", ldapOnlyConfig(t, "sample-simple.cfg"))
batteryOfTests(t, &env)
stopSvc(svc)
}
func TestSQLitePlugin(t *testing.T) {
matchingLibrary := doRunGetFirst(RD, "ls", "bin/sqlite.so")
if matchingLibrary != "bin/sqlite.so" {
_, err := os.Stat("bin/sqlite.so")
if err != nil {
t.Log("Unable to find sqlite plugin")
t.SkipNow()
}
@@ -333,14 +334,20 @@ func TestSQLitePlugin(t *testing.T) {
checkemployeetype: "",
}
svc := startSvc(SD, glauthBinary(), "-c", "pkg/plugins/glauth-sqlite/sample-database.cfg")
svc := startSvc(t, "127.0.0.1:3893", glauthBinary(), "-c", "pkg/plugins/glauth-sqlite/sample-database.cfg")
batteryOfTests(t, &env)
stopSvc(svc)
}
func TestLdapInjection(t *testing.T) {
matchingContainers := doRunGetFirst(RD, "sh", "-c", "docker ps | grep ldap-service | wc -l")
out, err := doRun("sh", "-c", "docker ps | grep ldap-service | wc -l")
if err != nil {
t.Log("Unable to find docker container:", out)
t.SkipNow()
}
matchingContainers := getFirst(out)
if matchingContainers != "1" {
t.Log("Unable to find docker container:", out)
t.SkipNow()
}
@@ -359,52 +366,89 @@ func TestLdapInjection(t *testing.T) {
checkemployeetype: "",
}
svc := startSvc(SD, glauthBinary(), "-c", "sample-ldap-injection.cfg")
svc := startSvc(t, "127.0.0.1:3893", glauthBinary(), "-c", "sample-ldap-injection.cfg")
batteryOfTests(t, &env)
stopSvc(svc)
}
// -----=============================================================================----
const SD = 3 // Start Delay
const RD = 2 // Response Delay
func startSvc(delay time.Duration, name string, arg ...string) *exec.Cmd {
cmd := exec.Command(name, arg...)
cmd.Start()
if delay != 0 {
time.Sleep(time.Second * delay)
func waitForPort(host string, timeout time.Duration) error {
start := time.Now()
for {
conn, err := ldap.Dial("tcp", host)
if err == nil {
err = conn.Bind("_", "_")
if err == nil {
conn.Close()
return fmt.Errorf("Successfully authenticated to glauth. This should not happen")
}
e := &ldap.Error{}
if errors.As(err, &e) && e.ResultCode == 49 {
conn.Close()
return nil
}
conn.Close()
// We have an error, it's probably a connection error or an error saying that ldap isn't setup yet
// try again
}
if time.Since(start) > timeout {
return fmt.Errorf("timeout waiting for port %s: %w", host, err)
}
time.Sleep(50 * time.Millisecond)
}
}
func startSvc(t *testing.T, addr string, name string, arg ...string) *exec.Cmd {
cmd := exec.Command(name, arg...)
cmd.Stderr = t.Output()
cmd.Stdout = t.Output()
if err := cmd.Start(); err != nil {
t.Fatal("Failed to start glauth:", err)
}
if err := waitForPort(addr, time.Second*2); err != nil {
t.Fatal("Failed to wait for glauth to start:", err)
}
// the port is listening but the ldap server may not be accepting connections yet
// TODO: make glauth listen as the last part of the initialization that way as soon as it listens it can process connections
return cmd
}
func stopSvc(svc *exec.Cmd) {
svc.Process.Kill()
svc.Process.Wait()
}
func doRunGetFirst(delay time.Duration, name string, arg ...string) string {
out := strings.SplitN(doRun(delay, name, arg...), "\n", 2)
if out == nil || len(out) < 1 {
func getFirst(output string) string {
out := strings.SplitN(output, "\n", 2)
if len(out) < 1 {
return "*fail*"
}
return out[0]
}
func doRunGetSecond(delay time.Duration, name string, arg ...string) string {
out := strings.SplitN(doRun(delay, name, arg...), "\n", 3)
if out == nil || len(out) < 2 {
func getSecond(output string) string {
out := strings.SplitN(output, "\n", 3)
if len(out) < 2 {
return "*fail*"
}
return out[1]
}
func doRun(delay time.Duration, name string, arg ...string) string {
out, err := exec.Command(name, arg...).Output()
func doRun(name string, arg ...string) (string, error) {
out, err := exec.Command(name, arg...).CombinedOutput()
if err != nil {
return string(bytes.TrimSpace(out)), err
}
return string(bytes.TrimSpace(out)), nil
}
func runAndSelect(t testing.TB, pick func(string) string, name string, arg ...string) string {
t.Helper()
out, err := doRun(name, arg...)
if err != nil {
t.Log(out)
return err.Error()
}
if delay != 0 {
time.Sleep(time.Second * delay)
}
return strings.TrimSpace(string(out))
return pick(out)
}
+1 -1
View File
@@ -1,6 +1,6 @@
module github.com/glauth/glauth/v2
go 1.21
go 1.25
require (
github.com/BurntSushi/toml v1.3.2
+2
View File
@@ -15,6 +15,8 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+18 -2
View File
@@ -24,6 +24,22 @@ echo "Fixing CI_BUILD_DIR"
# This script requires that "$CI_BUILD_DIR" is set to the repo root
GOOS="$(go env GOOS)"
GOARCH="$(go env GOARCH)"
if [[ "$GOARCH" = "arm" ]]; then
DIST_ARCH="arm-$(go env GOARM)"
else
DIST_ARCH="$GOARCH"
fi
GLAUTH_BINARY="$CI_BUILD_DIR/bin/$GOOS$GOARCH/glauth"
if [[ ! -x "$GLAUTH_BINARY" ]]; then
GLAUTH_BINARY="$CI_BUILD_DIR/bin/glauth-$GOOS-$DIST_ARCH"
fi
if [[ ! -x "$GLAUTH_BINARY" ]]; then
echo "Unable to find a runnable GLAuth binary: $GLAUTH_BINARY"
exit 1
fi
# Ensure ldap utils are installed (for example - when running this outside of CI)
if [[ ! `which ldapsearch` ]]; then
sudo apt-get -qq update && sudo apt-get -qq install -y ldap-utils || exit 1;
@@ -33,11 +49,11 @@ fi
echo "";
echo ""
echo "Version string of tested binary:"
"$CI_BUILD_DIR/bin/$(go env GOOS)$(go env GOARCH)/glauth" --version
"$GLAUTH_BINARY" --version
echo ""
# Start in background, capture PID
"$CI_BUILD_DIR/bin/$(go env GOOS)$(go env GOARCH)/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &> /dev/null &
"$GLAUTH_BINARY" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &> /dev/null &
# Use this instead to see glauth logs while running
# "$CI_BUILD_DIR/bin/$(go env GOOS)$(go env GOARCH)/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &