1// Copyright 2019 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package procfs 15 16import ( 17 "os" 18 "strings" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22) 23 24// The majority of test cases are covered in Test_parseSockstat. The top level 25// tests just check the basics for integration test purposes. 26 27func TestNetSockstat(t *testing.T) { 28 fs, err := NewFS(procTestFixtures) 29 if err != nil { 30 t.Fatalf("failed to open procfs: %v", err) 31 } 32 33 stat, err := fs.NetSockstat() 34 if err != nil { 35 t.Fatalf("failed to get sockstat: %v", err) 36 } 37 38 // IPv4 stats should include Used. 39 if stat.Used == nil { 40 t.Fatalf("IPv4 sockstat used value was nil") 41 } 42 if diff := cmp.Diff(1602, *stat.Used); diff != "" { 43 t.Fatalf("unexpected IPv4 used sockets (-want +got):\n%s", diff) 44 } 45 46 // TCP occurs first; do a basic sanity check. 47 if diff := cmp.Diff("TCP", stat.Protocols[0].Protocol); diff != "" { 48 t.Fatalf("unexpected socket protocol (-want +got):\n%s", diff) 49 } 50 if diff := cmp.Diff(35, stat.Protocols[0].InUse); diff != "" { 51 t.Fatalf("unexpected number of TCP sockets (-want +got):\n%s", diff) 52 } 53} 54 55func TestNetSockstat6(t *testing.T) { 56 fs, err := NewFS(procTestFixtures) 57 if err != nil { 58 t.Fatalf("failed to open procfs: %v", err) 59 } 60 61 stat, err := fs.NetSockstat6() 62 if err != nil { 63 t.Fatalf("failed to get sockstat: %v", err) 64 } 65 66 // IPv6 stats should not include Used. 67 if stat.Used != nil { 68 t.Fatalf("IPv6 sockstat used value was not nil") 69 } 70 71 // TCP6 occurs first; do a basic sanity check. 72 if diff := cmp.Diff("TCP6", stat.Protocols[0].Protocol); diff != "" { 73 t.Fatalf("unexpected socket protocol (-want +got):\n%s", diff) 74 } 75 if diff := cmp.Diff(17, stat.Protocols[0].InUse); diff != "" { 76 t.Fatalf("unexpected number of TCP sockets (-want +got):\n%s", diff) 77 } 78} 79 80func Test_readSockstatIsNotExist(t *testing.T) { 81 // On a machine with IPv6 disabled for example, we want to ensure that 82 // readSockstat returns an error that is compatible with os.IsNotExist. 83 // 84 // We can use a synthetic file path here to verify this behavior. 85 _, err := readSockstat("/does/not/exist") 86 if err == nil || !os.IsNotExist(err) { 87 t.Fatalf("error is not compatible with os.IsNotExist: %#v", err) 88 } 89} 90 91func Test_parseSockstat(t *testing.T) { 92 tests := []struct { 93 name string 94 s string 95 ok bool 96 stat *NetSockstat 97 }{ 98 { 99 name: "empty", 100 ok: true, 101 stat: &NetSockstat{}, 102 }, 103 { 104 name: "bad line", 105 s: ` 106sockets: used 107`, 108 }, 109 { 110 name: "bad key/value pairs", 111 s: ` 112TCP: inuse 32 orphan 113`, 114 }, 115 { 116 name: "IPv4", 117 s: ` 118sockets: used 1591 119TCP: inuse 32 orphan 0 tw 0 alloc 58 mem 13 120UDP: inuse 8 mem 115 121UDPLITE: inuse 0 122RAW: inuse 0 123FRAG: inuse 0 memory 0 124 `, 125 ok: true, 126 stat: &NetSockstat{ 127 Used: intp(1591), 128 Protocols: []NetSockstatProtocol{ 129 { 130 Protocol: "TCP", 131 InUse: 32, 132 Orphan: intp(0), 133 TW: intp(0), 134 Alloc: intp(58), 135 Mem: intp(13), 136 }, 137 { 138 Protocol: "UDP", 139 InUse: 8, 140 Mem: intp(115), 141 }, 142 { 143 Protocol: "UDPLITE", 144 }, 145 { 146 Protocol: "RAW", 147 }, 148 { 149 Protocol: "FRAG", 150 Memory: intp(0), 151 }, 152 }, 153 }, 154 }, 155 { 156 name: "IPv6", 157 s: ` 158TCP6: inuse 24 159UDP6: inuse 9 160UDPLITE6: inuse 0 161RAW6: inuse 1 162FRAG6: inuse 0 memory 0 163 `, 164 ok: true, 165 stat: &NetSockstat{ 166 Protocols: []NetSockstatProtocol{ 167 { 168 Protocol: "TCP6", 169 InUse: 24, 170 }, 171 { 172 Protocol: "UDP6", 173 InUse: 9, 174 }, 175 { 176 Protocol: "UDPLITE6", 177 }, 178 { 179 Protocol: "RAW6", 180 InUse: 1, 181 }, 182 { 183 Protocol: "FRAG6", 184 Memory: intp(0), 185 }, 186 }, 187 }, 188 }, 189 } 190 191 for _, tt := range tests { 192 t.Run(tt.name, func(t *testing.T) { 193 stat, err := parseSockstat(strings.NewReader(strings.TrimSpace(tt.s))) 194 if err != nil { 195 if tt.ok { 196 t.Fatalf("failed to parse sockstats: %v", err) 197 } 198 199 t.Logf("OK error: %v", err) 200 return 201 } 202 if !tt.ok { 203 t.Fatal("expected an error, but none occurred") 204 } 205 206 if diff := cmp.Diff(tt.stat, stat); diff != "" { 207 t.Errorf("unexpected sockstats (-want +got):\n%s", diff) 208 } 209 }) 210 } 211} 212 213func intp(i int) *int { return &i } 214