Fixed tests

graph-rework
noah metz 2023-06-03 18:56:14 -06:00
parent 9342169281
commit 08eb543af0
7 changed files with 111 additions and 91 deletions

@ -243,13 +243,7 @@ func (event * BaseEvent) Action(action string) (func() (string, error), bool) {
func NewBaseEvent(name string, description string, required_resources []Resource) (BaseEvent) { func NewBaseEvent(name string, description string, required_resources []Resource) (BaseEvent) {
done_resource := NewResource("event_done", "signal that event is done", []Resource{}) done_resource := NewResource("event_done", "signal that event is done", []Resource{})
event := BaseEvent{ event := BaseEvent{
BaseNode: BaseNode{ BaseNode: NewBaseNode(name, description, randid()),
name: name,
description: description,
id: randid(),
signal: make(chan GraphSignal, 100),
listeners: map[chan GraphSignal] chan GraphSignal{},
},
parent: nil, parent: nil,
children: []Event{}, children: []Event{},
child_info: map[string]EventInfo{}, child_info: map[string]EventInfo{},
@ -271,6 +265,12 @@ func NewBaseEvent(name string, description string, required_resources []Resource
} else { } else {
signal_fn, exists := event.Handler(signal.Type()) signal_fn, exists := event.Handler(signal.Type())
if exists == true { if exists == true {
log.Printf("EVENT_HANDLER: %s - %s", event.name, signal.Type())
if signal.Source() != nil {
log.Printf("SIGNAL: %s %s -> %+v", signal.Last(), signal.Source().Name(), signal)
} else {
log.Printf("SIGNAL: %s nil -> %+v", signal.Last(), signal)
}
return signal_fn(signal) return signal_fn(signal)
} }
} }

@ -76,6 +76,18 @@ type GraphNode interface {
UpdateChannel() chan GraphSignal UpdateChannel() chan GraphSignal
} }
func NewBaseNode(name string, description string, id string) BaseNode {
node := BaseNode{
name: name,
description: description,
id: id,
signal: make(chan GraphSignal, 100),
listeners: map[chan GraphSignal]chan GraphSignal{},
}
log.Printf("NEW_NODE: %s - %s", node.ID(), node.Name())
return node
}
// BaseNode is the most basic implementation of the GraphNode interface // BaseNode is the most basic implementation of the GraphNode interface
// It is used to implement functions common to Events and Resources // It is used to implement functions common to Events and Resources
type BaseNode struct { type BaseNode struct {
@ -138,6 +150,7 @@ func (node * BaseNode) UpdateListeners(update GraphSignal) {
select { select {
case listener <- update: case listener <- update:
default: default:
log.Printf("CLOSED_LISTENER: %s: %p", node.Name(), listener)
close(listener) close(listener)
closed = append(closed, listener) closed = append(closed, listener)
} }

@ -16,7 +16,7 @@ func fake_team(org string, id string, names []string) (*Team, []*Member) {
return team, members return team, members
} }
func fake_data() * EventManager { func fake_data() (* EventManager, *Arena, *Arena) {
resources := []Resource{} resources := []Resource{}
teams := []*Team{} teams := []*Team{}
@ -122,16 +122,43 @@ func fake_data() * EventManager {
} }
}(alliances, arenas, event_manager) }(alliances, arenas, event_manager)
return event_manager return event_manager, arenas[0], arenas[1]
}
func process_fake_arena(update GraphSignal, arena * Arena) {
if update.Type() == "event_start" {
log.Printf("FAKE_ARENA_ACTION: Match started on %s, queuing autonomous automatically", arena.Name())
SendUpdate(arena, NewSignal(nil, "queue_autonomous"))
} else if update.Type() == "autonomous_queued" {
log.Printf("FAKE_ARENA_ACTION: Autonomous queued on %s for %s, starting automatically at requested time", arena.Name(), update.Time())
signal := NewSignal(nil, "start_autonomous")
signal.time = update.Time()
SendUpdate(arena, signal)
}
} }
func main() { func main() {
go func() { go func() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
if false {
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
}
}() }()
event_manager := fake_data() event_manager, arena_1, arena_2 := fake_data()
// Fake arena clients
go func() {
arena_1_updates := arena_1.UpdateChannel()
arena_2_updates := arena_2.UpdateChannel()
for true {
select {
case update := <- arena_1_updates:
process_fake_arena(update, arena_1)
case update := <- arena_2_updates:
process_fake_arena(update, arena_2)
}
}
}()
log.Printf("Starting event_manager") log.Printf("Starting event_manager")
err := event_manager.Run() err := event_manager.Run()
if err != nil { if err != nil {

@ -4,20 +4,33 @@ import (
"testing" "testing"
"time" "time"
"fmt" "fmt"
"os"
"runtime/pprof"
) )
type graph_tester testing.T type graph_tester testing.T
const listner_timeout = 50 * time.Millisecond const listner_timeout = 50 * time.Millisecond
func (t * graph_tester) WaitForValue(listener chan GraphSignal, signal_type string, timeout time.Duration, str string) GraphSignal { func (t * graph_tester) WaitForValue(listener chan GraphSignal, signal_type string, source GraphNode, timeout time.Duration, str string) GraphSignal {
timeout_channel := time.After(timeout) timeout_channel := time.After(timeout)
for true { for true {
select { select {
case signal := <- listener: case signal := <- listener:
if signal.Type() == signal_type { if signal.Type() == signal_type {
if signal.Source() == nil || source == nil {
fmt.Printf("SIGNAL_TYPE_FOUND: %s - %s", signal.Type(), signal.Source())
if source == nil && signal.Source() == nil{
return signal return signal
} }
} else {
fmt.Printf("SIGNAL_TYPE_FOUND: %s - %s", signal.Type(), signal.Source().Name())
if signal.Source().ID() == source.ID() {
return signal
}
}
}
case <-timeout_channel: case <-timeout_channel:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
t.Fatal(str) t.Fatal(str)
return nil return nil
} }
@ -31,6 +44,7 @@ func (t * graph_tester) CheckForValue(listener chan GraphSignal, str string) Gra
case signal := <- listener: case signal := <- listener:
return signal return signal
case <-timeout: case <-timeout:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
t.Fatal(str) t.Fatal(str)
return nil return nil
} }
@ -40,7 +54,8 @@ func (t * graph_tester) CheckForNone(listener chan GraphSignal, str string) {
timeout := time.After(listner_timeout) timeout := time.After(listner_timeout)
select { select {
case sig := <- listener: case sig := <- listener:
t.Fatal(fmt.Printf("%s : %+v", str, sig)) pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
t.Fatal(fmt.Sprintf("%s : %+v", str, sig))
case <-timeout: case <-timeout:
} }
} }
@ -198,8 +213,8 @@ func TestLockResource(t * testing.T) {
} }
NotifyResourceLocked(r3) NotifyResourceLocked(r3)
(*graph_tester)(t).CheckForValue(r1_l, "No value on r1 update channel") (*graph_tester)(t).WaitForValue(r1_l, "lock_changed", r1, time.Second, "Wasn't notified of r1 lock on r1 after r3 lock")
(*graph_tester)(t).CheckForNone(rel, "Value on root_event update channel") (*graph_tester)(t).WaitForValue(rel, "lock_changed", r1, time.Second, "Wasn't notified of r1 lock on rel after r3 lock")
err = LockResource(r3, root_event) err = LockResource(r3, root_event)
if err == nil { if err == nil {
@ -226,26 +241,22 @@ func TestLockResource(t * testing.T) {
t.Fatal("Failed to unlock r3") t.Fatal("Failed to unlock r3")
} }
NotifyResourceUnlocked(r3) NotifyResourceUnlocked(r3)
(*graph_tester)(t).WaitForValue(r1_l, "lock_changed", r1, time.Second * 2, "Wasn't notified of r1 unlock on r1 after r3 unlock")
(*graph_tester)(t).CheckForValue(r1_l, "No update on r1 after unlocking r3")
(*graph_tester)(t).CheckForNone(rel, "Update on rel after unlocking r3")
err = LockResource(r4, root_event) err = LockResource(r4, root_event)
if err != nil { if err != nil {
t.Fatal("Failed to lock r4 after unlocking r3") t.Fatal("Failed to lock r4 after unlocking r3")
} }
NotifyResourceLocked(r4) NotifyResourceLocked(r4)
(*graph_tester)(t).WaitForValue(r1_l, "lock_changed", r1, time.Second * 2, "Wasn't notified of r1 lock on r1 after r4 lock")
(*graph_tester)(t).CheckForValue(r1_l, "No update on r1 after locking r4") (*graph_tester)(t).WaitForValue(rel, "lock_changed", r1, time.Second * 2, "Wasn't notified of r1 lock on r1 after r4 lock")
(*graph_tester)(t).CheckForNone(rel, "Update on rel after locking r4")
err = UnlockResource(r4, root_event) err = UnlockResource(r4, root_event)
if err != nil { if err != nil {
t.Fatal("Failed to unlock r4") t.Fatal("Failed to unlock r4")
} }
NotifyResourceUnlocked(r4) NotifyResourceUnlocked(r4)
(*graph_tester)(t).WaitForValue(r1_l, "lock_changed", r1, time.Second * 2, "Wasn't notified of r1 unlock on r1 after r4 lock")
(*graph_tester)(t).CheckForValue(r1_l, "No update on r1 after unlocking r4")
} }
func TestAddToEventQueue(t * testing.T) { func TestAddToEventQueue(t * testing.T) {
@ -392,18 +403,18 @@ func TestStartEventQueue(t * testing.T) {
t.Fatal("root event was not finished after starting") t.Fatal("root event was not finished after starting")
} }
(*graph_tester)(t).WaitForValue(e1_l, "event_done", e1, time.Second, "no e1 event_done")
if e1_r.Owner() != nil { if e1_r.Owner() != nil {
t.Fatal("e1 was not completed") t.Fatal("e1 was not completed")
} }
(*graph_tester)(t).CheckForValue(e1_l, "No update on e1 after running")
(*graph_tester)(t).WaitForValue(e2_l, "event_done", e2, time.Second, "no e2 event_done")
if e2_r.Owner() != nil { if e2_r.Owner() != nil {
t.Fatal("e2 was not completed") t.Fatal(fmt.Sprintf("e2 was not completed"))
} }
(*graph_tester)(t).CheckForValue(e2_l, "No update on e2 after running")
(*graph_tester)(t).WaitForValue(e3_l, "event_done", e3, time.Second, "no e3 event_done")
if e3_r.Owner() != nil { if e3_r.Owner() != nil {
t.Fatal("e3 was not completed") t.Fatal("e3 was not completed")
} }
(*graph_tester)(t).CheckForValue(e3_l, "No update on e3 after running")
} }

@ -10,21 +10,17 @@ import (
// (subscriber to team won't get update to alliance, but subscriber to alliance will get update to team) // (subscriber to team won't get update to alliance, but subscriber to alliance will get update to team)
func (resource * BaseResource) update(signal GraphSignal) { func (resource * BaseResource) update(signal GraphSignal) {
new_signal := signal.Trace(resource.ID()) new_signal := signal.Trace(resource.ID())
if signal.Type() == "lock_changed" {
for _, child := range resource.Children() {
SendUpdate(child, new_signal)
}
} else {
for _, parent := range resource.Parents() { for _, parent := range resource.Parents() {
SendUpdate(parent, new_signal) SendUpdate(parent, new_signal)
} }
if resource.lock_holder != nil { if resource.lock_holder != nil {
if resource.lock_holder.ID() != signal.Last() { if resource.lock_holder.ID() != signal.Last() {
SendUpdate(resource.lock_holder, new_signal) SendUpdate(resource.lock_holder, new_signal)
} }
} }
} }
}
// Resource is the interface that DAG nodes are made from // Resource is the interface that DAG nodes are made from
// A resource needs to be able to represent logical entities and connections to physical entities. // A resource needs to be able to represent logical entities and connections to physical entities.
@ -152,6 +148,10 @@ func NotifyResourceLocked(resource Resource) {
signal := NewSignal(resource, "lock_changed") signal := NewSignal(resource, "lock_changed")
signal.description = "lock" signal.description = "lock"
for _, child := range resource.Children() {
NotifyResourceLocked(child)
}
go SendUpdate(resource, signal) go SendUpdate(resource, signal)
} }
@ -159,6 +159,10 @@ func NotifyResourceUnlocked(resource Resource) {
signal := NewSignal(resource, "lock_changed") signal := NewSignal(resource, "lock_changed")
signal.description = "unlock" signal.description = "unlock"
for _, child := range(resource.Children()) {
NotifyResourceUnlocked(child)
}
go SendUpdate(resource, signal) go SendUpdate(resource, signal)
} }
@ -226,13 +230,7 @@ func (resource * BaseResource) AddParent(parent Resource) error {
func NewBaseResource(name string, description string, children []Resource) BaseResource { func NewBaseResource(name string, description string, children []Resource) BaseResource {
resource := BaseResource{ resource := BaseResource{
BaseNode: BaseNode{ BaseNode: NewBaseNode(name, description, randid()),
name: name,
description: description,
id: randid(),
listeners: map[chan GraphSignal]chan GraphSignal{},
signal: make(chan GraphSignal, 100),
},
parents: []Resource{}, parents: []Resource{},
children: children, children: children,
} }

@ -90,14 +90,12 @@ func (arena * Arena) lock(event Event) error {
func (arena * Arena) update(signal GraphSignal) { func (arena * Arena) update(signal GraphSignal) {
log.Printf("ARENA_UPDATE: %s", arena.Name()) log.Printf("ARENA_UPDATE: %s", arena.Name())
arena.signal <- signal arena.signal <- signal
new_signal := signal.Trace(arena.ID()) arena.BaseResource.update(signal)
arena.BaseResource.update(new_signal)
} }
func (arena * Arena) Connect(abort chan error) bool { func (arena * Arena) Connect(abort chan error) bool {
log.Printf("Connecting %s", arena.Name()) log.Printf("Connecting %s", arena.Name())
go func(arena * Arena, abort chan error) { go func(arena * Arena, abort chan error) {
owner := arena.Owner()
update_str := fmt.Sprintf("VIRTUAL_ARENA connected: %s", arena.Name()) update_str := fmt.Sprintf("VIRTUAL_ARENA connected: %s", arena.Name())
signal := NewSignal(arena, "resource_connected") signal := NewSignal(arena, "resource_connected")
signal.description = update_str signal.description = update_str
@ -110,27 +108,7 @@ func (arena * Arena) Connect(abort chan error) bool {
log.Printf("Virtual arena %s aborting", arena.Name()) log.Printf("Virtual arena %s aborting", arena.Name())
break break
case update := <- arena.signal: case update := <- arena.signal:
log.Printf("%s update: %+v", arena.Name(), update) log.Printf("FAKE_ARENA_ACTION: %s : %+v", arena.Name(), update)
new_owner := arena.Owner()
if new_owner != owner {
log.Printf("NEW_OWNER for %s", arena.Name())
if new_owner != nil {
log.Printf("new: %s", new_owner.Name())
} else {
log.Printf("new: nil")
}
if owner != nil {
log.Printf("old: %s", owner.Name())
} else {
log.Printf("old: nil")
}
owner = new_owner
if owner != nil {
} else {
}
}
} }
} }
}(arena, abort) }(arena, abort)
@ -184,7 +162,9 @@ func NewMatch(alliance0 * Alliance, alliance1 * Alliance, arena * Arena) * Match
match.control = "none" match.control = "none"
match.state = "autonomous_queued" match.state = "autonomous_queued"
match.control_start = time.Now().Add(start_slack) match.control_start = time.Now().Add(start_slack)
go SendUpdate(match, NewSignal(match, "autonomous_queued")) new_signal := NewSignal(match, "autonomous_queued")
new_signal.time = match.control_start
go SendUpdate(match, new_signal)
return "wait", nil return "wait", nil
} }
@ -225,7 +205,9 @@ func NewMatch(alliance0 * Alliance, alliance1 * Alliance, arena * Arena) * Match
match.control = "none" match.control = "none"
match.state = "driver_queued" match.state = "driver_queued"
match.control_start = time.Now().Add(start_slack) match.control_start = time.Now().Add(start_slack)
go SendUpdate(match, NewSignal(match, "driver_queued")) new_signal := NewSignal(match, "driver_queued")
new_signal.time = match.control_start
go SendUpdate(match, new_signal)
return "wait", nil return "wait", nil
} }

