1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #19519 from calavera/fix_event_channel_closing_race

Fix channel closing race in event tests.
This commit is contained in:
Brian Goff 2016-01-22 19:43:28 -05:00
commit feca36b379
3 changed files with 34 additions and 15 deletions

View file

@ -178,7 +178,8 @@ func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) {
} }
matcher := matchEventLine(buildID, "container", testActions) matcher := matchEventLine(buildID, "container", testActions)
go observer.Match(matcher) processor := processEventMatch(testActions)
go observer.Match(matcher, processor)
select { select {
case <-time.After(10 * time.Second): case <-time.After(10 * time.Second):

View file

@ -224,7 +224,8 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
} }
matcher := matchEventLine(containerID, "container", testActions) matcher := matchEventLine(containerID, "container", testActions)
go observer.Match(matcher) processor := processEventMatch(testActions)
go observer.Match(matcher, processor)
select { select {
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
@ -280,7 +281,8 @@ func (s *DockerSuite) TestEventsImageUntagDelete(c *check.C) {
} }
matcher := matchEventLine(imageID, "image", testActions) matcher := matchEventLine(imageID, "image", testActions)
go observer.Match(matcher) processor := processEventMatch(testActions)
go observer.Match(matcher, processor)
select { select {
case <-time.After(10 * time.Second): case <-time.After(10 * time.Second):

View file

@ -28,7 +28,13 @@ var (
) )
// eventMatcher is a function that tries to match an event input. // eventMatcher is a function that tries to match an event input.
type eventMatcher func(text string) bool // It returns true if the event matches and a map with
// a set of key/value to identify the match.
type eventMatcher func(text string) (map[string]string, bool)
// eventMatchProcessor is a function to handle an event match.
// It receives a map of key/value with the information extracted in a match.
type eventMatchProcessor func(matches map[string]string)
// eventObserver runs an events commands and observes its output. // eventObserver runs an events commands and observes its output.
type eventObserver struct { type eventObserver struct {
@ -79,13 +85,15 @@ func (e *eventObserver) Stop() {
} }
// Match tries to match the events output with a given matcher. // Match tries to match the events output with a given matcher.
func (e *eventObserver) Match(match eventMatcher) { func (e *eventObserver) Match(match eventMatcher, process eventMatchProcessor) {
for e.scanner.Scan() { for e.scanner.Scan() {
text := e.scanner.Text() text := e.scanner.Text()
e.buffer.WriteString(text) e.buffer.WriteString(text)
e.buffer.WriteString("\n") e.buffer.WriteString("\n")
match(text) if matches, ok := match(text); ok {
process(matches)
}
} }
err := e.scanner.Err() err := e.scanner.Err()
@ -106,7 +114,7 @@ func (e *eventObserver) CheckEventError(c *check.C, id, event string, match even
out, _ := dockerCmd(c, "events", "--since", e.startTime, "--until", until) out, _ := dockerCmd(c, "events", "--since", e.startTime, "--until", until)
events := strings.Split(strings.TrimSpace(out), "\n") events := strings.Split(strings.TrimSpace(out), "\n")
for _, e := range events { for _, e := range events {
if match(e) { if _, ok := match(e); ok {
foundEvent = true foundEvent = true
break break
} }
@ -119,22 +127,30 @@ func (e *eventObserver) CheckEventError(c *check.C, id, event string, match even
} }
// matchEventLine matches a text with the event regular expression. // matchEventLine matches a text with the event regular expression.
// It returns the action and true if the regular expression matches with the given id and event type. // It returns the matches and true if the regular expression matches with the given id and event type.
// It returns an empty string and false if there is no match. // It returns an empty map and false if there is no match.
func matchEventLine(id, eventType string, actions map[string]chan bool) eventMatcher { func matchEventLine(id, eventType string, actions map[string]chan bool) eventMatcher {
return func(text string) bool { return func(text string) (map[string]string, bool) {
matches := parseEventText(text) matches := parseEventText(text)
if len(matches) == 0 { if len(matches) == 0 {
return false return matches, false
} }
if matchIDAndEventType(matches, id, eventType) { if matchIDAndEventType(matches, id, eventType) {
if ch, ok := actions[matches["action"]]; ok { if _, ok := actions[matches["action"]]; ok {
close(ch) return matches, true
return true
} }
} }
return false return matches, false
}
}
// processEventMatch closes an action channel when an event line matches the expected action.
func processEventMatch(actions map[string]chan bool) eventMatchProcessor {
return func(matches map[string]string) {
if ch, ok := actions[matches["action"]]; ok {
close(ch)
}
} }
} }