288 lines
7.2 KiB
Go
288 lines
7.2 KiB
Go
package arthur
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.csclub.uwaterloo.ca/public/merlin/config"
|
|
"git.csclub.uwaterloo.ca/public/merlin/logger"
|
|
)
|
|
|
|
// Test that GetCommand is able to accept a connection and parse a request for the status
|
|
func TestStatusCommand(t *testing.T) {
|
|
r, w := net.Pipe()
|
|
|
|
go func() {
|
|
// will only finish write when EOF is sent
|
|
// only way to send EOF is to close
|
|
w.Write([]byte("status"))
|
|
w.Close()
|
|
}()
|
|
command, repoName := GetCommand(r)
|
|
if command != "status" {
|
|
t.Errorf("command for status should be \"status\", got " + command)
|
|
} else if repoName != "" {
|
|
t.Errorf("status should return an empty string for the repoName, got " + repoName)
|
|
}
|
|
}
|
|
|
|
// Test that GetCommand is able to accept a connection and parse a request for the a forced sync
|
|
func TestSyncCommand(t *testing.T) {
|
|
r, w := net.Pipe()
|
|
|
|
go func() {
|
|
w.Write([]byte("sync:ubuntu"))
|
|
w.Close()
|
|
}()
|
|
command, repoName := GetCommand(r)
|
|
r.Close()
|
|
if command != "sync" {
|
|
t.Errorf("command for sync:ubuntu should be \"sync\", got " + command)
|
|
} else if repoName != "ubuntu" {
|
|
t.Errorf("name of repo for sync:ubuntu should be \"ubuntu\", got " + repoName)
|
|
}
|
|
}
|
|
|
|
// Test that SendStatus returns the correct status for some repo state
|
|
func TestSendStatus(t *testing.T) {
|
|
saveRepoMap := config.RepoMap
|
|
defer func() {
|
|
config.RepoMap = saveRepoMap
|
|
}()
|
|
|
|
repoMap := make(map[string]*config.Repo)
|
|
repoMap["eeeee"] = &config.Repo{
|
|
Frequency: 30 * 86400,
|
|
State: &config.RepoState{
|
|
IsRunning: true,
|
|
LastAttemptStartTime: 1600000000,
|
|
},
|
|
}
|
|
repoMap["alinux"] = &config.Repo{
|
|
Frequency: 7*86400 + 3,
|
|
State: &config.RepoState{
|
|
IsRunning: true,
|
|
LastAttemptStartTime: 1620000000,
|
|
},
|
|
}
|
|
repoMap["lnux"] = &config.Repo{
|
|
Frequency: 86400,
|
|
State: &config.RepoState{
|
|
IsRunning: false,
|
|
LastAttemptStartTime: 1640000000,
|
|
},
|
|
}
|
|
config.RepoMap = repoMap
|
|
|
|
r, w := net.Pipe()
|
|
go func() {
|
|
SendStatus(w)
|
|
w.Close()
|
|
}()
|
|
msg, err := ioutil.ReadAll(r)
|
|
r.Close()
|
|
if err != nil {
|
|
t.Errorf(err.Error())
|
|
}
|
|
expected := `Repository Last Synced Next Expected Sync Running
|
|
alinux Sun, 02 May 2021 20:00:00 EDT Sun, 09 May 2021 20:00:03 EDT true
|
|
eeeee Sun, 13 Sep 2020 08:26:40 EDT Tue, 13 Oct 2020 08:26:40 EDT true
|
|
lnux Mon, 20 Dec 2021 06:33:20 EST Tue, 21 Dec 2021 06:33:20 EST false
|
|
`
|
|
if expected != string(msg) {
|
|
t.Errorf("Expected:\n" + expected + "\nGot:\n" + string(msg))
|
|
}
|
|
}
|
|
|
|
// Test that ForceSync behaves properly
|
|
func TestForceSync(t *testing.T) {
|
|
saveRepos := config.Repos
|
|
saveRepoMap := config.RepoMap
|
|
doneChan := make(chan config.SyncResult)
|
|
defer func() {
|
|
config.Repos = saveRepos
|
|
config.RepoMap = saveRepoMap
|
|
close(doneChan)
|
|
}()
|
|
|
|
// Part 1: run a dummy sync
|
|
repo := config.Repo{
|
|
Name: "nux",
|
|
SyncType: "csc-sync-dummy",
|
|
Frequency: 7 * 86400,
|
|
MaxTime: 30,
|
|
Logger: logger.NewLogger("nux", "/tmp/merlin_force_sync_test_log", false),
|
|
StateFile: "/tmp/merlin_force_sync_test_state",
|
|
DoneChan: doneChan,
|
|
State: &config.RepoState{
|
|
IsRunning: false,
|
|
LastAttemptStartTime: 0,
|
|
LastAttemptRunTime: 0,
|
|
LastAttemptExit: config.NOT_RUN_YET,
|
|
},
|
|
}
|
|
config.Repos = nil
|
|
config.Repos = append(config.Repos, &repo)
|
|
config.RepoMap = make(map[string]*config.Repo)
|
|
config.RepoMap["nux"] = &repo
|
|
|
|
r, w := net.Pipe()
|
|
go func() {
|
|
if !ForceSync(w, "nux") {
|
|
t.Errorf("Sync for nux did not start")
|
|
}
|
|
w.Close()
|
|
}()
|
|
msg, err := ioutil.ReadAll(r)
|
|
r.Close()
|
|
if err != nil {
|
|
t.Errorf(err.Error())
|
|
}
|
|
expected := "Forced sync for nux"
|
|
if expected != string(msg) {
|
|
t.Errorf("Expected:\n" + expected + "\nGot:\n" + string(msg))
|
|
}
|
|
|
|
select {
|
|
case result := <-doneChan:
|
|
if result.Exit != config.SUCCESS {
|
|
t.Errorf("Sync should exit with SUCCESS, got %d", result.Exit)
|
|
}
|
|
case <-time.After(3 * time.Second):
|
|
t.Errorf("Dummy sync should be done in 1 second, waited 3 seconds")
|
|
}
|
|
|
|
// Part 2: attempt the same thing but with repo.State.IsRunning = true
|
|
r, w = net.Pipe()
|
|
go func() {
|
|
if ForceSync(w, "nux") {
|
|
t.Errorf("Sync for nux should not have started")
|
|
}
|
|
w.Close()
|
|
}()
|
|
msg, err = ioutil.ReadAll(r)
|
|
r.Close()
|
|
if err != nil {
|
|
t.Errorf(err.Error())
|
|
}
|
|
expected = "Could not force sync: nux is already syncing."
|
|
if expected != string(msg) {
|
|
t.Errorf("Expected:\n" + expected + "\nGot:\n" + string(msg))
|
|
}
|
|
|
|
select {
|
|
case <-doneChan:
|
|
t.Errorf("Sync for nux should not have been started")
|
|
case <-time.After(2 * time.Second):
|
|
}
|
|
|
|
// Part 3: attempt a force sync with a repo that does not exist
|
|
r, w = net.Pipe()
|
|
go func() {
|
|
if ForceSync(w, "nixx") {
|
|
t.Errorf("Sync for nixx should not have started")
|
|
}
|
|
w.Close()
|
|
}()
|
|
msg, err = ioutil.ReadAll(r)
|
|
r.Close()
|
|
if err != nil {
|
|
t.Errorf(err.Error())
|
|
}
|
|
expected = "nixx is not tracked so cannot sync"
|
|
if expected != string(msg) {
|
|
t.Errorf("Expected:\n" + expected + "\nGot:\n" + string(msg))
|
|
}
|
|
}
|
|
|
|
// Test that StartListener stops properly when told to and that it properly creates a unix socket
|
|
func TestStartListener(t *testing.T) {
|
|
saveConf := config.Conf
|
|
connChan := make(chan net.Conn)
|
|
stopLisChan := make(chan struct{})
|
|
wait := make(chan struct{})
|
|
defer func() {
|
|
config.Conf = saveConf
|
|
close(connChan)
|
|
close(stopLisChan)
|
|
}()
|
|
config.Conf = config.Config{
|
|
SockPath: "/tmp/merlin_listener_test.sock",
|
|
}
|
|
|
|
// Test 1: check that closing/sending something to stopLisChan will stop the listener
|
|
// and that a new listener can be created after stopping the old one
|
|
go func() {
|
|
StartListener(connChan, stopLisChan)
|
|
wait <- struct{}{}
|
|
}()
|
|
stopLisChan <- struct{}{}
|
|
select {
|
|
case <-wait:
|
|
case <-time.After(3 * time.Second):
|
|
t.Errorf("StartListener should stop when struct{}{} is sent to stopLisChan")
|
|
}
|
|
|
|
go func() {
|
|
StartListener(connChan, stopLisChan)
|
|
wait <- struct{}{}
|
|
}()
|
|
close(stopLisChan)
|
|
select {
|
|
case <-wait:
|
|
case <-time.After(3 * time.Second):
|
|
t.Errorf("StartListener should stop when stopLisChan is closed")
|
|
}
|
|
close(wait)
|
|
|
|
// Test 2: check that connections can be made to the unix socket
|
|
// this test does not appear to be very stable (I think there is a race condition somewhere)
|
|
stopLisChan = make(chan struct{})
|
|
go StartListener(connChan, stopLisChan)
|
|
waitForMsg := func(expected string) {
|
|
select {
|
|
case conn := <-connChan:
|
|
msg, err := ioutil.ReadAll(conn)
|
|
if err != nil {
|
|
t.Errorf(err.Error())
|
|
} else if expected != string(msg) {
|
|
t.Errorf("Message expected was " + expected + " got " + string(msg))
|
|
}
|
|
conn.Close()
|
|
case <-time.After(3 * time.Second):
|
|
t.Errorf("StartListener should stop when struct{}{} is sent to stopLisChan")
|
|
}
|
|
}
|
|
sendMsg := func(msg string) {
|
|
<-time.After(500 * time.Millisecond)
|
|
send, err := net.Dial("unix", "/tmp/merlin_listener_test.sock")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
_, err = send.Write([]byte(msg))
|
|
if err != nil {
|
|
t.Errorf(err.Error())
|
|
}
|
|
send.Close()
|
|
}
|
|
go func() {
|
|
waitForMsg("status")
|
|
}()
|
|
sendMsg("status")
|
|
|
|
go func() {
|
|
waitForMsg("sync:uuunix")
|
|
}()
|
|
sendMsg("sync:uuunix")
|
|
|
|
go func() {
|
|
waitForMsg("$UPz2L2yWsE^UY8iG9JX@^dBb@5yb*")
|
|
}()
|
|
sendMsg("$UPz2L2yWsE^UY8iG9JX@^dBb@5yb*")
|
|
|
|
os.Remove("/tmp/merlin_listener_test.sock")
|
|
}
|