]> git.proxmox.com Git - pve-storage.git/blob - test/disklist_test.pm
Diskmanage: detect osds/journals/etc. created with ceph-volume
[pve-storage.git] / test / disklist_test.pm
1 package PVE::Diskmanage::Test;
2
3 use strict;
4 use warnings;
5
6 use lib qw(..);
7
8 use PVE::Diskmanage;
9 use PVE::Tools;
10
11 use Test::MockModule;
12 use Test::More;
13 use JSON;
14 use Data::Dumper;
15
16 my $testcasedir; # current case directory
17 my $testcount = 0; # testcount for TAP::Harness
18 my $diskmanage_module; # mockmodule for PVE::Diskmanage
19 my $print = 0;
20
21 sub mocked_run_command {
22 my ($cmd, %param) = @_;
23
24 my $outputlines = [];
25 if (my $ref = ref($cmd)) {
26 if ($cmd->[0] =~ m/udevadm/i) {
27 # simulate udevadm output
28 my $dev = $cmd->[3];
29 $dev =~ s|/sys/block/||;
30 @$outputlines = split(/\n/, read_test_file("${dev}_udevadm"));
31
32 } elsif ($cmd->[0] =~ m/smartctl/i) {
33 # simulate smartctl output
34 my $dev;
35 my $type;
36 if (@$cmd > 3) {
37 $dev = $cmd->[5];
38 $type = 'smart';
39 } else {
40 $dev = $cmd->[2];
41 $type = 'health';
42 }
43 $dev =~ s|/dev/||;
44 @$outputlines = split(/\n/, read_test_file("${dev}_${type}"));
45 } elsif ($cmd->[0] =~ m/sgdisk/i) {
46 # simulate sgdisk
47 die "implement me: @$cmd\n";
48 } elsif ($cmd->[0] =~ m/zpool/i) {
49 # simulate zpool output
50 @$outputlines = split(/\n/, read_test_file('zpool'));
51
52 } elsif ($cmd->[0] =~ m/pvs/i) {
53 # simulate lvs output
54 @$outputlines = split(/\n/, read_test_file('pvs'));
55 } elsif ($cmd->[0] =~ m/lvs/i) {
56 @$outputlines = split(/\n/, read_test_file('lvs'));
57 } else {
58 print "unexpected run_command call: '@$cmd', aborting\n";
59 die;
60 }
61 } else {
62 print "unexpected run_command call: '@$cmd', aborting\n";
63 die;
64 }
65
66 my $outfunc;
67 if ($param{outfunc}) {
68 $outfunc = $param{outfunc};
69 map { &$outfunc(($_)) } @$outputlines;
70
71 return 0;
72 }
73 }
74
75 sub mocked_get_sysdir_info {
76 my ($param) = @_;
77
78 my $originalsub = $diskmanage_module->original('get_sysdir_info');
79
80 $param =~ s|/sys/block|disk_tests/$testcasedir|;
81
82 return &$originalsub($param);
83 }
84
85 sub mocked_is_iscsi {
86 return 0;
87 }
88
89 sub mocked_dir_glob_foreach {
90 my ($dir, $regex, $sub) = @_;
91
92 my $lines = [];
93
94 # read lines in from file
95 if ($dir =~ m{^/sys/block$} ) {
96 @$lines = split(/\n/, read_test_file('disklist'));
97 } elsif ($dir =~ m{^/sys/block/([^/]+)}) {
98 @$lines = split(/\n/, read_test_file('partlist'));
99 }
100
101 foreach my $line (@$lines) {
102 if ($line =~ m/$regex/) {
103 &$sub($line);
104 }
105 }
106 }
107
108 sub mocked_parse_proc_mounts {
109 my $text = read_test_file('mounts');
110
111 my $mounts = [];
112
113 foreach my $line(split(/\n/, $text)) {
114 push @$mounts, [split(/\s+/, $line)];
115 }
116
117 return $mounts;
118 }
119
120 sub read_test_file {
121 my ($filename) = @_;
122
123 if (!-f "disk_tests/$testcasedir/$filename") {
124 print "file '$testcasedir/$filename' not found\n";
125 return '';
126 }
127 open (my $fh, '<', "disk_tests/$testcasedir/$filename")
128 or die "Cannot open disk_tests/$testcasedir/$filename: $!";
129
130 my $output = <$fh> // '';
131 chomp $output if $output;
132 while (my $line = <$fh>) {
133 chomp $line;
134 $output .= "\n$line";
135 }
136
137 return $output;
138 }
139
140
141 sub test_disk_list {
142 my ($testdir) = @_;
143 subtest "Test '$testdir'" => sub {
144 my $testcount = 0;
145 $testcasedir = $testdir;
146
147 my $disks;
148 my $expected_disk_list;
149 eval {
150 $disks = PVE::Diskmanage::get_disks();
151 };
152 warn $@ if $@;
153 $expected_disk_list = decode_json(read_test_file('disklist_expected.json'));
154
155 print Dumper($disks) if $print;
156 $testcount++;
157 is_deeply($disks, $expected_disk_list, 'disk list should be the same');
158
159 foreach my $disk (sort keys %$disks) {
160 my $smart;
161 my $expected_smart;
162 eval {
163 $smart = PVE::Diskmanage::get_smart_data("/dev/$disk");
164 print Dumper($smart) if $print;
165 $expected_smart = decode_json(read_test_file("${disk}_smart_expected.json"));
166 };
167
168 if ($smart && $expected_smart) {
169 $testcount++;
170 is_deeply($smart, $expected_smart, "smart data for '$disk' should be the same");
171 } elsif ($smart && -f "disk_tests/$testcasedir/${disk}_smart_expected.json") {
172 $testcount++;
173 ok(0, "could not parse expected smart for '$disk'\n");
174 }
175 }
176
177 done_testing($testcount);
178 };
179 }
180
181 # start reading tests:
182
183 if (@ARGV && $ARGV[0] eq 'print') {
184 $print = 1;
185 }
186
187 print("Setting up Mocking\n");
188 $diskmanage_module = new Test::MockModule('PVE::Diskmanage', no_auto => 1);
189 $diskmanage_module->mock('run_command' => \&mocked_run_command);
190 print("\tMocked run_command\n");
191 $diskmanage_module->mock('dir_glob_foreach' => \&mocked_dir_glob_foreach);
192 print("\tMocked dir_glob_foreach\n");
193 $diskmanage_module->mock('get_sysdir_info' => \&mocked_get_sysdir_info);
194 print("\tMocked get_sysdir_info\n");
195 $diskmanage_module->mock('is_iscsi' => \&mocked_is_iscsi);
196 print("\tMocked is_iscsi\n");
197 $diskmanage_module->mock('assert_blockdev' => sub { return 1; });
198 print("\tMocked assert_blockdev\n");
199 $diskmanage_module->mock('dir_is_empty' => sub {
200 # all partitions have a holder dir
201 my $val = shift;
202 if ($val =~ m|^/sys/block/.+/.+/|) {
203 return 0;
204 }
205 return 1;
206 });
207 print("\tMocked dir_is_empty\n");
208 my $tools_module= new Test::MockModule('PVE::ProcFSTools', no_auto => 1);
209 $tools_module->mock('parse_proc_mounts' => \&mocked_parse_proc_mounts);
210 print("\tMocked parse_proc_mounts\n");
211 print("Done Setting up Mocking\n\n");
212
213 print("Beginning Tests:\n\n");
214 opendir (my $dh, 'disk_tests')
215 or die "Cannot open disk_tests: $!";
216
217 while (readdir $dh) {
218 my $dir = $_;
219 next if $dir eq '.' or $dir eq '..';
220 $testcount++;
221 test_disk_list($dir);
222 }
223
224 done_testing($testcount);