From 668698584d8d8ac977b3343f0c174f6291e89878 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 30 Oct 2017 12:48:51 -0500 Subject: [PATCH 01/12] [autofile] test GroupReader more extensively (Refs #69) --- autofile/group.go | 10 +- autofile/group_test.go | 259 ++++++++++++++++------------------------- 2 files changed, 106 insertions(+), 163 deletions(-) diff --git a/autofile/group.go b/autofile/group.go index bbf77d27e..f2d0f2bae 100644 --- a/autofile/group.go +++ b/autofile/group.go @@ -596,14 +596,12 @@ func (gr *GroupReader) Read(p []byte) (n int, err error) { nn, err = gr.curReader.Read(p[n:]) n += nn if err == io.EOF { - // Open the next file - if err1 := gr.openFile(gr.curIndex + 1); err1 != nil { - return n, err1 - } if n >= lenP { return n, nil - } else { - continue + } else { // Open the next file + if err1 := gr.openFile(gr.curIndex + 1); err1 != nil { + return n, err1 + } } } else if err != nil { return n, err diff --git a/autofile/group_test.go b/autofile/group_test.go index 398ea3ae9..68baba824 100644 --- a/autofile/group_test.go +++ b/autofile/group_test.go @@ -1,8 +1,8 @@ package autofile import ( - "bytes" "errors" + "fmt" "io" "io/ioutil" "os" @@ -10,51 +10,38 @@ import ( "strings" "testing" - . "github.com/tendermint/tmlibs/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + cmn "github.com/tendermint/tmlibs/common" ) // NOTE: Returned group has ticker stopped func createTestGroup(t *testing.T, headSizeLimit int64) *Group { - testID := RandStr(12) + testID := cmn.RandStr(12) testDir := "_test_" + testID - err := EnsureDir(testDir, 0700) - if err != nil { - t.Fatal("Error creating dir", err) - } + err := cmn.EnsureDir(testDir, 0700) + require.NoError(t, err, "Error creating dir") headPath := testDir + "/myfile" g, err := OpenGroup(headPath) - if err != nil { - t.Fatal("Error opening Group", err) - } + require.NoError(t, err, "Error opening Group") g.SetHeadSizeLimit(headSizeLimit) g.stopTicker() - - if g == nil { - t.Fatal("Failed to create Group") - } + require.NotEqual(t, nil, g, "Failed to create Group") return g } func destroyTestGroup(t *testing.T, g *Group) { err := os.RemoveAll(g.Dir) - if err != nil { - t.Fatal("Error removing test Group directory", err) - } + require.NoError(t, err, "Error removing test Group directory") } func assertGroupInfo(t *testing.T, gInfo GroupInfo, minIndex, maxIndex int, totalSize, headSize int64) { - if gInfo.MinIndex != minIndex { - t.Errorf("GroupInfo MinIndex expected %v, got %v", minIndex, gInfo.MinIndex) - } - if gInfo.MaxIndex != maxIndex { - t.Errorf("GroupInfo MaxIndex expected %v, got %v", maxIndex, gInfo.MaxIndex) - } - if gInfo.TotalSize != totalSize { - t.Errorf("GroupInfo TotalSize expected %v, got %v", totalSize, gInfo.TotalSize) - } - if gInfo.HeadSize != headSize { - t.Errorf("GroupInfo HeadSize expected %v, got %v", headSize, gInfo.HeadSize) - } + assert := assert.New(t) + assert.Equal(minIndex, gInfo.MinIndex) + assert.Equal(maxIndex, gInfo.MaxIndex) + assert.Equal(totalSize, gInfo.TotalSize) + assert.Equal(headSize, gInfo.HeadSize) } func TestCheckHeadSizeLimit(t *testing.T) { @@ -65,10 +52,8 @@ func TestCheckHeadSizeLimit(t *testing.T) { // Write 1000 bytes 999 times. for i := 0; i < 999; i++ { - err := g.WriteLine(RandStr(999)) - if err != nil { - t.Fatal("Error appending to head", err) - } + err := g.WriteLine(cmn.RandStr(999)) + require.NoError(t, err, "Error appending to head") } g.Flush() assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000) @@ -78,9 +63,8 @@ func TestCheckHeadSizeLimit(t *testing.T) { assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000) // Write 1000 more bytes. - if err := g.WriteLine(RandStr(999)); err != nil { - t.Fatal("Error appending to head", err) - } + err := g.WriteLine(cmn.RandStr(999)) + require.NoError(t, err, "Error appending to head") g.Flush() // Calling checkHeadSizeLimit this time rolls it. @@ -88,9 +72,8 @@ func TestCheckHeadSizeLimit(t *testing.T) { assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1000000, 0) // Write 1000 more bytes. - if err := g.WriteLine(RandStr(999)); err != nil { - t.Fatal("Error appending to head", err) - } + err = g.WriteLine(cmn.RandStr(999)) + require.NoError(t, err, "Error appending to head") g.Flush() // Calling checkHeadSizeLimit does nothing. @@ -99,9 +82,8 @@ func TestCheckHeadSizeLimit(t *testing.T) { // Write 1000 bytes 999 times. for i := 0; i < 999; i++ { - if err := g.WriteLine(RandStr(999)); err != nil { - t.Fatal("Error appending to head", err) - } + err = g.WriteLine(cmn.RandStr(999)) + require.NoError(t, err, "Error appending to head") } g.Flush() assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 2000000, 1000000) @@ -111,10 +93,8 @@ func TestCheckHeadSizeLimit(t *testing.T) { assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0) // Write 1000 more bytes. - _, err := g.Head.Write([]byte(RandStr(999) + "\n")) - if err != nil { - t.Fatal("Error appending to head", err) - } + _, err = g.Head.Write([]byte(cmn.RandStr(999) + "\n")) + require.NoError(t, err, "Error appending to head") g.Flush() assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000) @@ -134,16 +114,12 @@ func TestSearch(t *testing.T) { for i := 0; i < 100; i++ { // The random junk at the end ensures that this INFO linen // is equally likely to show up at the end. - _, err := g.Head.Write([]byte(Fmt("INFO %v %v\n", i, RandStr(123)))) - if err != nil { - t.Error("Failed to write to head") - } + _, err := g.Head.Write([]byte(fmt.Sprintf("INFO %v %v\n", i, cmn.RandStr(123)))) + require.NoError(t, err, "Failed to write to head") g.checkHeadSizeLimit() for j := 0; j < 10; j++ { - _, err := g.Head.Write([]byte(RandStr(123) + "\n")) - if err != nil { - t.Error("Failed to write to head") - } + _, err1 := g.Head.Write([]byte(cmn.RandStr(123) + "\n")) + require.NoError(t, err1, "Failed to write to head") g.checkHeadSizeLimit() } } @@ -173,17 +149,11 @@ func TestSearch(t *testing.T) { for i := 0; i < 100; i++ { t.Log("Testing for i", i) gr, match, err := g.Search("INFO", makeSearchFunc(i)) - if err != nil { - t.Fatal("Failed to search for line:", err) - } - if !match { - t.Error("Expected Search to return exact match") - } + require.NoError(t, err, "Failed to search for line") + assert.True(t, match, "Expected Search to return exact match") line, err := gr.ReadLine() - if err != nil { - t.Fatal("Failed to read line after search", err) - } - if !strings.HasPrefix(line, Fmt("INFO %v ", i)) { + require.NoError(t, err, "Failed to read line after search") + if !strings.HasPrefix(line, fmt.Sprintf("INFO %v ", i)) { t.Fatal("Failed to get correct line") } // Make sure we can continue to read from there. @@ -203,7 +173,7 @@ func TestSearch(t *testing.T) { if !strings.HasPrefix(line, "INFO ") { continue } - if !strings.HasPrefix(line, Fmt("INFO %v ", cur)) { + if !strings.HasPrefix(line, fmt.Sprintf("INFO %v ", cur)) { t.Fatalf("Unexpected INFO #. Expected %v got:\n%v", cur, line) } cur += 1 @@ -215,35 +185,23 @@ func TestSearch(t *testing.T) { // We should get the first available line. { gr, match, err := g.Search("INFO", makeSearchFunc(-999)) - if err != nil { - t.Fatal("Failed to search for line:", err) - } - if match { - t.Error("Expected Search to not return exact match") - } + require.NoError(t, err, "Failed to search for line") + assert.False(t, match, "Expected Search to not return exact match") line, err := gr.ReadLine() - if err != nil { - t.Fatal("Failed to read line after search", err) - } + require.NoError(t, err, "Failed to read line after search") if !strings.HasPrefix(line, "INFO 0 ") { t.Error("Failed to fetch correct line, which is the earliest INFO") } err = gr.Close() - if err != nil { - t.Error("Failed to close GroupReader", err) - } + require.NoError(t, err, "Failed to close GroupReader") } // Now search for something that is too large. // We should get an EOF error. { gr, _, err := g.Search("INFO", makeSearchFunc(999)) - if err != io.EOF { - t.Error("Expected to get an EOF error") - } - if gr != nil { - t.Error("Expected to get nil GroupReader") - } + assert.Equal(t, io.EOF, err) + assert.Nil(t, gr) } // Cleanup @@ -264,18 +222,14 @@ func TestRotateFile(t *testing.T) { // Read g.Head.Path+"000" body1, err := ioutil.ReadFile(g.Head.Path + ".000") - if err != nil { - t.Error("Failed to read first rolled file") - } + assert.NoError(t, err, "Failed to read first rolled file") if string(body1) != "Line 1\nLine 2\nLine 3\n" { t.Errorf("Got unexpected contents: [%v]", string(body1)) } // Read g.Head.Path body2, err := ioutil.ReadFile(g.Head.Path) - if err != nil { - t.Error("Failed to read first rolled file") - } + assert.NoError(t, err, "Failed to read first rolled file") if string(body2) != "Line 4\nLine 5\nLine 6\n" { t.Errorf("Got unexpected contents: [%v]", string(body2)) } @@ -300,15 +254,9 @@ func TestFindLast1(t *testing.T) { g.Flush() match, found, err := g.FindLast("#") - if err != nil { - t.Error("Unexpected error", err) - } - if !found { - t.Error("Expected found=True") - } - if match != "# b" { - t.Errorf("Unexpected match: [%v]", match) - } + assert.NoError(t, err) + assert.True(t, found) + assert.Equal(t, "# b", match) // Cleanup destroyTestGroup(t, g) @@ -330,15 +278,9 @@ func TestFindLast2(t *testing.T) { g.Flush() match, found, err := g.FindLast("#") - if err != nil { - t.Error("Unexpected error", err) - } - if !found { - t.Error("Expected found=True") - } - if match != "# b" { - t.Errorf("Unexpected match: [%v]", match) - } + assert.NoError(t, err) + assert.True(t, found) + assert.Equal(t, "# b", match) // Cleanup destroyTestGroup(t, g) @@ -360,15 +302,9 @@ func TestFindLast3(t *testing.T) { g.Flush() match, found, err := g.FindLast("#") - if err != nil { - t.Error("Unexpected error", err) - } - if !found { - t.Error("Expected found=True") - } - if match != "# b" { - t.Errorf("Unexpected match: [%v]", match) - } + assert.NoError(t, err) + assert.True(t, found) + assert.Equal(t, "# b", match) // Cleanup destroyTestGroup(t, g) @@ -388,15 +324,9 @@ func TestFindLast4(t *testing.T) { g.Flush() match, found, err := g.FindLast("#") - if err != nil { - t.Error("Unexpected error", err) - } - if found { - t.Error("Expected found=False") - } - if match != "" { - t.Errorf("Unexpected match: [%v]", match) - } + assert.NoError(t, err) + assert.False(t, found) + assert.Empty(t, match) // Cleanup destroyTestGroup(t, g) @@ -411,22 +341,18 @@ func TestWrite(t *testing.T) { read := make([]byte, len(written)) gr, err := g.NewReader(0) - if err != nil { - t.Fatalf("Failed to create reader: %v", err) - } - _, err = gr.Read(read) - if err != nil { - t.Fatalf("Failed to read data: %v", err) - } + require.NoError(t, err, "failed to create reader") - if !bytes.Equal(written, read) { - t.Errorf("%s, %s should be equal", string(written), string(read)) - } + _, err = gr.Read(read) + assert.NoError(t, err, "failed to read data") + assert.Equal(t, written, read) // Cleanup destroyTestGroup(t, g) } +// test that Read reads the required amount of bytes from all the files in the +// group and returns no error if n == size of the given slice. func TestGroupReaderRead(t *testing.T) { g := createTestGroup(t, 0) @@ -441,22 +367,47 @@ func TestGroupReaderRead(t *testing.T) { totalWrittenLength := len(professor) + len(frankenstein) read := make([]byte, totalWrittenLength) gr, err := g.NewReader(0) - if err != nil { - t.Fatalf("Failed to create reader: %v", err) - } - n, err := gr.Read(read) - if err != nil { - t.Fatalf("Failed to read data: %v", err) - } - if n != totalWrittenLength { - t.Errorf("Failed to read enough bytes: wanted %d, but read %d", totalWrittenLength, n) - } + require.NoError(t, err, "failed to create reader") + n, err := gr.Read(read) + assert.NoError(t, err, "failed to read data") + assert.Equal(t, totalWrittenLength, n, "not enough bytes read") professorPlusFrankenstein := professor professorPlusFrankenstein = append(professorPlusFrankenstein, frankenstein...) - if !bytes.Equal(read, professorPlusFrankenstein) { - t.Errorf("%s, %s should be equal", string(professorPlusFrankenstein), string(read)) - } + assert.Equal(t, professorPlusFrankenstein, read) + + // Cleanup + destroyTestGroup(t, g) +} + +// test that Read returns an error if number of bytes read < size of +// the given slice. Subsequent call should return 0, io.EOF. +func TestGroupReaderRead2(t *testing.T) { + g := createTestGroup(t, 0) + + professor := []byte("Professor Monster") + g.Write(professor) + g.Flush() + g.RotateFile() + frankenstein := []byte("Frankenstein's Monster") + frankensteinPart := []byte("Frankenstein") + g.Write(frankensteinPart) // note writing only a part + g.Flush() + + totalLength := len(professor) + len(frankenstein) + read := make([]byte, totalLength) + gr, err := g.NewReader(0) + require.NoError(t, err, "failed to create reader") + + // 1) n < (size of the given slice), io.EOF + n, err := gr.Read(read) + assert.Equal(t, io.EOF, err) + assert.Equal(t, len(professor)+len(frankensteinPart), n, "Read more/less bytes than it is in the group") + + // 2) 0, io.EOF + n, err = gr.Read([]byte("0")) + assert.Equal(t, io.EOF, err) + assert.Equal(t, 0, n) // Cleanup destroyTestGroup(t, g) @@ -465,9 +416,7 @@ func TestGroupReaderRead(t *testing.T) { func TestMinIndex(t *testing.T) { g := createTestGroup(t, 0) - if g.MinIndex() != 0 { - t.Error("MinIndex should be zero at the beginning") - } + assert.Zero(t, g.MinIndex(), "MinIndex should be zero at the beginning") // Cleanup destroyTestGroup(t, g) @@ -476,17 +425,13 @@ func TestMinIndex(t *testing.T) { func TestMaxIndex(t *testing.T) { g := createTestGroup(t, 0) - if g.MaxIndex() != 0 { - t.Error("MaxIndex should be zero at the beginning") - } + assert.Zero(t, g.MaxIndex(), "MaxIndex should be zero at the beginning") g.WriteLine("Line 1") g.Flush() g.RotateFile() - if g.MaxIndex() != 1 { - t.Error("MaxIndex should point to the last file") - } + assert.Equal(t, 1, g.MaxIndex(), "MaxIndex should point to the last file") // Cleanup destroyTestGroup(t, g) From d8dd4970693ed840341fd04be9b07f27912a6864 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 30 Oct 2017 13:01:18 -0500 Subject: [PATCH 02/12] fix metalinter errors --- autofile/group_test.go | 9 ++++----- cli/setup_test.go | 44 +++++++++++++++++------------------------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/autofile/group_test.go b/autofile/group_test.go index 68baba824..c4f68f057 100644 --- a/autofile/group_test.go +++ b/autofile/group_test.go @@ -37,11 +37,10 @@ func destroyTestGroup(t *testing.T, g *Group) { } func assertGroupInfo(t *testing.T, gInfo GroupInfo, minIndex, maxIndex int, totalSize, headSize int64) { - assert := assert.New(t) - assert.Equal(minIndex, gInfo.MinIndex) - assert.Equal(maxIndex, gInfo.MaxIndex) - assert.Equal(totalSize, gInfo.TotalSize) - assert.Equal(headSize, gInfo.HeadSize) + assert.Equal(t, minIndex, gInfo.MinIndex) + assert.Equal(t, maxIndex, gInfo.MaxIndex) + assert.Equal(t, totalSize, gInfo.TotalSize) + assert.Equal(t, headSize, gInfo.HeadSize) } func TestCheckHeadSizeLimit(t *testing.T) { diff --git a/cli/setup_test.go b/cli/setup_test.go index 4e606ac7a..692da26d3 100644 --- a/cli/setup_test.go +++ b/cli/setup_test.go @@ -14,8 +14,6 @@ import ( ) func TestSetupEnv(t *testing.T) { - assert, require := assert.New(t), require.New(t) - cases := []struct { args []string env map[string]string @@ -51,22 +49,20 @@ func TestSetupEnv(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) err := RunWithArgs(cmd, args, tc.env) - require.Nil(err, i) - assert.Equal(tc.expected, foo, i) + require.Nil(t, err, i) + assert.Equal(t, tc.expected, foo, i) } } func TestSetupConfig(t *testing.T) { - assert, require := assert.New(t), require.New(t) - // we pre-create two config files we can refer to in the rest of // the test cases. cval1, cval2 := "fubble", "wubble" conf1, err := WriteDemoConfig(map[string]string{"boo": cval1}) - require.Nil(err) + require.Nil(t, err) // make sure it handles dashed-words in the config, and ignores random info conf2, err := WriteDemoConfig(map[string]string{"boo": cval2, "foo": "bar", "two-words": "WORD"}) - require.Nil(err) + require.Nil(t, err) cases := []struct { args []string @@ -110,9 +106,9 @@ func TestSetupConfig(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) err := RunWithArgs(cmd, args, tc.env) - require.Nil(err, i) - assert.Equal(tc.expected, foo, i) - assert.Equal(tc.expectedTwo, two, i) + require.Nil(t, err, i) + assert.Equal(t, tc.expected, foo, i) + assert.Equal(t, tc.expectedTwo, two, i) } } @@ -123,16 +119,14 @@ type DemoConfig struct { } func TestSetupUnmarshal(t *testing.T) { - assert, require := assert.New(t), require.New(t) - // we pre-create two config files we can refer to in the rest of // the test cases. cval1, cval2 := "someone", "else" conf1, err := WriteDemoConfig(map[string]string{"name": cval1}) - require.Nil(err) + require.Nil(t, err) // even with some ignored fields, should be no problem conf2, err := WriteDemoConfig(map[string]string{"name": cval2, "foo": "bar"}) - require.Nil(err) + require.Nil(t, err) // unused is not declared on a flag and remains from base base := DemoConfig{ @@ -189,14 +183,12 @@ func TestSetupUnmarshal(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) err := RunWithArgs(cmd, args, tc.env) - require.Nil(err, i) - assert.Equal(tc.expected, cfg, i) + require.Nil(t, err, i) + assert.Equal(t, tc.expected, cfg, i) } } func TestSetupTrace(t *testing.T) { - assert, require := assert.New(t), require.New(t) - cases := []struct { args []string env map[string]string @@ -224,16 +216,16 @@ func TestSetupTrace(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) stdout, stderr, err := RunCaptureWithArgs(cmd, args, tc.env) - require.NotNil(err, i) - require.Equal("", stdout, i) - require.NotEqual("", stderr, i) + require.NotNil(t, err, i) + require.Equal(t, "", stdout, i) + require.NotEqual(t, "", stderr, i) msg := strings.Split(stderr, "\n") desired := fmt.Sprintf("ERROR: %s", tc.expected) - assert.Equal(desired, msg[0], i) - if tc.long && assert.True(len(msg) > 2, i) { + assert.Equal(t, desired, msg[0], i) + if tc.long && assert.True(t, len(msg) > 2, i) { // the next line starts the stack trace... - assert.Contains(msg[1], "TestSetupTrace", i) - assert.Contains(msg[2], "setup_test.go", i) + assert.Contains(t, msg[1], "TestSetupTrace", i) + assert.Contains(t, msg[2], "setup_test.go", i) } } } From 88481fc363af0b6c905868fa4ad70adf587638c5 Mon Sep 17 00:00:00 2001 From: Wolf Date: Sat, 4 Nov 2017 06:06:20 +0100 Subject: [PATCH 03/12] Make iterating over keys possible (#63) * Make iterating over keys possible * add test for cmap - test Keys() and Values() respectively * one cmap per test-case --- common/cmap.go | 11 ++++++++ common/cmap_test.go | 63 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 common/cmap_test.go diff --git a/common/cmap.go b/common/cmap.go index e2a140dd0..c65c27d4c 100644 --- a/common/cmap.go +++ b/common/cmap.go @@ -51,6 +51,17 @@ func (cm *CMap) Clear() { cm.m = make(map[string]interface{}) } +func (cm *CMap) Keys() []string { + cm.l.Lock() + defer cm.l.Unlock() + + keys := []string{} + for k := range cm.m { + keys = append(keys, k) + } + return keys +} + func (cm *CMap) Values() []interface{} { cm.l.Lock() defer cm.l.Unlock() diff --git a/common/cmap_test.go b/common/cmap_test.go new file mode 100644 index 000000000..a04f0a7d2 --- /dev/null +++ b/common/cmap_test.go @@ -0,0 +1,63 @@ +package common + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIterateKeysWithValues(t *testing.T) { + cmap := NewCMap() + + for i := 1; i <= 10; i++ { + cmap.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i)) + } + + // Testing size + assert.Equal(t, cmap.Size(), 10, "overall size should be 10") + assert.Equal(t, len(cmap.Keys()), 10, "should be 10 keys") + assert.Equal(t, len(cmap.Values()), 10, "should be 10 values") + + // Iterating Keys, checking for matching Value + for _, key := range cmap.Keys() { + val := strings.Replace(key, "key", "value", -1) + assert.Equal(t, cmap.Get(key), val) + } + + // Test if all keys are within []Keys() + keys := cmap.Keys() + for i := 1; i <= 10; i++ { + assert.True(t, contains(keys, fmt.Sprintf("key%d", i)), "cmap.Keys() should contain key") + } + + // Delete 1 Key + cmap.Delete("key1") + + assert.NotEqual(t, len(keys), len(cmap.Keys()), "[]keys and []Keys() should not be equal, they are copies, one item was removed") + +} + +func TestContains(t *testing.T) { + cmap := NewCMap() + + cmap.Set("key1", "value1") + + // Test for known values + assert.True(t, cmap.Has("key1"), "should contain key1") + assert.Equal(t, cmap.Get("key1"), "value1", "key1.value() should be value1") + + // Test for unknown values + assert.False(t, cmap.Has("key2"), "should not contain key2") + assert.Nil(t, cmap.Get("key2"), "does not contain key2") +} + +func contains(array []string, value string) (bool) { + for _, val := range array { + if val == value { + return true + } + } + return false +} From b658294a13c95e726d0c9d5b1b782ff0fee777aa Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Sat, 4 Nov 2017 00:09:16 -0500 Subject: [PATCH 04/12] use assert.Contains in cmap_test --- common/cmap_test.go | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/common/cmap_test.go b/common/cmap_test.go index a04f0a7d2..c665a7f3e 100644 --- a/common/cmap_test.go +++ b/common/cmap_test.go @@ -16,27 +16,26 @@ func TestIterateKeysWithValues(t *testing.T) { } // Testing size - assert.Equal(t, cmap.Size(), 10, "overall size should be 10") - assert.Equal(t, len(cmap.Keys()), 10, "should be 10 keys") - assert.Equal(t, len(cmap.Values()), 10, "should be 10 values") + assert.Equal(t, 10, cmap.Size()) + assert.Equal(t, 10, len(cmap.Keys())) + assert.Equal(t, 10, len(cmap.Values())) // Iterating Keys, checking for matching Value for _, key := range cmap.Keys() { val := strings.Replace(key, "key", "value", -1) - assert.Equal(t, cmap.Get(key), val) + assert.Equal(t, val, cmap.Get(key)) } // Test if all keys are within []Keys() keys := cmap.Keys() for i := 1; i <= 10; i++ { - assert.True(t, contains(keys, fmt.Sprintf("key%d", i)), "cmap.Keys() should contain key") + assert.Contains(t, keys, fmt.Sprintf("key%d", i), "cmap.Keys() should contain key") } // Delete 1 Key cmap.Delete("key1") assert.NotEqual(t, len(keys), len(cmap.Keys()), "[]keys and []Keys() should not be equal, they are copies, one item was removed") - } func TestContains(t *testing.T) { @@ -45,19 +44,10 @@ func TestContains(t *testing.T) { cmap.Set("key1", "value1") // Test for known values - assert.True(t, cmap.Has("key1"), "should contain key1") - assert.Equal(t, cmap.Get("key1"), "value1", "key1.value() should be value1") + assert.True(t, cmap.Has("key1")) + assert.Equal(t, "value1", cmap.Get("key1")) // Test for unknown values - assert.False(t, cmap.Has("key2"), "should not contain key2") - assert.Nil(t, cmap.Get("key2"), "does not contain key2") -} - -func contains(array []string, value string) (bool) { - for _, val := range array { - if val == value { - return true - } - } - return false + assert.False(t, cmap.Has("key2")) + assert.Nil(t, cmap.Get("key2")) } From 49d75e223eded02597b7a45d877bc7001d4d66f0 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Fri, 3 Nov 2017 23:51:39 -0500 Subject: [PATCH 05/12] use os.Process#Kill (Fixes #73) --- common/os.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/common/os.go b/common/os.go index 81f703c7d..36fc969fa 100644 --- a/common/os.go +++ b/common/os.go @@ -35,6 +35,8 @@ func GoPath() string { return path } +// TrapSignal catches the SIGTERM and executes cb function. After that it exits +// with code 1. func TrapSignal(cb func()) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) @@ -50,10 +52,13 @@ func TrapSignal(cb func()) { select {} } -// Kill the running process by sending itself SIGTERM +// Kill the running process by sending itself SIGTERM. func Kill() error { - pid := os.Getpid() - return syscall.Kill(pid, syscall.SIGTERM) + p, err := os.FindProcess(os.Getpid()) + if err != nil { + return err + } + return p.Signal(syscall.SIGTERM) } func Exit(s string) { From 4b989151ed7008c2412b94ed37bf4c974b33b6f7 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 6 Nov 2017 14:18:42 -0500 Subject: [PATCH 06/12] log logger's errors (Refs #29) --- log/tm_logger.go | 15 ++++++++++++--- log/tm_logger_test.go | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/log/tm_logger.go b/log/tm_logger.go index dc6932dd8..d49e8d22b 100644 --- a/log/tm_logger.go +++ b/log/tm_logger.go @@ -52,19 +52,28 @@ func NewTMLoggerWithColorFn(w io.Writer, colorFn func(keyvals ...interface{}) te // Info logs a message at level Info. func (l *tmLogger) Info(msg string, keyvals ...interface{}) { lWithLevel := kitlevel.Info(l.srcLogger) - kitlog.With(lWithLevel, msgKey, msg).Log(keyvals...) + if err := kitlog.With(lWithLevel, msgKey, msg).Log(keyvals...); err != nil { + errLogger := kitlevel.Error(l.srcLogger) + kitlog.With(errLogger, msgKey, msg).Log("err", err) + } } // Debug logs a message at level Debug. func (l *tmLogger) Debug(msg string, keyvals ...interface{}) { lWithLevel := kitlevel.Debug(l.srcLogger) - kitlog.With(lWithLevel, msgKey, msg).Log(keyvals...) + if err := kitlog.With(lWithLevel, msgKey, msg).Log(keyvals...); err != nil { + errLogger := kitlevel.Error(l.srcLogger) + kitlog.With(errLogger, msgKey, msg).Log("err", err) + } } // Error logs a message at level Error. func (l *tmLogger) Error(msg string, keyvals ...interface{}) { lWithLevel := kitlevel.Error(l.srcLogger) - kitlog.With(lWithLevel, msgKey, msg).Log(keyvals...) + lWithMsg := kitlog.With(lWithLevel, msgKey, msg) + if err := lWithMsg.Log(keyvals...); err != nil { + lWithMsg.Log("err", err) + } } // With returns a new contextual logger with keyvals prepended to those passed diff --git a/log/tm_logger_test.go b/log/tm_logger_test.go index 8cd2f8274..b2b600ad2 100644 --- a/log/tm_logger_test.go +++ b/log/tm_logger_test.go @@ -1,12 +1,26 @@ package log_test import ( + "bytes" "io/ioutil" + "strings" "testing" + "github.com/go-logfmt/logfmt" "github.com/tendermint/tmlibs/log" ) +func TestLoggerLogsItsErrors(t *testing.T) { + var buf bytes.Buffer + + logger := log.NewTMLogger(&buf) + logger.Info("foo", "baz baz", "bar") + msg := strings.TrimSpace(buf.String()) + if !strings.Contains(msg, logfmt.ErrInvalidKey.Error()) { + t.Errorf("Expected logger msg to contain ErrInvalidKey, got %s", msg) + } +} + func BenchmarkTMLoggerSimple(b *testing.B) { benchmarkRunner(b, log.NewTMLogger(ioutil.Discard), baseInfoMessage) } From 69447564b8dedd3da5368e901b0afe9d76e2e9a3 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 6 Nov 2017 15:44:21 -0500 Subject: [PATCH 07/12] encode complex types as "%+v" (Refs #18) --- log/tmfmt_logger.go | 8 ++++++-- log/tmfmt_logger_test.go | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/log/tmfmt_logger.go b/log/tmfmt_logger.go index 2b464a6b0..d03979718 100644 --- a/log/tmfmt_logger.go +++ b/log/tmfmt_logger.go @@ -35,7 +35,8 @@ type tmfmtLogger struct { } // NewTMFmtLogger returns a logger that encodes keyvals to the Writer in -// Tendermint custom format. +// Tendermint custom format. Note complex types (structs, maps, slices) +// formatted as "%+v". // // Each log event produces no more than one call to w.Write. // The passed Writer must be safe for concurrent use by multiple goroutines if @@ -103,7 +104,10 @@ KeyvalueLoop: } } - if err := enc.EncodeKeyval(keyvals[i], keyvals[i+1]); err != nil { + err := enc.EncodeKeyval(keyvals[i], keyvals[i+1]) + if err == logfmt.ErrUnsupportedValueType { + enc.EncodeKeyval(keyvals[i], fmt.Sprintf("%+v", keyvals[i+1])) + } else if err != nil { return err } } diff --git a/log/tmfmt_logger_test.go b/log/tmfmt_logger_test.go index 62eb32a03..a07b323c6 100644 --- a/log/tmfmt_logger_test.go +++ b/log/tmfmt_logger_test.go @@ -30,8 +30,10 @@ func TestTMFmtLogger(t *testing.T) { assert.Regexp(t, regexp.MustCompile(`N\[.+\] unknown \s+ a=1 err=error\n$`), buf.String()) buf.Reset() - err := logger.Log("std_map", map[int]int{1: 2}, "my_map", mymap{0: 0}) - assert.NotNil(t, err) + if err := logger.Log("std_map", map[int]int{1: 2}, "my_map", mymap{0: 0}); err != nil { + t.Fatal(err) + } + assert.Regexp(t, regexp.MustCompile(`N\[.+\] unknown \s+ std_map=map\[1:2\] my_map=special_behavior\n$`), buf.String()) buf.Reset() if err := logger.Log("level", "error"); err != nil { From 4ea6340f1ac343d2dafb606cf11ee1c971c5a8ef Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Sat, 11 Nov 2017 11:25:30 -0500 Subject: [PATCH 08/12] add .editorconfig --- .editorconfig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..82f774362 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[Makefile] +indent_style = tab + +[*.sh] +indent_style = tab + +[*.proto] +indent_style = space +indent_size = 2 From 135a1a7cd78215105a55308c167b3331c225e00b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 20 Nov 2017 03:06:18 +0000 Subject: [PATCH 09/12] db: sort keys for memdb iterator --- db/mem_db.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/mem_db.go b/db/mem_db.go index 077427509..2f507321b 100644 --- a/db/mem_db.go +++ b/db/mem_db.go @@ -2,6 +2,7 @@ package db import ( "fmt" + "sort" "strings" "sync" ) @@ -127,6 +128,8 @@ func (db *MemDB) IteratorPrefix(prefix []byte) Iterator { it.keys = append(it.keys, key) } } + // and we need to sort them + sort.Strings(it.keys) return it } From d3bac7a6fefaeaec662c8b8483c1728ba2bd746c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 27 Nov 2017 19:49:30 +0000 Subject: [PATCH 10/12] clist: reduce numTimes in test --- clist/clist_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clist/clist_test.go b/clist/clist_test.go index 2063cf465..9d5272de5 100644 --- a/clist/clist_test.go +++ b/clist/clist_test.go @@ -149,7 +149,7 @@ func _TestGCRandom(t *testing.T) { func TestScanRightDeleteRandom(t *testing.T) { const numElements = 10000 - const numTimes = 100000 + const numTimes = 1000 const numScanners = 10 l := New() From 4e705a3157512d757e459c2c86dd2d38068e7bc0 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 27 Nov 2017 21:37:15 -0600 Subject: [PATCH 11/12] update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c380fdcd0..b0aa90d7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 0.4.1 (November 27, 2017) + +FEATURES: + - [common] `Keys()` method on `CMap` + +IMPROVEMENTS: + - [log] complex types now encoded as "%+v" by default if `String()` method is undefined (previously resulted in error) + - [log] logger logs its own errors + +BUG FIXES: + - [common] fixed `Kill()` to build on Windows (Windows does not have `syscall.Kill`) + ## 0.4.0 (October 26, 2017) BREAKING: From 3244f73f32497457987770d4b76523f9d3afdfe9 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 27 Nov 2017 21:37:39 -0600 Subject: [PATCH 12/12] update version --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index c1635d202..c30887b49 100644 --- a/version/version.go +++ b/version/version.go @@ -1,3 +1,3 @@ package version -const Version = "0.4.0" +const Version = "0.4.1"