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	"strings"
18	"testing"
19)
20
21func TestPSIStats(t *testing.T) {
22	t.Run("fake", func(*testing.T) {
23		stats, err := getProcFixtures(t).PSIStatsForResource("fake")
24		if err == nil {
25			t.Fatal("fake resource does not have PSI statistics")
26		}
27
28		if stats.Some != nil || stats.Full != nil {
29			t.Error("a fake resource cannot have PSILine entries")
30		}
31	})
32
33	t.Run("cpu", func(t *testing.T) {
34		stats, err := getProcFixtures(t).PSIStatsForResource("cpu")
35		if err != nil {
36			t.Fatal(err)
37		}
38
39		if stats.Full != nil {
40			t.Fatal("cpu resource cannot have 'full' stats")
41		}
42
43		if stats.Some == nil {
44			t.Fatal("cpu resource should not have nil 'some' stats")
45		}
46
47		testCases := []struct {
48			name string
49			got  float64
50			want float64
51		}{
52			{"Avg10", stats.Some.Avg10, 0.1},
53			{"Avg60", stats.Some.Avg60, 2.0},
54			{"Avg300", stats.Some.Avg300, 3.85},
55			{"Total", float64(stats.Some.Total), 15.0},
56		}
57
58		for _, tc := range testCases {
59			t.Run(tc.name, func(t *testing.T) {
60				if tc.got != tc.want {
61					t.Errorf("got: %f, want: %f", tc.got, tc.want)
62				}
63			})
64		}
65	})
66
67	res := []string{"memory", "io"}
68
69	for _, resource := range res {
70		t.Run(resource, func(t *testing.T) {
71			stats, err := getProcFixtures(t).PSIStatsForResource(resource)
72			if err != nil {
73				t.Fatal(err)
74			}
75
76			if stats.Full == nil {
77				t.Fatalf("%s resource must not have nil 'full' stats", resource)
78			}
79
80			if stats.Some == nil {
81				t.Fatalf("%s resource must not have nil 'some' stats", resource)
82			}
83
84			testCases := []struct {
85				name string
86				got  float64
87				want float64
88			}{
89				{"some/Avg10", stats.Some.Avg10, 0.1},
90				{"some/Avg60", stats.Some.Avg60, 2.0},
91				{"some/Avg300", stats.Some.Avg300, 3.85},
92				{"some/Total", float64(stats.Some.Total), 15.0},
93				{"full/Avg10", stats.Full.Avg10, 0.2},
94				{"full/Avg60", stats.Full.Avg60, 3.0},
95				{"full/Avg300", stats.Full.Avg300, 4.95},
96				{"full/Total", float64(stats.Full.Total), 25.0},
97			}
98
99			for _, tc := range testCases {
100				t.Run(tc.name, func(t *testing.T) {
101					if tc.got != tc.want {
102						t.Errorf("got: %f, want: %f", tc.got, tc.want)
103					}
104				})
105			}
106		})
107	}
108}
109
110// TestParsePSIStats tests the edge cases that we won't run into when running TestPSIStats
111func TestParsePSIStats(t *testing.T) {
112	t.Run("unknown measurement type", func(t *testing.T) {
113		raw := "nonesense haha test=fake"
114		_, err := parsePSIStats("fake", strings.NewReader(raw))
115		if err != nil {
116			t.Error("unknown measurement type must be ignored")
117		}
118	})
119
120	t.Run("malformed measurement", func(t *testing.T) {
121		t.Run("some", func(t *testing.T) {
122			raw := `some avg10=0.10 avg60=2.00 avg300=3.85 total=oops
123full avg10=0.20 avg60=3.00 avg300=teddy total=25`
124			stats, err := parsePSIStats("fake", strings.NewReader(raw))
125			if err == nil {
126				t.Error("a malformed line must result in a parse error")
127			}
128
129			if stats.Some != nil || stats.Full != nil {
130				t.Error("a parse error must result in a nil PSILine")
131			}
132		})
133		t.Run("full", func(t *testing.T) {
134			raw := `some avg10=0.10 avg60=2.00 avg300=3.85 total=1
135full avg10=0.20 avg60=3.00 avg300=test total=25`
136			stats, err := parsePSIStats("fake", strings.NewReader(raw))
137			t.Log(err)
138			t.Log(stats)
139			if err == nil {
140				t.Error("a malformed line must result in a parse error")
141			}
142
143			if stats.Some != nil || stats.Full != nil {
144				t.Error("a parse error must result in a nil PSILine")
145			}
146		})
147
148	})
149}
150