blob: d49f598552e3378dba4822d38b78067a10ea79c5 [file] [log] [blame] [edit]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package platform
import (
"context"
"fmt"
"io/ioutil"
"path/filepath"
"strconv"
"strings"
"syscall"
"chromiumos/tast/errors"
"chromiumos/tast/local/firmware"
"chromiumos/tast/local/spaced"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: Spaced,
Desc: "Checks that spaced queries work",
Contacts: []string{"sarthakkukreti@chromium.org", "chromeos-storage@google.com"},
Attr: []string{"group:mainline", "informational"},
})
}
// sysfsRootDeviceSize fetches the root device size from /sys/block/<dev>/size.
func sysfsRootDeviceSize(ctx context.Context) (uint64, error) {
// Check actual root device size.
rootdev, err := firmware.RootDevice(ctx)
if err != nil {
return 0, errors.Wrap(err, "failed to fetch root device")
}
fp := fmt.Sprintf("/sys/block/%s/size", filepath.Base(rootdev))
content, err := ioutil.ReadFile(fp)
if err != nil {
return 0, errors.Wrapf(err, "reading filepath %s", fp)
}
size, err := strconv.ParseUint(strings.TrimSpace(string(content)), 10, 64)
if err != nil {
return 0, errors.Wrap(err, "failed to parse root device size as uint64")
}
// Size is in sectors; return in bytes.
return size * 512, nil
}
// statFreeDiskSpace gets the free space on the filesystem using statfs().
func statFreeDiskSpace(ctx context.Context, path string) (uint64, error) {
var stat syscall.Statfs_t
if err := syscall.Statfs(path, &stat); err != nil {
return 0, errors.Wrapf(err, "failed to get disk stats for %s", path)
}
return stat.Bavail * uint64(stat.Bsize), nil
}
// statTotalDiskSpace gets the total space on the filesystem using statfs().
func statTotalDiskSpace(ctx context.Context, path string) (uint64, error) {
var stat syscall.Statfs_t
if err := syscall.Statfs(path, &stat); err != nil {
return 0, errors.Wrapf(err, "failed to get disk stats for %s", path)
}
return stat.Blocks * uint64(stat.Bsize), nil
}
func Spaced(ctx context.Context, s *testing.State) {
const (
// Path to check disk space queries on.
statefulMount = "/mnt/stateful_partition/"
// Disk space margin to consider when comparing against expected values.
spaceMarginBytes = 100 * 1024 * 1024
)
spaced, err := spaced.NewClient(ctx)
if err != nil {
s.Fatal("Failed to create spaced client: ", err)
}
// Check D-Bus queries.
rootDeviceSize, err := spaced.RootDeviceSize(ctx)
if err != nil {
s.Fatal("Failed to query root device size: ", err)
}
expectedRootDeviceSize, err := sysfsRootDeviceSize(ctx)
if err != nil {
s.Fatal("Failed to get actual root device size: ", err)
}
if rootDeviceSize != expectedRootDeviceSize {
s.Fatalf("Invalid root device size: got %d, want: 0 < size < %d", rootDeviceSize, expectedRootDeviceSize)
}
freeDiskSpace, err := spaced.FreeDiskSpace(ctx, statefulMount)
if err != nil {
s.Fatal("Failed to query free disk space: ", err)
}
expectedFreeDiskSpace, err := statFreeDiskSpace(ctx, statefulMount)
if err != nil {
s.Fatal("Failed to get expected free disk space: ", err)
}
if freeDiskSpace <= 0 || freeDiskSpace > expectedFreeDiskSpace+spaceMarginBytes {
s.Fatalf("Invalid free disk space; got %d, want: 0 < size < %d", freeDiskSpace, expectedFreeDiskSpace+spaceMarginBytes)
}
totalDiskSpace, err := spaced.TotalDiskSpace(ctx, statefulMount)
if err != nil {
s.Fatal("Failed to query total disk space: ", err)
}
expectedTotalDiskSpace, err := statTotalDiskSpace(ctx, statefulMount)
if err != nil {
s.Fatal("Failed to get expected total disk space: ", err)
}
if totalDiskSpace <= 0 || totalDiskSpace > expectedTotalDiskSpace+spaceMarginBytes {
s.Fatalf("Invalid total disk space; got %d, want: 0 < size < %d", totalDiskSpace, expectedTotalDiskSpace+spaceMarginBytes)
}
}