Select Git revision
notifications_test.go
single_test.go 7.60 KiB
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package stoppable
import (
"fmt"
"sync/atomic"
"testing"
"time"
)
// Tests that NewSingle returns a Single with the correct name and running.
func TestNewSingle(t *testing.T) {
name := "threadName"
single := NewSingle(name)
if single.name != name {
t.Errorf("NewSingle returned Single with incorrect name."+
"\nexpected: %s\nreceived: %s", name, single.name)
}
if single.status != Running {
t.Errorf("NewSingle returned Single with incorrect status."+
"\nexpected: %s\nreceived: %s", Running, single.status)
}
}
// Unit test of Single.Name.
func TestSingle_Name(t *testing.T) {
name := "threadName"
single := NewSingle(name)
if name != single.Name() {
t.Errorf("Name did not return the expected name."+
"\nexpected: %s\nreceived: %s", name, single.Name())
}
}
// Tests that Single.GetStatus returns the expected Status.
func TestSingle_GetStatus(t *testing.T) {
single := NewSingle("threadName")
status := single.GetStatus()
if status != Running {
t.Errorf("GetStatus returned the wrong status."+
"\nexpected: %s\nreceived: %s", Running, status)
}
atomic.StoreUint32((*uint32)(&single.status), uint32(Stopping))
status = single.GetStatus()
if status != Stopping {
t.Errorf("GetStatus returned the wrong status."+
"\nexpected: %s\nreceived: %s", Stopping, status)
}
atomic.StoreUint32((*uint32)(&single.status), uint32(Stopped))
status = single.GetStatus()
if status != Stopped {
t.Errorf("GetStatus returned the wrong status."+
"\nexpected: %s\nreceived: %s", Stopped, status)
}
}
// Tests that Single.IsRunning returns the expected value when the Single is
// marked as running, stopping, and stopped.
func TestSingle_IsRunning(t *testing.T) {
single := NewSingle("threadName")
if result := single.IsRunning(); !result {
t.Errorf("IsRunning returned the wrong value when running."+
"\nexpected: %t\nreceived: %t", true, result)
}
single.status = Stopping
if result := single.IsRunning(); result {
t.Errorf("IsRunning returned the wrong value when stopping."+
"\nexpected: %t\nreceived: %t", false, result)
}
single.status = Stopped
if result := single.IsRunning(); result {
t.Errorf("IsRunning returned the wrong value when stopped."+
"\nexpected: %t\nreceived: %t", false, result)
}
}
// Tests that Single.IsStopping returns the expected value when the Single is
// marked as running, stopping, and stopped.
func TestSingle_IsStopping(t *testing.T) {
single := NewSingle("threadName")
if result := single.IsStopping(); result {
t.Errorf("IsStopping returned the wrong value when running."+
"\nexpected: %t\nreceived: %t", true, result)
}
single.status = Stopping
if result := single.IsStopping(); !result {
t.Errorf("IsStopping returned the wrong value when stopping."+
"\nexpected: %t\nreceived: %t", false, result)
}
single.status = Stopped
if result := single.IsStopping(); result {
t.Errorf("IsStopping returned the wrong value when stopped."+
"\nexpected: %t\nreceived: %t", false, result)
}
}
// Tests that Single.IsStopped returns the expected value when the Single is
// marked as running, stopping, and stopped.
func TestSingle_IsStopped(t *testing.T) {
single := NewSingle("threadName")
if result := single.IsStopped(); result {
t.Errorf("IsStopped returned the wrong value when running."+
"\nexpected: %t\nreceived: %t", true, result)
}
single.status = Stopping
if result := single.IsStopped(); result {
t.Errorf("IsStopped returned the wrong value when stopping."+
"\nexpected: %t\nreceived: %t", false, result)
}
single.status = Stopped
if result := single.IsStopped(); !result {
t.Errorf("IsStopped returned the wrong value when stopped."+
"\nexpected: %t\nreceived: %t", false, result)
}
}
// Tests that Single.toStopping changes the status to stopping.
func TestSingle_toStopping(t *testing.T) {
single := NewSingle("threadName")
err := single.toStopping()
if err != nil {
t.Errorf("toStopping returned an error: %+v", err)
}
if single.status != Stopping {
t.Errorf("toStopping failed to set the status correctly."+
"\nexpected: %s\nreceived: %s", Stopping, single.status)
}
}
// Error path: tests that Single.toStopping returns an error when failing to
// change the status to stopping when the current status is not running.
func TestSingle_toStopping_StatusError(t *testing.T) {
single := NewSingle("threadName")
single.status = Stopped
expectedErr := fmt.Sprintf(
toStoppingErr, single.Name(), single.GetStatus(), Running)
err := single.toStopping()
if err == nil || err.Error() != expectedErr {
t.Errorf("toStopping failed to return the expected error."+
"\nexpected: %s\nreceived: %+v", expectedErr, err)
}
if single.status != Stopped {
t.Errorf("toStopping changed the status when the compare failed."+
"\nexpected: %s\nreceived: %s", Stopped, single.status)
}
}
// Tests that Single.ToStopped changes the status to stopped.
func TestSingle_ToStopped(t *testing.T) {
single := NewSingle("threadName")
single.status = Stopping
single.ToStopped()
if single.status != Stopped {
t.Errorf("ToStopped failed to set the status correctly."+
"\nexpected: %s\nreceived: %s", Stopped, single.status)
}
}
// Panic path: tests that Single.ToStopped panics when failing to change the
// status to stopped when the current status is not stopping.
func TestSingle_ToStopped_StatusPanic(t *testing.T) {
single := NewSingle("threadName")
defer func() {
if r := recover(); r == nil {
t.Errorf("ToStopped failed to panic when the status should not " +
"have changed.")
} else {
if single.status != Running {
t.Errorf("ToStopped changed the status when the compare failed."+
"\nexpected: %s\nreceived: %s", Running, single.status)
}
}
}()
single.status = Running
single.ToStopped()
}
// Tests that Single.Quit returns a channel that is triggered when the Single
// quit channel is triggered.
func TestSingle_Quit(t *testing.T) {
single := NewSingle("threadName")
go func() {
select {
case <-time.NewTimer(5 * time.Millisecond).C:
t.Error("Timed out waiting for quit channel.")
case <-single.Quit():
}
}()
single.quit <- struct{}{}
}
// Test happy path of Single.Close().
func TestSingle_Close(t *testing.T) {
single := NewSingle("threadName")
timeout := 10 * time.Millisecond
go func() {
select {
case <-time.NewTimer(timeout).C:
t.Errorf("Timed out waiting to receive on quit channel after %s.",
timeout)
case <-single.Quit():
if !single.IsStopping() {
t.Errorf("Status of stoppable incorrect."+
"\nexpected: %s\nreceived: %s", Stopping, single.status)
}
atomic.StoreUint32((*uint32)(&single.status), uint32(Stopped))
}
}()
err := single.Close()
if err != nil {
t.Errorf("Close returned an error: %v", err)
}
}
// Error path: tests that Single.Close returns an error when the status fails
// to change to stopping.
func TestSingle_Close_Error(t *testing.T) {
single := NewSingle("threadName")
single.status = Stopped
expectedErr := fmt.Sprintf(
toStoppingErr, single.Name(), single.GetStatus(), Running)
err := single.Close()
if err == nil || err.Error() != expectedErr {
t.Errorf("Close did not return the expected error."+
"\nexpected: %s\nreceived: %v", expectedErr, err)
}
}