-
Notifications
You must be signed in to change notification settings - Fork 1
/
mockdisk.go
131 lines (114 loc) · 4.55 KB
/
mockdisk.go
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
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2020 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package disks
import (
"fmt"
"github.com/snapcore/snapd/osutil"
)
// MockDiskMapping is an implementation of Disk for mocking purposes, it is
// exported so that other packages can easily mock a specific disk layout
// without needing to mock the mount setup, sysfs, or udev commands just to test
// high level logic.
// DevNum must be a unique string per unique mocked disk, if only one disk is
// being mocked it can be left empty.
type MockDiskMapping struct {
FilesystemLabelToPartUUID map[string]string
DiskHasPartitions bool
DevNum string
}
// FindMatchingPartitionUUID returns a matching PartitionUUID for the specified
// label if it exists. Part of the Disk interface.
func (d *MockDiskMapping) FindMatchingPartitionUUID(label string) (string, error) {
osutil.MustBeTestBinary("mock disks only to be used in tests")
if partuuid, ok := d.FilesystemLabelToPartUUID[label]; ok {
return partuuid, nil
}
return "", FilesystemLabelNotFoundError{Label: label}
}
// HasPartitions returns if the mock disk has partitions or not. Part of the
// Disk interface.
func (d *MockDiskMapping) HasPartitions() bool {
return d.DiskHasPartitions
}
// MountPointIsFromDisk returns if the disk that the specified mount point comes
// from is the same disk as the object. Part of the Disk interface.
func (d *MockDiskMapping) MountPointIsFromDisk(mountpoint string, opts *Options) (bool, error) {
osutil.MustBeTestBinary("mock disks only to be used in tests")
// this is relying on the fact that DiskFromMountPoint should have been
// mocked for us to be using this mockDisk method anyways
otherDisk, err := DiskFromMountPoint(mountpoint, opts)
if err != nil {
return false, err
}
if otherDisk.Dev() == d.Dev() && otherDisk.HasPartitions() == d.HasPartitions() {
return true, nil
}
return false, nil
}
// Dev returns a unique representation of the mock disk that is suitable for
// comparing two mock disks to see if they are the same. Part of the Disk
// interface.
func (d *MockDiskMapping) Dev() string {
return d.DevNum
}
// Mountpoint is a combination of a mountpoint location and whether that
// mountpoint is a decrypted device. It is only used in identifying mount points
// with MountPointIsFromDisk and DiskFromMountPoint with
// MockMountPointDisksToPartitionMapping.
type Mountpoint struct {
Mountpoint string
IsDecryptedDevice bool
}
// MockMountPointDisksToPartitionMapping will mock DiskFromMountPoint such that
// the specified mapping is returned/used. Specifically, keys in the provided
// map are mountpoints, and the values for those keys are the disks that will
// be returned from DiskFromMountPoint or used internally in
// MountPointIsFromDisk.
func MockMountPointDisksToPartitionMapping(mockedMountPoints map[Mountpoint]*MockDiskMapping) (restore func()) {
osutil.MustBeTestBinary("mock disks only to be used in tests")
// verify that all unique MockDiskMapping's have unique DevNum's
alreadySeen := make(map[string]*MockDiskMapping, len(mockedMountPoints))
for _, mockDisk := range mockedMountPoints {
if old, ok := alreadySeen[mockDisk.DevNum]; ok {
if mockDisk != old {
// we already saw a disk with this DevNum as a different pointer
// so just assume it's different
msg := fmt.Sprintf("mocked disks %+v and %+v have the same DevNum (%s) but are not the same object", old, mockDisk, mockDisk.DevNum)
panic(msg)
}
// otherwise same ptr, no point in comparing them
} else {
// didn't see it before, save it now
alreadySeen[mockDisk.DevNum] = mockDisk
}
}
old := diskFromMountPoint
diskFromMountPoint = func(mountpoint string, opts *Options) (Disk, error) {
if opts == nil {
opts = &Options{}
}
m := Mountpoint{mountpoint, opts.IsDecryptedDevice}
if mockedDisk, ok := mockedMountPoints[m]; ok {
return mockedDisk, nil
}
return nil, fmt.Errorf("mountpoint %s not mocked", mountpoint)
}
return func() {
diskFromMountPoint = old
}
}