diff --git a/current/activity_test.go b/current/activity_test.go index 2418d91487143a821bc60cb62a5b528ee00b442b..4950b693cc0808789f1ddde4aada9f94260c9fe1 100644 --- a/current/activity_test.go +++ b/current/activity_test.go @@ -22,7 +22,7 @@ func TestActivity_String(t *testing.T) { for st := NOT_STARTED; st <= NUM_STATES; st++ { if st.String() != expectedActivityStringer[st] { t.Errorf("Activity %d did not string correctly: expected: %s,"+ - "recieved: %s", uint8(st), expectedActivityStringer[st], st.String()) + "received: %s", uint8(st), expectedActivityStringer[st], st.String()) } } } diff --git a/go.mod b/go.mod index 138c38b422db2cece1926bbc050563c63de93ca1..a4be63564783aaf7942edeb35d6c4aed8ed6dac9 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,16 @@ module gitlab.com/elixxir/primitives go 1.13 require ( + github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 + github.com/kr/text v0.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pkg/errors v0.9.1 github.com/spf13/jwalterweatherman v1.1.0 - gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c + github.com/stretchr/testify v1.5.1 // indirect + gitlab.com/xx_network/primitives v0.0.2 + golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/go.sum b/go.sum index f73cf89e91cdc55c98a0e158a677d392f66db58b..ecfe1bb9457baa12efc9e34d1fdc12d2056653db 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,26 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= -gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c h1:tGe3QtCC6St63FuxVAaDtHSx0BCNqzCsfjbRo5jacWM= -gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA= +gitlab.com/xx_network/primitives v0.0.2 h1:Aqe0rg2yGhioEGCHvBRyEKHwS4GS8q/pqKwCDRkc4qA= +gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/knownRounds/knownRounds.go b/knownRounds/knownRounds.go index a801fba5dfc13a04232fd8b18e18f6679fa4b131..556427fd60c98eaa13d66cc46c3a7c2a9d830287 100644 --- a/knownRounds/knownRounds.go +++ b/knownRounds/knownRounds.go @@ -92,6 +92,7 @@ func (kr *KnownRounds) Unmarshal(data []byte) error { } // Copy values over + copy(kr.bitStream, dkr.BitStream) kr.firstUnchecked = id.Round(dkr.FirstUnchecked) kr.lastChecked = id.Round(dkr.LastChecked) kr.fuPos = int(dkr.FirstUnchecked % 64) @@ -126,6 +127,9 @@ func (kr *KnownRounds) Check(rid id.Round) { } pos := kr.getBitStreamPos(rid) + // Set round as checked + kr.bitStream.set(pos) + // If the round ID is newer, then set it as the last checked ID and uncheck // all the newly added rounds in the buffer if rid > kr.lastChecked { diff --git a/rateLimiting/bucket.go b/rateLimiting/bucket.go index d15bfb233bfa457a593fa8be9c918cb2099055ee..6a723c65103878bd6c010998aa0edc0a15ff2e6c 100644 --- a/rateLimiting/bucket.go +++ b/rateLimiting/bucket.go @@ -9,6 +9,7 @@ package rateLimiting import ( + "encoding/json" "sync" "time" ) @@ -131,3 +132,53 @@ func (b *Bucket) update() { // Update timestamp b.lastUpdate = updateTime } + +// AddToDB isn't meaningfully serializable, so if necessary it should be +// populated after the fact +type bucketDisk struct { + Capacity uint32 // Maximum number of tokens the bucket can hold + Remaining uint32 // Current number of tokens in the bucket + LeakRate float64 // Rate that the bucket leaks tokens at [tokens/ns] + LastUpdate int64 // Time that the bucket was most recently updated + Locked bool // When true, prevents bucket from being deleted when stale + Whitelist bool // When true, adding tokens always returns true +} + +func (b *Bucket) MarshalJSON() ([]byte, error) { + b.Lock() + defer b.Unlock() + return json.Marshal(&bucketDisk{ + Capacity: b.capacity, + Remaining: b.remaining, + LeakRate: b.leakRate, + LastUpdate: b.lastUpdate, + Locked: b.locked, + Whitelist: b.whitelist, + }) +} + +// Problem: Doesn't include db func +func (b *Bucket) UnmarshalJSON(data []byte) error { + var bd bucketDisk + err := json.Unmarshal(data, &bd) + if err != nil { + return err + } + + b.Lock() + b.whitelist = bd.Whitelist + b.locked = bd.Locked + b.lastUpdate = bd.LastUpdate + b.leakRate = bd.LeakRate + b.remaining = bd.Remaining + b.capacity = bd.Capacity + b.Unlock() + return nil +} + +// This function should be called after unmarshalling if you need a db function +func (b *Bucket) SetAddToDB(dbFunc func(uint32, int64)) { + b.Lock() + b.addToDb = dbFunc + b.Unlock() +} diff --git a/rateLimiting/bucketMap_test.go b/rateLimiting/bucketMap_test.go index fdc2c49590a92633a6b762580ae6f445fe047889..c7e57e927928ff5c4362ab51e649cb8398da2ec5 100644 --- a/rateLimiting/bucketMap_test.go +++ b/rateLimiting/bucketMap_test.go @@ -428,7 +428,7 @@ func TestBucketMap_AddAllBuckets(t *testing.T) { bp.Key) } else if !reflect.DeepEqual(b, CreateBucketFromParams(bp, nil)) { t.Errorf("addAllBuckets() created bucket %s with incorrect values."+ - "\n\texpected: %+v\n\trecieved: %+v", bp.Key, + "\n\texpected: %+v\n\treceived: %+v", bp.Key, CreateBucketFromParams(bp, nil), b) } } diff --git a/rateLimiting/bucket_test.go b/rateLimiting/bucket_test.go index bdbb0ddfb71ae63a58eb2d4000810e2ab9e873d6..a3c2d5b1459b57c5f4afd54de91e85c28d1b52df 100644 --- a/rateLimiting/bucket_test.go +++ b/rateLimiting/bucket_test.go @@ -7,6 +7,7 @@ package rateLimiting import ( + "encoding/json" "math/rand" "reflect" "testing" @@ -93,7 +94,7 @@ func TestCreateBucketFromParams(t *testing.T) { if !reflect.DeepEqual(expectedBucket, testBucket) { t.Errorf("CreateBucketFromParams() produced an incorrect bucket."+ - "\n\texepcted: %+v\n\trecieved: %+v", expectedBucket, testBucket) + "\n\texepcted: %+v\n\treceived: %+v", expectedBucket, testBucket) } } @@ -337,3 +338,36 @@ func TestAdd_ThreadSafe(t *testing.T) { return } } + +// Tests that MarshalJSON and UnmarshalJSON can serialize and deserialize buckets +func TestBucket_MarshalUnmarshal(t *testing.T) { + b := CreateBucketFromLeakRatio(10, 1, nil) + + data, err := json.Marshal(b) + if err != nil { + t.Fatal(err) + } + t.Log(string(data)) + var b2 Bucket + err = json.Unmarshal(data, &b2) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(b, &b2) { + t.Error("buckets should be equal after serialization/deserialization") + } +} + +// Tests that AddToDB can be set up after marshalling/unmarshalling +func TestBucket_AddToDB(t *testing.T) { + called := false + + var b2 Bucket + b2.SetAddToDB(func(u uint32, i int64) { + called = true + }) + b2.addToDb(0, 0) + if !called { + t.Error("addToDb should have been called") + } +} diff --git a/states/states_test.go b/states/states_test.go index 0faa40321ec668e12bb2d7c9e991c839b9a7abff..154049c28febd110143e06578f7ecbc0381200dd 100644 --- a/states/states_test.go +++ b/states/states_test.go @@ -18,7 +18,7 @@ func TestActivity_String(t *testing.T) { for st := PENDING; st <= NUM_STATES; st++ { if st.String() != expectedStateStringer[st] { t.Errorf("Round %d did not string correctly: expected: %s,"+ - "recieved: %s", uint8(st), expectedStateStringer[st], st.String()) + "received: %s", uint8(st), expectedStateStringer[st], st.String()) } } } diff --git a/switchboard/any.go b/switchboard/any.go deleted file mode 100644 index ecb85a146e4398e44404dd704ee7ee8cd6cdef7a..0000000000000000000000000000000000000000 --- a/switchboard/any.go +++ /dev/null @@ -1,11 +0,0 @@ -package switchboard - -import "gitlab.com/xx_network/primitives/id" - -// ID to respond to any message type -const AnyType = int32(0) - -//ID to respond to any user -func AnyUser() *id.ID { - return &id.ZeroUser -} diff --git a/switchboard/any_test.go b/switchboard/any_test.go deleted file mode 100644 index 1f31bccd885ee97d19213812fb2b0cbfc1fd6a2a..0000000000000000000000000000000000000000 --- a/switchboard/any_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package switchboard - -import ( - "gitlab.com/xx_network/primitives/id" - "testing" -) - -//tests that AnyUser returns the correct user -func TestAnyUser(t *testing.T) { - au := AnyUser() - if !au.Cmp(&id.ZeroUser) { - t.Errorf("Wrong user returned from AnyUser") - } -} diff --git a/switchboard/byID.go b/switchboard/byID.go deleted file mode 100644 index ad7197452e80db9220a589f5c4a880caf15532e4..0000000000000000000000000000000000000000 --- a/switchboard/byID.go +++ /dev/null @@ -1,63 +0,0 @@ -package switchboard - -import ( - "github.com/golang-collections/collections/set" - "gitlab.com/xx_network/primitives/id" -) - -type byId struct { - list map[id.ID]*set.Set - generic *set.Set -} - -// builds a new byID structure -// registers an empty ID and the designated zero ID as generic -func newById() *byId { - bi := &byId{ - list: make(map[id.ID]*set.Set), - generic: set.New(), - } - - //make the zero IDs, which are defined as any, all point to the generic - bi.list[*AnyUser()] = bi.generic - bi.list[id.ID{}] = bi.generic - - return bi -} - -// returns a set associated with the passed ID unioned with the generic return -func (bi *byId) Get(uid *id.ID) *set.Set { - lookup, ok := bi.list[*uid] - if !ok { - return bi.generic - } else { - return lookup.Union(bi.generic) - } -} - -// adds a listener to a set for the given ID. Creates a new set to add it to if -// the set does not exist -func (bi *byId) Add(uid *id.ID, l Listener) *set.Set { - s, ok := bi.list[*uid] - if !ok { - s = set.New(l) - bi.list[*uid] = s - } else { - s.Insert(l) - } - - return s -} - -// Removes the passed listener from the set for UserID and -// deletes the set if it is empty if the ID is not a generic one -func (bi *byId) Remove(uid *id.ID, l Listener) { - s, ok := bi.list[*uid] - if ok { - s.Remove(l) - - if s.Len() == 0 && !uid.Cmp(AnyUser()) && !uid.Cmp(&id.ID{}) { - delete(bi.list, *uid) - } - } -} diff --git a/switchboard/byID_test.go b/switchboard/byID_test.go deleted file mode 100644 index 683a68f0a8ab3a10d989ba3425d87f9451e6c94b..0000000000000000000000000000000000000000 --- a/switchboard/byID_test.go +++ /dev/null @@ -1,308 +0,0 @@ -package switchboard - -import ( - "github.com/golang-collections/collections/set" - "gitlab.com/xx_network/primitives/id" - "testing" -) - -// tests the newByID functions forms a properly constructed byId -func TestById_newById(t *testing.T) { - nbi := newById() - - if nbi.list == nil { - t.Errorf("No list created") - } - - if nbi.generic == nil { - t.Errorf("No generic created") - } - - if nbi.generic != nbi.list[id.ZeroUser] { - t.Errorf("zero user not registered as generic") - } - - if nbi.generic != nbi.list[id.ID{}] { - t.Errorf("zero id not registered as generic") - } -} - -// tests that when nothing has been added an empty set is returned -func TestById_Get_Empty(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - s := nbi.Get(uid) - - if s.Len() != 0 { - t.Errorf("Should not have returned a set") - } -} - -//tests that getting a set for a specific ID returns that set -func TestById_Get_Selected(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - set1 := set.New(0) - - nbi.list[*uid] = set1 - - s := nbi.Get(uid) - - if s.Len() == 0 { - t.Errorf("Should have returned a set") - } - - if !s.SubsetOf(set1) || !set1.SubsetOf(s) { - t.Errorf("Wrong set returned") - } -} - -// tests that when getting a specific ID which is not there returns the generic -// set if is present -func TestById_Get_Generic(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - nbi.generic.Insert(0) - - s := nbi.Get(uid) - - if s.Len() == 0 { - t.Errorf("Should have returned a set") - } - - if !s.SubsetOf(nbi.generic) || !nbi.generic.SubsetOf(s) { - t.Errorf("Wrong set returned") - } -} - -// tests that when getting a specific ID is there and there are elements -// in the generic that the union of the two is returned -func TestById_Get_GenericSelected(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - set1 := set.New(0) - - nbi.list[*uid] = set1 - - nbi.generic.Insert(1) - - s := nbi.Get(uid) - - if s.Len() == 0 { - t.Errorf("Should have returned a set") - } - - setUnion := set1.Union(nbi.generic) - - if !s.SubsetOf(setUnion) || !setUnion.SubsetOf(s) { - t.Errorf("Wrong set returned") - } -} - -// Tests that when adding to a set which does not exist, the set is created -func TestById_Add_New(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - l := &funcListener{} - - nbi.Add(uid, l) - - s := nbi.list[*uid] - - if s.Len() != 1 { - t.Errorf("Should a set of the wrong size") - } - - if !s.Has(l) { - t.Errorf("Wrong set returned") - } -} - -// Tests that when adding to a set which does exist, the set is retained and -// added to -func TestById_Add_Old(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - l1 := &funcListener{} - l2 := &funcListener{} - - set1 := set.New(l1) - - nbi.list[*uid] = set1 - - nbi.Add(uid, l2) - - s := nbi.list[*uid] - - if s.Len() != 2 { - t.Errorf("Should have returned a set") - } - - if !s.Has(l1) { - t.Errorf("Set does not include the initial listener") - } - - if !s.Has(l2) { - t.Errorf("Set does not include the new listener") - } -} - -// Tests that when adding to a generic ID, the listener is added to the -// generic set -func TestById_Add_Generic(t *testing.T) { - nbi := newById() - - l1 := &funcListener{} - l2 := &funcListener{} - - nbi.Add(&id.ID{}, l1) - nbi.Add(AnyUser(), l2) - - s := nbi.generic - - if s.Len() != 2 { - t.Errorf("Should have returned a set of size 2") - } - - if !s.Has(l1) { - t.Errorf("Set does not include the ZeroUser listener") - } - - if !s.Has(l2) { - t.Errorf("Set does not include the empty user listener") - } -} - -// Tests that removing a listener from a set with multiple listeners removes the -// listener but maintains the set -func TestById_Remove_ManyInSet(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - l1 := &funcListener{} - l2 := &funcListener{} - - set1 := set.New(l1, l2) - - nbi.list[*uid] = set1 - - nbi.Remove(uid, l1) - - if _, ok := nbi.list[*uid]; !ok { - t.Errorf("Set removed when it should not have been") - } - - if set1.Len() != 1 { - t.Errorf("Set is incorrect length after the remove call: %v", - set1.Len()) - } - - if set1.Has(l1) { - t.Errorf("Listener 1 still in set, it should not be") - } - - if !set1.Has(l2) { - t.Errorf("Listener 2 not still in set, it should be") - } - -} - -// Tests that removing a listener from a set with a single listener removes the -// listener and the set -func TestById_Remove_SingleInSet(t *testing.T) { - nbi := newById() - - uid := id.NewIdFromUInt(42, id.User, t) - - l1 := &funcListener{} - - set1 := set.New(l1) - - nbi.list[*uid] = set1 - - nbi.Remove(uid, l1) - - if _, ok := nbi.list[*uid]; ok { - t.Errorf("Set not removed when it should have been") - } - - if set1.Len() != 0 { - t.Errorf("Set is incorrect length after the remove call: %v", - set1.Len()) - } - - if set1.Has(l1) { - t.Errorf("Listener 1 still in set, it should not be") - } -} - -// Tests that removing a listener from a set with a single listener removes the -// listener and not the set when the ID iz ZeroUser -func TestById_Remove_SingleInSet_ZeroUser(t *testing.T) { - nbi := newById() - - uid := &id.ZeroUser - - l1 := &funcListener{} - - set1 := set.New(l1) - - nbi.list[*uid] = set1 - - nbi.Remove(uid, l1) - - if _, ok := nbi.list[*uid]; !ok { - t.Errorf("Set removed when it should not have been") - } - - if set1.Len() != 0 { - t.Errorf("Set is incorrect length after the remove call: %v", - set1.Len()) - } - - if set1.Has(l1) { - t.Errorf("Listener 1 still in set, it should not be") - } -} - -// Tests that removing a listener from a set with a single listener removes the -// listener and not the set when the ID iz ZeroUser -func TestById_Remove_SingleInSet_EmptyUser(t *testing.T) { - nbi := newById() - - uid := &id.ID{} - - l1 := &funcListener{} - - set1 := set.New(l1) - - nbi.list[*uid] = set1 - - nbi.Remove(uid, l1) - - if _, ok := nbi.list[*uid]; !ok { - t.Errorf("Set removed when it should not have been") - } - - if set1.Len() != 0 { - t.Errorf("Set is incorrect length after the remove call: %v", - set1.Len()) - } - - if set1.Has(l1) { - t.Errorf("Listener 1 still in set, it should not be") - } -} diff --git a/switchboard/byType.go b/switchboard/byType.go deleted file mode 100644 index 01b1182aebc21ba36b7e05c74ba5bbd0ab8ec90d..0000000000000000000000000000000000000000 --- a/switchboard/byType.go +++ /dev/null @@ -1,63 +0,0 @@ -package switchboard - -import ( - "github.com/golang-collections/collections/set" -) - -type byType struct { - list map[int32]*set.Set - generic *set.Set -} - -// builds a new byType structure -// registers an AnyType as generic -func newByType() *byType { - bt := &byType{ - list: make(map[int32]*set.Set), - generic: set.New(), - } - - // make the zero messages, which are defined as AnyType, - // point to the generic - bt.list[AnyType] = bt.generic - - return bt -} - -// returns a set associated with the passed messageType unioned with the -// generic return -func (bt *byType) Get(messageType int32) *set.Set { - lookup, ok := bt.list[messageType] - if !ok { - return bt.generic - } else { - return lookup.Union(bt.generic) - } -} - -// adds a listener to a set for the given messageType. Creates a new set to add -// it to if the set does not exist -func (bt *byType) Add(messageType int32, r Listener) *set.Set { - s, ok := bt.list[messageType] - if !ok { - s = set.New(r) - bt.list[messageType] = s - } else { - s.Insert(r) - } - - return s -} - -// Removes the passed listener from the set for messageType and -// deletes the set if it is empty and the type is not AnyType -func (bt *byType) Remove(mt int32, l Listener) { - s, ok := bt.list[mt] - if ok { - s.Remove(l) - - if s.Len() == 0 && mt != AnyType { - delete(bt.list, mt) - } - } -} diff --git a/switchboard/byType_test.go b/switchboard/byType_test.go deleted file mode 100644 index 016909bb018e611589f1749097dc42ebd77a8afb..0000000000000000000000000000000000000000 --- a/switchboard/byType_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package switchboard - -import ( - "github.com/golang-collections/collections/set" - "testing" -) - -func TestByType_newByType(t *testing.T) { - nbt := newByType() - - if nbt.list == nil { - t.Errorf("No list created") - } - - if nbt.generic == nil { - t.Errorf("No generic created") - } - - if nbt.generic != nbt.list[0] { - t.Errorf("zero message type not registered as generic") - } - -} - -func TestByType_Get_Empty(t *testing.T) { - nbt := newByType() - - s := nbt.Get(42) - - if s.Len() != 0 { - t.Errorf("Should not have returned a set") - } -} - -func TestByType_Get_Selected(t *testing.T) { - nbt := newByType() - - m := int32(42) - - set1 := set.New(0) - - nbt.list[m] = set1 - - s := nbt.Get(m) - - if s.Len() == 0 { - t.Errorf("Should have returned a set") - } - - if !s.SubsetOf(set1) || !set1.SubsetOf(s) { - t.Errorf("Wrong set returned") - } -} - -func TestByType_Get_Generic(t *testing.T) { - nbt := newByType() - - m := int32(42) - - nbt.generic.Insert(0) - - s := nbt.Get(m) - - if s.Len() == 0 { - t.Errorf("Should have returned a set") - } - - if !s.SubsetOf(nbt.generic) || !nbt.generic.SubsetOf(s) { - t.Errorf("Wrong set returned") - } -} - -func TestByType_Get_GenericSelected(t *testing.T) { - nbt := newByType() - - m := int32(42) - - nbt.generic.Insert(1) - - set1 := set.New(0) - - nbt.list[m] = set1 - - s := nbt.Get(m) - - if s.Len() == 0 { - t.Errorf("Should have returned a set") - } - - setUnion := set1.Union(nbt.generic) - - if !s.SubsetOf(setUnion) || !setUnion.SubsetOf(s) { - t.Errorf("Wrong set returned") - } -} - -// Tests that when adding to a set which does not exist, the set is created -func TestByType_Add_New(t *testing.T) { - nbt := newByType() - - m := int32(42) - - l := &funcListener{} - - nbt.Add(m, l) - - s := nbt.list[m] - - if s.Len() != 1 { - t.Errorf("Should a set of the wrong size") - } - - if !s.Has(l) { - t.Errorf("Wrong set returned") - } -} - -// Tests that when adding to a set which does exist, the set is retained and -// added to -func TestByType_Add_Old(t *testing.T) { - nbt := newByType() - - m := int32(42) - - l1 := &funcListener{} - l2 := &funcListener{} - - set1 := set.New(l1) - - nbt.list[m] = set1 - - nbt.Add(m, l2) - - s := nbt.list[m] - - if s.Len() != 2 { - t.Errorf("Should have returned a set") - } - - if !s.Has(l1) { - t.Errorf("Set does not include the initial listener") - } - - if !s.Has(l2) { - t.Errorf("Set does not include the new listener") - } -} - -// Tests that when adding to a generic ID, the listener is added to the -// generic set -func TestByType_Add_Generic(t *testing.T) { - nbt := newByType() - - l1 := &funcListener{} - - nbt.Add(AnyType, l1) - - s := nbt.generic - - if s.Len() != 1 { - t.Errorf("Should have returned a set of size 2") - } - - if !s.Has(l1) { - t.Errorf("Set does not include the ZeroUser listener") - } -} - -// Tests that removing a listener from a set with a single listener removes the -// listener and the set -func TestByType_Remove_SingleInSet(t *testing.T) { - nbt := newByType() - - m := int32(42) - - l1 := &funcListener{} - - set1 := set.New(l1) - - nbt.list[m] = set1 - - nbt.Remove(m, l1) - - if _, ok := nbt.list[m]; ok { - t.Errorf("Set not removed when it should have been") - } - - if set1.Len() != 0 { - t.Errorf("Set is incorrect length after the remove call: %v", - set1.Len()) - } - - if set1.Has(l1) { - t.Errorf("Listener 1 still in set, it should not be") - } -} - -// Tests that removing a listener from a set with a single listener removes the -// listener and not the set when the ID iz ZeroUser -func TestByType_Remove_SingleInSet_AnyType(t *testing.T) { - nbt := newByType() - - m := AnyType - - l1 := &funcListener{} - - set1 := set.New(l1) - - nbt.list[m] = set1 - - nbt.Remove(m, l1) - - if _, ok := nbt.list[m]; !ok { - t.Errorf("Set removed when it should not have been") - } - - if set1.Len() != 0 { - t.Errorf("Set is incorrect length after the remove call: %v", - set1.Len()) - } - - if set1.Has(l1) { - t.Errorf("Listener 1 still in set, it should not be") - } -} diff --git a/switchboard/listener.go b/switchboard/listener.go deleted file mode 100644 index a3a23340d0f55aa0d92bf81b4d57fe267d3802d0..0000000000000000000000000000000000000000 --- a/switchboard/listener.go +++ /dev/null @@ -1,116 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the LICENSE file // -//////////////////////////////////////////////////////////////////////////////////////////// - -package switchboard - -import ( - jww "github.com/spf13/jwalterweatherman" - "gitlab.com/xx_network/primitives/id" -) - -type Item interface { - GetSender() *id.ID - GetMessageType() int32 -} - -//interface for a listener adhere to -type Listener interface { - // the Hear function is called to exercise the listener, passing in the - // data as an item - Hear(item Item) - // Returns a name, used for debugging - Name() string -} - -// This function type defines callbacks that get passed when the listener is -// listened to. It will always be called in its own goroutine. It may be called -// multiple times simultaneously -type ListenerFunc func(item Item) - -// id object returned when a listener is created and is used to delete it from -// the system -type ListenerID struct { - userID *id.ID - messageType int32 - listener Listener -} - -//getter for userID -func (lid ListenerID) GetUserID() *id.ID { - return lid.userID -} - -//getter for message type -func (lid ListenerID) GetMessageType() int32 { - return lid.messageType -} - -//getter for name -func (lid ListenerID) GetName() string { - return lid.listener.Name() -} - -/*internal listener implementations*/ - -//listener based off of a function -type funcListener struct { - listener ListenerFunc - name string -} - -// creates a new FuncListener Adhereing to the listener interface out of the -// passed function and name, returns a pointer to the result -func newFuncListener(listener ListenerFunc, name string) *funcListener { - return &funcListener{ - listener: listener, - name: name, - } -} - -// Adheres to the Hear function of the listener interface, calls the internal -// function with the passed item -func (fl *funcListener) Hear(item Item) { - fl.listener(item) -} - -// Adheres to the Name function of the listener interface, returns a name. -// used for debugging -func (fl *funcListener) Name() string { - return fl.name -} - -//listener based off of a channel -type chanListener struct { - listener chan Item - name string -} - -// creates a new ChanListener Adhereing to the listener interface out of the -// passed channel and name, returns a pointer to the result -func newChanListener(listener chan Item, name string) *chanListener { - return &chanListener{ - listener: listener, - name: name, - } -} - -// Adheres to the Hear function of the listener interface, calls the passed the -// heard item across the channel. Drops the item if it cannot put it into the -// channel immediately -func (cl *chanListener) Hear(item Item) { - select { - case cl.listener <- item: - default: - jww.WARN.Printf("Switchboard failed to speak on channel "+ - "listener %s", cl.name) - } -} - -// Adheres to the Name function of the listener interface, returns a name. -// used for debugging -func (cl *chanListener) Name() string { - return cl.name -} diff --git a/switchboard/listener_test.go b/switchboard/listener_test.go deleted file mode 100644 index 30ac99ccc693cefb5a995e886ad4e88b0c106c6f..0000000000000000000000000000000000000000 --- a/switchboard/listener_test.go +++ /dev/null @@ -1,163 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the LICENSE file // -//////////////////////////////////////////////////////////////////////////////////////////// - -package switchboard - -import ( - "gitlab.com/xx_network/primitives/id" - "reflect" - "testing" - "time" -) - -//verify func listener adheres to the listener interface -var _ Listener = &funcListener{} - -//verify chan listener adheres to the listener interface -var _ Listener = &chanListener{} - -//test listenerID returns the userID -func TestListenerID_GetUserID(t *testing.T) { - lid := ListenerID{ - userID: id.NewIdFromUInt(42, id.User, t), - messageType: 42, - listener: nil, - } - - if !lid.GetUserID().Cmp(lid.userID) { - t.Errorf("Returned userID does not match") - } -} - -//test listenerID returns the messageType -func TestListenerID_GetMessageType(t *testing.T) { - lid := ListenerID{ - userID: id.NewIdFromUInt(42, id.User, t), - messageType: 42, - listener: nil, - } - - if lid.GetMessageType() != lid.messageType { - t.Errorf("Returned message type does not match") - } -} - -//test listenerID returns the name -func TestListenerID_GetName(t *testing.T) { - name := "test" - - lid := ListenerID{ - userID: id.NewIdFromUInt(42, id.User, t), - messageType: 42, - listener: newFuncListener(nil, name), - } - - if lid.GetName() != name { - t.Errorf("Returned name type does not match") - } -} - -//tests new function listener creates the funcListener properly -func TestNewFuncListener(t *testing.T) { - f := func(item Item) {} - name := "test" - listener := newFuncListener(f, name) - - if listener.listener == nil { - t.Errorf("function is wrong") - } - - if listener.name != name { - t.Errorf("name is wrong") - } -} - -//tests FuncListener Hear works -func TestFuncListener_Hear(t *testing.T) { - m := &Message{ - Contents: []byte{0, 1, 2, 3}, - Sender: id.NewIdFromUInt(42, id.User, t), - MessageType: 69, - } - - heard := make(chan Item, 1) - - f := func(item Item) { - heard <- item - } - - listener := newFuncListener(f, "test") - - listener.Hear(m) - - select { - case item := <-heard: - if !reflect.DeepEqual(item.(*Message), m) { - t.Errorf("Heard message did not match") - } - case <-time.After(5 * time.Millisecond): - t.Errorf("Did not hear") - } -} - -// Test FuncListener returns the correct name -func TestFuncListener_Name(t *testing.T) { - name := "test" - listener := newFuncListener(nil, name) - - if listener.Name() != name { - t.Errorf("Name did not match") - } -} - -//tests new chan listener creates the chanListener properly -func TestNewChanListener(t *testing.T) { - c := make(chan Item) - name := "test" - listener := newChanListener(c, name) - - if listener.listener == nil { - t.Errorf("function is wrong") - } - - if listener.name != name { - t.Errorf("name is wrong") - } -} - -//tests ChanListener Hear works -func TestChanListener_Hear(t *testing.T) { - m := &Message{ - Contents: []byte{0, 1, 2, 3}, - Sender: id.NewIdFromUInt(42, id.User, t), - MessageType: 69, - } - - heard := make(chan Item, 1) - - listener := newChanListener(heard, "test") - - listener.Hear(m) - - select { - case item := <-heard: - if !reflect.DeepEqual(item.(*Message), m) { - t.Errorf("Heard message did not match") - } - case <-time.After(5 * time.Millisecond): - t.Errorf("Did not hear") - } -} - -// Test FuncListener returns the correct name -func TestChanListener_Name(t *testing.T) { - name := "test" - listener := newChanListener(nil, name) - - if listener.Name() != name { - t.Errorf("Name did not match") - } -} diff --git a/switchboard/switchboard.go b/switchboard/switchboard.go deleted file mode 100644 index 4aed9b3b6a3de72bb0101740a245be796cdf080f..0000000000000000000000000000000000000000 --- a/switchboard/switchboard.go +++ /dev/null @@ -1,166 +0,0 @@ -package switchboard - -import ( - "errors" - "github.com/golang-collections/collections/set" - jww "github.com/spf13/jwalterweatherman" - "gitlab.com/xx_network/primitives/id" - "sync" -) - -type Switchboard struct { - id *byId - messageType *byType - - mux sync.RWMutex -} - -// New generates and returns a new switchboard object. -func New() *Switchboard { - return &Switchboard{ - id: newById(), - messageType: newByType(), - } -} - -// Registers a new listener. Returns the ID of the new listener. -// Keep this around if you want to be able to delete the listener later. -// -// name is used for debug printing and not checked for uniqueness -// -// user: 0 for all, or any user ID to listen for messages from a particular -// user. 0 can be id.ZeroUser or id.ZeroID -// messageType: 0 for all, or any message type to listen for messages of that -// type. 0 can be switchboard.AnyType -// newListener: something implementing the Listener interface. Do not -// pass nil to this. -// -// If a message matches multiple listeners, all of them will hear the message. -func (sw *Switchboard) RegisterListener(user *id.ID, messageType int32, - newListener Listener) (ListenerID, error) { - - // check the input data is valid - if user == nil { - return ListenerID{}, errors.New("cannot register listener to nil user") - } - - if newListener == nil { - return ListenerID{}, errors.New("cannot register nil listener") - } - - //register the listener by both ID and messageType - sw.mux.Lock() - - sw.id.Add(user, newListener) - sw.messageType.Add(messageType, newListener) - - sw.mux.Unlock() - - //return a ListenerID so it can be unregistered in the future - return ListenerID{ - userID: user, - messageType: messageType, - listener: newListener, - }, nil -} - -// Registers a new listener built around the passed function. -// Returns the ID of the new listener. -// Keep this around if you want to be able to delete the listener later. -// -// name is used for debug printing and not checked for uniqueness -// -// user: 0 for all, or any user ID to listen for messages from a particular -// user. 0 can be id.ZeroUser or id.ZeroID -// messageType: 0 for all, or any message type to listen for messages of that -// type. 0 can be switchboard.AnyType -// newListener: a function implementing the ListenerFunc function type. -// Do not pass nil to this. -// -// If a message matches multiple listeners, all of them will hear the message. -func (sw *Switchboard) RegisterFunc(name string, user *id.ID, messageType int32, - newListener ListenerFunc) (ListenerID, error) { - // check that the input data is valid - if newListener == nil { - return ListenerID{}, - errors.New("cannot register listener with nil func") - } - - // generate a funcListener object adhering to the listener interface - fl := newFuncListener(newListener, name) - - //register the listener and return the result - return sw.RegisterListener(user, messageType, fl) -} - -// Registers a new listener built around the passed channel. -// Returns the ID of the new listener. -// Keep this around if you want to be able to delete the listener later. -// -// name is used for debug printing and not checked for uniqueness -// -// user: 0 for all, or any user ID to listen for messages from a particular -// user. 0 can be id.ZeroUser or id.ZeroID -// messageType: 0 for all, or any message type to listen for messages of that -// type. 0 can be switchboard.AnyType -// newListener: an item channel. -// Do not pass nil to this. -// -// If a message matches multiple listeners, all of them will hear the message. -func (sw *Switchboard) RegisterChannel(name string, user *id.ID, - messageType int32, newListener chan Item) (ListenerID, error) { - // check that the input data is valid - if newListener == nil { - return ListenerID{}, - errors.New("cannot register listener with nil channel") - } - - // generate a chanListener object adhering to the listener interface - cl := newChanListener(newListener, name) - - //register the listener and return the result - return sw.RegisterListener(user, messageType, cl) -} - -// Speak broadcasts a message to the appropriate listeners. -// each is spoken to in their own goroutine -func (sw *Switchboard) Speak(item Item) { - sw.mux.RLock() - defer sw.mux.RUnlock() - - // Matching listeners: include those that match all criteria perfectly, as - // well as those that do not care about certain criteria - matches := sw.matchListeners(item) - - //Execute hear on all matched listeners in a new goroutine - matches.Do(func(i interface{}) { - r := i.(Listener) - go r.Hear(item) - }) - - // print to log if nothing was heard - if matches.Len() == 0 { - jww.ERROR.Printf( - "Message of type %v from user %q didn't match any listeners in"+ - " the map", item.GetMessageType(), item.GetSender()) - } -} - -// Unregister removes the listener with the specified ID so it will no longer -// get called -func (sw *Switchboard) Unregister(listenerID ListenerID) { - sw.mux.Lock() - - sw.id.Remove(listenerID.userID, listenerID.listener) - sw.messageType.Remove(listenerID.messageType, listenerID.listener) - - sw.mux.Unlock() -} - -// finds all listeners who match the items sender or ID, or have those fields -// as generic -func (sw *Switchboard) matchListeners(item Item) *set.Set { - idSet := sw.id.Get(item.GetSender()) - typeSet := sw.messageType.Get(item.GetMessageType()) - return idSet.Intersection(typeSet) -} diff --git a/switchboard/switchboard_test.go b/switchboard/switchboard_test.go deleted file mode 100644 index f408729cb989bd3d0a197b20d2174f1d96e70787..0000000000000000000000000000000000000000 --- a/switchboard/switchboard_test.go +++ /dev/null @@ -1,369 +0,0 @@ -package switchboard - -import ( - "gitlab.com/xx_network/primitives/id" - "strings" - "testing" - "time" -) - -//testing message structure -type Message struct { - Contents []byte - Sender *id.ID - MessageType int32 -} - -func (m *Message) GetSender() *id.ID { - return m.Sender -} - -func (m *Message) GetMessageType() int32 { - return m.MessageType -} - -// tests that New create a correctly structured switchboard -func TestNew(t *testing.T) { - sw := New() - - if sw.id == nil { - t.Errorf("did not create an id map") - } - - if sw.messageType == nil { - t.Errorf("did not create a messageType map") - } -} - -//Tests that register listener handles errors properly -func TestSwitchboard_RegisterListener_Errors(t *testing.T) { - sw := New() - _, err := sw.RegisterListener(nil, 0, &funcListener{}) - - if err == nil { - t.Errorf("A nil userID should have caused an error") - } - - if err != nil && !strings.Contains(err.Error(), "cannot register listener to nil user") { - t.Errorf("A nil userID caused the wrong error") - } - - _, err = sw.RegisterListener(id.NewIdFromUInt(42, id.User, t), 0, nil) - - if err == nil { - t.Errorf("A nil listener should have caused an error") - } - - if err != nil && !strings.Contains(err.Error(), "cannot register nil listener") { - t.Errorf("A nil listener caused the wrong error") - } -} - -//Tests that RegisterListener properly registers the listeners -func TestSwitchboard_RegisterListener(t *testing.T) { - sw := New() - - l := &funcListener{} - - uid := id.NewIdFromUInt(42, id.User, t) - - mt := int32(69) - - lid, err := sw.RegisterListener(uid, mt, l) - - //check the returns - if err != nil { - t.Errorf("Register Listener should not have errored: %s", err) - } - - if lid.messageType != mt { - t.Errorf("ListenerID message type is wrong") - } - - if !lid.userID.Cmp(uid) { - t.Errorf("ListenerID userID is wrong") - } - - if lid.listener != l { - t.Errorf("ListenerID listener is wrong") - } - - //check that the listener is registered in the appropriate location - setID := sw.id.Get(uid) - - if !setID.Has(l) { - t.Errorf("Listener is not registered by ID") - } - - setType := sw.messageType.Get(mt) - - if !setType.Has(l) { - t.Errorf("Listener is not registered by Message Type") - } - -} - -//Tests that register funcListener handles errors properly -func TestSwitchboard_RegisterFunc_Errors(t *testing.T) { - sw := New() - _, err := sw.RegisterFunc("test", nil, 0, func(Item) {}) - - if err == nil { - t.Errorf("A nil userID should have caused an error") - } - - if err != nil && !strings.Contains(err.Error(), "cannot register listener to nil user") { - t.Errorf("A nil userID caused the wrong error") - } - - _, err = sw.RegisterFunc("test", id.NewIdFromUInt(42, id.User, t), 0, nil) - - if err == nil { - t.Errorf("A nil listener func should have caused an error") - } - - if err != nil && !strings.Contains(err.Error(), "cannot register listener with nil func") { - t.Errorf("A nil listener caused func the wrong error") - } -} - -//Tests that RegisterFunc properly registers the listeners -func TestSwitchboard_RegisterFunc(t *testing.T) { - sw := New() - - heard := false - - l := func(Item) { heard = true } - - uid := id.NewIdFromUInt(42, id.User, t) - - mt := int32(69) - - lid, err := sw.RegisterFunc("test", uid, mt, l) - - //check the returns - if err != nil { - t.Errorf("Register Listener should not have errored: %s", err) - } - - if lid.messageType != mt { - t.Errorf("ListenerID message type is wrong") - } - - if !lid.userID.Cmp(uid) { - t.Errorf("ListenerID userID is wrong") - } - - //check that the listener is registered in the appropriate location - setID := sw.id.Get(uid) - - if !setID.Has(lid.listener) { - t.Errorf("Listener is not registered by ID") - } - - setType := sw.messageType.Get(mt) - - if !setType.Has(lid.listener) { - t.Errorf("Listener is not registered by Message Type") - } - - lid.listener.Hear(nil) - if !heard { - t.Errorf("Func listener not registered correctly") - } -} - -//Tests that register chanListener handles errors properly -func TestSwitchboard_RegisterChan_Errors(t *testing.T) { - sw := New() - _, err := sw.RegisterChannel("test", nil, 0, make(chan Item)) - - if err == nil { - t.Errorf("A nil userID should have caused an error") - } - - if err != nil && !strings.Contains(err.Error(), "cannot register listener to nil user") { - t.Errorf("A nil userID caused the wrong error") - } - - _, err = sw.RegisterChannel("test", id.NewIdFromUInt(42, id.User, t), 0, nil) - - if err == nil { - t.Errorf("A nil channel func should have caused an error") - } - - if err != nil && !strings.Contains(err.Error(), "cannot register listener with nil channel") { - t.Errorf("A nil listener caused func the wrong error") - } -} - -//Tests that RegisterChan properly registers the listeners -func TestSwitchboard_RegisterChan(t *testing.T) { - sw := New() - - ch := make(chan Item, 1) - - uid := id.NewIdFromUInt(42, id.User, t) - - mt := int32(69) - - lid, err := sw.RegisterChannel("test", uid, mt, ch) - - //check the returns - if err != nil { - t.Errorf("Register Listener should not have errored: %s", err) - } - - if lid.messageType != mt { - t.Errorf("ListenerID message type is wrong") - } - - if !lid.userID.Cmp(uid) { - t.Errorf("ListenerID userID is wrong") - } - - //check that the listener is registered in the appropriate location - setID := sw.id.Get(uid) - - if !setID.Has(lid.listener) { - t.Errorf("Listener is not registered by ID") - } - - setType := sw.messageType.Get(mt) - - if !setType.Has(lid.listener) { - t.Errorf("Listener is not registered by Message Type") - } - - lid.listener.Hear(nil) - select { - case <-ch: - case <-time.After(5 * time.Millisecond): - t.Errorf("Chan listener not registered correctly") - } -} - -//tests all combinations of hits and misses for speak -func TestSwitchboard_Speak(t *testing.T) { - - uids := []*id.ID{{}, AnyUser(), id.NewIdFromUInt(42, id.User, t), id.NewIdFromUInt(69, id.User, t)} - mts := []int32{AnyType, 42, 69} - - for _, uidReg := range uids { - for _, mtReg := range mts { - - //create the registrations - sw := New() - ch1 := make(chan Item, 1) - ch2 := make(chan Item, 1) - - _, err := sw.RegisterChannel("test", uidReg, mtReg, ch1) - - if err != nil { - t.Errorf("Register Listener should not have errored: %s", err) - } - - _, err = sw.RegisterChannel("test", uidReg, mtReg, ch2) - - if err != nil { - t.Errorf("Register Listener should not have errored: %s", err) - } - - //send every possible message - for _, uid := range uids { - for _, mt := range mts { - if uid.Cmp(&id.ID{}) || mt == AnyType { - continue - } - - m := &Message{ - Contents: []byte{0, 1, 2, 3}, - Sender: uid, - MessageType: mt, - } - - sw.Speak(m) - - shouldHear := (m.Sender.Cmp(uidReg) || - uidReg.Cmp(&id.ID{}) || uidReg.Cmp(AnyUser())) && - (m.MessageType == mtReg || mtReg == AnyType) - - var heard1 bool - - select { - case <-ch1: - heard1 = true - case <-time.After(5 * time.Millisecond): - heard1 = false - } - - if shouldHear != heard1 { - t.Errorf("Correct operation not recorded "+ - "for listener 1: Expected: %v, Occured: %v", - shouldHear, heard1) - } - - var heard2 bool - - select { - case <-ch2: - heard2 = true - case <-time.After(5 * time.Millisecond): - heard2 = false - } - - if shouldHear != heard2 { - t.Errorf("Correct operation not recorded "+ - "for listener 2: Expected: %v, Occured: %v", - shouldHear, heard2) - } - } - } - } - } -} - -//tests that Unregister removes the listener and only the listener -func TestSwitchboard_Unregister(t *testing.T) { - sw := New() - - uid := id.NewIdFromUInt(42, id.User, t) - mt := int32(69) - - l := func(Item) {} - - lid1, err := sw.RegisterFunc("a", uid, mt, l) - if err != nil { - t.Errorf("RegisterFunc should not have errored: %s", err) - } - - lid2, err := sw.RegisterFunc("a", uid, mt, l) - if err != nil { - t.Errorf("RegisterFunc should not have errored: %s", err) - } - - sw.Unregister(lid1) - - //get sets to check - setID := sw.id.Get(uid) - setType := sw.messageType.Get(mt) - - //check that the removed listener is not registered - if setID.Has(lid1.listener) { - t.Errorf("Removed Listener is registered by ID, should not be") - } - - if setType.Has(lid1.listener) { - t.Errorf("Removed Listener not registered by Message Type, " + - "should not be") - } - - //check that the not removed listener is still registered - if !setID.Has(lid2.listener) { - t.Errorf("Remaining Listener is not registered by ID") - } - - if !setType.Has(lid2.listener) { - t.Errorf("Remaining Listener is not registered by Message Type") - } -} diff --git a/utils/gen.go b/utils/gen.go deleted file mode 100644 index 594ac279cfb7d4605d9e58c02c295428085ddacc..0000000000000000000000000000000000000000 --- a/utils/gen.go +++ /dev/null @@ -1,83 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the LICENSE file // -//////////////////////////////////////////////////////////////////////////////////////////// - -// Provides functions for writing a version information file - -package utils - -import ( - "bufio" - "io/ioutil" - "os" - "os/exec" - "strings" - "text/template" - "time" -) - -// Version file generation consumed by higher-level repos -func GenerateVersionFile(version string) { - gitversion := GenerateGitVersion() - deps := ReadGoMod() - - f, err := os.Create("version_vars.go") - if err != nil { - panic(err) - } - - err = packageTemplate.Execute(f, struct { - Timestamp time.Time - GITVER string - DEPENDENCIES string - VERSION string - }{ - Timestamp: time.Now(), - GITVER: gitversion, - DEPENDENCIES: deps, - VERSION: version, - }) - if err != nil { - panic(err) - } - - err = f.Close() - if err != nil { - panic(err) - } -} - -// Determine current Git version information -func GenerateGitVersion() string { - cmd := exec.Command("git", "show", "--oneline") - stdoutStderr, err := cmd.CombinedOutput() - if err != nil { - panic(err) - } - scanner := bufio.NewScanner(strings.NewReader(string(stdoutStderr))) - for scanner.Scan() { - return scanner.Text() - } - return "UNKNOWNVERSION" -} - -// Read in go modules file -func ReadGoMod() string { - r, err := ioutil.ReadFile("go.mod") - if err != nil { - panic(err) - } - return string(r) -} - -// Template for version_vars.go -var packageTemplate = template.Must(template.New("").Parse( - "// Code generated by go generate; DO NOT EDIT.\n" + - "// This file was generated by robots at\n" + - "// {{ .Timestamp }}\n" + - "package cmd\n\n" + - "const GITVERSION = `{{ .GITVER }}`\n" + - "const SEMVER = \"{{ .VERSION }}\"\n" + - "const DEPENDENCIES = `{{ .DEPENDENCIES }}`\n")) diff --git a/utils/utils.go b/utils/utils.go deleted file mode 100644 index 92fbb73d4d7f05c622cc4e4c660d11a190f258dc..0000000000000000000000000000000000000000 --- a/utils/utils.go +++ /dev/null @@ -1,215 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the LICENSE file // -//////////////////////////////////////////////////////////////////////////////////////////// - -// Package utils contains general utility functions used by our system. -// They are generic and perform basic tasks. As of writing, it mostly contains -// file IO functions to make our system be able file IO independent of platform. - -package utils - -import ( - "github.com/mitchellh/go-homedir" - "github.com/pkg/errors" - "io/ioutil" - "os" - "path/filepath" -) - -const ( - // Permissions for new files/directories - FilePerms = os.FileMode(0644) - DirPerms = os.ModePerm -) - -// ExpandPath replaces the '~' character with the user's home directory and -// cleans the path using the following rules: -// 1. Replace multiple Separator elements with a single one. -// 2. Eliminate each . path name element (the current directory). -// 3. Eliminate each inner .. path name element (the parent directory) -// along with the non-.. element that precedes it. -// 4. Eliminate .. elements that begin a rooted path: that is, replace -// "/.." by "/" at the beginning of a path, assuming Separator is '/'. -// 5. The returned path ends in a slash only if it represents a root -// directory. -// 6. Any occurrences of slash are replaced by Separator. -func ExpandPath(path string) (string, error) { - // If the path is empty, then return nothing - if path == "" { - return "", nil - } - - // Replace the '~' character with the user's home directory - path, err := homedir.Expand(path) - if err != nil { - return "", err - } - - // Cleans the path using the rules in the function description - path = filepath.Clean(path) - - return path, nil -} - -// mkdirAll creates all the folders in a path that do not exist. If the path -// already exists, then nothing is done and nil is returned. -func mkdirAll(path string, perm os.FileMode) error { - // Strip file name from the path - dir := filepath.Dir(path) - - // Create the directories - return os.MkdirAll(dir, perm) -} - -// MakeDirs expands and cleans the path and then creates all the folders in a -// path that do not exist. -func MakeDirs(path string, perm os.FileMode) error { - // Expand '~' to user's home directory and clean the path - path, err := ExpandPath(path) - if err != nil { - return err - } - - // Create all directories in path, if they do not already exist - return mkdirAll(path, perm) -} - -// WriteFile creates any directories in the path that do not exists and write -// the specified data to the file. -func WriteFile(path string, data []byte, filePerm, dirPerm os.FileMode) error { - // Expand '~' to user's home directory and clean the path - path, err := ExpandPath(path) - if err != nil { - return err - } - - // Make an directories in the path that do not already exist - err = mkdirAll(path, dirPerm) - if err != nil { - return err - } - - // Write to the specified file - err = ioutil.WriteFile(path, data, filePerm) - return err -} - -// ReadFile expands and cleans the specified path, reads the file, and returns -// its contents. -func ReadFile(path string) ([]byte, error) { - // Expand '~' to user's home directory and clean the path - path, err := ExpandPath(path) - if err != nil { - return nil, err - } - - // Read the file and return the contents - return ioutil.ReadFile(path) -} - -// Exist checks if a file or directory exists at the specified path. -func Exists(path string) bool { - // Check if a file or directory exists at the path - _, exists := exists(path) - - return exists -} - -// FileExists checks if the file at the path exists. It returns false if the -// file does not exist or if it is a directory. -func FileExists(path string) bool { - // Get file description information and if the file exists - info, exists := exists(path) - - isFile := false - if info != nil { - isFile = !info.IsDir() - } - - // Check if the file is a directory - return exists && isFile -} - -// DirExists checks if the directory at the path exists. It returns false if the -// directory does not exist or if it is a file. -func DirExists(path string) bool { - // Get file description information and if the directory exists - info, exists := exists(path) - - // Check if the file is a directory - return exists && info.IsDir() -} - -// exist checks if a file or directory exists at the specified path and also -// returns the file's FileInfo. -func exists(path string) (os.FileInfo, bool) { - // Expand '~' to user's home directory and clean the path - path, err := ExpandPath(path) - if err != nil { - return nil, false - } - - // Get file description information and path errors - info, err := os.Stat(path) - - // Check if a file or directory exists at the path - return info, !os.IsNotExist(err) -} - -// SearchDefaultLocations searches for a file path in a default directory in -// a number of hard-coded paths, including the user's home folder and /etc/. If -// the file is found, its full path is returned. Otherwise, the path is blank -// and an error is returned. -// -// Note that defaultDirectory MUST be a relative path. By default, when checking -// the home directory a "." is prepended the to defaultDirectory. -func SearchDefaultLocations(defaultFileName string, defaultDirectory string) (string, error) { - // Get the user's home directory - defaultDirs, err := getDefaultSearchDirs(defaultDirectory) - if err != nil { - return "", errors.Errorf("Could not get home directory: %+v", err) - } - - // Search the directories for the file - for _, dir := range defaultDirs { - // Format the path and check for errors - path := dir + "/" + defaultFileName - foundFilePath, err := ExpandPath(path) - if err != nil { - return "", errors.Errorf("Error expanding path %s: %v", path, err) - } - - // If the file exists, return its path - if FileExists(foundFilePath) { - return foundFilePath, nil - } - } - - return "", errors.Errorf("Could not find %s in any of the directories: %v", - defaultFileName, defaultDirs) -} - -// getDefaultSearchDirs retrieves the list of default directories to search for -// configuration files in. Note that defaultDirectory MUST be a relative path. -func getDefaultSearchDirs(defaultDirectory string) ([]string, error) { - var searchDirs []string - - // Get the user's home directory - home, err := homedir.Dir() - if err != nil { - return nil, errors.Errorf("Could not get home directory: %+v", err) - } - - // Add the home directory to the search - searchDirs = append(searchDirs, filepath.Clean(home+"/."+defaultDirectory+"/")) - - // Add /opt/ to the search - searchDirs = append(searchDirs, filepath.Clean("/opt/"+defaultDirectory+"/")) - - // Add /etc/ to the search - searchDirs = append(searchDirs, filepath.Clean("/etc/"+defaultDirectory+"/")) - - return searchDirs, nil -} diff --git a/utils/utils_test.go b/utils/utils_test.go deleted file mode 100644 index d2fbc105ac2a688a81f7c3b74436a33a28688cb3..0000000000000000000000000000000000000000 --- a/utils/utils_test.go +++ /dev/null @@ -1,622 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the LICENSE file // -//////////////////////////////////////////////////////////////////////////////////////////// - -// Contains utility operations used throughout the repo - -package utils - -import ( - "bytes" - "errors" - "fmt" - "github.com/mitchellh/go-homedir" - "os" - "path/filepath" - "reflect" - "testing" - "time" -) - -const sep = string(filepath.Separator) - -// Tests that ExpandPath() properly expands the the "~" character. -func TestExpandPath_Happy(t *testing.T) { - path := sep + "test123" + sep + "test.txt" - testPath := "~" + path - homeDir, _ := homedir.Dir() - expectPath := homeDir + path - newPath, err := ExpandPath(testPath) - - if err != nil { - t.Errorf("ExpandPath() produced an unexpected error: %v", err) - } - - if newPath != expectPath { - t.Errorf("ExpandPath() did not correctly expand the \"~\" character in the path %s"+ - "\n\texpected: %s\n\treceived: %s", testPath, expectPath, newPath) - } -} - -// Tests that the path is unchanged by ExpandPath(). -func TestExpandPath_Default(t *testing.T) { - path := sep + "test123" + sep + "test.txt" - newPath, err := ExpandPath(path) - - if err != nil { - t.Errorf("ExpandPath() produced an unexpected error: %v", err) - } - - if newPath != path { - t.Errorf("ExpandPath() unexpectedly modified the path %s"+ - "\n\texpected: %s\n\treceived: %s", path, path, newPath) - } -} - -// Tests that for an empty path, ExpandPath() returns an empty string. -func TestExpandPath_EmptyPath(t *testing.T) { - path := "" - newPath, err := ExpandPath(path) - - if err != nil { - t.Errorf("ExpandPath() produced an unexpected error: %v", err) - } - - if newPath != path { - t.Errorf("ExpandPath() unexpectedly modified the path %s"+ - "\n\texpected: %s\n\treceived: %s", path, path, newPath) - } -} - -// Tests that ExpandPath() returns an error for an invalid path. -func TestExpandPath_PathError(t *testing.T) { - path := "~a/test/test.txt" - _, err := ExpandPath(path) - - if err == nil { - t.Errorf("ExpandPath() did not produce error when expected:"+ - "\n\texpected: %v\n\treceived: %v", - errors.New("cannot expand user-specific home dir"), err) - } -} - -// Tests that mkdirAll() creates the directories in the specified path (includes -// the file name) by checking if the directory structure exists. -func TestMkdirAll(t *testing.T) { - path := "temp/temp2/test.txt" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := mkdirAll(path, DirPerms) - if err != nil { - t.Errorf("mkdirAll() produced an unexpected error: %v", err) - } - - if _, err = os.Stat(filepath.Dir(path)); os.IsExist(err) { - t.Errorf("mkdirAll() did not correctly make the directories:"+ - "\n\t%s", path) - } -} - -// Tests that mkdirAll() creates the directories in the specified path (does not -// include the file name) by checking if the directory structure exists. -func TestMkdirAll_DirectoryPath(t *testing.T) { - path := "temp/temp2/" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := mkdirAll(path, DirPerms) - if err != nil { - t.Errorf("mkdirAll() produced an unexpected error: %v", err) - } - - if _, err = os.Stat(filepath.Dir(path)); os.IsExist(err) { - t.Errorf("mkdirAll() did not correctly make the directories:"+ - "\n\t%s", path) - } -} - -// Tests that mkdirAll() does nothing for an empty path. -func TestMkdirAll_EmptyPath(t *testing.T) { - path := "" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := mkdirAll(path, DirPerms) - if err != nil { - t.Errorf("mkdirAll() produced an unexpected error: %v", err) - } - - if _, err = os.Stat(filepath.Dir(path)); os.IsExist(err) { - t.Errorf("mkdirAll() did not correctly make the directories:"+ - "\n\t%s", path) - } -} - -// Tests MakeDirs() by checking if the directory structure exists. -func TestMakeDirs(t *testing.T) { - path := "temp/temp2/test.txt" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := MakeDirs(path, DirPerms) - if err != nil { - t.Errorf("MakeDirs() produced an unexpected error: %v", err) - } - - if _, err = os.Stat(filepath.Dir(path)); os.IsExist(err) { - t.Errorf("MakeDirs() did not correctly make the directories:"+ - "\n\t%s", path) - } -} - -// Tests that MakeDirs() produces an error on an invalid path. -func TestMakeDirs_PathError(t *testing.T) { - path := "~a/test/test.txt" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := MakeDirs(path, DirPerms) - if err == nil { - t.Errorf("MakeDirs() did not produce error when expected:"+ - "\n\texpected: %v\n\treceived: %v", - errors.New("cannot expand user-specific home dir"), err) - } -} - -// Tests WriteFile() by checking if the directory structure and the -// file exists. -func TestWriteFile(t *testing.T) { - dirPath := "temp/temp2" - path := dirPath + "/test.txt" - data := []byte("test data") - - // Delete the test file at the end - defer func() { - err := os.RemoveAll("temp/") - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", "temp/", err) - } - }() - - err := os.MkdirAll(dirPath, os.ModePerm) - if err != nil { - t.Errorf("MkdirAll() produced an unexpected error: %v", err) - } - - err = WriteFile(path, data, DirPerms, FilePerms) - if err != nil { - t.Errorf("WriteFile() produced an unexpected error: %v", err) - } - - if _, err = os.Stat(path); os.IsExist(err) { - t.Errorf("WriteFile() did not correctly make the directories:"+ - "\n\t%s", path) - } -} - -// Tests that WriteFile() returns an error with a malformed path. -func TestWriteFile_PathError(t *testing.T) { - path := "~a/temp/temp2/test.txt" - data := []byte("test data") - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := WriteFile(path, data, DirPerms, FilePerms) - if err == nil { - t.Errorf("WriteFile() did not produce error when expected:"+ - "\n\texpected: %v\n\treceived: %v", - errors.New("cannot expand user-specific home dir"), err) - } -} - -// Tests that ReadFile() properly reads the contents of a file created by -// WriteFile(). -func TestReadFile(t *testing.T) { - path := "test.txt" - data := []byte("Test string.") - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := WriteFile(path, data, FilePerms, FilePerms) - if err != nil { - t.Errorf("WriteFile() produced an unexpected error: %v", err) - } - - testData, err := ReadFile(path) - if err != nil { - t.Errorf("ReadFile() produced an unexpected error: %v", err) - } - - if !bytes.Equal(testData, data) { - t.Errorf("ReadFile() did not return the correct data from the file %s"+ - "\n\texpected: %s\n\treceived: %s", path, data, testData) - } -} - -// Tests that ReadFile() returns an error with a malformed path. -func TestReadFile_PathError(t *testing.T) { - path := "~a/temp/temp2/test.txt" - _, err := ReadFile(path) - - if err == nil { - t.Errorf("ReadFile() did not produce error when expected:"+ - "\n\texpected: %v\n\treceived: %v", - errors.New("cannot expand user-specific home dir"), err) - } -} - -// Tests that TestExist() correctly finds a file that exists. -func TestExist(t *testing.T) { - path := "test.txt" - data := []byte("Test string.") - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := WriteFile(path, data, FilePerms, FilePerms) - if err != nil { - t.Errorf("WriteFile() produced an unexpected error: %v", err) - } - - exists := Exists(path) - if !exists { - t.Errorf("Exists() did not find a file that should exist") - } -} - -// Tests that TestExist() correctly finds a directory that exists. -func TestExist_Dir(t *testing.T) { - path := "a/" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := MakeDirs(path+"d", DirPerms) - if err != nil { - t.Errorf("MakeDirs() produced an unexpected error: %v", err) - } - - exists := Exists(path) - if !exists { - t.Errorf("Exists() did not find a directory that should exist") - } -} - -// Tests that TestExist() returns false when a file does not exist. -func TestExist_NoFileError(t *testing.T) { - path := "test.txt" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - exists := Exists(path) - if exists { - t.Errorf("Exists() found a file when one does not exist") - } -} - -// Tests that FileExists() correctly finds a file that exists. -func TestFileExists(t *testing.T) { - path := "test.txt" - data := []byte("Test string.") - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := WriteFile(path, data, FilePerms, FilePerms) - if err != nil { - t.Errorf("WriteFile() produced an unexpected error: %v", err) - } - - exists := FileExists(path) - if !exists { - t.Errorf("FileExists() did not find a file that should exist") - } -} - -// Tests that FileExists() false when the file is a directory. -func TestFileExists_DirError(t *testing.T) { - path := "a/d" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := MakeDirs(path, DirPerms) - if err != nil { - t.Errorf("MakeDirs() produced an unexpected error: %v", err) - } - - exists := FileExists(path) - if exists { - t.Errorf("FileExists() found a directory when it was looking for a file") - } -} - -// Tests that FileExists() returns false when a file does not exist. -func TestFileExists_NoFileError(t *testing.T) { - path := "test.txt" - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - exists := FileExists(path) - if exists { - t.Errorf("FileExists() found a file when one does not exist") - } -} - -// Tests that DirExists() correctly finds a directory that exists. -func TestDirExists(t *testing.T) { - path := "a/" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := MakeDirs(path+"d", DirPerms) - if err != nil { - t.Errorf("MakeDirs() produced an unexpected error: %v", err) - } - - exists := DirExists(path) - if !exists { - t.Errorf("DirExists() did not find a directory that should exist") - } -} - -// Tests that DirExists() false when the file is a directory. -func TestDirExists_FileError(t *testing.T) { - path := "test.txt" - data := []byte("Test string.") - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := WriteFile(path, data, FilePerms, FilePerms) - if err != nil { - t.Errorf("WriteFile() produced an unexpected error: %v", err) - } - - exists := DirExists(path) - if exists { - t.Errorf("DirExists() found a file when it was looking for a directory") - } -} - -// Tests that DirExists() returns false when a file does not exist. -func TestDirExists_NoDirError(t *testing.T) { - path := "a/b/c/" - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - exists := FileExists(path) - if exists { - t.Errorf("DirExists() found a directroy when one does not exist") - } -} - -// Tests that Test_exist() correctly finds a file that exists and returns the -// correct FileInfo. -func Test_exist(t *testing.T) { - path := "test.txt" - data := []byte("Test string.") - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", path, err) - } - }() - - err := WriteFile(path, data, FilePerms, FilePerms) - if err != nil { - t.Errorf("WriteFile() produced an unexpected error: %v", err) - } - - info, exists := exists(path) - expectedInfo, err := os.Stat(path) - - if !exists && err != nil { - t.Errorf("exists() did not find a file that should exist:"+ - "\n\t%v", err) - } else if !exists { - t.Errorf("exists() did not find a file that should exist") - } - - if !reflect.DeepEqual(info, expectedInfo) { - t.Errorf("exists() did not return the expected FileInfo."+ - "\n\texpected: %v\n\treceived: %v", expectedInfo, info) - } -} - -// Tests that Test_exist() returns false when a file does not exist. and returns -// a nil FileInfo. -func Test_exist_NoFileError(t *testing.T) { - path := "test.txt" - - info, exists := exists(path) - - if exists { - t.Errorf("exists() found a file when one does not exist") - } - - if info != nil { - t.Errorf("exists() unexpectedly returned a non-nil FileInfo."+ - "\n\texpected: %v\n\treceived: %v", nil, info) - } -} - -// Tests that SearchDefaultLocations() finds the specified file in the user's -// home directory -func TestSearchDefaultLocations(t *testing.T) { - testDir := fmt.Sprintf("testDir-%d/", time.Now().Nanosecond()) - testFile := fmt.Sprintf("testFile-%d.txt", time.Now().Nanosecond()) - testPath := testDir + testFile - expectedPath, err := ExpandPath("~/." + testPath) - if err != nil { - t.Fatalf("ExpandPath() failed to exapnd the path %s: %+v", testPath, err) - } - expectedDir, err := ExpandPath("~/" + testDir) - if err != nil { - t.Fatalf("ExpandPath() failed to exapnd the path %s: %+v", testPath, err) - } - - // Delete the test file at the end - defer func() { - err := os.RemoveAll(expectedDir) - if err != nil { - t.Fatalf("Error deleting test file %#v:\n%v", expectedDir, err) - } - }() - - err = WriteFile(expectedPath, []byte("TEST"), FilePerms, DirPerms) - if err != nil { - t.Fatalf("WriteFile() failed to create file %s: %+v", testPath, err) - } - - foundPath, err := SearchDefaultLocations(testFile, testDir) - if err != nil { - t.Errorf("SearchDefaultLocations() produced an unexpected error: %+v", - err) - } - - if foundPath != expectedPath { - t.Errorf("SearchDefaultLocations() did not find the correct file."+ - "\n\texpected: %s\n\treceived: %s", expectedPath, foundPath) - } -} - -// Tests that SearchDefaultLocations() return an error when the file does not -// exist. -func TestSearchDefaultLocations_NotFoundError(t *testing.T) { - testDir := fmt.Sprintf(".testDir-%d/", time.Now().Nanosecond()) - testFile := fmt.Sprintf("testFile-%d.txt", time.Now().Nanosecond()) - - foundPath, err := SearchDefaultLocations(testFile, testDir) - if err == nil { - t.Errorf("SearchDefaultLocations() did not error when expected.") - } - - if foundPath != "" { - t.Errorf("SearchDefaultLocations() did not return an empty path on error."+ - "\n\texpected: %s\n\treceived: %s", "", foundPath) - } -} - -// Tests that getDefaultSearchDirs generates the correct list of default paths. -func TestGetDefaultSearchDirs(t *testing.T) { - testDir := "xxnetwork" - expectedDir0, err := ExpandPath("~/." + testDir + "/") - expectedDir1, err := ExpandPath("/opt/" + testDir + "/") - expectedDir2, err := ExpandPath("/etc/" + testDir + "/") - - testDirs, err := getDefaultSearchDirs(testDir) - if err != nil { - t.Errorf("getDefaultSearchDirs() produced an unxpected error: %+v", err) - } - - if testDirs[0] != expectedDir0 { - t.Errorf("getDefaultSearchDirs() did not return the correct path for "+ - "home.\n\texpected: %s\n\treceived: %s", expectedDir0, testDirs[0]) - } - - if testDirs[1] != expectedDir1 { - t.Errorf("getDefaultSearchDirs() did not return the correct path for "+ - "/etc/.\n\texpected: %s\n\treceived: %s", expectedDir1, testDirs[1]) - } - - if testDirs[2] != expectedDir2 { - t.Errorf("getDefaultSearchDirs() did not return the correct path for "+ - "/etc/.\n\texpected: %s\n\treceived: %s", expectedDir2, testDirs[2]) - } -}