| // SPDX-License-Identifier: BSD-3-Clause |
| package cpu |
| |
| import ( |
| "errors" |
| "os" |
| "runtime" |
| "testing" |
| "time" |
| |
| "github.com/stretchr/testify/assert" |
| "github.com/stretchr/testify/require" |
| |
| "github.com/shirou/gopsutil/v4/internal/common" |
| ) |
| |
| func TestTimes(t *testing.T) { |
| v, err := Times(false) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| assert.NotEmptyf(t, v, "could not get CPUs: %s", err) |
| empty := TimesStat{} |
| for _, vv := range v { |
| assert.NotEqualf(t, vv, empty, "could not get CPU User: %v", vv) |
| } |
| |
| // test sum of per cpu stats is within margin of error for cpu total stats |
| cpuTotal, err := Times(false) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| assert.NotEmptyf(t, cpuTotal, "could not get CPUs: %s", err) |
| perCPU, err := Times(true) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| assert.NotEmptyf(t, perCPU, "could not get CPUs: %s", err) |
| var perCPUUserTimeSum float64 |
| var perCPUSystemTimeSum float64 |
| var perCPUIdleTimeSum float64 |
| for _, pc := range perCPU { |
| perCPUUserTimeSum += pc.User |
| perCPUSystemTimeSum += pc.System |
| perCPUIdleTimeSum += pc.Idle |
| } |
| margin := 2.0 |
| t.Log(cpuTotal[0]) |
| |
| if cpuTotal[0].User == 0 && cpuTotal[0].System == 0 && cpuTotal[0].Idle == 0 { |
| t.Error("could not get cpu values") |
| } |
| if cpuTotal[0].User != 0 { |
| assert.InEpsilon(t, cpuTotal[0].User, perCPUUserTimeSum, margin) |
| } |
| if cpuTotal[0].System != 0 { |
| assert.InEpsilon(t, cpuTotal[0].System, perCPUSystemTimeSum, margin) |
| } |
| if cpuTotal[0].Idle != 0 { |
| assert.InEpsilon(t, cpuTotal[0].Idle, perCPUIdleTimeSum, margin) |
| } |
| } |
| |
| func TestCounts(t *testing.T) { |
| logicalCount, err := Counts(true) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| assert.NotZerof(t, logicalCount, "could not get logical CPU counts: %v", logicalCount) |
| t.Logf("logical cores: %d", logicalCount) |
| physicalCount, err := Counts(false) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| assert.NotZerof(t, physicalCount, "could not get physical CPU counts: %v", physicalCount) |
| t.Logf("physical cores: %d", physicalCount) |
| assert.GreaterOrEqualf(t, logicalCount, physicalCount, "logical CPU count should be greater than or equal to physical CPU count: %v >= %v", logicalCount, physicalCount) |
| } |
| |
| func TestTimeStat_String(t *testing.T) { |
| v := TimesStat{ |
| CPU: "cpu0", |
| User: 100.1, |
| System: 200.1, |
| Idle: 300.1, |
| } |
| e := `{"cpu":"cpu0","user":100.1,"system":200.1,"idle":300.1,"nice":0.0,"iowait":0.0,"irq":0.0,"softirq":0.0,"steal":0.0,"guest":0.0,"guestNice":0.0}` |
| assert.JSONEqf(t, e, v.String(), "CPUTimesStat string is invalid: %v", v) |
| } |
| |
| func TestInfo(t *testing.T) { |
| v, err := Info() |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| assert.NotEmptyf(t, v, "could not get CPU Info") |
| for _, vv := range v { |
| assert.NotEmptyf(t, vv.ModelName, "could not get CPU Info: %v", vv) |
| if runtime.GOOS == "windows" { |
| assert.NotEmptyf(t, vv.VendorID, "could not get Vendor ID: %v", vv) |
| assert.NotEmptyf(t, vv.Family, "could not get CPU Family: %v", vv) |
| assert.Positivef(t, vv.Mhz, "could not get CPU Mhz: %v", vv) |
| assert.Positivef(t, vv.Cores, "could not get CPU Cores: %v", vv) |
| } |
| } |
| t.Log(v) |
| } |
| |
| func testPercent(t *testing.T, percpu bool) { |
| t.Helper() |
| numcpu := runtime.NumCPU() |
| testCount := 3 |
| |
| if runtime.GOOS != "windows" { |
| testCount = 100 |
| v, err := Percent(time.Millisecond, percpu) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| // Skip CI which CPU num is different |
| if os.Getenv("CI") != "true" { |
| if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) { |
| t.Fatalf("wrong number of entries from CPUPercent: %v", v) |
| } |
| } |
| } |
| for i := 0; i < testCount; i++ { |
| duration := time.Duration(10) * time.Microsecond |
| v, err := Percent(duration, percpu) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| for _, percent := range v { |
| // Check for slightly greater then 100% to account for any rounding issues. |
| if percent < 0.0 || percent > 100.0001*float64(numcpu) { |
| t.Fatalf("CPUPercent value is invalid: %f", percent) |
| } |
| } |
| } |
| } |
| |
| func testPercentLastUsed(t *testing.T, percpu bool) { |
| t.Helper() |
| numcpu := runtime.NumCPU() |
| testCount := 10 |
| |
| if runtime.GOOS != "windows" { |
| testCount = 2 |
| v, err := Percent(time.Millisecond, percpu) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| // Skip CI which CPU num is different |
| if os.Getenv("CI") != "true" { |
| if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) { |
| t.Fatalf("wrong number of entries from CPUPercent: %v", v) |
| } |
| } |
| } |
| for i := 0; i < testCount; i++ { |
| v, err := Percent(0, percpu) |
| if errors.Is(err, common.ErrNotImplementedError) { |
| t.Skip("not implemented") |
| } |
| require.NoError(t, err) |
| time.Sleep(1 * time.Millisecond) |
| for _, percent := range v { |
| // Check for slightly greater then 100% to account for any rounding issues. |
| if percent < 0.0 || percent > 100.0001*float64(numcpu) { |
| t.Fatalf("CPUPercent value is invalid: %f", percent) |
| } |
| } |
| } |
| } |
| |
| func TestPercent(t *testing.T) { |
| testPercent(t, false) |
| } |
| |
| func TestPercentPerCpu(t *testing.T) { |
| testPercent(t, true) |
| } |
| |
| func TestPercentIntervalZero(t *testing.T) { |
| testPercentLastUsed(t, false) |
| } |
| |
| func TestPercentIntervalZeroPerCPU(t *testing.T) { |
| testPercentLastUsed(t, true) |
| } |