func TestMemoryStats(t *testing.T) { helper := NewCgroupTestUtil("memory", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "memory.stat": memoryStatContents, "memory.usage_in_bytes": memoryUsageContents, "memory.limit_in_bytes": memoryLimitContents, "memory.max_usage_in_bytes": memoryMaxUsageContents, "memory.failcnt": memoryFailcnt, "memory.memsw.usage_in_bytes": memoryUsageContents, "memory.memsw.max_usage_in_bytes": memoryMaxUsageContents, "memory.memsw.failcnt": memoryFailcnt, "memory.memsw.limit_in_bytes": memoryLimitContents, "memory.kmem.usage_in_bytes": memoryUsageContents, "memory.kmem.max_usage_in_bytes": memoryMaxUsageContents, "memory.kmem.failcnt": memoryFailcnt, "memory.kmem.limit_in_bytes": memoryLimitContents, }) memory := &MemoryGroup{} actualStats := *cgroups.NewStats() err := memory.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } expectedStats := cgroups.MemoryStats{Cache: 512, Usage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, SwapUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, KernelUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, Stats: map[string]uint64{"cache": 512, "rss": 1024}} expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats) }
func TestCpuStats(t *testing.T) { helper := NewCgroupTestUtil("cpu", t) defer helper.cleanup() const ( kNrPeriods = 2000 kNrThrottled = 200 kThrottledTime = uint64(18446744073709551615) ) cpuStatContent := fmt.Sprintf("nr_periods %d\n nr_throttled %d\n throttled_time %d\n", kNrPeriods, kNrThrottled, kThrottledTime) helper.writeFileContents(map[string]string{ "cpu.stat": cpuStatContent, }) cpu := &CpuGroup{} actualStats := *cgroups.NewStats() err := cpu.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } expectedStats := cgroups.ThrottlingData{ Periods: kNrPeriods, ThrottledPeriods: kNrThrottled, ThrottledTime: kThrottledTime} expectThrottlingDataEquals(t, expectedStats, actualStats.CpuStats.ThrottlingData) }
func TestGetMetrics(t *testing.T) { Convey("Given docker id and running containers info", t, func() { longDockerId := "1234567890ab9207edb4e6188cf5be3294c23c936ca449c3d48acd2992e357a8" containersInfo := []ContainerInfo{ContainerInfo{Id: longDockerId}} mountPoint := "cgroup/mount/point/path" stats := cgroups.NewStats() Convey("and docker plugin initialized", func() { mockClient := new(ClientMock) mockStats := new(StatsMock) mockTools := new(ToolsMock) mockWrapper := map[string]Stats{"cpu": mockStats} mockTools.On( "Map2Namespace", mock.Anything, mock.AnythingOfType("string"), mock.AnythingOfType("*[]string"), ).Return().Run( func(args mock.Arguments) { id := args.String(1) ns := args.Get(2).(*[]string) *ns = append(*ns, filepath.Join(id, "cpu_stats/cpu_usage/total_usage")) }) mockClient.On("FindCgroupMountpoint", "cpu").Return(mountPoint, nil) mockStats.On("GetStats", mock.AnythingOfType("string"), mock.AnythingOfType("*cgroups.Stats")).Return(nil) d := &docker{ stats: stats, client: mockClient, tools: mockTools, groupWrap: mockWrapper, containersInfo: containersInfo, hostname: "", } Convey("When GetMetrics is called", func() { mts, err := d.GetMetricTypes(plugin.PluginConfigType{}) Convey("Then no error should be reported", func() { So(err, ShouldBeNil) }) Convey("Then one explicit metric should be returned and wildcard docker id metric", func() { So(len(mts), ShouldEqual, 2) }) Convey("Then metric namespace should be correctly set", func() { ns := filepath.Join(mts[0].Namespace()...) expected := filepath.Join( NS_VENDOR, NS_CLASS, NS_PLUGIN, longDockerId[:12], "cpu_stats", "cpu_usage", "total_usage") So(ns, ShouldEqual, expected) }) }) }) }) }
func newCgroupsStats() *cgroups.Stats { cgroupStats := cgroups.NewStats() // set names of default memory statistics which are supported for _, memstatName := range listOfMemoryStats { cgroupStats.MemoryStats.Stats[memstatName] = 0 } return cgroupStats }
func TestCollectMetricsWildcard(t *testing.T) { Convey("Given * wildcard in requested metric type", t, func() { mountPoint := "cgroup/mount/point/path" longDockerId1 := "1234567890ab9207edb4e6188cf5be3294c23c936ca449c3d48acd2992e357a8" longDockerId2 := "0987654321yz9207edb4e6188cf5be3294c23c936ca449c3d48acd2992e357a8" ns := []string{NS_VENDOR, NS_CLASS, NS_PLUGIN, "*", "cpu_stats", "cpu_usage", "total_usage"} metricTypes := []plugin.PluginMetricType{plugin.PluginMetricType{Namespace_: ns}} Convey("and docker plugin intitialized", func() { stats := cgroups.NewStats() mockClient := new(ClientMock) mockStats := new(StatsMock) mockTools := new(ToolsMock) mockWrapper := map[string]Stats{"cpu": mockStats} mockClient.On("FindCgroupMountpoint", "cpu").Return(mountPoint, nil) mockStats.On("GetStats", mock.AnythingOfType("string"), stats).Return(nil) mockTools.On("GetValueByNamespace", mock.AnythingOfType("*cgroups.Stats"), mock.Anything).Return(43) d := &docker{ stats: stats, client: mockClient, tools: mockTools, containersInfo: []ContainerInfo{ ContainerInfo{Id: longDockerId1}, ContainerInfo{Id: longDockerId2}}, groupWrap: mockWrapper, hostname: "", } Convey("When CollectMetric is called", func() { mts, err := d.CollectMetrics(metricTypes) Convey("Then error should not be reported", func() { So(err, ShouldBeNil) }) Convey("Two metrics should be returned", func() { So(len(mts), ShouldEqual, 2) }) Convey("Metric value should be correctly set", func() { So(mts[0].Data(), ShouldEqual, 43) So(mts[1].Data(), ShouldEqual, 43) }) }) }) }) }
func (v VMStatFile) readAll() ([]byte, error) { stats := cgroups.NewStats() v.blkioGroup.GetStats(v.cgroupdir, stats) vmstat, err := ioutil.ReadFile("/proc/vmstat") if err != nil { return []byte{}, fmt.Errorf("failed to read /proc/vmstat: %v", err) } return getVMStat(vmstat, stats.BlkioStats) }
func (ds DiskStatsFile) readAll() ([]byte, error) { stats := cgroups.NewStats() ds.blkioGroup.GetStats(ds.cgroupdir, stats) diskStats, err := ioutil.ReadFile("/proc/diskstats") if err != nil { return []byte{}, fmt.Errorf("failed to read /proc/diskstats: %v", err) } return getDiskStats(diskStats, stats.BlkioStats), nil }
func TestNoCpuStatFile(t *testing.T) { helper := NewCgroupTestUtil("cpu", t) defer helper.cleanup() cpu := &CpuGroup{} actualStats := *cgroups.NewStats() err := cpu.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal("Expected not to fail, but did") } }
func TestHugetlbStatsNoUsageFile(t *testing.T) { helper := NewCgroupTestUtil("hugetlb", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ maxUsage: hugetlbMaxUsageContents, }) hugetlb := &HugetlbGroup{} actualStats := *cgroups.NewStats() err := hugetlb.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } }
func TestNonCFQBlkioStats(t *testing.T) { helper := NewCgroupTestUtil("blkio", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "blkio.io_service_bytes_recursive": "", "blkio.io_serviced_recursive": "", "blkio.io_queued_recursive": "", "blkio.sectors_recursive": "", "blkio.io_service_time_recursive": "", "blkio.io_wait_time_recursive": "", "blkio.io_merged_recursive": "", "blkio.time_recursive": "", "blkio.throttle.io_service_bytes": throttleServiceBytes, "blkio.throttle.io_serviced": throttleServiced, }) blkio := &BlkioGroup{} actualStats := *cgroups.NewStats() err := blkio.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } // Verify expected stats. expectedStats := cgroups.BlkioStats{} appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 11030528, "Read") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 23, "Write") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 42, "Sync") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 11030528, "Async") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 11030528, "Total") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 11030528, "Read") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 23, "Write") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 42, "Sync") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 11030528, "Async") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 252, 0, 11030528, "Total") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 164, "Read") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 23, "Write") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 42, "Sync") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 164, "Async") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 164, "Total") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 164, "Read") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 23, "Write") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 42, "Sync") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 164, "Async") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 252, 0, 164, "Total") expectBlkioStatsEquals(t, expectedStats, actualStats.BlkioStats) }
func (m *Manager) GetStats() (*cgroups.Stats, error) { m.mu.Lock() defer m.mu.Unlock() stats := cgroups.NewStats() for name, path := range m.Paths { sys, err := subsystems.Get(name) if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { continue } if err := sys.GetStats(path, stats); err != nil { return nil, err } } return stats, nil }
func TestMemoryStatsNoMaxUsageFile(t *testing.T) { helper := NewCgroupTestUtil("memory", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "memory.stat": memoryStatContents, "memory.usage_in_bytes": memoryUsageContents, }) memory := &MemoryGroup{} actualStats := *cgroups.NewStats() err := memory.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } }
func TestGetStats(t *testing.T) { Convey("Given docker id, stats, client", t, func() { dockerId := "1234567890ab" mountPoint := "mount/point/path" mockStats := new(StatsMock) mockClient := new(ClientMock) stats := cgroups.NewStats() mockClient.On("FindCgroupMountpoint", "cpu").Return(mountPoint, nil) mockStats.On("GetStats", mock.AnythingOfType("string"), stats).Return(nil).Run( func(args mock.Arguments) { arg := args.Get(1).(*cgroups.Stats) arg.CpuStats.CpuUsage.TotalUsage = 43 arg.CpuStats.CpuUsage.PercpuUsage = []uint64{99, 88} }) Convey("and cgroups stats wrapper", func() { mockWrapper := map[string]Stats{"cpu": mockStats} Convey("When docker stats are requested", func() { d := &docker{ stats: stats, client: mockClient, tools: new(MyTools), containersInfo: []ContainerInfo{}, groupWrap: mockWrapper, hostname: "", } err := d.getStats(dockerId) Convey("Then no error should be reported", func() { So(err, ShouldBeNil) }) Convey("Then stats should be set", func() { So(stats.CpuStats.CpuUsage.TotalUsage, ShouldEqual, 43) So(stats.CpuStats.CpuUsage.PercpuUsage[0], ShouldEqual, 99) So(stats.CpuStats.CpuUsage.PercpuUsage[1], ShouldEqual, 88) }) }) }) }) }
func TestMemoryStatsNoStatFile(t *testing.T) { helper := NewCgroupTestUtil("memory", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "memory.usage_in_bytes": memoryUsageContents, "memory.max_usage_in_bytes": memoryMaxUsageContents, "memory.limit_in_bytes": memoryLimitContents, }) memory := &MemoryGroup{} actualStats := *cgroups.NewStats() err := memory.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } }
func TestHugetlbStatsNoMaxUsageFile(t *testing.T) { helper := NewCgroupTestUtil("hugetlb", t) defer helper.cleanup() for _, pageSize := range HugePageSizes { helper.writeFileContents(map[string]string{ fmt.Sprintf(usage, pageSize): hugetlbUsageContents, }) } hugetlb := &HugetlbGroup{} actualStats := *cgroups.NewStats() err := hugetlb.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } }
func (mi MemInfoFile) readAll() ([]byte, error) { stats := cgroups.NewStats() mi.memCgroup.GetStats(mi.cgroupdir, stats) memStats := stats.MemoryStats mls := mi.getLimits() memInfo := fmt.Sprintf(content, mls[hardLimit]/1024, (mls[hardLimit]-memStats.Usage.Usage)/1024, (mls[hardLimit]-memStats.Usage.Usage)/1024, 0, memStats.Stats["total_cache"]/1024, 0, ) logrus.Debugf("memInfo \n%s", memInfo) return []byte(memInfo), nil }
func TestInvalidCpuStat(t *testing.T) { helper := NewCgroupTestUtil("cpu", t) defer helper.cleanup() cpuStatContent := `nr_periods 2000 nr_throttled 200 throttled_time fortytwo` helper.writeFileContents(map[string]string{ "cpu.stat": cpuStatContent, }) cpu := &CpuGroup{} actualStats := *cgroups.NewStats() err := cpu.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failed stat parsing.") } }
func TestHugetlbStats(t *testing.T) { helper := NewCgroupTestUtil("hugetlb", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ usage: hugetlbUsageContents, maxUsage: hugetlbMaxUsageContents, failcnt: hugetlbFailcnt, }) hugetlb := &HugetlbGroup{} actualStats := *cgroups.NewStats() err := hugetlb.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } expectedStats := cgroups.HugetlbStats{Usage: 128, MaxUsage: 256, Failcnt: 100} expectHugetlbStatEquals(t, expectedStats, actualStats.HugetlbStats[hugePageSize[0]]) }
func TestDiskStats(t *testing.T) { stats := cgroups.NewStats() pkgPath := packagePath() if pkgPath == "" { t.Skip("failed to find pkg path") } hackDir := filepath.Join(pkgPath, "src/github.com/chenchun/cgroupfs/hack/") blkioCgroup := &fs.BlkioGroup{} blkioCgroup.GetStats(filepath.Join(hackDir, "blkio"), stats) diskStats, err := ioutil.ReadFile(filepath.Join(hackDir, "/proc/diskstats")) if err != nil { t.Fatalf("failed to read /proc/diskstats: %v", err) } ret := string(getDiskStats(diskStats, stats.BlkioStats)) if ret != "8 0 sda 137 1 1608 730 377 3 3392 263 0 0 688\n" { t.Fatalf("%q", ret) } }
func TestPidsStats(t *testing.T) { helper := NewCgroupTestUtil("pids", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "pids.current": strconv.Itoa(1337), "pids.max": strconv.Itoa(maxLimited), }) pids := &PidsGroup{} stats := *cgroups.NewStats() if err := pids.GetStats(helper.CgroupPath, &stats); err != nil { t.Fatal(err) } if stats.PidsStats.Current != 1337 { t.Fatalf("Expected %d, got %d for pids.current", 1337, stats.PidsStats.Current) } }
func TestBlkioStatsNoQueuedFile(t *testing.T) { helper := NewCgroupTestUtil("blkio", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, "blkio.io_serviced_recursive": servicedRecursiveContents, "blkio.sectors_recursive": sectorsRecursiveContents, "blkio.io_service_time_recursive": serviceTimeRecursiveContents, "blkio.io_wait_time_recursive": waitTimeRecursiveContents, "blkio.io_merged_recursive": mergedRecursiveContents, "blkio.time_recursive": timeRecursiveContents, }) blkio := &BlkioGroup{} actualStats := *cgroups.NewStats() err := blkio.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatalf("Failed unexpectedly: %s", err) } }
func TestBlkioStatsUnexpectedFieldType(t *testing.T) { helper := NewCgroupTestUtil("blkio", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "blkio.io_service_bytes_recursive": "8:0 Read Write", "blkio.io_serviced_recursive": servicedRecursiveContents, "blkio.io_queued_recursive": queuedRecursiveContents, "blkio.sectors_recursive": sectorsRecursiveContents, "blkio.io_service_time_recursive": serviceTimeRecursiveContents, "blkio.io_wait_time_recursive": waitTimeRecursiveContents, "blkio.io_merged_recursive": mergedRecursiveContents, "blkio.time_recursive": timeRecursiveContents, }) blkio := &BlkioGroup{} actualStats := *cgroups.NewStats() err := blkio.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected to fail, but did not") } }
// Docker plugin initializer func NewDocker() (*docker, error) { host, _ := os.Hostname() // create new docker client dockerClient := client.NewDockerClient() // list all running containers containers, err := dockerClient.ListContainers() if err != nil { return nil, err } d := &docker{ stats: cgroups.NewStats(), client: dockerClient, tools: new(tls.MyTools), containersInfo: containers, groupWrap: wrapper.Cgroups2Stats, hostname: host} return d, nil }
func TestHugetlbStats(t *testing.T) { helper := NewCgroupTestUtil("hugetlb", t) defer helper.cleanup() for _, pageSize := range HugePageSizes { helper.writeFileContents(map[string]string{ fmt.Sprintf(usage, pageSize): hugetlbUsageContents, fmt.Sprintf(maxUsage, pageSize): hugetlbMaxUsageContents, fmt.Sprintf(failcnt, pageSize): hugetlbFailcnt, }) } hugetlb := &HugetlbGroup{} actualStats := *cgroups.NewStats() err := hugetlb.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } expectedStats := cgroups.HugetlbStats{Usage: 128, MaxUsage: 256, Failcnt: 100} for _, pageSize := range HugePageSizes { expectHugetlbStatEquals(t, expectedStats, actualStats.HugetlbStats[pageSize]) } }
func TestBlkioStats(t *testing.T) { helper := NewCgroupTestUtil("blkio", t) defer helper.cleanup() helper.writeFileContents(map[string]string{ "blkio.io_service_bytes_recursive": serviceBytesRecursiveContents, "blkio.io_serviced_recursive": servicedRecursiveContents, "blkio.io_queued_recursive": queuedRecursiveContents, "blkio.io_service_time_recursive": serviceTimeRecursiveContents, "blkio.io_wait_time_recursive": waitTimeRecursiveContents, "blkio.io_merged_recursive": mergedRecursiveContents, "blkio.time_recursive": timeRecursiveContents, "blkio.sectors_recursive": sectorsRecursiveContents, }) blkio := &BlkioGroup{} actualStats := *cgroups.NewStats() err := blkio.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } // Verify expected stats. expectedStats := cgroups.BlkioStats{} appendBlkioStatEntry(&expectedStats.SectorsRecursive, 8, 0, 1024, "") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 100, "Read") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 200, "Write") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 300, "Sync") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 500, "Async") appendBlkioStatEntry(&expectedStats.IoServiceBytesRecursive, 8, 0, 500, "Total") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 10, "Read") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 40, "Write") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 20, "Sync") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 30, "Async") appendBlkioStatEntry(&expectedStats.IoServicedRecursive, 8, 0, 50, "Total") appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 1, "Read") appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 4, "Write") appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 2, "Sync") appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 3, "Async") appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 5, "Total") appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 173959, "Read") appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 0, "Write") appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 0, "Sync") appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 173959, "Async") appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 17395, "Total") appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Read") appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 0, "Write") appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 0, "Sync") appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Async") appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Total") appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 5, "Read") appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 10, "Write") appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 0, "Sync") appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 0, "Async") appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 15, "Total") appendBlkioStatEntry(&expectedStats.IoTimeRecursive, 8, 0, 8, "") expectBlkioStatsEquals(t, expectedStats, actualStats.BlkioStats) }