From 3710f676707f992be0d0ba1228a589a3269cf672 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sun, 13 Nov 2011 13:30:08 +0000 Subject: [PATCH 01/16] gofix weekly fixes for logging. --- logging/mock_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/logging/mock_test.go b/logging/mock_test.go index 418b996..1d64fa0 100644 --- a/logging/mock_test.go +++ b/logging/mock_test.go @@ -1,7 +1,6 @@ package logging import ( - "os" "strings" "testing" ) @@ -13,7 +12,7 @@ type mockWriter struct { written []byte } -func (w *mockWriter) Write(p []byte) (n int, err os.Error) { +func (w *mockWriter) Write(p []byte) (n int, err error) { w.written = append(w.written, p...) return len(p), nil } @@ -62,7 +61,7 @@ func newMock(t *testing.T) (*logger, *writerMap) { logMap[lv] = makeLogger(w) } // Set the default log level high enough that everything will get logged - return New(logMap, (1 << 31) - 1, false), wMap + return New(logMap, (1<<31)-1, false), wMap } // When you expect something to be logged but don't care so much what level at. @@ -89,7 +88,6 @@ func (wm *writerMap) Expect(exp string) { } } - // When you expect nothing to be logged func (wm *writerMap) ExpectNothing() { for lv, w := range wm.m { From 0dc19703ab4d3d4dbf91c0d36e744366877520c0 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sun, 13 Nov 2011 13:32:10 +0000 Subject: [PATCH 02/16] gofix weekly fixes for event. --- event/registry.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/event/registry.go b/event/registry.go index 7df894d..7323ecc 100644 --- a/event/registry.go +++ b/event/registry.go @@ -3,8 +3,8 @@ package event import ( "container/list" "strings" - "sync/atomic" "sync" + "sync/atomic" ) type HandlerID uint32 @@ -67,7 +67,8 @@ func (r *registry) AddHandler(h Handler, names ...string) { } r.Lock() defer r.Unlock() -N: for _, name := range names { +N: + for _, name := range names { name = strings.ToLower(name) if _, ok := r.events[name]; !ok { r.events[name] = list.New() @@ -97,7 +98,7 @@ func (r *registry) DelHandler(h Handler, names ...string) { if len(names) == 0 { for name, l := range r.events { if _del(l, h.Id()) { - r.events[name] = nil, false + delete(r.events, name) } } } else { @@ -105,7 +106,7 @@ func (r *registry) DelHandler(h Handler, names ...string) { name = strings.ToLower(name) if l, ok := r.events[name]; ok { if _del(l, h.Id()) { - r.events[name] = nil, false + delete(r.events, name) } } } @@ -122,7 +123,7 @@ func (r *registry) ClearEvents(name string) { defer r.Unlock() if l, ok := r.events[name]; ok { l.Init() // I hope this is enough to GC all list elements. - r.events[name] = nil, false + delete(r.events, name) } } From 81eb9ee3dfebbdbab9a3b90c389b290cde400914 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sun, 13 Nov 2011 13:32:53 +0000 Subject: [PATCH 03/16] gofix weekly fixes for state. --- state/channel.go | 18 +++++++++--------- state/nick.go | 16 ++++++++-------- state/tracker.go | 10 +++++----- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/state/channel.go b/state/channel.go index d555b22..1735a52 100644 --- a/state/channel.go +++ b/state/channel.go @@ -11,9 +11,9 @@ import ( type Channel struct { Name, Topic string Modes *ChanMode - lookup map[string]*Nick + lookup map[string]*Nick nicks map[*Nick]*ChanPrivs - l logging.Logger + l logging.Logger } // A struct representing the modes of an IRC Channel @@ -93,11 +93,11 @@ func init() { func NewChannel(name string, l logging.Logger) *Channel { return &Channel{ - Name: name, - Modes: new(ChanMode), - nicks: make(map[*Nick]*ChanPrivs), + Name: name, + Modes: new(ChanMode), + nicks: make(map[*Nick]*ChanPrivs), lookup: make(map[string]*Nick), - l: l, + l: l, } } @@ -125,8 +125,8 @@ func (ch *Channel) addNick(nk *Nick, cp *ChanPrivs) { // Disassociates a Nick from a Channel. func (ch *Channel) delNick(nk *Nick) { if _, ok := ch.nicks[nk]; ok { - ch.nicks[nk] = nil, false - ch.lookup[nk.Nick] = nil, false + delete(ch.nicks, nk) + delete(ch.lookup, nk.Nick) } else { ch.l.Warn("Channel.delNick(): %s not on %s.", nk.Nick, ch.Name) } @@ -181,7 +181,7 @@ func (ch *Channel) ParseModes(modes string, modeargs ...string) { } case 'q', 'a', 'o', 'h', 'v': if len(modeargs) != 0 { - if nk, ok := ch.lookup[modeargs[0]]; ok { + if nk, ok := ch.lookup[modeargs[0]]; ok { cp := ch.nicks[nk] switch m { case 'q': diff --git a/state/nick.go b/state/nick.go index 6dc4089..c3dba75 100644 --- a/state/nick.go +++ b/state/nick.go @@ -9,9 +9,9 @@ import ( type Nick struct { Nick, Ident, Host, Name string Modes *NickMode - lookup map[string]*Channel + lookup map[string]*Channel chans map[*Channel]*ChanPrivs - l logging.Logger + l logging.Logger } // A struct representing the modes of an IRC Nick (User Modes) @@ -46,11 +46,11 @@ func init() { func NewNick(n string, l logging.Logger) *Nick { return &Nick{ - Nick: n, - Modes: new(NickMode), - chans: make(map[*Channel]*ChanPrivs), + Nick: n, + Modes: new(NickMode), + chans: make(map[*Channel]*ChanPrivs), lookup: make(map[string]*Channel), - l: l, + l: l, } } @@ -78,8 +78,8 @@ func (nk *Nick) addChannel(ch *Channel, cp *ChanPrivs) { // Disassociates a Channel from a Nick. func (nk *Nick) delChannel(ch *Channel) { if _, ok := nk.chans[ch]; ok { - nk.chans[ch] = nil, false - nk.lookup[ch.Name] = nil, false + delete(nk.chans, ch) + delete(nk.lookup, ch.Name) } else { nk.l.Warn("Nick.delChannel(): %s not on %s.", nk.Nick, ch.Name) } diff --git a/state/tracker.go b/state/tracker.go index 2ee8f2e..17f4799 100644 --- a/state/tracker.go +++ b/state/tracker.go @@ -45,7 +45,7 @@ func NewTracker(mynick string, l logging.Logger) *stateTracker { st := &stateTracker{ chans: make(map[string]*Channel), nicks: make(map[string]*Nick), - l: l, + l: l, } st.me = st.NewNick(mynick) return st @@ -88,12 +88,12 @@ func (st *stateTracker) ReNick(old, neu string) { if nk, ok := st.nicks[old]; ok { if _, ok := st.nicks[neu]; !ok { nk.Nick = neu - st.nicks[old] = nil, false + delete(st.nicks, old) st.nicks[neu] = nk for ch, _ := range nk.chans { // We also need to update the lookup maps of all the channels // the nick is on, to keep things in sync. - ch.lookup[old] = nil, false + delete(ch.lookup, old) ch.lookup[neu] = nk } } else { @@ -123,7 +123,7 @@ func (st *stateTracker) delNick(nk *Nick) { st.l.Error("StateTracker.DelNick(): TRYING TO DELETE ME :-(") return } - st.nicks[nk.Nick] = nil, false + delete(st.nicks, nk.Nick) for ch, _ := range nk.chans { nk.delChannel(ch) ch.delNick(nk) @@ -165,7 +165,7 @@ func (st *stateTracker) DelChannel(c string) { } func (st *stateTracker) delChannel(ch *Channel) { - st.chans[ch.Name] = nil, false + delete(st.chans, ch.Name) for nk, _ := range ch.nicks { ch.delNick(nk) nk.delChannel(ch) From 9d5159a2202dfe3a21e9b13d5b2b7e48036f8efa Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sun, 13 Nov 2011 13:34:32 +0000 Subject: [PATCH 04/16] gofix weekly fixes for client. --- client/connection.go | 43 +++++++++++++++++++------------------- client/mocknetconn_test.go | 15 ++++++------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/client/connection.go b/client/connection.go index 26dcf79..126e2d9 100644 --- a/client/connection.go +++ b/client/connection.go @@ -3,12 +3,13 @@ package client import ( "bufio" "crypto/tls" + "errors" + "fmt" "github.com/fluffle/goirc/event" "github.com/fluffle/goirc/logging" "github.com/fluffle/goirc/state" - "fmt" "net" - "os" + "strings" "time" ) @@ -87,20 +88,20 @@ func Client(nick, ident, name string, return nil } conn := &Conn{ - ER: r, - ED: r, - l: l, - st: false, - in: make(chan *Line, 32), - out: make(chan string, 32), - cSend: make(chan bool), - cLoop: make(chan bool), - SSL: false, - SSLConfig: nil, - Timeout: 300, - Flood: false, - badness: 0, - lastsent: 0, + ER: r, + ED: r, + l: l, + st: false, + in: make(chan *Line, 32), + out: make(chan string, 32), + cSend: make(chan bool), + cLoop: make(chan bool), + SSL: false, + SSLConfig: nil, + Timeout: 300, + Flood: false, + badness: 0, + lastsent: 0, } conn.addIntHandlers() conn.Me = state.NewNick(nick, l) @@ -146,9 +147,9 @@ func (conn *Conn) initialise() { // on the connection to the IRC server, set Conn.SSL to true before calling // Connect(). The port will default to 6697 if ssl is enabled, and 6667 // otherwise. You can also provide an optional connect password. -func (conn *Conn) Connect(host string, pass ...string) os.Error { +func (conn *Conn) Connect(host string, pass ...string) error { if conn.Connected { - return os.NewError(fmt.Sprintf( + return errors.New(fmt.Sprintf( "irc.Connect(): already connected to %s, cannot connect to %s", conn.Host, host)) } @@ -220,7 +221,7 @@ func (conn *Conn) recv() { for { s, err := conn.io.ReadString('\n') if err != nil { - conn.l.Error("irc.recv(): %s", err.String()) + conn.l.Error("irc.recv(): %s", err.Error()) conn.shutdown() return } @@ -262,12 +263,12 @@ func (conn *Conn) write(line string) { } if _, err := conn.io.WriteString(line + "\r\n"); err != nil { - conn.l.Error("irc.send(): %s", err.String()) + conn.l.Error("irc.send(): %s", err.Error()) conn.shutdown() return } if err := conn.io.Flush(); err != nil { - conn.l.Error("irc.send(): %s", err.String()) + conn.l.Error("irc.send(): %s", err.Error()) conn.shutdown() return } diff --git a/client/mocknetconn_test.go b/client/mocknetconn_test.go index 596efbf..95146fe 100644 --- a/client/mocknetconn_test.go +++ b/client/mocknetconn_test.go @@ -1,6 +1,7 @@ package client import ( + "io" "net" "os" "strings" @@ -96,7 +97,7 @@ func (m *mockNetConn) ExpectNothing() { } // Implement net.Conn interface -func (m *mockNetConn) Read(b []byte) (int, os.Error) { +func (m *mockNetConn) Read(b []byte) (int, error) { if m.closed { return 0, os.EINVAL } @@ -106,12 +107,12 @@ func (m *mockNetConn) Read(b []byte) (int, os.Error) { l = len(s) copy(b, s) case <-m.closers[mockReadCloser]: - return 0, os.EOF + return 0, io.EOF } return l, nil } -func (m *mockNetConn) Write(s []byte) (int, os.Error) { +func (m *mockNetConn) Write(s []byte) (int, error) { if m.closed { return 0, os.EINVAL } @@ -121,7 +122,7 @@ func (m *mockNetConn) Write(s []byte) (int, os.Error) { return len(s), nil } -func (m *mockNetConn) Close() os.Error { +func (m *mockNetConn) Close() error { if m.closed { return os.EINVAL } @@ -142,18 +143,18 @@ func (m *mockNetConn) RemoteAddr() net.Addr { return &net.IPAddr{net.IPv4(127, 0, 0, 1)} } -func (m *mockNetConn) SetTimeout(ns int64) os.Error { +func (m *mockNetConn) SetTimeout(ns int64) error { m.rt = ns m.wt = ns return nil } -func (m *mockNetConn) SetReadTimeout(ns int64) os.Error { +func (m *mockNetConn) SetReadTimeout(ns int64) error { m.rt = ns return nil } -func (m *mockNetConn) SetWriteTimeout(ns int64) os.Error { +func (m *mockNetConn) SetWriteTimeout(ns int64) error { m.wt = ns return nil } From 01d58fc748a9bfa4fc1fac72b29afbd035e5f6e8 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Fri, 3 Feb 2012 23:13:00 +0000 Subject: [PATCH 05/16] Update weekly to reflect the new location of gomock. --- state/mock_tracker.go | 110 +++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/state/mock_tracker.go b/state/mock_tracker.go index b223432..1ad2469 100644 --- a/state/mock_tracker.go +++ b/state/mock_tracker.go @@ -4,7 +4,7 @@ package state import ( - gomock "gomock.googlecode.com/hg/gomock" + gomock "github.com/dsymonds/gomock/gomock" ) // Mock of StateTracker interface @@ -24,127 +24,127 @@ func NewMockStateTracker(ctrl *gomock.Controller) *MockStateTracker { return mock } -func (m *MockStateTracker) EXPECT() *_MockStateTrackerRecorder { - return m.recorder +func (_m *MockStateTracker) EXPECT() *_MockStateTrackerRecorder { + return _m.recorder } -func (m *MockStateTracker) NewNick(nick string) *Nick { - ret := m.ctrl.Call(m, "NewNick", nick) +func (_m *MockStateTracker) NewNick(nick string) *Nick { + ret := _m.ctrl.Call(_m, "NewNick", nick) ret0, _ := ret[0].(*Nick) return ret0 } -func (mr *_MockStateTrackerRecorder) NewNick(arg0 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "NewNick", arg0) +func (_mr *_MockStateTrackerRecorder) NewNick(arg0 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "NewNick", arg0) } -func (m *MockStateTracker) GetNick(nick string) *Nick { - ret := m.ctrl.Call(m, "GetNick", nick) +func (_m *MockStateTracker) GetNick(nick string) *Nick { + ret := _m.ctrl.Call(_m, "GetNick", nick) ret0, _ := ret[0].(*Nick) return ret0 } -func (mr *_MockStateTrackerRecorder) GetNick(arg0 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "GetNick", arg0) +func (_mr *_MockStateTrackerRecorder) GetNick(arg0 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "GetNick", arg0) } -func (m *MockStateTracker) ReNick(old string, neu string) { - m.ctrl.Call(m, "ReNick", old, neu) +func (_m *MockStateTracker) ReNick(old string, neu string) { + _m.ctrl.Call(_m, "ReNick", old, neu) } -func (mr *_MockStateTrackerRecorder) ReNick(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "ReNick", arg0, arg1) +func (_mr *_MockStateTrackerRecorder) ReNick(arg0, arg1 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "ReNick", arg0, arg1) } -func (m *MockStateTracker) DelNick(nick string) { - m.ctrl.Call(m, "DelNick", nick) +func (_m *MockStateTracker) DelNick(nick string) { + _m.ctrl.Call(_m, "DelNick", nick) } -func (mr *_MockStateTrackerRecorder) DelNick(arg0 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "DelNick", arg0) +func (_mr *_MockStateTrackerRecorder) DelNick(arg0 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "DelNick", arg0) } -func (m *MockStateTracker) NewChannel(channel string) *Channel { - ret := m.ctrl.Call(m, "NewChannel", channel) +func (_m *MockStateTracker) NewChannel(channel string) *Channel { + ret := _m.ctrl.Call(_m, "NewChannel", channel) ret0, _ := ret[0].(*Channel) return ret0 } -func (mr *_MockStateTrackerRecorder) NewChannel(arg0 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "NewChannel", arg0) +func (_mr *_MockStateTrackerRecorder) NewChannel(arg0 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "NewChannel", arg0) } -func (m *MockStateTracker) GetChannel(channel string) *Channel { - ret := m.ctrl.Call(m, "GetChannel", channel) +func (_m *MockStateTracker) GetChannel(channel string) *Channel { + ret := _m.ctrl.Call(_m, "GetChannel", channel) ret0, _ := ret[0].(*Channel) return ret0 } -func (mr *_MockStateTrackerRecorder) GetChannel(arg0 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "GetChannel", arg0) +func (_mr *_MockStateTrackerRecorder) GetChannel(arg0 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "GetChannel", arg0) } -func (m *MockStateTracker) DelChannel(channel string) { - m.ctrl.Call(m, "DelChannel", channel) +func (_m *MockStateTracker) DelChannel(channel string) { + _m.ctrl.Call(_m, "DelChannel", channel) } -func (mr *_MockStateTrackerRecorder) DelChannel(arg0 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "DelChannel", arg0) +func (_mr *_MockStateTrackerRecorder) DelChannel(arg0 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "DelChannel", arg0) } -func (m *MockStateTracker) Me() *Nick { - ret := m.ctrl.Call(m, "Me") +func (_m *MockStateTracker) Me() *Nick { + ret := _m.ctrl.Call(_m, "Me") ret0, _ := ret[0].(*Nick) return ret0 } -func (mr *_MockStateTrackerRecorder) Me() *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "Me") +func (_mr *_MockStateTrackerRecorder) Me() *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "Me") } -func (m *MockStateTracker) IsOn(channel string, nick string) (*ChanPrivs, bool) { - ret := m.ctrl.Call(m, "IsOn", channel, nick) +func (_m *MockStateTracker) IsOn(channel string, nick string) (*ChanPrivs, bool) { + ret := _m.ctrl.Call(_m, "IsOn", channel, nick) ret0, _ := ret[0].(*ChanPrivs) ret1, _ := ret[1].(bool) return ret0, ret1 } -func (mr *_MockStateTrackerRecorder) IsOn(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "IsOn", arg0, arg1) +func (_mr *_MockStateTrackerRecorder) IsOn(arg0, arg1 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "IsOn", arg0, arg1) } -func (m *MockStateTracker) Associate(channel *Channel, nick *Nick) *ChanPrivs { - ret := m.ctrl.Call(m, "Associate", channel, nick) +func (_m *MockStateTracker) Associate(channel *Channel, nick *Nick) *ChanPrivs { + ret := _m.ctrl.Call(_m, "Associate", channel, nick) ret0, _ := ret[0].(*ChanPrivs) return ret0 } -func (mr *_MockStateTrackerRecorder) Associate(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "Associate", arg0, arg1) +func (_mr *_MockStateTrackerRecorder) Associate(arg0, arg1 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "Associate", arg0, arg1) } -func (m *MockStateTracker) Dissociate(channel *Channel, nick *Nick) { - m.ctrl.Call(m, "Dissociate", channel, nick) +func (_m *MockStateTracker) Dissociate(channel *Channel, nick *Nick) { + _m.ctrl.Call(_m, "Dissociate", channel, nick) } -func (mr *_MockStateTrackerRecorder) Dissociate(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "Dissociate", arg0, arg1) +func (_mr *_MockStateTrackerRecorder) Dissociate(arg0, arg1 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "Dissociate", arg0, arg1) } -func (m *MockStateTracker) Wipe() { - m.ctrl.Call(m, "Wipe") +func (_m *MockStateTracker) Wipe() { + _m.ctrl.Call(_m, "Wipe") } -func (mr *_MockStateTrackerRecorder) Wipe() *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "Wipe") +func (_mr *_MockStateTrackerRecorder) Wipe() *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "Wipe") } -func (m *MockStateTracker) String() string { - ret := m.ctrl.Call(m, "String") +func (_m *MockStateTracker) String() string { + ret := _m.ctrl.Call(_m, "String") ret0, _ := ret[0].(string) return ret0 } -func (mr *_MockStateTrackerRecorder) String() *gomock.Call { - return mr.mock.ctrl.RecordCall(mr.mock, "String") +func (_mr *_MockStateTrackerRecorder) String() *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "String") } From 3387f6fb996ec5d1d0a88367fa9f9be10a9eae3c Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Fri, 3 Feb 2012 23:45:41 +0000 Subject: [PATCH 06/16] Correct import path. --- state/tracker_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/tracker_test.go b/state/tracker_test.go index 30d7856..fd4699a 100644 --- a/state/tracker_test.go +++ b/state/tracker_test.go @@ -2,7 +2,7 @@ package state import ( "github.com/fluffle/golog/logging" - "gomock.googlecode.com/hg/gomock" + gomock "github.com/dsymonds/gomock/gomock" "testing" ) From be271308c9456ebecf316ec06362f96c6f85fea8 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Fri, 3 Feb 2012 23:48:20 +0000 Subject: [PATCH 07/16] Correct import path, again. --- client/connection_test.go | 2 +- client/handlers_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/connection_test.go b/client/connection_test.go index b7b4888..5bada41 100644 --- a/client/connection_test.go +++ b/client/connection_test.go @@ -5,7 +5,7 @@ import ( "github.com/fluffle/goevent/event" "github.com/fluffle/golog/logging" "github.com/fluffle/goirc/state" - "gomock.googlecode.com/hg/gomock" + gomock "github.com/dsymonds/gomock/gomock" "testing" "time" ) diff --git a/client/handlers_test.go b/client/handlers_test.go index e4b3e78..55e21d6 100644 --- a/client/handlers_test.go +++ b/client/handlers_test.go @@ -2,7 +2,7 @@ package client import ( "github.com/fluffle/goirc/state" - "gomock.googlecode.com/hg/gomock" + gomock "github.com/dsymonds/gomock/gomock" "testing" ) From b23215d09b373e509faf3f0be946ad528152a6d0 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sat, 4 Feb 2012 00:51:06 +0000 Subject: [PATCH 08/16] Gofix run. --- client/connection.go | 8 ++++---- client/line.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/connection.go b/client/connection.go index b91d335..98efbbc 100644 --- a/client/connection.go +++ b/client/connection.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" "github.com/fluffle/goevent/event" - "github.com/fluffle/golog/logging" "github.com/fluffle/goirc/state" + "github.com/fluffle/golog/logging" "net" "strings" "time" @@ -228,7 +228,7 @@ func (conn *Conn) recv() { conn.l.Debug("<- %s", s) if line := parseLine(s); line != nil { - line.Time = time.LocalTime() + line.Time = time.Now() conn.in <- line } else { conn.l.Warn("irc.recv(): problems parsing line:\n %s", s) @@ -279,12 +279,12 @@ func (conn *Conn) rateLimit(chars int64) int64 { // Hybrid's algorithm allows for 2 seconds per line and an additional // 1/120 of a second per character on that line. linetime := 2*second + chars*second/120 - elapsed := time.Nanoseconds() - conn.lastsent + elapsed := time.Now().Sub(conn.lastsent) if conn.badness += linetime - elapsed; conn.badness < 0 { // negative badness times are badness... conn.badness = int64(0) } - conn.lastsent = time.Nanoseconds() + conn.lastsent = time.Now() // If we've sent more than 10 second's worth of lines according to the // calculation above, then we're at risk of "Excess Flood". if conn.badness > 10*second { diff --git a/client/line.go b/client/line.go index 789d3cc..706d373 100644 --- a/client/line.go +++ b/client/line.go @@ -14,7 +14,7 @@ type Line struct { Nick, Ident, Host, Src string Cmd, Raw string Args []string - Time *time.Time + Time time.Time } // NOTE: this doesn't copy l.Time (this should be read-only anyway) From dfb6f94b568b9c775f0c98dddc62a2ea0c0b6416 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sat, 4 Feb 2012 01:12:41 +0000 Subject: [PATCH 09/16] Manually managing deadlines is going to *suck*. --- client/connection.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/connection.go b/client/connection.go index 98efbbc..d207c15 100644 --- a/client/connection.go +++ b/client/connection.go @@ -54,9 +54,6 @@ type Conn struct { SSL bool SSLConfig *tls.Config - // Socket timeout, in seconds. Defaulted to 5m in New(). - Timeout int64 - // Set this to true to disable flood protection and false to re-enable Flood bool @@ -97,7 +94,6 @@ func Client(nick, ident, name string, cLoop: make(chan bool), SSL: false, SSLConfig: nil, - Timeout: 300, Flood: false, badness: 0, lastsent: 0, @@ -191,7 +187,6 @@ func (conn *Conn) postConnect() { conn.io = bufio.NewReadWriter( bufio.NewReader(conn.sock), bufio.NewWriter(conn.sock)) - conn.sock.SetTimeout(conn.Timeout * second) go conn.send() go conn.recv() go conn.runLoop() From 1c62354cb87a81f03b4457f7baa13ff917299888 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sat, 4 Feb 2012 01:13:07 +0000 Subject: [PATCH 10/16] Rewrite flood limiting for new time behaviour. --- client/connection.go | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/client/connection.go b/client/connection.go index d207c15..93af1cb 100644 --- a/client/connection.go +++ b/client/connection.go @@ -13,10 +13,6 @@ import ( "time" ) -const ( - second = int64(1e9) -) - // An IRC connection is represented by this struct. type Conn struct { // Connection Hostname and Nickname @@ -58,7 +54,8 @@ type Conn struct { Flood bool // Internal counters for flood protection - badness, lastsent int64 + badness time.Duration + lastsent time.Time } // Creates a new IRC connection object, but doesn't connect to anything so @@ -96,7 +93,7 @@ func Client(nick, ident, name string, SSLConfig: nil, Flood: false, badness: 0, - lastsent: 0, + lastsent: time.Now(), } conn.addIntHandlers() conn.Me = state.NewNick(nick, l) @@ -248,10 +245,10 @@ func (conn *Conn) runLoop() { // using Hybrid's algorithm to rate limit if conn.Flood is false. func (conn *Conn) write(line string) { if !conn.Flood { - if t := conn.rateLimit(int64(len(line))); t != 0 { + if t := conn.rateLimit(len(line)); t != 0 { // sleep for the current line's time value before sending it conn.l.Debug("irc.rateLimit(): Flood! Sleeping for %.2f secs.", - float64(t)/float64(second)) + t.Seconds()) <-time.After(t) } } @@ -270,19 +267,19 @@ func (conn *Conn) write(line string) { } // Implement Hybrid's flood control algorithm to rate-limit outgoing lines. -func (conn *Conn) rateLimit(chars int64) int64 { +func (conn *Conn) rateLimit(chars int) time.Duration { // Hybrid's algorithm allows for 2 seconds per line and an additional // 1/120 of a second per character on that line. - linetime := 2*second + chars*second/120 + linetime := 2*time.Second + time.Duration(chars)*time.Second/120 elapsed := time.Now().Sub(conn.lastsent) if conn.badness += linetime - elapsed; conn.badness < 0 { // negative badness times are badness... - conn.badness = int64(0) + conn.badness = 0 } conn.lastsent = time.Now() // If we've sent more than 10 second's worth of lines according to the // calculation above, then we're at risk of "Excess Flood". - if conn.badness > 10*second { + if conn.badness > 10*time.Second { return linetime } return 0 From eb87e56f96d035759a481121f280a2575254fac8 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sat, 4 Feb 2012 01:16:19 +0000 Subject: [PATCH 11/16] Mock net.Conn needs updating for interface changes. --- client/mocknetconn_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/mocknetconn_test.go b/client/mocknetconn_test.go index 95146fe..2306153 100644 --- a/client/mocknetconn_test.go +++ b/client/mocknetconn_test.go @@ -24,7 +24,7 @@ type mockNetConn struct { rc chan bool closed bool - rt, wt int64 + rt, wt time.Time } func MockNetConn(t *testing.T) *mockNetConn { @@ -143,18 +143,18 @@ func (m *mockNetConn) RemoteAddr() net.Addr { return &net.IPAddr{net.IPv4(127, 0, 0, 1)} } -func (m *mockNetConn) SetTimeout(ns int64) error { - m.rt = ns - m.wt = ns +func (m *mockNetConn) SetDeadline(t time.Time) error { + m.rt = t + m.wt = t return nil } -func (m *mockNetConn) SetReadTimeout(ns int64) error { - m.rt = ns +func (m *mockNetConn) SetReadDeadline(t time.Time) error { + m.rt = t return nil } -func (m *mockNetConn) SetWriteTimeout(ns int64) error { - m.wt = ns +func (m *mockNetConn) SetWriteDeadline(t time.Time) error { + m.wt = t return nil } From 6fd04236fbdc025b693576ce38703c1e31a926f6 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sat, 4 Feb 2012 01:32:48 +0000 Subject: [PATCH 12/16] "Fix" testing of ratelimiting code. --- client/connection_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/client/connection_test.go b/client/connection_test.go index 5bada41..923d6aa 100644 --- a/client/connection_test.go +++ b/client/connection_test.go @@ -342,8 +342,8 @@ func TestWrite(t *testing.T) { s.nc.Expect("yo momma") // Flood control is disabled -- setUp sets c.Flood = true -- so we should - // not have set c.badness or c.lastsent at this point. - if c.badness != 0 || c.lastsent != 0 { + // not have set c.badness at this point. + if c.badness != 0 { t.Errorf("Flood control used when Flood = true.") } @@ -351,8 +351,8 @@ func TestWrite(t *testing.T) { c.write("she so useless") s.nc.Expect("she so useless") - // The lastsent time should have been updated now. - if c.lastsent == 0 { + // The lastsent time should have been updated very recently... + if time.Now().Sub(c.lastsent) > time.Millisecond { t.Errorf("Flood control not used when Flood = false.") } @@ -378,12 +378,11 @@ func TestRateLimit(t *testing.T) { c, s := setUp(t) defer s.tearDown() - if c.badness != 0 || c.lastsent != 0 { + if c.badness != 0 { t.Errorf("Bad initial values for rate limit variables.") } - // badness will still be 0 because lastsent was 0 before rateLimit. - if l := c.rateLimit(60); l != 0 || c.badness != 0 || c.lastsent == 0 { + if l := c.rateLimit(60); l != 0 || c.badness == 0 { t.Errorf("Rate limit variables not updated correctly after rateLimit.") } // So, time at the nanosecond resolution is a bit of a bitch. Choosing 60 @@ -391,11 +390,12 @@ func TestRateLimit(t *testing.T) { // 2.5 seconds minus the delta between the two ratelimit calls. This should // be minimal but it's guaranteed that it won't be zero. Use 1us as a fuzz. // This seems to be the minimum timer resolution, on my laptop at least... - if l := c.rateLimit(60); l != 0 || c.badness - int64(25*1e8) > 1e3 { + if l := c.rateLimit(60); l != 0 || c.badness - 25*1e8 > time.Microsecond { t.Errorf("Rate limit calculating badness incorrectly.") } // At this point, we can tip over the badness scale, with a bit of help. - if l := c.rateLimit(360); l == 80*1e8 || c.badness - int64(105*1e8) > 1e3 { + if l := c.rateLimit(360); l == 80*1e8 || + c.badness - 105*1e8 > time.Microsecond { t.Errorf("Rate limit failed to return correct limiting values.") } } From a78aed7e7cc1c5a75d43ecad8ec940696b6cf514 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sat, 4 Feb 2012 23:32:39 +0000 Subject: [PATCH 13/16] Functions are not comparable any more, so only compare event names. --- client/connection_test.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/client/connection_test.go b/client/connection_test.go index 923d6aa..6e9e4e5 100644 --- a/client/connection_test.go +++ b/client/connection_test.go @@ -91,8 +91,12 @@ func TestClientAndStateTracking(t *testing.T) { l := logging.NewMockLogger(ctrl) st := state.NewMockStateTracker(ctrl) - for n, h := range intHandlers { - r.EXPECT().AddHandler(h, n) + for n, _ := range intHandlers { + // We can't use EXPECT() here as comparisons of functions are + // no longer valid in Go, which causes reflect.DeepEqual to bail. + // Instead, ignore the function arg and just ensure that all the + // handler names are correctly passed to AddHandler. + ctrl.RecordCall(r, "AddHandler", gomock.Any(), []string{n}) } c := Client("test", "test", "Testing IRC", r, l) @@ -109,8 +113,9 @@ func TestClientAndStateTracking(t *testing.T) { } // OK, while we're here with a mock event registry... - for n, h := range stHandlers { - r.EXPECT().AddHandler(h, n) + for n, _ := range stHandlers { + // See above. + ctrl.RecordCall(r, "AddHandler", gomock.Any(), []string{n}) } c.EnableStateTracking() @@ -127,8 +132,9 @@ func TestClientAndStateTracking(t *testing.T) { me := c.Me c.ST = st st.EXPECT().Wipe() - for n, h := range stHandlers { - r.EXPECT().DelHandler(h, n) + for n, _ := range stHandlers { + // See above. + ctrl.RecordCall(r, "DelHandler", gomock.Any(), []string{n}) } c.DisableStateTracking() if c.st || c.ST != nil || c.Me != me { From cb5001bb2792ae782cf3e0cadad7bb1417159f5b Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Sat, 4 Feb 2012 23:34:09 +0000 Subject: [PATCH 14/16] Rate limit testing was not testing properly. Needed abs() and some fixes for time changes. --- client/connection_test.go | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/client/connection_test.go b/client/connection_test.go index 6e9e4e5..badd45d 100644 --- a/client/connection_test.go +++ b/client/connection_test.go @@ -388,20 +388,36 @@ func TestRateLimit(t *testing.T) { t.Errorf("Bad initial values for rate limit variables.") } - if l := c.rateLimit(60); l != 0 || c.badness == 0 { - t.Errorf("Rate limit variables not updated correctly after rateLimit.") + // We'll be needing this later... + abs := func(i time.Duration) time.Duration { + if (i < 0) { + return -i + } + return i } + + // Since the changes to the time module, c.lastsent is now a time.Time. + // It's initialised on client creation to time.Now() which for the purposes + // of this test was probably around 1.2 ms ago. This is inconvenient. + // Making it >10s ago effectively clears out the inconsistency, as this + // makes elapsed > linetime and thus zeros c.badness and resets c.lastsent. + c.lastsent = time.Now().Add(-10 * time.Second) + if l := c.rateLimit(60); l != 0 || c.badness != 0 { + t.Errorf("Rate limit got non-zero badness from long-ago lastsent.") + } + // So, time at the nanosecond resolution is a bit of a bitch. Choosing 60 // characters as the line length means we should be increasing badness by // 2.5 seconds minus the delta between the two ratelimit calls. This should - // be minimal but it's guaranteed that it won't be zero. Use 1us as a fuzz. - // This seems to be the minimum timer resolution, on my laptop at least... - if l := c.rateLimit(60); l != 0 || c.badness - 25*1e8 > time.Microsecond { + // be minimal but it's guaranteed that it won't be zero. Use 10us as a fuzz. + if l := c.rateLimit(60); l != 0 || abs(c.badness - 25*1e8) > 10 * time.Microsecond { t.Errorf("Rate limit calculating badness incorrectly.") } - // At this point, we can tip over the badness scale, with a bit of help. - if l := c.rateLimit(360); l == 80*1e8 || - c.badness - 105*1e8 > time.Microsecond { + // At this point, we can tip over the badness scale, with a bit of help. + // 720 chars => +8 seconds of badness => 10.5 seconds => ratelimit + if l := c.rateLimit(720); l != 8 * time.Second || + abs(c.badness - 105*1e8) > 10 * time.Microsecond { t.Errorf("Rate limit failed to return correct limiting values.") + t.Errorf("l=%d, badness=%d", l, c.badness) } } From dbdc470c5c43862e47205e426cc4658150bc0440 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Mon, 14 May 2012 22:51:01 +0100 Subject: [PATCH 15/16] Fix os.EINVAL -> os.ErrInvalid change. --- client/mocknetconn_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/mocknetconn_test.go b/client/mocknetconn_test.go index 2306153..76835f9 100644 --- a/client/mocknetconn_test.go +++ b/client/mocknetconn_test.go @@ -99,7 +99,7 @@ func (m *mockNetConn) ExpectNothing() { // Implement net.Conn interface func (m *mockNetConn) Read(b []byte) (int, error) { if m.closed { - return 0, os.EINVAL + return 0, os.ErrInvalid } l := 0 select { @@ -114,7 +114,7 @@ func (m *mockNetConn) Read(b []byte) (int, error) { func (m *mockNetConn) Write(s []byte) (int, error) { if m.closed { - return 0, os.EINVAL + return 0, os.ErrInvalid } b := make([]byte, len(s)) copy(b, s) @@ -124,7 +124,7 @@ func (m *mockNetConn) Write(s []byte) (int, error) { func (m *mockNetConn) Close() error { if m.closed { - return os.EINVAL + return os.ErrInvalid } // Shut down *ALL* the goroutines! // This will trigger an EOF event in Read() too From e3ba7b6b9609536c1f6b98e716eb48ab18523f27 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Wed, 6 Jun 2012 15:22:06 +0100 Subject: [PATCH 16/16] Fix up README. --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fc6c8dc..b9d440e 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,9 @@ GoIRC Client Framework Pretty simple, really: - goinstall github.com/fluffle/goirc + go get github.com/fluffle/goirc/client -You can build the test client also with: - - make - ./gobot - -This will connect to freenode and join `#go-nuts` by default, so be careful ;-) +There is some example code that demonstrates usage of the library in `client.go`. This will connect to freenode and join `#go-nuts` by default, so be careful ;-) ### Using the framework