Simplified and debugged the filter logic.
--- a/xmpp/filter.go Mon Sep 09 02:13:07 2013 +0100
+++ b/xmpp/filter.go Mon Sep 09 04:16:16 2013 +0100
@@ -7,31 +7,21 @@
// the top of the stack. Receive stanzas at the bottom of the stack on
// input. Send stanzas out the top of the stack on output.
func filterMgr(filterAdd <-chan Filter, input <-chan Stanza, output chan<- Stanza) {
- botFiltIn := output
- topFiltOut := input
-
-loop:
+ defer close(output)
for {
select {
case stan, ok := <-input:
if !ok {
- break loop
- }
- botFiltIn <- stan
-
- case stan, ok := <-topFiltOut:
- if !ok {
- break loop
+ return
}
output <- stan
case filt := <-filterAdd:
- newTop := make(chan Stanza)
- go filt(topFiltOut, newTop)
- topFiltOut = newTop
+ ch := make(chan Stanza)
+ go filt(input, ch)
+ input = ch
}
}
- close(botFiltIn)
}
// AddRecvFilter adds a new filter to the top of the stack through which
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xmpp/filter_test.go Mon Sep 09 04:16:16 2013 +0100
@@ -0,0 +1,67 @@
+package xmpp
+
+import (
+ "fmt"
+ "strconv"
+ "testing"
+)
+
+func TestCloseIn(t *testing.T) {
+ add := make(chan Filter)
+ in := make(chan Stanza)
+ out := make(chan Stanza)
+ go filterMgr(add, in, out)
+ close(in)
+ _, ok := <-out
+ if ok {
+ fmt.Errorf("out didn't close")
+ }
+}
+
+func passthru(in <-chan Stanza, out chan<- Stanza) {
+ defer close(out)
+ for stan := range in {
+ out <- stan
+ }
+}
+
+func TestFilters(t *testing.T) {
+ for n := 0; n < 10; n++ {
+ filterN(n, t)
+ }
+}
+
+func filterN(numFilts int, t *testing.T) {
+ add := make(chan Filter)
+ in := make(chan Stanza)
+ out := make(chan Stanza)
+ go filterMgr(add, in, out)
+ for i := 0; i < numFilts; i++ {
+ add <- passthru
+ }
+ go func() {
+ for i := 0; i < 100; i++ {
+ msg := Message{}
+ msg.Id = fmt.Sprintf("%d", i)
+ in <- &msg
+ }
+ }()
+ for i := 0; i < 100; i++ {
+ stan := <-out
+ msg, ok := stan.(*Message)
+ if !ok {
+ t.Errorf("N = %d: msg %d not a Message: %#v", numFilts,
+ i, stan)
+ continue
+ }
+ n, err := strconv.Atoi(msg.Header.Id)
+ if err != nil {
+ t.Errorf("N = %d: msg %d parsing ID '%s': %v", numFilts,
+ i, msg.Header.Id, err)
+ continue
+ }
+ if n != i {
+ t.Errorf("N = %d: msg %d wrong id %d", numFilts, i, n)
+ }
+ }
+}