148 lines
3.5 KiB
Go
148 lines
3.5 KiB
Go
// Unit tests for eventList coalescing and drain semantics.
|
|
|
|
package fswatch
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// clear is only used by tests; live code drains via drain() so the
|
|
// snapshot and the reset happen atomically.
|
|
func (el *eventList) clear() {
|
|
el.mu.Lock()
|
|
defer el.mu.Unlock()
|
|
el.entries = nil
|
|
el.err = nil
|
|
}
|
|
|
|
func TestEventListCreateThenDelete(t *testing.T) {
|
|
t.Parallel()
|
|
var el eventList
|
|
el.create("a")
|
|
el.remove("a")
|
|
if el.size() != 1 {
|
|
t.Fatalf("size after create+remove want 1, got %d", el.size())
|
|
}
|
|
if got := el.getEvents(); len(got) != 0 {
|
|
t.Fatalf("getEvents should drop create+delete, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestEventListDeleteThenCreate(t *testing.T) {
|
|
t.Parallel()
|
|
var el eventList
|
|
el.remove("a")
|
|
el.create("a")
|
|
got := el.getEvents()
|
|
if len(got) != 1 {
|
|
t.Fatalf("expected 1 event, got %d", len(got))
|
|
}
|
|
// "Assume update event when rapidly removed and created".
|
|
if got[0].Kind != EventUpdate {
|
|
t.Fatalf("expected update, got %v", got[0].Kind)
|
|
}
|
|
}
|
|
|
|
func TestEventListCreateDeleteCreate(t *testing.T) {
|
|
t.Parallel()
|
|
var el eventList
|
|
el.create("a")
|
|
el.remove("a")
|
|
el.create("a")
|
|
got := el.getEvents()
|
|
if len(got) != 1 {
|
|
t.Fatalf("expected 1 event, got %d", len(got))
|
|
}
|
|
if got[0].Kind != EventUpdate {
|
|
t.Fatalf("create+delete+create should coalesce to update, got %v", got[0].Kind)
|
|
}
|
|
}
|
|
|
|
func TestEventListErrorIsLatchedAndCleared(t *testing.T) {
|
|
t.Parallel()
|
|
var el eventList
|
|
if el.hasError() {
|
|
t.Fatal("fresh eventList should have no error")
|
|
}
|
|
if got := el.getError(); got != nil {
|
|
t.Fatalf("fresh getError want nil, got %v", got)
|
|
}
|
|
el.setError(errors.New("first"))
|
|
el.setError(errors.New("second")) // only first wins
|
|
if !el.hasError() {
|
|
t.Fatal("hasError should be true after setError")
|
|
}
|
|
if got := el.getError(); got == nil || got.Error() != "first" {
|
|
t.Fatalf("getError want first, got %v", got)
|
|
}
|
|
el.clear()
|
|
if el.hasError() {
|
|
t.Fatal("clear should drop the error")
|
|
}
|
|
if got := el.getError(); got != nil {
|
|
t.Fatalf("post-clear getError want nil, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestEventListDrainIsAtomic(t *testing.T) {
|
|
t.Parallel()
|
|
var el eventList
|
|
el.create("a")
|
|
el.update("b")
|
|
el.setError(errors.New("oops"))
|
|
|
|
events, err := el.drain()
|
|
if err == nil {
|
|
t.Fatal("drain should return the error")
|
|
}
|
|
if len(events) != 2 {
|
|
t.Fatalf("drain should return 2 events, got %d", len(events))
|
|
}
|
|
|
|
events2, err2 := el.drain()
|
|
if err2 != nil {
|
|
t.Fatalf("second drain should have no error, got %v", err2)
|
|
}
|
|
if len(events2) != 0 {
|
|
t.Fatalf("second drain should be empty, got %d", len(events2))
|
|
}
|
|
}
|
|
|
|
func TestEventListDrainReturnsErrorWithEvents(t *testing.T) {
|
|
t.Parallel()
|
|
var el eventList
|
|
el.create("file.txt")
|
|
el.setError(errors.New("overflow"))
|
|
|
|
events, err := el.drain()
|
|
if err == nil {
|
|
t.Fatal("expected error from drain")
|
|
}
|
|
if len(events) != 1 {
|
|
t.Fatalf("expected 1 event alongside error, got %d", len(events))
|
|
}
|
|
}
|
|
|
|
func TestEventListDrainForSequences(t *testing.T) {
|
|
t.Parallel()
|
|
var el eventList
|
|
el.create("file.txt")
|
|
startAfterCreate := el.sequence()
|
|
el.remove("file.txt")
|
|
|
|
eventsByCallback, err := el.drainForSequences([]uint64{0, startAfterCreate})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(eventsByCallback[0]) != 0 {
|
|
t.Fatalf("create+delete should cancel for original callback, got %v", eventsByCallback[0])
|
|
}
|
|
if len(eventsByCallback[1]) != 1 {
|
|
t.Fatalf("expected delete for later callback, got %v", eventsByCallback[1])
|
|
}
|
|
if got := eventsByCallback[1][0]; got.Kind != EventDelete || got.Path != "file.txt" {
|
|
t.Fatalf("expected delete for file.txt, got %v", got)
|
|
}
|
|
}
|