mirror of
https://github.com/hibiken/asynq.git
synced 2025-10-03 17:22:01 +08:00
(cli): Refactor dash package
This commit is contained in:
@@ -72,13 +72,19 @@ func Run(opts Options) {
|
|||||||
fmt.Printf("failed to initialize screen: %v\n", err)
|
fmt.Printf("failed to initialize screen: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
// Set default text style
|
s.SetStyle(baseStyle) // set default text style
|
||||||
s.SetStyle(baseStyle)
|
opts.PollInterval = 2 * time.Second
|
||||||
|
|
||||||
inspector := asynq.NewInspector(asynq.RedisClientOpt{Addr: ":6379"})
|
|
||||||
|
|
||||||
// channels to send/receive data fetched asynchronously
|
|
||||||
var (
|
var (
|
||||||
|
state = State{} // confined in this goroutine only; DO NOT SHARE
|
||||||
|
|
||||||
|
inspector = asynq.NewInspector(asynq.RedisClientOpt{Addr: ":6379"})
|
||||||
|
ticker = time.NewTicker(opts.PollInterval)
|
||||||
|
|
||||||
|
eventCh = make(chan tcell.Event)
|
||||||
|
done = make(chan struct{})
|
||||||
|
|
||||||
|
// channels to send/receive data fetched asynchronously
|
||||||
errorCh = make(chan error)
|
errorCh = make(chan error)
|
||||||
queueCh = make(chan *asynq.QueueInfo)
|
queueCh = make(chan *asynq.QueueInfo)
|
||||||
queuesCh = make(chan []*asynq.QueueInfo)
|
queuesCh = make(chan []*asynq.QueueInfo)
|
||||||
@@ -86,17 +92,6 @@ func Run(opts Options) {
|
|||||||
tasksCh = make(chan []*asynq.TaskInfo)
|
tasksCh = make(chan []*asynq.TaskInfo)
|
||||||
redisInfoCh = make(chan *redisInfo)
|
redisInfoCh = make(chan *redisInfo)
|
||||||
)
|
)
|
||||||
go fetchQueues(inspector, queuesCh, errorCh, opts)
|
|
||||||
|
|
||||||
var state State // contained in this goroutine only; do not share
|
|
||||||
|
|
||||||
// draw initial screen
|
|
||||||
drawDash(s, &state, opts)
|
|
||||||
|
|
||||||
eventCh := make(chan tcell.Event)
|
|
||||||
done := make(chan struct{})
|
|
||||||
opts.PollInterval = 2 * time.Second
|
|
||||||
ticker := time.NewTicker(opts.PollInterval)
|
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
f := dataFetcher{
|
f := dataFetcher{
|
||||||
@@ -111,16 +106,22 @@ func Run(opts Options) {
|
|||||||
redisInfoCh,
|
redisInfoCh,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d := dashDrawer{
|
||||||
|
s,
|
||||||
|
opts,
|
||||||
|
}
|
||||||
|
|
||||||
h := keyEventHandler{
|
h := keyEventHandler{
|
||||||
s: s,
|
s: s,
|
||||||
fetcher: &f,
|
fetcher: &f,
|
||||||
|
drawer: &d,
|
||||||
state: &state,
|
state: &state,
|
||||||
opts: opts,
|
|
||||||
done: done,
|
done: done,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Double check that we are not leaking goroutine with this one.
|
go fetchQueues(inspector, queuesCh, errorCh, opts)
|
||||||
go s.ChannelEvents(eventCh, done)
|
go s.ChannelEvents(eventCh, done) // TODO: Double check that we are not leaking goroutine with this one.
|
||||||
|
d.draw(&state) // draw initial screen
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// Update screen
|
// Update screen
|
||||||
@@ -158,31 +159,31 @@ func Run(opts Options) {
|
|||||||
case queues := <-queuesCh:
|
case queues := <-queuesCh:
|
||||||
state.queues = queues
|
state.queues = queues
|
||||||
state.err = nil
|
state.err = nil
|
||||||
drawDash(s, &state, opts)
|
d.draw(&state)
|
||||||
|
|
||||||
case q := <-queueCh:
|
case q := <-queueCh:
|
||||||
state.selectedQueue = q
|
state.selectedQueue = q
|
||||||
state.err = nil
|
state.err = nil
|
||||||
drawDash(s, &state, opts)
|
d.draw(&state)
|
||||||
|
|
||||||
case groups := <-groupsCh:
|
case groups := <-groupsCh:
|
||||||
state.groups = groups
|
state.groups = groups
|
||||||
state.err = nil
|
state.err = nil
|
||||||
drawDash(s, &state, opts)
|
d.draw(&state)
|
||||||
|
|
||||||
case tasks := <-tasksCh:
|
case tasks := <-tasksCh:
|
||||||
state.tasks = tasks
|
state.tasks = tasks
|
||||||
state.err = nil
|
state.err = nil
|
||||||
drawDash(s, &state, opts)
|
d.draw(&state)
|
||||||
|
|
||||||
case redisInfo := <-redisInfoCh:
|
case redisInfo := <-redisInfoCh:
|
||||||
state.redisInfo = *redisInfo
|
state.redisInfo = *redisInfo
|
||||||
state.err = nil
|
state.err = nil
|
||||||
drawDash(s, &state, opts)
|
d.draw(&state)
|
||||||
|
|
||||||
case err := <-errorCh:
|
case err := <-errorCh:
|
||||||
state.err = err
|
state.err = err
|
||||||
drawDash(s, &state, opts)
|
d.draw(&state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,7 +16,18 @@ import (
|
|||||||
"github.com/mattn/go-runewidth"
|
"github.com/mattn/go-runewidth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func drawDash(s tcell.Screen, state *State, opts Options) {
|
// drawer draws UI with the given state.
|
||||||
|
type drawer interface {
|
||||||
|
draw(state *State)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dashDrawer struct {
|
||||||
|
s tcell.Screen
|
||||||
|
opts Options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dd *dashDrawer) draw(state *State) {
|
||||||
|
s, opts := dd.s, dd.opts
|
||||||
s.Clear()
|
s.Clear()
|
||||||
// Simulate data update on every render
|
// Simulate data update on every render
|
||||||
d := NewScreenDrawer(s)
|
d := NewScreenDrawer(s)
|
||||||
|
@@ -11,6 +11,15 @@ import (
|
|||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type fetcher interface {
|
||||||
|
fetchQueues()
|
||||||
|
fetchQueueInfo(qname string)
|
||||||
|
fetchRedisInfo()
|
||||||
|
fetchTasks(qname string, taskState asynq.TaskState, pageSize, pageNum int)
|
||||||
|
fetchAggregatingTasks(qname, group string, pageSize, pageNum int)
|
||||||
|
fetchGroups(qname string)
|
||||||
|
}
|
||||||
|
|
||||||
type dataFetcher struct {
|
type dataFetcher struct {
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
inspector *asynq.Inspector
|
inspector *asynq.Inspector
|
||||||
|
@@ -11,13 +11,15 @@ import (
|
|||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// keyEventHandler handles keyboard events and updates the state.
|
||||||
|
// It delegates data fetching to fetcher and UI rendering to drawer.
|
||||||
type keyEventHandler struct {
|
type keyEventHandler struct {
|
||||||
s tcell.Screen
|
s tcell.Screen
|
||||||
state *State
|
state *State
|
||||||
opts Options
|
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
|
|
||||||
fetcher *dataFetcher
|
fetcher fetcher
|
||||||
|
drawer drawer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) quit() {
|
func (h *keyEventHandler) quit() {
|
||||||
@@ -62,16 +64,15 @@ func (h *keyEventHandler) HandleKeyEvent(ev *tcell.EventKey) {
|
|||||||
|
|
||||||
func (h *keyEventHandler) goBack() {
|
func (h *keyEventHandler) goBack() {
|
||||||
var (
|
var (
|
||||||
s = h.s
|
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view == viewTypeHelp {
|
if state.view == viewTypeHelp {
|
||||||
state.view = state.prevView // exit help
|
state.view = state.prevView // exit help
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
} else if state.view == viewTypeQueueDetails {
|
} else if state.view == viewTypeQueueDetails {
|
||||||
state.view = viewTypeQueues
|
state.view = viewTypeQueues
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
} else {
|
} else {
|
||||||
h.quit()
|
h.quit()
|
||||||
}
|
}
|
||||||
@@ -92,11 +93,11 @@ func (h *keyEventHandler) downKeyQueues() {
|
|||||||
} else {
|
} else {
|
||||||
h.state.queueTableRowIdx = 0 // loop back
|
h.state.queueTableRowIdx = 0 // loop back
|
||||||
}
|
}
|
||||||
drawDash(h.s, h.state, h.opts)
|
h.drawer.draw(h.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) downKeyQueueDetails() {
|
func (h *keyEventHandler) downKeyQueueDetails() {
|
||||||
s, state, opts := h.s, h.state, h.opts
|
s, state := h.s, h.state
|
||||||
if shouldShowGroupTable(state) {
|
if shouldShowGroupTable(state) {
|
||||||
if state.groupTableRowIdx < groupPageSize(s) {
|
if state.groupTableRowIdx < groupPageSize(s) {
|
||||||
state.groupTableRowIdx++
|
state.groupTableRowIdx++
|
||||||
@@ -110,7 +111,7 @@ func (h *keyEventHandler) downKeyQueueDetails() {
|
|||||||
state.taskTableRowIdx = 0 // loop back
|
state.taskTableRowIdx = 0 // loop back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawDash(s, state, opts)
|
h.drawer.draw(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) handleUpKey() {
|
func (h *keyEventHandler) handleUpKey() {
|
||||||
@@ -123,17 +124,17 @@ func (h *keyEventHandler) handleUpKey() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) upKeyQueues() {
|
func (h *keyEventHandler) upKeyQueues() {
|
||||||
s, state, opts := h.s, h.state, h.opts
|
state := h.state
|
||||||
if state.queueTableRowIdx == 0 {
|
if state.queueTableRowIdx == 0 {
|
||||||
state.queueTableRowIdx = len(state.queues)
|
state.queueTableRowIdx = len(state.queues)
|
||||||
} else {
|
} else {
|
||||||
state.queueTableRowIdx--
|
state.queueTableRowIdx--
|
||||||
}
|
}
|
||||||
drawDash(s, state, opts)
|
h.drawer.draw(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) upKeyQueueDetails() {
|
func (h *keyEventHandler) upKeyQueueDetails() {
|
||||||
s, state, opts := h.s, h.state, h.opts
|
s, state := h.s, h.state
|
||||||
if shouldShowGroupTable(state) {
|
if shouldShowGroupTable(state) {
|
||||||
if state.groupTableRowIdx == 0 {
|
if state.groupTableRowIdx == 0 {
|
||||||
state.groupTableRowIdx = groupPageSize(s)
|
state.groupTableRowIdx = groupPageSize(s)
|
||||||
@@ -147,7 +148,7 @@ func (h *keyEventHandler) upKeyQueueDetails() {
|
|||||||
state.taskTableRowIdx--
|
state.taskTableRowIdx--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawDash(s, state, opts)
|
h.drawer.draw(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) handleEnterKey() {
|
func (h *keyEventHandler) handleEnterKey() {
|
||||||
@@ -163,8 +164,8 @@ func (h *keyEventHandler) enterKeyQueues() {
|
|||||||
var (
|
var (
|
||||||
s = h.s
|
s = h.s
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.queueTableRowIdx != 0 {
|
if state.queueTableRowIdx != 0 {
|
||||||
state.selectedQueue = state.queues[state.queueTableRowIdx-1]
|
state.selectedQueue = state.queues[state.queueTableRowIdx-1]
|
||||||
@@ -173,7 +174,7 @@ func (h *keyEventHandler) enterKeyQueues() {
|
|||||||
state.tasks = nil
|
state.tasks = nil
|
||||||
state.pageNum = 1
|
state.pageNum = 1
|
||||||
f.fetchTasks(state.selectedQueue.Queue, state.taskState, taskPageSize(s), state.pageNum)
|
f.fetchTasks(state.selectedQueue.Queue, state.taskState, taskPageSize(s), state.pageNum)
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,15 +182,15 @@ func (h *keyEventHandler) enterKeyQueueDetails() {
|
|||||||
var (
|
var (
|
||||||
s = h.s
|
s = h.s
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if shouldShowGroupTable(state) && state.groupTableRowIdx != 0 {
|
if shouldShowGroupTable(state) && state.groupTableRowIdx != 0 {
|
||||||
state.selectedGroup = state.groups[state.groupTableRowIdx-1]
|
state.selectedGroup = state.groups[state.groupTableRowIdx-1]
|
||||||
state.tasks = nil
|
state.tasks = nil
|
||||||
state.pageNum = 1
|
state.pageNum = 1
|
||||||
f.fetchAggregatingTasks(state.selectedQueue.Queue, state.selectedGroup.Group, taskPageSize(s), state.pageNum)
|
f.fetchAggregatingTasks(state.selectedQueue.Queue, state.selectedGroup.Group, taskPageSize(s), state.pageNum)
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +198,8 @@ func (h *keyEventHandler) handleLeftKey() {
|
|||||||
var (
|
var (
|
||||||
s = h.s
|
s = h.s
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view == viewTypeQueueDetails {
|
if state.view == viewTypeQueueDetails {
|
||||||
state.taskState = prevTaskState(state.taskState)
|
state.taskState = prevTaskState(state.taskState)
|
||||||
@@ -211,7 +212,7 @@ func (h *keyEventHandler) handleLeftKey() {
|
|||||||
} else {
|
} else {
|
||||||
f.fetchTasks(state.selectedQueue.Queue, state.taskState, taskPageSize(s), state.pageNum)
|
f.fetchTasks(state.selectedQueue.Queue, state.taskState, taskPageSize(s), state.pageNum)
|
||||||
}
|
}
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,8 +220,8 @@ func (h *keyEventHandler) handleRightKey() {
|
|||||||
var (
|
var (
|
||||||
s = h.s
|
s = h.s
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view == viewTypeQueueDetails {
|
if state.view == viewTypeQueueDetails {
|
||||||
state.taskState = nextTaskState(state.taskState)
|
state.taskState = nextTaskState(state.taskState)
|
||||||
@@ -233,7 +234,7 @@ func (h *keyEventHandler) handleRightKey() {
|
|||||||
} else {
|
} else {
|
||||||
f.fetchTasks(state.selectedQueue.Queue, state.taskState, taskPageSize(s), state.pageNum)
|
f.fetchTasks(state.selectedQueue.Queue, state.taskState, taskPageSize(s), state.pageNum)
|
||||||
}
|
}
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,8 +242,8 @@ func (h *keyEventHandler) nextPage() {
|
|||||||
var (
|
var (
|
||||||
s = h.s
|
s = h.s
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view == viewTypeQueueDetails {
|
if state.view == viewTypeQueueDetails {
|
||||||
if shouldShowGroupTable(state) {
|
if shouldShowGroupTable(state) {
|
||||||
@@ -252,7 +253,7 @@ func (h *keyEventHandler) nextPage() {
|
|||||||
end := start + pageSize
|
end := start + pageSize
|
||||||
if end <= total {
|
if end <= total {
|
||||||
state.pageNum++
|
state.pageNum++
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pageSize := taskPageSize(s)
|
pageSize := taskPageSize(s)
|
||||||
@@ -269,8 +270,8 @@ func (h *keyEventHandler) prevPage() {
|
|||||||
var (
|
var (
|
||||||
s = h.s
|
s = h.s
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view == viewTypeQueueDetails {
|
if state.view == viewTypeQueueDetails {
|
||||||
if shouldShowGroupTable(state) {
|
if shouldShowGroupTable(state) {
|
||||||
@@ -278,7 +279,7 @@ func (h *keyEventHandler) prevPage() {
|
|||||||
start := (state.pageNum - 1) * pageSize
|
start := (state.pageNum - 1) * pageSize
|
||||||
if start > 0 {
|
if start > 0 {
|
||||||
state.pageNum--
|
state.pageNum--
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if state.pageNum > 1 {
|
if state.pageNum > 1 {
|
||||||
@@ -291,67 +292,62 @@ func (h *keyEventHandler) prevPage() {
|
|||||||
|
|
||||||
func (h *keyEventHandler) showQueues() {
|
func (h *keyEventHandler) showQueues() {
|
||||||
var (
|
var (
|
||||||
s = h.s
|
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view != viewTypeQueues {
|
if state.view != viewTypeQueues {
|
||||||
f.fetchQueues()
|
f.fetchQueues()
|
||||||
state.view = viewTypeQueues
|
state.view = viewTypeQueues
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) showServers() {
|
func (h *keyEventHandler) showServers() {
|
||||||
var (
|
var (
|
||||||
s = h.s
|
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view != viewTypeServers {
|
if state.view != viewTypeServers {
|
||||||
//TODO Start data fetch and reset ticker
|
//TODO Start data fetch and reset ticker
|
||||||
state.view = viewTypeServers
|
state.view = viewTypeServers
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) showSchedulers() {
|
func (h *keyEventHandler) showSchedulers() {
|
||||||
var (
|
var (
|
||||||
s = h.s
|
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view != viewTypeSchedulers {
|
if state.view != viewTypeSchedulers {
|
||||||
//TODO Start data fetch and reset ticker
|
//TODO Start data fetch and reset ticker
|
||||||
state.view = viewTypeSchedulers
|
state.view = viewTypeSchedulers
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) showRedisInfo() {
|
func (h *keyEventHandler) showRedisInfo() {
|
||||||
var (
|
var (
|
||||||
s = h.s
|
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
|
||||||
f = h.fetcher
|
f = h.fetcher
|
||||||
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view != viewTypeRedis {
|
if state.view != viewTypeRedis {
|
||||||
f.fetchRedisInfo()
|
f.fetchRedisInfo()
|
||||||
state.view = viewTypeRedis
|
state.view = viewTypeRedis
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *keyEventHandler) showHelp() {
|
func (h *keyEventHandler) showHelp() {
|
||||||
var (
|
var (
|
||||||
s = h.s
|
|
||||||
state = h.state
|
state = h.state
|
||||||
opts = h.opts
|
d = h.drawer
|
||||||
)
|
)
|
||||||
if state.view != viewTypeHelp {
|
if state.view != viewTypeHelp {
|
||||||
state.prevView = state.view
|
state.prevView = state.view
|
||||||
state.view = viewTypeHelp
|
state.view = viewTypeHelp
|
||||||
drawDash(s, state, opts)
|
d.draw(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
70
tools/asynq/cmd/dash/key_event_test.go
Normal file
70
tools/asynq/cmd/dash/key_event_test.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2022 Kentaro Hibino. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package dash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/hibiken/asynq"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeKeyEventHandler(state *State) *keyEventHandler {
|
||||||
|
return &keyEventHandler{
|
||||||
|
s: tcell.NewSimulationScreen("UTF-8"),
|
||||||
|
state: state,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
fetcher: &fakeFetcher{},
|
||||||
|
drawer: &fakeDrawer{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type keyEventHandlerTest struct {
|
||||||
|
desc string // test description
|
||||||
|
state *State // initial state, to be mutated by the handler
|
||||||
|
events []*tcell.EventKey // keyboard events
|
||||||
|
wantState State // expected state after the events
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyEventHandler(t *testing.T) {
|
||||||
|
tests := []*keyEventHandlerTest{
|
||||||
|
{
|
||||||
|
desc: "navigates to help page",
|
||||||
|
state: &State{view: viewTypeQueues},
|
||||||
|
events: []*tcell.EventKey{tcell.NewEventKey(tcell.KeyRune, '?', tcell.ModNone)},
|
||||||
|
wantState: State{view: viewTypeHelp},
|
||||||
|
},
|
||||||
|
// TODO: Add more tests
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
h := makeKeyEventHandler(tc.state)
|
||||||
|
for _, e := range tc.events {
|
||||||
|
h.HandleKeyEvent(e)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(tc.wantState, *tc.state, cmp.AllowUnexported(State{}, redisInfo{})); diff != "" {
|
||||||
|
t.Errorf("after state was %+v, want %+v: (-want,+got)\n%s", *tc.state, tc.wantState, diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** fake implementation for tests ***/
|
||||||
|
|
||||||
|
type fakeFetcher struct{}
|
||||||
|
|
||||||
|
func (f *fakeFetcher) fetchQueues() {}
|
||||||
|
func (f *fakeFetcher) fetchQueueInfo(qname string) {}
|
||||||
|
func (f *fakeFetcher) fetchRedisInfo() {}
|
||||||
|
func (f *fakeFetcher) fetchTasks(qname string, taskState asynq.TaskState, pageSize, pageNum int) {}
|
||||||
|
func (f *fakeFetcher) fetchAggregatingTasks(qname, group string, pageSize, pageNum int) {}
|
||||||
|
func (f *fakeFetcher) fetchGroups(qname string) {}
|
||||||
|
|
||||||
|
type fakeDrawer struct{}
|
||||||
|
|
||||||
|
func (d *fakeDrawer) draw(s *State) {}
|
@@ -7,6 +7,7 @@ require (
|
|||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.9.0
|
||||||
github.com/gdamore/tcell/v2 v2.5.1
|
github.com/gdamore/tcell/v2 v2.5.1
|
||||||
github.com/go-redis/redis/v8 v8.11.4
|
github.com/go-redis/redis/v8 v8.11.4
|
||||||
|
github.com/google/go-cmp v0.5.6
|
||||||
github.com/hibiken/asynq v0.23.0
|
github.com/hibiken/asynq v0.23.0
|
||||||
github.com/hibiken/asynq/x v0.0.0-20220131170841-349f4c50fb1d
|
github.com/hibiken/asynq/x v0.0.0-20220131170841-349f4c50fb1d
|
||||||
github.com/mattn/go-runewidth v0.0.13
|
github.com/mattn/go-runewidth v0.0.13
|
||||||
|
Reference in New Issue
Block a user