@ -149,32 +149,21 @@ func TestNewMatch(t *testing.T) {
}() }()
go func(arena_c chan GraphSignal) { go func(arena_c chan GraphSignal) {
(*graph_tester)(t).WaitForValue(arena_c, "event_start", 1*time.Second, "no event_start") (*graph_tester)(t).WaitForValue(arena_c, "event_start", match, 1*time.Second, "no event_start")
(*graph_tester)(t).CheckForNone(arena_c, "update to match after starting")
SendUpdate(arena, NewSignal(nil, "queue_autonomous")) SendUpdate(arena, NewSignal(nil, "queue_autonomous"))
(*graph_tester)(t).WaitForValue(arena_c, "autonomous_queued", 1*time.Second, "no autonomous_queued") (*graph_tester)(t).WaitForValue(arena_c, "autonomous_queued", match, 1*time.Second, "no autonomous_queued")
(*graph_tester)(t).CheckForNone(arena_c, "update to match after queueing autonomous")
auton_signal := NewSignal(nil, "start_autonomous") auton_signal := NewSignal(nil, "start_autonomous")
auton_signal.time = time.Now() auton_signal.time = time.Now()
SendUpdate(arena, auton_signal) SendUpdate(arena, auton_signal)
(*graph_tester)(t).WaitForValue(arena_c, "autonomous_running", 1*time.Second, "no autonomous_running") (*graph_tester)(t).WaitForValue(arena_c, "autonomous_running", match, 1*time.Second, "no autonomous_running")
(*graph_tester)(t).CheckForNone(arena_c, "update to match after starting autonomous") (*graph_tester)(t).WaitForValue(arena_c, "autonomous_done", match, 6*time.Second, "no autonomous_done")
time.Sleep(TEMP_AUTON_TIME)
time.Sleep(time.Millisecond * 100)
(*graph_tester)(t).WaitForValue(arena_c, "autonomous_done", 6*time.Second, "no autonomous_done")
(*graph_tester)(t).CheckForNone(arena_c, "update to match after ending autonomous")
SendUpdate(arena, NewSignal(nil, "queue_driver")) SendUpdate(arena, NewSignal(nil, "queue_driver"))
(*graph_tester)(t).WaitForValue(arena_c, "driver_queued", 1*time.Second, "no driver_queued") (*graph_tester)(t).WaitForValue(arena_c, "driver_queued", match, 1*time.Second, "no driver_queued")
(*graph_tester)(t).CheckForNone(arena_c, "update to match after queueing driver")
driver_signal := NewSignal(nil, "start_driver") driver_signal := NewSignal(nil, "start_driver")
driver_signal.time = time.Now() driver_signal.time = time.Now()
SendUpdate(arena, driver_signal) SendUpdate(arena, driver_signal)
(*graph_tester)(t).WaitForValue(arena_c, "driver_running", 1*time.Second, "no driver_running") (*graph_tester)(t).WaitForValue(arena_c, "driver_running", match, 1*time.Second, "no driver_running")
(*graph_tester)(t).CheckForNone(arena_c, "update to match after starting driver") (*graph_tester)(t).WaitForValue(arena_c, "driver_done", match, 6*time.Second, "no driver_done")
time.Sleep(TEMP_DRIVE_TIME)
time.Sleep(time.Millisecond * 100)
(*graph_tester)(t).WaitForValue(arena_c, "driver_done", 1*time.Second, "no driver_done")
(*graph_tester)(t).CheckForNone(arena_c, "update to match after game done 3")
}(arena_c) }(arena_c)
err := event_manager.Run() err := event_manager.Run()