// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This package aids in the testing of code that uses channels. package script import ( "fmt"; "os"; "rand"; "reflect"; "strings"; ) // An Event is an element in a partially ordered set that either sends a value // to a channel or expects a value from a channel. type Event struct { name string; occurred bool; predecessors []*Event; action action; } type action interface { // getSend returns nil if the action is not a send action. getSend() sendAction; // getRecv returns nil if the action is not a receive action. getRecv() recvAction; // getChannel returns the channel that the action operates on. getChannel() interface{}; } type recvAction interface { recvMatch(interface{}) bool; } type sendAction interface { send(); } // isReady returns true if all the predecessors of an Event have occurred. func (e Event) isReady() bool { for _, predecessor := range e.predecessors { if !predecessor.occurred { return false } } return true; } // A Recv action reads a value from a channel and uses reflect.DeepMatch to // compare it with an expected value. type Recv struct { Channel interface{}; Expected interface{}; } func (r Recv) getRecv() recvAction { return r } func (Recv) getSend() sendAction { return nil } func (r Recv) getChannel() interface{} { return r.Channel } func (r Recv) recvMatch(chanEvent interface{}) bool { c, ok := chanEvent.(channelRecv); if !ok || c.channel != r.Channel { return false } return reflect.DeepEqual(c.value, r.Expected); } // A RecvMatch action reads a value from a channel and calls a function to // determine if the value matches. type RecvMatch struct { Channel interface{}; Match func(interface{}) bool; } func (r RecvMatch) getRecv() recvAction { return r } func (RecvMatch) getSend() sendAction { return nil } func (r RecvMatch) getChannel() interface{} { return r.Channel } func (r RecvMatch) recvMatch(chanEvent interface{}) bool { c, ok := chanEvent.(channelRecv); if !ok || c.channel != r.Channel { return false } return r.Match(c.value); } // A Closed action matches if the given channel is closed. The closing is // treated as an event, not a state, thus Closed will only match once for a // given channel. type Closed struct { Channel interface{}; } func (r Closed) getRecv() recvAction { return r } func (Closed) getSend() sendAction { return nil } func (r Closed) getChannel() interface{} { return r.Channel } func (r Closed) recvMatch(chanEvent interface{}) bool { c, ok := chanEvent.(channelClosed); if !ok || c.channel != r.Channel { return false } return true; } // A Send action sends a value to a channel. The value must match the // type of the channel exactly unless the channel if of type chan interface{}. type Send struct { Channel interface{}; Value interface{}; } func (Send) getRecv() recvAction { return nil } func (s Send) getSend() sendAction { return s } func (s Send) getChannel() interface{} { return s.Channel } func newEmptyInterface(args ...) reflect.Value { return reflect.NewValue(args).(*reflect.StructValue).Field(0) } func (s Send) send() { // With reflect.ChanValue.Send, we must match the types exactly. So, if // s.Channel is a chan interface{} we convert s.Value to an interface{} // first. c := reflect.NewValue(s.Channel).(*reflect.ChanValue); var v reflect.Value; if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 { v = newEmptyInterface(s.Value) } else { v = reflect.NewValue(s.Value) } c.Send(v); } // A Close action closes the given channel. type Close struct { Channel interface{}; } func (Close) getRecv() recvAction { return nil } func (s Close) getSend() sendAction { return s } func (s Close) getChannel() interface{} { return s.Channel } func (s Close) send() { reflect.NewValue(s.Channel).(*reflect.ChanValue).Close() } // A ReceivedUnexpected error results if no active Events match a value // received from a channel. type ReceivedUnexpected struct { Value interface{}; ready []*Event; } func (r ReceivedUnexpected) String() string { names := make([]string, len(r.ready)); for i, v := range r.ready { names[i] = v.name } return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", ")); } // A SetupError results if there is a error with the configuration of a set of // Events. type SetupError string func (s SetupError) String() string { return string(s) } func NewEvent(name string, predecessors []*Event, action action) *Event { e := &Event{name, false, predecessors, action}; return e; } // Given a set of Events, Perform repeatedly iterates over the set and finds the // subset of ready Events (that is, all of their predecessors have // occurred). From that subset, it pseudo-randomly selects an Event to perform. // If the Event is a send event, the send occurs and Perform recalculates the ready // set. If the event is a receive event, Perform waits for a value from any of the // channels that are contained in any of the events. That value is then matched // against the ready events. The first event that matches is considered to // have occurred and Perform recalculates the ready set. // // Perform continues this until all Events have occurred. // // Note that uncollected goroutines may still be reading from any of the // channels read from after Perform returns. // // For example, consider the problem of testing a function that reads values on // one channel and echos them to two output channels. To test this we would // create three events: a send event and two receive events. Each of the // receive events must list the send event as a predecessor but there is no // ordering between the receive events. // // send := NewEvent("send", nil, Send{c, 1}); // recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1}); // recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1}); // Perform(0, []*Event{send, recv1, recv2}); // // At first, only the send event would be in the ready set and thus Perform will // send a value to the input channel. Now the two receive events are ready and // Perform will match each of them against the values read from the output channels. // // It would be invalid to list one of the receive events as a predecessor of // the other. At each receive step, all the receive channels are considered, // thus Perform may see a value from a channel that is not in the current ready // set and fail. func Perform(seed int64, events []*Event) (err os.Error) { r := rand.New(rand.NewSource(seed)); channels, err := getChannels(events); if err != nil { return } multiplex := make(chan interface{}); for _, channel := range channels { go recvValues(multiplex, channel) } Outer: for { ready, err := readyEvents(events); if err != nil { return err } if len(ready) == 0 { // All events occurred. break } event := ready[r.Intn(len(ready))]; if send := event.action.getSend(); send != nil { send.send(); event.occurred = true; continue; } v := <-multiplex; for _, event := range ready { if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) { event.occurred = true; continue Outer; } } return ReceivedUnexpected{v, ready}; } return nil; } // getChannels returns all the channels listed in any receive events. func getChannels(events []*Event) ([]interface{}, os.Error) { channels := make([]interface{}, len(events)); j := 0; for _, event := range events { if recv := event.action.getRecv(); recv == nil { continue } c := event.action.getChannel(); if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok { return nil, SetupError("one of the channel values is not a channel") } duplicate := false; for _, other := range channels[0:j] { if c == other { duplicate = true; break; } } if !duplicate { channels[j] = c; j++; } } return channels[0:j], nil; } // recvValues is a multiplexing helper function. It reads values from the given // channel repeatedly, wrapping them up as either a channelRecv or // channelClosed structure, and forwards them to the multiplex channel. func recvValues(multiplex chan<- interface{}, channel interface{}) { c := reflect.NewValue(channel).(*reflect.ChanValue); for { v := c.Recv(); if c.Closed() { multiplex <- channelClosed{channel}; return; } multiplex <- channelRecv{channel, v.Interface()}; } } type channelClosed struct { channel interface{}; } type channelRecv struct { channel interface{}; value interface{}; } // readyEvents returns the subset of events that are ready. func readyEvents(events []*Event) ([]*Event, os.Error) { ready := make([]*Event, len(events)); j := 0; eventsWaiting := false; for _, event := range events { if event.occurred { continue } eventsWaiting = true; if event.isReady() { ready[j] = event; j++; } } if j == 0 && eventsWaiting { names := make([]string, len(events)); for _, event := range events { if event.occurred { continue } names[j] = event.name; } return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", ")); } return ready[0:j], nil; }