1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// Copyright (c) 2022-2025, Sylabs Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package user
import (
"bufio"
"context"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
var corpus = filepath.Join("..", "..", "test", "images")
func Test_Unmount(t *testing.T) {
if _, err := exec.LookPath("squashfuse"); err != nil {
t.Skip("squashfuse not found, skipping mount tests")
}
fusermountPath, err := exec.LookPath("fusermount")
if err != nil {
t.Skip("fusermount not found, skipping mount tests")
}
tests := []struct {
name string
mountSIF string
mountPath string
opts []UnmountOpt
wantErr bool
wantUnmounted bool
}{
{
name: "Mounted",
mountSIF: filepath.Join(corpus, "one-group.sif"),
mountPath: t.TempDir(),
wantErr: false,
wantUnmounted: true,
},
{
name: "NotMounted",
mountSIF: "",
mountPath: t.TempDir(),
wantErr: true,
},
{
name: "NotSquashfuse",
mountSIF: "",
mountPath: "/dev",
wantErr: true,
},
{
name: "FusermountBare",
mountSIF: "",
mountPath: t.TempDir(),
opts: []UnmountOpt{OptUnmountFusermountPath("fusermount")},
wantErr: true,
},
{
name: "FusermountValid",
mountSIF: filepath.Join(corpus, "one-group.sif"),
mountPath: t.TempDir(),
opts: []UnmountOpt{OptUnmountFusermountPath(fusermountPath)},
wantErr: false,
wantUnmounted: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.mountSIF != "" {
err := Mount(context.Background(), tt.mountSIF, tt.mountPath)
if err != nil {
t.Fatal(err)
}
}
err := Unmount(context.Background(), tt.mountPath, tt.opts...)
if err != nil && !tt.wantErr {
t.Errorf("Unexpected error: %s", err)
}
if err == nil && tt.wantErr {
t.Error("Unexpected success")
}
mounted, err := isMounted(tt.mountPath)
if err != nil {
t.Fatal(err)
}
if tt.wantUnmounted && mounted {
t.Errorf("Expected %s to be unmounted, but it is mounted", tt.mountPath)
}
})
}
}
var errBadMountInfo = errors.New("bad mount info")
func isMounted(mountPath string) (bool, error) {
mountPath, err := filepath.Abs(mountPath)
if err != nil {
return false, err
}
mi, err := os.Open("/proc/self/mountinfo")
if err != nil {
return false, fmt.Errorf("failed to open /proc/self/mountinfo: %w", err)
}
defer mi.Close()
scanner := bufio.NewScanner(mi)
for scanner.Scan() {
fields := strings.Split(scanner.Text(), " ")
if len(fields) < 5 {
return false, fmt.Errorf("not enough mountinfo fields: %w", errBadMountInfo)
}
//nolint:lll
// 1348 63 0:77 / /tmp/siftool-mount-956028386 ro,nosuid,nodev,relatime shared:646 - fuse.squashfuse squashfuse ro,user_id=1000,group_id=100
mntTarget := fields[4]
if mntTarget == mountPath {
return true, nil
}
}
return false, nil
}
|