Compare commits

..

1 Commits

Author SHA1 Message Date
ad640636c3
ACN state handling & tests 2023-10-02 10:36:55 +02:00
4 changed files with 260 additions and 43 deletions

1
acn.go

@ -103,6 +103,7 @@ func turnAcnOn(m *model) tea.Msg {
func turnAcnOff(m *model, quitProgram bool) tea.Msg {
if m.acnState != offline {
logToFile(*m, "Shutting down application and ACN now")
m.app.Shutdown()
m.acn.Close()
}

10
logger.go Normal file

@ -0,0 +1,10 @@
package main
import "log"
// LogToFile logs a message to a log file.
func logToFile(m model, msg string) {
if m.debug {
log.Printf("debug: %s", msg)
}
}

@ -17,46 +17,53 @@ const (
cwtchTestLogFile = "cwtch-test.log"
)
func setup(t *testing.T) (model, *os.File, *openPrivacyLog.Logger) {
_, err := tea.LogToFile(cairdeTestLogFile, "debug")
if err != nil {
t.Fatal(err)
}
var currentUser *user.User
var cairdeLogHandler *os.File
var cwtchLogHandler *openPrivacyLog.Logger
cairdeLogHandler, err := os.OpenFile(cairdeTestLogFile, os.O_RDONLY, 0644)
if err != nil {
t.Fatal(err)
}
cwtchLog, err := openPrivacyLog.NewFile(openPrivacyLog.LevelDebug, cwtchTestLogFile)
if err == nil {
openPrivacyLog.SetStd(cwtchLog)
}
user, err := user.Current()
if err != nil {
t.Fatal(err)
}
return newModel(user.Username, user.HomeDir, true), cairdeLogHandler, cwtchLog
func TestMain(m *testing.M) {
defer setupAndTeardown()()
m.Run()
}
func teardown(t *testing.T, cairdeLog *os.File) {
if err := cairdeLog.Close(); err != nil {
t.Fatal(err)
func setupAndTeardown() func() {
_, err := tea.LogToFile(cairdeTestLogFile, "debug")
if err != nil {
panic(err)
}
if err := os.Remove(cairdeTestLogFile); err != nil {
t.Fatal(err)
cairdeLogHandler, err = os.OpenFile(cairdeTestLogFile, os.O_RDONLY, 0644)
if err != nil {
panic(err)
}
if err := os.Remove(cwtchTestLogFile); err != nil {
t.Fatal(err)
cwtchLogHandler, err = openPrivacyLog.NewFile(openPrivacyLog.LevelDebug, cwtchTestLogFile)
if err == nil {
openPrivacyLog.SetStd(cwtchLogHandler)
}
currentUser, err = user.Current()
if err != nil {
panic(err)
}
return func() {
if err := cairdeLogHandler.Close(); err != nil {
panic(err)
}
if err := os.Remove(cairdeTestLogFile); err != nil {
panic(err)
}
if err := os.Remove(cwtchTestLogFile); err != nil {
panic(err)
}
}
}
func TestOnOff(t *testing.T) {
m, cairdeLog, _ := setup(t)
m := newModel(currentUser.Username, currentUser.HomeDir, true)
testModel := teatest.NewTestModel(t, m)
testModel.Send(tea.KeyMsg{
@ -65,18 +72,17 @@ func TestOnOff(t *testing.T) {
})
testModel.WaitFinished(t, teatest.WithFinalTimeout(time.Second))
teardown(t, cairdeLog)
}
func TestAcnOnOff(t *testing.T) {
m, cairdeLog, _ := setup(t)
m := newModel(currentUser.Username, currentUser.HomeDir, true)
testModel := teatest.NewTestModel(t, m)
testModel.Type("/acn on")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLog,
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN is up and running, all engines go"))
},
@ -88,7 +94,7 @@ func TestAcnOnOff(t *testing.T) {
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLog,
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN successfully turned off"))
},
@ -102,12 +108,213 @@ func TestAcnOnOff(t *testing.T) {
})
testModel.WaitFinished(t, teatest.WithFinalTimeout(time.Second))
teardown(t, cairdeLog)
}
// test acn on and then quit, clean
// test acn on and then on, asks to hold
// test acn on, then off, asks to hold, wait, then off
// test acn on and then quit, asks to hold
// test acn off, tells it is off
func TestAcnOnThenQuit(t *testing.T) {
m := newModel(currentUser.Username, currentUser.HomeDir, true)
testModel := teatest.NewTestModel(t, m)
testModel.Type("/acn on")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN is up and running, all engines go"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/quit")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("Shutting down application and ACN now"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
testModel.WaitFinished(t, teatest.WithFinalTimeout(time.Second))
}
func TestAcnOnThenOnAsksToHold(t *testing.T) {
m := newModel(currentUser.Username, currentUser.HomeDir, true)
testModel := teatest.NewTestModel(t, m)
testModel.Type("/acn on")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("Initialising Tor ACN"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/acn on")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN still initialising, please hold"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN is up and running, all engines go"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/quit")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("Shutting down application and ACN now"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
testModel.WaitFinished(t, teatest.WithFinalTimeout(time.Second))
}
func TestOnThenOffAsksToWait(t *testing.T) {
m := newModel(currentUser.Username, currentUser.HomeDir, true)
testModel := teatest.NewTestModel(t, m)
testModel.Type("/acn on")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("Initialising Tor ACN..."))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/acn on")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN still initialising, please hold"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN is up and running, all engines go"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/quit")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("Shutting down application and ACN now"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
testModel.WaitFinished(t, teatest.WithFinalTimeout(time.Second))
}
func TestAcnOnThenQuitAsksToWait(t *testing.T) {
m := newModel(currentUser.Username, currentUser.HomeDir, true)
testModel := teatest.NewTestModel(t, m)
testModel.Type("/acn on")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("Initialising Tor ACN..."))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/quit")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN still initialising, please hold"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN is up and running, all engines go"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/quit")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("Shutting down application and ACN now"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
testModel.WaitFinished(t, teatest.WithFinalTimeout(time.Second))
}
func TestAcnOffIsOff(t *testing.T) {
m := newModel(currentUser.Username, currentUser.HomeDir, true)
testModel := teatest.NewTestModel(t, m)
testModel.Type("/acn off")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
teatest.WaitFor(
t, cairdeLogHandler,
func(bts []byte) bool {
return bytes.Contains(bts, []byte("ACN is currently offline"))
},
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*10),
)
testModel.Type("/quit")
testModel.Send(tea.KeyMsg{Type: tea.KeyEnter})
testModel.WaitFinished(t, teatest.WithFinalTimeout(time.Second))
}

@ -133,6 +133,7 @@ func (m model) sendStatusCmd(lines ...string) tea.Cmd {
// we want to render messages to the status buffer but still have work to do.
func (m model) sendStatus(lines ...string) {
for _, line := range lines {
logToFile(m, line)
m.statusBuffer <- line
}
}
@ -411,9 +412,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case sendStatusMsg:
cmds = append(cmds, func() tea.Msg {
for _, line := range msg.lines {
if m.debug {
log.Printf("sendStatusMsg: %s", line)
}
logToFile(m, line)
m.statusBuffer <- line
}
return nil