Skip to content

Commit

Permalink
Merge pull request #357 from ablagoev/fix-proc-net-dev-parsing
Browse files Browse the repository at this point in the history
Improve /proc/net/dev parsing to include all edge cases
  • Loading branch information
shirou authored Apr 30, 2017
2 parents 1f6e626 + f7dd4f9 commit 9a4a916
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 2 deletions.
9 changes: 7 additions & 2 deletions net/net_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,20 @@ func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
return nil, err
}

parts := make([]string, 2)

statlen := len(lines) - 1

ret := make([]IOCountersStat, 0, statlen)

for _, line := range lines[2:] {
parts := strings.SplitN(line, ": ", 2)
if len(parts) != 2 {
separatorPos := strings.LastIndex(line, ":")
if separatorPos == -1 {
continue
}
parts[0] = line[0:separatorPos]
parts[1] = line[separatorPos+1:]

interfaceName := strings.TrimSpace(parts[0])
if interfaceName == "" {
continue
Expand Down
67 changes: 67 additions & 0 deletions net/net_linux_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,81 @@
package net

import (
"fmt"
"io/ioutil"
"os"
"strings"
"syscall"
"testing"

"github.com/shirou/gopsutil/internal/common"
"github.com/stretchr/testify/assert"
)

func TestIOCountersByFileParsing(t *testing.T) {
// Prpare a temporary file, which will be read during the test
tmpfile, err := ioutil.TempFile("", "proc_dev_net")
defer os.Remove(tmpfile.Name()) // clean up

assert.Nil(t, err, "Temporary file creation failed: ", err)

cases := [4][2]string{
[2]string{"eth0: ", "eth1: "},
[2]string{"eth0:0: ", "eth1:0: "},
[2]string{"eth0:", "eth1:"},
[2]string{"eth0:0:", "eth1:0:"},
}
for _, testCase := range cases {
err = tmpfile.Truncate(0)
assert.Nil(t, err, "Temporary file truncating problem: ", err)

// Parse interface name for assertion
interface0 := strings.TrimSpace(testCase[0])
interface0 = interface0[:len(interface0)-1]

interface1 := strings.TrimSpace(testCase[1])
interface1 = interface1[:len(interface1)-1]

// Replace the interfaces from the test case
proc := []byte(fmt.Sprintf("Inter-| Receive | Transmit\n face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n %s1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\n %s100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600\n", testCase[0], testCase[1]))

// Write /proc/net/dev sample output
_, err = tmpfile.Write(proc)
assert.Nil(t, err, "Temporary file writing failed: ", err)

counters, err := IOCountersByFile(true, tmpfile.Name())

assert.Nil(t, err)
assert.NotEmpty(t, counters)
assert.Equal(t, 2, len(counters))
assert.Equal(t, interface0, counters[0].Name)
assert.Equal(t, 1, int(counters[0].BytesRecv))
assert.Equal(t, 2, int(counters[0].PacketsRecv))
assert.Equal(t, 3, int(counters[0].Errin))
assert.Equal(t, 4, int(counters[0].Dropin))
assert.Equal(t, 5, int(counters[0].Fifoin))
assert.Equal(t, 9, int(counters[0].BytesSent))
assert.Equal(t, 10, int(counters[0].PacketsSent))
assert.Equal(t, 11, int(counters[0].Errout))
assert.Equal(t, 12, int(counters[0].Dropout))
assert.Equal(t, 13, int(counters[0].Fifoout))
assert.Equal(t, interface1, counters[1].Name)
assert.Equal(t, 100, int(counters[1].BytesRecv))
assert.Equal(t, 200, int(counters[1].PacketsRecv))
assert.Equal(t, 300, int(counters[1].Errin))
assert.Equal(t, 400, int(counters[1].Dropin))
assert.Equal(t, 500, int(counters[1].Fifoin))
assert.Equal(t, 900, int(counters[1].BytesSent))
assert.Equal(t, 1000, int(counters[1].PacketsSent))
assert.Equal(t, 1100, int(counters[1].Errout))
assert.Equal(t, 1200, int(counters[1].Dropout))
assert.Equal(t, 1300, int(counters[1].Fifoout))
}

err = tmpfile.Close()
assert.Nil(t, err, "Temporary file closing failed: ", err)
}

func TestGetProcInodesAll(t *testing.T) {
if os.Getenv("CIRCLECI") == "true" {
t.Skip("Skip CI")
Expand Down

0 comments on commit 9a4a916

Please sign in to comment.