mirror of
https://github.com/prashantgupta24/automatic-mouse-mover.git
synced 2024-12-21 16:04:10 +00:00
added tests for app
This commit is contained in:
parent
bba12a2242
commit
a60d85577a
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,7 @@
|
||||
vendor/
|
||||
bin/
|
||||
log/
|
||||
log/
|
||||
|
||||
# coverage
|
||||
*.html
|
||||
*.out
|
12
Makefile
12
Makefile
@ -1,3 +1,6 @@
|
||||
COVER_PROFILE=cover.out
|
||||
COVER_HTML=cover.html
|
||||
|
||||
all: open
|
||||
|
||||
build: clean
|
||||
@ -16,8 +19,13 @@ clean:
|
||||
start:
|
||||
go run cmd/main.go
|
||||
|
||||
test:
|
||||
go test -v -race -failfast ./...
|
||||
coverage: $(COVER_HTML)
|
||||
|
||||
$(COVER_HTML): $(COVER_PROFILE)
|
||||
go tool cover -html=$(COVER_PROFILE) -o $(COVER_HTML)
|
||||
|
||||
$(COVER_PROFILE):
|
||||
go test -v -failfast -race -coverprofile=$(COVER_PROFILE) ./...
|
||||
|
||||
vet:
|
||||
go vet $(shell glide nv)
|
||||
|
@ -2,8 +2,6 @@ package mousemover
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-vgo/robotgo"
|
||||
@ -13,14 +11,6 @@ import (
|
||||
|
||||
var instance *MouseMover
|
||||
|
||||
//MouseMover is the main struct for the app
|
||||
type MouseMover struct {
|
||||
quit chan struct{}
|
||||
mutex sync.RWMutex
|
||||
runningStatus bool
|
||||
logFile *os.File
|
||||
}
|
||||
|
||||
const (
|
||||
timeout = 100 //ms
|
||||
logDir = "log"
|
||||
@ -29,9 +19,10 @@ const (
|
||||
|
||||
//Start the main app
|
||||
func (m *MouseMover) Start() {
|
||||
if m.isRunning() {
|
||||
if m.state.isRunning() {
|
||||
return
|
||||
}
|
||||
m.state = &state{}
|
||||
m.quit = make(chan struct{})
|
||||
|
||||
heartbeatInterval := 60 //value always in seconds
|
||||
@ -49,38 +40,40 @@ func (m *MouseMover) Start() {
|
||||
|
||||
func (m *MouseMover) run(heartbeatCh chan *tracker.Heartbeat, activityTracker *tracker.Instance) {
|
||||
go func() {
|
||||
if m.isRunning() {
|
||||
state := m.state
|
||||
if state != nil && state.isRunning() {
|
||||
return
|
||||
}
|
||||
state.updateRunningStatus(true)
|
||||
|
||||
logger := getLogger(m, false) //set writeToFile=true only for debugging
|
||||
m.updateRunningStatus(true)
|
||||
movePixel := 10
|
||||
var lastMoved time.Time
|
||||
isSystemSleeping := false
|
||||
didNotMoveTimes := 0
|
||||
// var lastMoved time.Time
|
||||
// didNotMoveTimes := 0
|
||||
for {
|
||||
select {
|
||||
case heartbeat := <-heartbeatCh:
|
||||
if !heartbeat.WasAnyActivity {
|
||||
if isSystemSleeping {
|
||||
if state.isSystemSleeping() {
|
||||
logger.Infof("system sleeping")
|
||||
continue
|
||||
}
|
||||
mouseMoveSuccessCh := make(chan bool)
|
||||
go moveAndCheck(movePixel, mouseMoveSuccessCh)
|
||||
go moveAndCheck(state, movePixel, mouseMoveSuccessCh)
|
||||
select {
|
||||
case wasMouseMoveSuccess := <-mouseMoveSuccessCh:
|
||||
if wasMouseMoveSuccess {
|
||||
lastMoved = time.Now()
|
||||
logger.Infof("moved mouse at : %v\n\n", lastMoved)
|
||||
state.updateLastMouseMovedTime(time.Now())
|
||||
logger.Infof("moved mouse at : %v\n\n", state.getLastMouseMovedTime())
|
||||
movePixel *= -1
|
||||
didNotMoveTimes = 0
|
||||
state.updateDidNotMoveCount(0)
|
||||
} else {
|
||||
didNotMoveTimes++
|
||||
didNotMoveCount := state.getDidNotMoveCount()
|
||||
state.updateDidNotMoveCount(didNotMoveCount + 1)
|
||||
msg := fmt.Sprintf("Mouse pointer cannot be moved at %v. Last moved at %v. Happened %v times. See README for details.",
|
||||
time.Now(), lastMoved, didNotMoveTimes)
|
||||
time.Now(), state.getLastMouseMovedTime(), state.getDidNotMoveCount())
|
||||
logger.Errorf(msg)
|
||||
if didNotMoveTimes >= 3 {
|
||||
if state.getDidNotMoveCount() >= 3 {
|
||||
go func() {
|
||||
robotgo.ShowAlert("Error with Automatic Mouse Mover", msg)
|
||||
}()
|
||||
@ -96,16 +89,16 @@ func (m *MouseMover) run(heartbeatCh chan *tracker.Heartbeat, activityTracker *t
|
||||
for activityType, times := range heartbeat.ActivityMap {
|
||||
logger.Infof("activityType : %v times: %v\n", activityType, len(times))
|
||||
if activityType == activity.MachineSleep {
|
||||
isSystemSleeping = true
|
||||
state.updateMachineSleepStatus(true)
|
||||
} else if activityType == activity.MachineWake {
|
||||
isSystemSleeping = false
|
||||
state.updateMachineSleepStatus(false)
|
||||
}
|
||||
}
|
||||
logger.Infof("\n\n\n")
|
||||
}
|
||||
case <-m.quit:
|
||||
logger.Infof("stopping mouse mover")
|
||||
m.updateRunningStatus(false)
|
||||
state.updateRunningStatus(false)
|
||||
activityTracker.Quit()
|
||||
return
|
||||
}
|
||||
@ -116,7 +109,7 @@ func (m *MouseMover) run(heartbeatCh chan *tracker.Heartbeat, activityTracker *t
|
||||
//Quit the app
|
||||
func (m *MouseMover) Quit() {
|
||||
//making it idempotent
|
||||
if m != nil && m.isRunning() {
|
||||
if m != nil && m.state.isRunning() {
|
||||
m.quit <- struct{}{}
|
||||
}
|
||||
if m.logFile != nil {
|
||||
@ -127,7 +120,9 @@ func (m *MouseMover) Quit() {
|
||||
//GetInstance gets the singleton instance for mouse mover app
|
||||
func GetInstance() *MouseMover {
|
||||
if instance == nil {
|
||||
instance = &MouseMover{}
|
||||
instance = &MouseMover{
|
||||
state: &state{},
|
||||
}
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package mousemover
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-vgo/robotgo"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -36,7 +37,11 @@ func getLogger(m *MouseMover, doWriteToFile bool) *log.Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
func moveAndCheck(movePixel int, mouseMoveSuccessCh chan bool) {
|
||||
func moveAndCheck(state *state, movePixel int, mouseMoveSuccessCh chan bool) {
|
||||
if state.override != nil { //we don't want to move mouse for tests
|
||||
mouseMoveSuccessCh <- state.override.valueToReturn
|
||||
return
|
||||
}
|
||||
currentX, currentY := robotgo.GetMousePos()
|
||||
moveToX := currentX + movePixel
|
||||
moveToY := currentY + movePixel
|
||||
@ -52,13 +57,51 @@ func moveAndCheck(movePixel int, mouseMoveSuccessCh chan bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MouseMover) isRunning() bool {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
return m.runningStatus
|
||||
//getters and setters for state variable
|
||||
func (s *state) isRunning() bool {
|
||||
s.mutex.RLock()
|
||||
defer s.mutex.RUnlock()
|
||||
return s.isAppRunning
|
||||
}
|
||||
func (m *MouseMover) updateRunningStatus(isRunning bool) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
m.runningStatus = isRunning
|
||||
|
||||
func (s *state) updateRunningStatus(isRunning bool) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
s.isAppRunning = isRunning
|
||||
}
|
||||
|
||||
func (s *state) isSystemSleeping() bool {
|
||||
s.mutex.RLock()
|
||||
defer s.mutex.RUnlock()
|
||||
return s.isSysSleeping
|
||||
}
|
||||
|
||||
func (s *state) updateMachineSleepStatus(isSleeping bool) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
s.isSysSleeping = isSleeping
|
||||
}
|
||||
|
||||
func (s *state) getLastMouseMovedTime() time.Time {
|
||||
s.mutex.RLock()
|
||||
defer s.mutex.RUnlock()
|
||||
return s.lastMouseMovedTime
|
||||
}
|
||||
|
||||
func (s *state) updateLastMouseMovedTime(time time.Time) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
s.lastMouseMovedTime = time
|
||||
}
|
||||
|
||||
func (s *state) getDidNotMoveCount() int {
|
||||
s.mutex.RLock()
|
||||
defer s.mutex.RUnlock()
|
||||
return s.didNotMoveCount
|
||||
}
|
||||
|
||||
func (s *state) updateDidNotMoveCount(count int) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
s.didNotMoveCount = count
|
||||
}
|
||||
|
@ -7,21 +7,23 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/prashantgupta24/activity-tracker/pkg/activity"
|
||||
"github.com/prashantgupta24/activity-tracker/pkg/tracker"
|
||||
)
|
||||
|
||||
type TestMover struct {
|
||||
suite.Suite
|
||||
activityTracker *tracker.Instance
|
||||
heartbeatCh chan *tracker.Heartbeat
|
||||
heartbeatCh chan *tracker.Heartbeat
|
||||
}
|
||||
|
||||
func TestSuite(t *testing.T) {
|
||||
suite.Run(t, new(TestMover))
|
||||
}
|
||||
|
||||
//Run once before all tests
|
||||
func (suite *TestMover) SetupSuite() {
|
||||
heartbeatInterval := 60
|
||||
heartbeatInterval := 60
|
||||
workerInterval := 10
|
||||
|
||||
suite.activityTracker = &tracker.Instance{
|
||||
@ -29,14 +31,20 @@ func (suite *TestMover) SetupSuite() {
|
||||
WorkerInterval: workerInterval,
|
||||
}
|
||||
|
||||
suite.heartbeatCh= make(chan *tracker.Heartbeat)
|
||||
suite.heartbeatCh = make(chan *tracker.Heartbeat)
|
||||
}
|
||||
|
||||
//Run once before each test
|
||||
func (suite *TestMover) SetupTest() {
|
||||
instance = nil
|
||||
}
|
||||
|
||||
func (suite *TestMover) TestAppStart() {
|
||||
t := suite.T()
|
||||
mouseMover := GetInstance()
|
||||
mouseMover.run(suite.heartbeatCh, suite.activityTracker)
|
||||
time.Sleep(time.Millisecond * 500) //wait for app to start
|
||||
assert.True(t, mouseMover.state.isRunning(), "app should have started")
|
||||
}
|
||||
func (suite *TestMover) TestSingleton() {
|
||||
t := suite.T()
|
||||
|
||||
@ -46,15 +54,83 @@ func (suite *TestMover) TestSingleton() {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
|
||||
mouseMover2 := GetInstance()
|
||||
assert.True(t, mouseMover2.isRunning(), "instance should have started")
|
||||
assert.True(t, mouseMover2.state.isRunning(), "instance should have started")
|
||||
}
|
||||
func (suite *TestMover) TestAppStartAndStop() {
|
||||
|
||||
func (suite *TestMover) TestSystemSleep() {
|
||||
t := suite.T()
|
||||
mouseMover := GetInstance()
|
||||
mouseMover.run(suite.heartbeatCh, suite.activityTracker)
|
||||
|
||||
heartbeatCh := make(chan *tracker.Heartbeat)
|
||||
mouseMover.run(heartbeatCh, suite.activityTracker)
|
||||
time.Sleep(time.Millisecond * 500) //wait for app to start
|
||||
assert.True(t, mouseMover.isRunning(), "app should have started")
|
||||
mouseMover.Quit()
|
||||
time.Sleep(time.Millisecond * 1000) //wait for app to stop
|
||||
assert.False(t, mouseMover.isRunning(), "app should have stopped")
|
||||
assert.True(t, mouseMover.state.isRunning(), "instance should have started")
|
||||
assert.False(t, mouseMover.state.isSystemSleeping(), "machine should not be sleeping")
|
||||
|
||||
//fake a machine-sleep activity
|
||||
machineSleepActivityMap := make(map[activity.Type][]time.Time)
|
||||
var timeArray []time.Time
|
||||
timeArray = append(timeArray, time.Now())
|
||||
machineSleepActivityMap[activity.MachineSleep] = timeArray
|
||||
heartbeatCh <- &tracker.Heartbeat{
|
||||
WasAnyActivity: true,
|
||||
ActivityMap: machineSleepActivityMap,
|
||||
}
|
||||
time.Sleep(time.Millisecond * 500) //wait for it to be registered
|
||||
assert.True(t, mouseMover.state.isSystemSleeping(), "machine should be sleeping now")
|
||||
}
|
||||
|
||||
func (suite *TestMover) TestMouseMoveSuccess() {
|
||||
t := suite.T()
|
||||
mouseMover := GetInstance()
|
||||
|
||||
state := &state{
|
||||
override: &override{
|
||||
valueToReturn: true,
|
||||
},
|
||||
}
|
||||
mouseMover.state = state
|
||||
heartbeatCh := make(chan *tracker.Heartbeat)
|
||||
|
||||
mouseMover.run(heartbeatCh, suite.activityTracker)
|
||||
time.Sleep(time.Millisecond * 500) //wait for app to start
|
||||
assert.True(t, state.isRunning(), "instance should have started")
|
||||
assert.False(t, state.isSystemSleeping(), "machine should not be sleeping")
|
||||
assert.True(t, time.Time.IsZero(state.getLastMouseMovedTime()), "should be default")
|
||||
assert.Equal(t, state.getDidNotMoveCount(), 0, "should be 0")
|
||||
|
||||
heartbeatCh <- &tracker.Heartbeat{
|
||||
WasAnyActivity: false,
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 500) //wait for it to be registered
|
||||
assert.False(t, time.Time.IsZero(state.getLastMouseMovedTime()), "should be default but is ", state.getLastMouseMovedTime())
|
||||
}
|
||||
|
||||
func (suite *TestMover) TestMouseMoveFailure() {
|
||||
t := suite.T()
|
||||
mouseMover := GetInstance()
|
||||
|
||||
state := &state{
|
||||
override: &override{
|
||||
valueToReturn: false,
|
||||
},
|
||||
}
|
||||
mouseMover.state = state
|
||||
heartbeatCh := make(chan *tracker.Heartbeat)
|
||||
|
||||
mouseMover.run(heartbeatCh, suite.activityTracker)
|
||||
time.Sleep(time.Millisecond * 500) //wait for app to start
|
||||
assert.True(t, state.isRunning(), "instance should have started")
|
||||
assert.False(t, state.isSystemSleeping(), "machine should not be sleeping")
|
||||
assert.True(t, time.Time.IsZero(state.getLastMouseMovedTime()), "should be default")
|
||||
assert.Equal(t, state.getDidNotMoveCount(), 0, "should be 0")
|
||||
|
||||
heartbeatCh <- &tracker.Heartbeat{
|
||||
WasAnyActivity: false,
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 500) //wait for it to be registered
|
||||
assert.True(t, time.Time.IsZero(state.getLastMouseMovedTime()), "should be default but is ", state.getLastMouseMovedTime())
|
||||
assert.NotEqual(t, state.getDidNotMoveCount(), 0, "should not be 0")
|
||||
}
|
||||
|
29
pkg/mousemover/types.go
Normal file
29
pkg/mousemover/types.go
Normal file
@ -0,0 +1,29 @@
|
||||
package mousemover
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
//MouseMover is the main struct for the app
|
||||
type MouseMover struct {
|
||||
quit chan struct{}
|
||||
logFile *os.File
|
||||
state *state
|
||||
}
|
||||
|
||||
//state manages the internal working of the app
|
||||
type state struct {
|
||||
mutex sync.RWMutex
|
||||
isAppRunning bool
|
||||
isSysSleeping bool
|
||||
lastMouseMovedTime time.Time
|
||||
didNotMoveCount int
|
||||
override *override
|
||||
}
|
||||
|
||||
//only needed for tests
|
||||
type override struct {
|
||||
valueToReturn bool
|
||||
}
|
Loading…
Reference in New Issue
Block a user