From f188c7de0c845e4e271664225be89eab5ca2bf18 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 2 Apr 2020 00:26:53 +0100 Subject: [PATCH 1/8] snow: Add test coverage of ConcurrentRepolls == 0 --- snow/consensus/snowball/parameters_test.go | 37 +++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/snow/consensus/snowball/parameters_test.go b/snow/consensus/snowball/parameters_test.go index 6860725..8ad16dc 100644 --- a/snow/consensus/snowball/parameters_test.go +++ b/snow/consensus/snowball/parameters_test.go @@ -4,6 +4,7 @@ package snowball import ( + "fmt" "testing" ) @@ -78,16 +79,28 @@ func TestParametersInvalidBetaRogue(t *testing.T) { } func TestParametersInvalidConcurrentRepolls(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 2, - } - - if err := p.Valid(); err == nil { - t.Fatalf("Should have failed due to invalid concurrent repolls") - } + tests := []Parameters{ + Parameters{ + K: 1, + Alpha: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 2, + }, + Parameters{ + K: 1, + Alpha: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 0, + }, + } + for _, p := range tests { + label := fmt.Sprintf("ConcurrentRepolls=%d", p.ConcurrentRepolls) + t.Run(label, func(t *testing.T) { + if err := p.Valid(); err == nil { + t.Error("Should have failed due to invalid concurrent repolls") + } + }) + } } - From 599756feb8052eda9ac8c50b0e35e441a6ef56c0 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 2 Apr 2020 22:31:53 +0100 Subject: [PATCH 2/8] utils: Add test for IPDesc.Equal --- utils/ip_test.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 utils/ip_test.go diff --git a/utils/ip_test.go b/utils/ip_test.go new file mode 100644 index 0000000..a9ab956 --- /dev/null +++ b/utils/ip_test.go @@ -0,0 +1,64 @@ +// (c) 2020, Alex Willmer. All rights reserved. +// See the file LICENSE for licensing terms. + +package utils + +import ( + "fmt" + "net" + "testing" +) + +func TestIPDescEqual(t *testing.T) { + tests := []struct { + ipDesc1 IPDesc + ipDesc2 IPDesc + result bool + }{ + // Expected equal + { + IPDesc{net.ParseIP("127.0.0.1"), 0}, + IPDesc{net.ParseIP("127.0.0.1"), 0}, + true, + }, { + IPDesc{net.ParseIP("::1"), 0}, + IPDesc{net.ParseIP("::1"), 0}, + true, + }, { + IPDesc{net.ParseIP("127.0.0.1"), 0}, + IPDesc{net.ParseIP("::ffff:127.0.0.1"), 0}, + true, + }, + + // Expected unequal + { + IPDesc{net.ParseIP("127.0.0.1"), 0}, + IPDesc{net.ParseIP("1.2.3.4"), 0}, + false, + }, { + IPDesc{net.ParseIP("::1"), 0}, + IPDesc{net.ParseIP("2001::1"), 0}, + false, + }, { + IPDesc{net.ParseIP("127.0.0.1"), 0}, + IPDesc{net.ParseIP("127.0.0.1"), 1}, + false, + }, + } + for i, tt := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + if tt.ipDesc1.IP == nil { + t.Error("ipDesc1 nil") + } else if tt.ipDesc2.IP == nil { + t.Error("ipDesc2 nil") + } + result := tt.ipDesc1.Equal(tt.ipDesc2) + if result && result != tt.result { + t.Error("Expected IPDesc to be equal, but they were not") + } + if !result && result != tt.result { + t.Error("Expected IPDesc to be unequal, but they were equal") + } + }) + } +} From 631615d90741adfbf2757702c9cee7a96097d3a6 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 2 Apr 2020 22:33:38 +0100 Subject: [PATCH 3/8] utils: Add test for IPDesc.PortString --- utils/ip_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/utils/ip_test.go b/utils/ip_test.go index a9ab956..04cb9e6 100644 --- a/utils/ip_test.go +++ b/utils/ip_test.go @@ -62,3 +62,22 @@ func TestIPDescEqual(t *testing.T) { }) } } + +func TestIPDescPortString(t *testing.T) { + tests := []struct { + ipDesc IPDesc + result string + }{ + {IPDesc{net.ParseIP("127.0.0.1"), 0}, ":0"}, + {IPDesc{net.ParseIP("::1"), 42}, ":42"}, + {IPDesc{net.ParseIP("::ffff:127.0.0.1"), 65535}, ":65535"}, + {IPDesc{net.IP{}, 1234}, ":1234"}, + } + for _, tt := range tests { + t.Run(tt.result, func(t *testing.T) { + if result := tt.ipDesc.PortString(); result != tt.result { + t.Errorf("Expected %q, got %q", tt.result, result) + } + }) + } +} From ab33249844f77515c923c55eec798516623ee39c Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 2 Apr 2020 22:34:46 +0100 Subject: [PATCH 4/8] utils: Add test for IPDesc.String --- utils/ip_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/utils/ip_test.go b/utils/ip_test.go index 04cb9e6..a950a5a 100644 --- a/utils/ip_test.go +++ b/utils/ip_test.go @@ -81,3 +81,22 @@ func TestIPDescPortString(t *testing.T) { }) } } + +func TestIPDescString(t *testing.T) { + tests := []struct { + ipDesc IPDesc + result string + }{ + {IPDesc{net.ParseIP("127.0.0.1"), 0}, "127.0.0.1:0"}, + {IPDesc{net.ParseIP("::1"), 42}, "::1:42"}, + {IPDesc{net.ParseIP("::ffff:127.0.0.1"), 65535}, "127.0.0.1:65535"}, + {IPDesc{net.IP{}, 1234}, ":1234"}, + } + for _, tt := range tests { + t.Run(tt.result, func(t *testing.T) { + if result := tt.ipDesc.String(); result != tt.result { + t.Errorf("Expected %q, got %q", tt.result, result) + } + }) + } +} From 02d59da7ab425607501f4d3f26d12cb4425a4a3c Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 2 Apr 2020 22:44:43 +0100 Subject: [PATCH 5/8] utils: Add tests for ToIPDesc(), fix IPv6 handling --- utils/ip.go | 13 ++++++------ utils/ip_test.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/utils/ip.go b/utils/ip.go index cca055d..8a8985d 100644 --- a/utils/ip.go +++ b/utils/ip.go @@ -8,7 +8,6 @@ import ( "fmt" "net" "strconv" - "strings" ) var ( @@ -33,21 +32,21 @@ func (ipDesc IPDesc) PortString() string { } func (ipDesc IPDesc) String() string { - return fmt.Sprintf("%s%s", ipDesc.IP, ipDesc.PortString()) + return net.JoinHostPort(ipDesc.IP.String(), fmt.Sprintf("%d", ipDesc.Port)) } // ToIPDesc ... -// TODO: this was kinda hacked together, it should be verified. func ToIPDesc(str string) (IPDesc, error) { - parts := strings.Split(str, ":") - if len(parts) != 2 { + host, portStr, err := net.SplitHostPort(str) + if err != nil { return IPDesc{}, errBadIP } - port, err := strconv.ParseUint(parts[1], 10 /*=base*/, 16 /*=size*/) + port, err := strconv.ParseUint(portStr, 10 /*=base*/, 16 /*=size*/) if err != nil { + // TODO: Should this return a locally defined error? (e.g. errBadPort) return IPDesc{}, err } - ip := net.ParseIP(parts[0]) + ip := net.ParseIP(host) if ip == nil { return IPDesc{}, errBadIP } diff --git a/utils/ip_test.go b/utils/ip_test.go index a950a5a..179014f 100644 --- a/utils/ip_test.go +++ b/utils/ip_test.go @@ -88,7 +88,7 @@ func TestIPDescString(t *testing.T) { result string }{ {IPDesc{net.ParseIP("127.0.0.1"), 0}, "127.0.0.1:0"}, - {IPDesc{net.ParseIP("::1"), 42}, "::1:42"}, + {IPDesc{net.ParseIP("::1"), 42}, "[::1]:42"}, {IPDesc{net.ParseIP("::ffff:127.0.0.1"), 65535}, "127.0.0.1:65535"}, {IPDesc{net.IP{}, 1234}, ":1234"}, } @@ -100,3 +100,52 @@ func TestIPDescString(t *testing.T) { }) } } + +func TestToIPDescError(t *testing.T) { + tests := []struct { + in string + out IPDesc + }{ + {"", IPDesc{}}, + {":", IPDesc{}}, + {"abc:", IPDesc{}}, + {":abc", IPDesc{}}, + {"abc:abc", IPDesc{}}, + {"127.0.0.1:", IPDesc{}}, + {":1", IPDesc{}}, + {"::1", IPDesc{}}, + {"::1:42", IPDesc{}}, + } + for _, tt := range tests { + t.Run(tt.in, func(t *testing.T) { + result, err := ToIPDesc(tt.in) + if err == nil { + t.Errorf("Unexpected success") + } + if !tt.out.Equal(result) { + t.Errorf("Expected %v, got %v", tt.out, result) + } + }) + } +} + +func TestToIPDesc(t *testing.T) { + tests := []struct { + in string + out IPDesc + }{ + {"127.0.0.1:42", IPDesc{net.ParseIP("127.0.0.1"), 42}}, + {"[::1]:42", IPDesc{net.ParseIP("::1"), 42}}, + } + for _, tt := range tests { + t.Run(tt.in, func(t *testing.T) { + result, err := ToIPDesc(tt.in) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + if !tt.out.Equal(result) { + t.Errorf("Expected %#v, got %#v", tt.out, result) + } + }) + } +} From 0f94bdf24b7f621f954db8aa78241b131a275c33 Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Fri, 3 Apr 2020 01:00:19 -0400 Subject: [PATCH 6/8] Removed broken + invalid test --- vms/spdagvm/vm_test.go | 85 ------------------------------------------ 1 file changed, 85 deletions(-) diff --git a/vms/spdagvm/vm_test.go b/vms/spdagvm/vm_test.go index 03a3b8e..75e8d1c 100644 --- a/vms/spdagvm/vm_test.go +++ b/vms/spdagvm/vm_test.go @@ -4,7 +4,6 @@ package spdagvm import ( - "math" "testing" "github.com/ava-labs/gecko/database/memdb" @@ -724,87 +723,3 @@ func TestIssuePendingDependency(t *testing.T) { ctx.Lock.Unlock() } - -// Ensure that an error is returned if an address will have more than -// math.MaxUint64 NanoAva -func TestTxOutputOverflow(t *testing.T) { - // Modify the genesis tx so the address controlled by [keys[0]] - // has math.MaxUint64 NanoAva - initBalances := map[string]uint64{ - keys[0].PublicKey().Address().String(): math.MaxUint64, - keys[1].PublicKey().Address().String(): defaultInitBalance, - keys[2].PublicKey().Address().String(): defaultInitBalance, - } - genesisTx := GenesisTx(initBalances) - - // Initialize vm - vmDB := memdb.New() - msgChan := make(chan common.Message, 1) - ctx.Lock.Lock() - vm := &VM{} - vm.Initialize(ctx, vmDB, genesisTx.Bytes(), msgChan, nil) - vm.batchTimeout = 0 - - // Create a new private key - testPK, err := vm.CreateKey() - if err != nil { - t.Fatalf("CreateKey(): %s", err) - } - // Get the address controlled by the new private key - testAddr, err := vm.GetAddress(testPK) - if err != nil { - t.Fatalf("GetAddress(%q): %s", testPK, err) - } - - // Get string repr. of keys[0] - cb58 := formatting.CB58{Bytes: keys[0].Bytes()} - privKey0 := cb58.String() - - // Send [math.MaxUint64 - txFeeTest] NanoAva from [privKey0] to [testAddr] - _, err = vm.Send(math.MaxUint64-txFeeTest, "", testAddr, []string{privKey0}) - if err != nil { - t.Fatalf("Send(%d,%q,%q,%v): failed with error - %s", uint64(math.MaxUint64-txFeeTest), "", testAddr, []string{privKey0}, err) - } - ctx.Lock.Unlock() - - if msg := <-msgChan; msg != common.PendingTxs { - t.Fatalf("Wrong message") - } - - // Accept the transaction - ctx.Lock.Lock() - if txs := vm.PendingTxs(); len(txs) != 1 { - t.Fatalf("PendingTxs(): returned wrong number of transactions - expected: %d; returned: %d", 1, len(txs)) - } else { - txs[0].Accept() - } - if txs := vm.PendingTxs(); len(txs) != 0 { - t.Fatalf("PendingTxs(): there should not have been any pending transactions") - } - - // Ensure that [testAddr] has balance [math.MaxUint64 - txFeeTest] - if testbal, err := vm.GetBalance(testAddr, ""); err != nil { - t.Fatalf("GetBalance(%q): %s", testAddr, err) - } else if testbal != math.MaxUint64-txFeeTest { - t.Fatalf("GetBalance(%q,%q): Balance Not Equal(%d,%d)", testAddr, "", uint64(math.MaxUint64-txFeeTest), testbal) - } - - // Ensure that the address controlled by [keys[0]] has balance 0 - if testbal, err := vm.GetBalance(keys[0].PublicKey().Address().String(), ""); err != nil { - t.Fatalf("GetBalance(%q): %s", keys[0].PublicKey().Address().String(), err) - } else if testbal != 0 { - // Balance of new address should be 0 - t.Fatalf("GetBalance(%q,%q): Balance Not Equal(%d,%d)", keys[0].PublicKey().Address().String(), "", 0, testbal) - } - - cb58.Bytes = keys[1].Bytes() - privKey1 := cb58.String() - - // Send [2*txFeeTest+1] NanoAva from [key1Str] to [testAddr] - // Should overflow [testAddr] by 1 - _, err = vm.Send(2*txFeeTest+1, "", testAddr, []string{privKey1}) - if err == errOutputOverflow { - t.Fatalf("Expected output to overflow but it did not") - } - ctx.Lock.Unlock() -} From 5442ea365e3ef2c2084f86877ceb07fd3d77cce2 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sat, 4 Apr 2020 13:55:02 +0100 Subject: [PATCH 7/8] snow: Add test for validators.Set.Set --- snow/validators/set_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/snow/validators/set_test.go b/snow/validators/set_test.go index 5ad381c..0518555 100644 --- a/snow/validators/set_test.go +++ b/snow/validators/set_test.go @@ -10,6 +10,31 @@ import ( "github.com/ava-labs/gecko/ids" ) +func TestSetSet(t *testing.T) { + vdr0 := NewValidator(ids.ShortEmpty, 1) + vdr1_0 := NewValidator(ids.NewShortID([20]byte{0xFF}), 1) + // Should replace vdr1_0, because later additions replace earlier ones + vdr1_1 := NewValidator(ids.NewShortID([20]byte{0xFF}), math.MaxInt64-1) + // Should be discarded, because it has a weight of 0 + vdr2 := NewValidator(ids.NewShortID([20]byte{0xAA}), 0) + + s := NewSet() + s.Set([]Validator{vdr0, vdr1_0, vdr1_1, vdr2}) + + if !s.Contains(vdr0.ID()) { + t.Fatal("Should have contained vdr0", vdr0.ID()) + } + if !s.Contains(vdr1_0.ID()) { + t.Fatal("Should have contained vdr1", vdr1_0.ID()) + } + if sampled := s.Sample(1); !sampled[0].ID().Equals(vdr1_0.ID()) { + t.Fatal("Should have sampled vdr1") + } + if len := s.Len(); len != 2 { + t.Fatalf("Got size %d, expected 2", len) + } +} + func TestSamplerSample(t *testing.T) { vdr0 := GenerateRandomValidator(1) vdr1 := GenerateRandomValidator(math.MaxInt64 - 1) From cf69425775ee983f91dcfe6afa945c1e60d697dd Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 5 Apr 2020 00:55:12 +0100 Subject: [PATCH 8/8] ids: Add tests for Aliaser Tests cover Aliaser.Lookup, Aliaser.Aliases, Aliaser.PrimaryAlias, and Aliaser.Alias. --- ids/aliases_test.go | 113 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 ids/aliases_test.go diff --git a/ids/aliases_test.go b/ids/aliases_test.go new file mode 100644 index 0000000..8f8cb31 --- /dev/null +++ b/ids/aliases_test.go @@ -0,0 +1,113 @@ +// (c) 2020, Alex Willmer. All rights reserved. +// See the file LICENSE for licensing terms. + +package ids + +import ( + "reflect" + "testing" +) + +func TestAliaserLookupError(t *testing.T) { + emptyAliaser := Aliaser{} + emptyAliaser.Initialize() + tests := []struct { + label string + aliaser Aliaser + alias string + res ID + }{ + {"Unitialized", Aliaser{}, "Batwoman", ID{}}, + {"Empty", emptyAliaser, "Batman", ID{}}, + } + for _, tt := range tests { + t.Run(tt.label, func(t *testing.T) { + res, err := tt.aliaser.Lookup(tt.alias) + if !tt.res.Equals(res) { + t.Errorf("Got %v, expected %v", res, tt.res) + } + if err == nil { + t.Error("Expected an error due to missing alias") + } + }) + } +} + +func TestAliaserLookup(t *testing.T) { + id := NewID([32]byte{'K', 'a', 't', 'e', ' ', 'K', 'a', 'n', 'e'}) + aliaser := Aliaser{} + aliaser.Initialize() + aliaser.Alias(id, "Batwoman") + + res, err := aliaser.Lookup("Batwoman") + if err != nil { + t.Fatalf("Unexpected error %q", err) + } + if !id.Equals(res) { + t.Fatalf("Got %v, expected %v", res, id) + } +} + +func TestAliaserAliasesEmpty(t *testing.T) { + id := NewID([32]byte{'J', 'a', 'm', 'e', 's', ' ', 'G', 'o', 'r', 'd', 'o', 'n'}) + aliaser := Aliaser{} + aliaser.Initialize() + + aliases := aliaser.Aliases(id) + if len(aliases) != 0 { + t.Fatalf("Unexpected aliases %#v", aliases) + } +} + +func TestAliaserAliases(t *testing.T) { + id := NewID([32]byte{'B', 'r', 'u', 'c', 'e', ' ', 'W', 'a', 'y', 'n', 'e'}) + aliaser := Aliaser{} + aliaser.Initialize() + aliaser.Alias(id, "Batman") + aliaser.Alias(id, "Dark Knight") + + aliases := aliaser.Aliases(id) + expected := []string{"Batman", "Dark Knight"} + if !reflect.DeepEqual(aliases, expected) { + t.Fatalf("Got %v, expected %v", aliases, expected) + } +} + +func TestAliaserPrimaryAlias(t *testing.T) { + id1 := NewID([32]byte{'J', 'a', 'm', 'e', 's', ' ', 'G', 'o', 'r', 'd', 'o', 'n'}) + id2 := NewID([32]byte{'B', 'r', 'u', 'c', 'e', ' ', 'W', 'a', 'y', 'n', 'e'}) + aliaser := Aliaser{} + aliaser.Initialize() + aliaser.Alias(id2, "Batman") + aliaser.Alias(id2, "Dark Knight") + + res, err := aliaser.PrimaryAlias(id1) + if res != "" { + t.Fatalf("Unexpected alias for %v", id1) + } + if err == nil { + t.Fatal("Expected an error given an id with no aliases") + } + + res, err = aliaser.PrimaryAlias(id2) + expected := "Batman" + if res != expected { + t.Fatalf("Got %v, expected %v", res, expected) + } + if err != nil { + t.Fatalf("Unexpected error %v", err) + } +} + +func TestAliaserAliasClash(t *testing.T) { + id1 := NewID([32]byte{'B', 'r', 'u', 'c', 'e', ' ', 'W', 'a', 'y', 'n', 'e'}) + id2 := NewID([32]byte{'D', 'i', 'c', 'k', ' ', 'G', 'r', 'a', 'y', 's', 'o', 'n'}) + aliaser := Aliaser{} + aliaser.Initialize() + aliaser.Alias(id1, "Batman") + + err := aliaser.Alias(id2, "Batman") + if err == nil { + t.Fatalf("Expected an error, due to an existing alias") + } +}