1# Copyright (c) 2008-2013 Zmanda, Inc. All Rights Reserved. 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, but 9# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 10# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11# for more details. 12# 13# You should have received a copy of the GNU General Public License along 14# with this program; if not, write to the Free Software Foundation, Inc., 15# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16# 17# Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300 18# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com 19 20use Test::More tests => 550; 21use File::Path qw( mkpath rmtree ); 22use Sys::Hostname; 23use Carp; 24use strict; 25use warnings; 26 27use lib "@amperldir@"; 28use Installcheck; 29use Installcheck::Mock; 30use Installcheck::Config; 31use Amanda::Debug; 32use Amanda::Device qw( :constants ); 33use Amanda::Config qw( :getconf :init ); 34use Amanda::Xfer qw( :constants ); 35use Amanda::Header qw( :constants ); 36use Amanda::Paths; 37use Amanda::Constants; 38use Amanda::Util; 39use Amanda::MainLoop; 40use IO::Socket; 41 42my $dev; 43my $dev_name; 44my ($vtape1, $vtape2); 45my ($input_filename, $output_filename) = 46 ( "$Installcheck::TMP/input.tmp", "$Installcheck::TMP/output.tmp" ); 47my $taperoot = "$Installcheck::TMP/Amanda_Device_test_tapes"; 48my $testconf; 49 50# we'll need some vtapes.. 51sub mkvtape { 52 my ($num) = @_; 53 54 my $mytape = "$taperoot/$num"; 55 if (-d $mytape) { rmtree($mytape); } 56 mkpath("$mytape/data"); 57 return $mytape; 58} 59 60 61# make up a fake dumpfile_t to write with 62my $dumpfile = Amanda::Header->new(); 63$dumpfile->{type} = $Amanda::Header::F_DUMPFILE; 64$dumpfile->{datestamp} = "20070102030405"; 65$dumpfile->{dumplevel} = 0; 66$dumpfile->{compressed} = 1; 67$dumpfile->{name} = "localhost"; 68$dumpfile->{disk} = "/home"; 69$dumpfile->{program} = "INSTALLCHECK"; 70 71my $write_file_count = 5; 72sub write_file { 73 my ($seed, $length, $filenum) = @_; 74 75 $dumpfile->{'datestamp'} = "2000010101010$filenum"; 76 77 ok($dev->start_file($dumpfile), 78 "start file $filenum") 79 or diag($dev->error_or_status()); 80 81 is($dev->file(), $filenum, 82 "Device has correct filenum"); 83 84 croak ("selected file size $length is *way* too big") 85 unless ($length < 1024*1024*10); 86 ok(Amanda::Device::write_random_to_device($seed, $length, $dev), 87 "write random data"); 88 89 if(ok($dev->in_file(), 90 "still in_file")) { 91 ok($dev->finish_file(), 92 "finish_file") 93 or diag($dev->error_or_status()); 94 } else { 95 pass("not in file, so not calling finish_file"); 96 } 97} 98 99my $verify_file_count = 4; 100sub verify_file { 101 my ($seed, $length, $filenum) = @_; 102 103 ok(my $read_dumpfile = $dev->seek_file($filenum), 104 "seek to file $filenum") 105 or diag($dev->error_or_status()); 106 is($dev->file(), $filenum, 107 "device is really at file $filenum"); 108 ok(header_for($read_dumpfile, $filenum), 109 "header is correct") 110 or diag($dev->error_or_status()); 111 ok(Amanda::Device::verify_random_from_device($seed, $length, $dev), 112 "verified file contents"); 113} 114 115sub header_for { 116 my ($hdr, $filenum) = @_; 117 return ($hdr and $hdr->{'datestamp'} eq "2000010101010$filenum"); 118} 119 120# properties test 121 122my @common_properties = ( 123 'appendable', 124 'block_size', 125 'canonical_name', 126 'concurrency', 127 'max_block_size', 128 'medium_access_type', 129 'min_block_size', 130 'partial_deletion', 131 'full_deletion', 132 'streaming', 133); 134 135sub properties_include { 136 my ($got, $should_include, $msg) = @_; 137 my %got = map { $_->{'name'}, 1 } @$got; 138 my @missing = grep { !defined($got{$_}) } @$should_include; 139 if (@missing) { 140 fail($msg); 141 diag(" Expected properties: " . join(", ", @$should_include)); 142 diag(" Got properties: " . join(", ", @$got)); 143 diag(" Missing properties: " . join(", ", @missing)); 144 } else { 145 pass($msg); 146 } 147} 148 149#### 150## get stuff set up 151 152$testconf = Installcheck::Config->new(); 153$testconf->write(); 154config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF') == $CFGERR_OK 155 or die("Could not load configuration"); 156 157# put the debug messages somewhere 158Amanda::Debug::dbopen("installcheck"); 159Installcheck::log_test_output(); 160 161#### 162## Test errors a little bit 163 164$dev = Amanda::Device->new("foobar:"); 165isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 166 "creation of a bogus 'foobar:' device fails"); 167 168$dev = Amanda::Device->new("rait:{{"); 169isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 170 "creation of a bogus 'rait:{{' device fails"); 171 172$dev = Amanda::Device->new("rait:{a,b"); 173isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 174 "creation of a bogus 'rait:{a,b' device fails"); 175 176#### 177## first, test out the 'null' device. 178 179$dev_name = "null:"; 180 181$dev = Amanda::Device->new($dev_name); 182is($dev->status(), $DEVICE_STATUS_SUCCESS, 183 "create null device") 184 or diag $dev->error_or_status(); 185ok($dev->start($ACCESS_WRITE, "NULL1", "19780615010203"), 186 "start null device in write mode") 187 or diag $dev->error_or_status(); 188 189# try properties 190properties_include([ $dev->property_list() ], [ @common_properties ], 191 "necessary properties listed on null device"); 192is($dev->property_get("canonical_name"), "null:", 193 "property_get(canonical_name) on null device"); 194is($dev->property_get("caNONical-name"), "null:", 195 "property_get(caNONical-name) on null device (case, dash-insensitivity)"); 196is_deeply([ $dev->property_get("canonical_name") ], 197 [ "null:", $PROPERTY_SURETY_GOOD, $PROPERTY_SOURCE_DEFAULT ], 198 "extended property_get returns correct surety/source"); 199for my $prop ($dev->property_list()) { 200 next unless $prop->{'name'} eq 'canonical_name'; 201 is($prop->{'description'}, 202 "The most reliable device name to use to refer to this device.", 203 "property info for canonical name is correct"); 204} 205ok(!$dev->property_get("full_deletion"), 206 "property_get(full_deletion) on null device"); 207is($dev->property_get("comment"), undef, 208 "no comment by default"); 209ok($dev->property_set("comment", "well, that was silly"), 210 "set comment property"); 211is($dev->property_get("comment"), "well, that was silly", 212 "comment correctly stored"); 213 214# and write a file to it 215write_file(0xabcde, 1024*256, 1); 216 217# (don't finish the device, testing the finalize method's cleanup) 218 219#### 220## Now some full device tests 221 222## VFS device 223 224$vtape1 = mkvtape(1); 225$dev_name = "file:$vtape1"; 226 227$dev = Amanda::Device->new($dev_name); 228is($dev->status(), $DEVICE_STATUS_SUCCESS, 229 "$dev_name: create successful") 230 or diag($dev->error_or_status()); 231 232properties_include([ $dev->property_list() ], 233 [ @common_properties, 'max_volume_usage' ], 234 "necessary properties listed on vfs device"); 235 236# play with properties a little bit 237ok($dev->property_set("comment", 16), 238 "set an string property to an integer"); 239 240ok($dev->property_set("comment", 16.0), 241 "set an string property to a float"); 242 243ok($dev->property_set("comment", "hi mom"), 244 "set an string property to a string"); 245 246ok($dev->property_set("comment", "32768"), 247 "set an integer property to a simple string"); 248 249ok($dev->property_set("comment", "32k"), 250 "set an integer property to a string with a unit"); 251 252ok($dev->property_set("block_size", 32768), 253 "set an integer property to an integer"); 254 255ok(!($dev->property_set("invalid-property-name", 32768)), 256 "set an invalid-property-name"); 257 258$dev->read_label(); 259ok($dev->status() & $DEVICE_STATUS_VOLUME_UNLABELED, 260 "initially unlabeled") 261 or diag($dev->error_or_status()); 262 263ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 264 "start in write mode") 265 or diag($dev->error_or_status()); 266 267ok(!($dev->status() & $DEVICE_STATUS_VOLUME_UNLABELED), 268 "not unlabeled anymore") 269 or diag($dev->error_or_status()); 270 271for (my $i = 1; $i <= 3; $i++) { 272 write_file(0x2FACE, $dev->block_size()*10+17, $i); 273} 274 275ok($dev->finish(), 276 "finish device after write") 277 or diag($dev->error_or_status()); 278 279$dev->read_label(); 280ok(!($dev->status()), 281 "no error, at all, from read_label") 282 or diag($dev->error_or_status()); 283 284# append one more copy, to test ACCESS_APPEND 285 286ok($dev->start($ACCESS_APPEND, undef, undef), 287 "start in append mode") 288 or diag($dev->error_or_status()); 289 290write_file(0xD0ED0E, $dev->block_size()*4, 4); 291 292ok($dev->finish(), 293 "finish device after append") 294 or diag($dev->error_or_status()); 295 296# try reading the third file back, creating a new device 297# object first, and skipping the read-label step. 298 299$dev = undef; 300$dev = Amanda::Device->new($dev_name); 301is($dev->status(), $DEVICE_STATUS_SUCCESS, 302 "$dev_name: re-create successful") 303 or diag($dev->error_or_status()); 304 305ok($dev->start($ACCESS_READ, undef, undef), 306 "start in read mode") 307 or diag($dev->error_or_status()); 308 309verify_file(0x2FACE, $dev->block_size()*10+17, 3); 310 311{ 312 # try two seek_file's in a row 313 my $hdr = $dev->seek_file(3); 314 is($hdr? $hdr->{'type'} : -1, $Amanda::Header::F_DUMPFILE, "seek_file the first time"); 315 $hdr = $dev->seek_file(3); 316 is($hdr? $hdr->{'type'} : -1, $Amanda::Header::F_DUMPFILE, "seek_file the second time"); 317} 318 319ok($dev->finish(), 320 "finish device after read") 321 or diag($dev->error_or_status()); 322 323# test erase 324ok($dev->erase(), 325 "erase device") 326 or diag($dev->error_or_status()); 327 328ok($dev->erase(), 329 "erase device (again)") 330 or diag($dev->error_or_status()); 331 332ok($dev->finish(), 333 "finish device after erase") 334 or diag($dev->error_or_status()); 335 336# test monitor_free_space property (testing the monitoring would require a 337# dedicated partition for the tests - it's not worth it) 338 339ok($dev->property_get("monitor_free_space"), 340 "monitor_free_space property is set by default"); 341 342ok($dev->property_set("monitor_free_space", 0), 343 "monitor_free_space property can be set to false"); 344 345ok(!$dev->property_get("monitor_free_space"), 346 "monitor_free_space property value 'sticks'"); 347 348# test the LEOM functionality 349 350$dev = undef; 351$dev = Amanda::Device->new($dev_name); 352is($dev->status(), $DEVICE_STATUS_SUCCESS, 353 "$dev_name: re-create successful") 354 or diag($dev->error_or_status()); 355ok($dev->property_set("MAX_VOLUME_USAGE", "512k"), 356 "set MAX_VOLUME_USAGE to test LEOM"); 357ok($dev->property_set("LEOM", 1), 358 "set LEOM"); 359ok($dev->property_set("ENFORCE_MAX_VOLUME_USAGE", 0), 360 "set ENFORCE_MAX_VOLUME_USAGE"); 361 362ok($dev->start($ACCESS_WRITE, 'TESTCONF23', undef), 363 "start in write mode") 364 or diag($dev->error_or_status()); 365 366ok($dev->start_file($dumpfile), 367 "start file 1") 368 or diag($dev->error_or_status()); 369 370ok(Amanda::Device::write_random_to_device(0xCAFE, 440*1024, $dev), 371 "write random data into the early-warning zone"); 372 373ok(!$dev->is_eom, 374 "device does not indicates LEOM after writing when ENFORCE_MAX_VOLUME_USAGE is FALSE"); 375 376ok($dev->finish_file(), 377 "..but a finish_file is allowed to complete") 378 or diag($dev->error_or_status()); 379 380ok($dev->finish(), 381 "finish device after LEOM test") 382 or diag($dev->error_or_status()); 383 384$dev = undef; 385$dev = Amanda::Device->new($dev_name); 386is($dev->status(), $DEVICE_STATUS_SUCCESS, 387 "$dev_name: re-create successful") 388 or diag($dev->error_or_status()); 389ok($dev->property_set("MAX_VOLUME_USAGE", "512k"), 390 "set MAX_VOLUME_USAGE to test LEOM"); 391ok($dev->property_set("LEOM", 1), 392 "set LEOM"); 393ok($dev->property_set("ENFORCE_MAX_VOLUME_USAGE", 1), 394 "set ENFORCE_MAX_VOLUME_USAGE"); 395 396ok($dev->start($ACCESS_WRITE, 'TESTCONF23', undef), 397 "start in write mode") 398 or diag($dev->error_or_status()); 399 400ok($dev->start_file($dumpfile), 401 "start file 1") 402 or diag($dev->error_or_status()); 403 404ok(!$dev->is_eom, 405 "device does not indicate LEOM before writing"); 406 407ok(Amanda::Device::write_random_to_device(0xCAFE, 440*1024, $dev), 408 "write random data into the early-warning zone"); 409 410ok($dev->is_eom, 411 "device indicates LEOM after writing"); 412 413ok($dev->finish_file(), 414 "..but a finish_file is allowed to complete") 415 or diag($dev->error_or_status()); 416 417ok($dev->finish(), 418 "finish device after LEOM test") 419 or diag($dev->error_or_status()); 420 421$dev = undef; 422$dev = Amanda::Device->new($dev_name); 423is($dev->status(), $DEVICE_STATUS_SUCCESS, 424 "$dev_name: re-create successful") 425 or diag($dev->error_or_status()); 426ok($dev->property_set("MAX_VOLUME_USAGE", "512k"), 427 "set MAX_VOLUME_USAGE to test LEOM"); 428ok($dev->property_set("LEOM", 1), 429 "set LEOM"); 430 431ok($dev->start($ACCESS_WRITE, 'TESTCONF23', undef), 432 "start in write mode") 433 or diag($dev->error_or_status()); 434 435ok($dev->start_file($dumpfile), 436 "start file 1") 437 or diag($dev->error_or_status()); 438 439ok(!$dev->is_eom, 440 "device does not indicate LEOM before writing"); 441 442ok(Amanda::Device::write_random_to_device(0xCAFE, 440*1024, $dev), 443 "write random data into the early-warning zone"); 444 445ok($dev->is_eom, 446 "device indicates LEOM after writing as default value of ENFORCE_MAX_VOLUME_USAGE is true for vfs device"); 447 448ok($dev->finish_file(), 449 "..but a finish_file is allowed to complete") 450 or diag($dev->error_or_status()); 451 452ok($dev->finish(), 453 "finish device after LEOM test") 454 or diag($dev->error_or_status()); 455 456$dev = undef; 457$dev = Amanda::Device->new($dev_name); 458is($dev->status(), $DEVICE_STATUS_SUCCESS, 459 "$dev_name: re-create successful") 460 or diag($dev->error_or_status()); 461ok($dev->property_set("MAX_VOLUME_USAGE", "160k"), 462 "set MAX_VOLUME_USAGE to test LEOM while writing the first header"); 463ok($dev->property_set("LEOM", 1), 464 "set LEOM"); 465 466ok($dev->start($ACCESS_WRITE, 'TESTCONF23', undef), 467 "start in write mode") 468 or diag($dev->error_or_status()); 469 470ok($dev->start_file($dumpfile), 471 "start file 1") 472 or diag($dev->error_or_status()); 473 474ok($dev->is_eom, 475 "device indicates LEOM after writing first header"); 476 477ok($dev->finish_file(), 478 "..but a finish_file is allowed to complete") 479 or diag($dev->error_or_status()); 480 481ok($dev->finish(), 482 "finish device after LEOM test") 483 or diag($dev->error_or_status()); 484 485## dvdrw device 486 487$vtape1 = mkvtape(1); 488$dev_name = "dvdrw:$vtape1:/dev/scd0"; 489 490$dev = Amanda::Device->new($dev_name); 491is($dev->status(), $DEVICE_STATUS_SUCCESS, 492 "$dev_name: create successful") 493 or diag($dev->error_or_status()); 494 495properties_include([ $dev->property_list() ], 496 [ @common_properties, 'max_volume_usage' ], 497 "necessary properties listed on vfs device"); 498 499# play with properties a little bit 500ok($dev->property_set("DVDRW_GROWISOFS_COMMAND", "/path/to/growisofs"), 501 "set DVDRW_GROWISOFS_COMMAND"); 502 503ok($dev->property_set("dvdrw_mount_command", "/path/to/mount"), 504 "set dvdrw_mount_command"); 505 506ok($dev->property_set("dvdrw_umount_command", "/path/to/umount"), 507 "set dvdrw_umount_command"); 508 509ok($dev->property_set("block_size", 32768), 510 "set an integer property to an integer"); 511 512ok(!($dev->property_set("invalid-property-name", 32768)), 513 "set an invalid-property-name"); 514 515#### 516## Test a RAIT device of two vfs devices. 517 518($vtape1, $vtape2) = (mkvtape(1), mkvtape(2)); 519$dev_name = "rait:file:{$vtape1,$vtape2}"; 520 521$dev = Amanda::Device->new($dev_name); 522is($dev->status(), $DEVICE_STATUS_SUCCESS, 523 "$dev_name: create successful") 524 or diag($dev->error_or_status()); 525 526ok($dev->configure(1), "configure device"); 527 528properties_include([ $dev->property_list() ], [ @common_properties ], 529 "necessary properties listed on rait device"); 530 531is($dev->property_get("block_size"), 32768, # (RAIT default) 532 "rait device calculates a default block size correctly"); 533 534ok($dev->property_set("block_size", 32768*16), 535 "rait device accepts an explicit block size"); 536 537is($dev->property_get("block_size"), 32768*16, 538 "..and remembers it"); 539 540ok($dev->property_set("max_volume_usage", 32768*1000), 541 "rait device accepts property MAX_VOLUME_USAGE"); 542 543is($dev->property_get("max_volume_usage"), 32768*1000, 544 "..and remembers it"); 545 546$dev->read_label(); 547ok($dev->status() & $DEVICE_STATUS_VOLUME_UNLABELED, 548 "initially unlabeled") 549 or diag($dev->error_or_status()); 550 551ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 552 "start in write mode") 553 or diag($dev->error_or_status()); 554 555ok(!($dev->status() & $DEVICE_STATUS_VOLUME_UNLABELED), 556 "not unlabeled anymore") 557 or diag($dev->error_or_status()); 558 559for (my $i = 1; $i <= 3; $i++) { 560 write_file(0x2FACE, $dev->block_size()*10+17, $i); 561} 562 563ok($dev->finish(), 564 "finish device after write") 565 or diag($dev->error_or_status()); 566 567$dev->read_label(); 568ok(!($dev->status()), 569 "no error, at all, from read_label") 570 or diag($dev->error_or_status()); 571 572# append one more copy, to test ACCESS_APPEND 573 574ok($dev->start($ACCESS_APPEND, undef, undef), 575 "start in append mode") 576 or diag($dev->error_or_status()); 577 578write_file(0xD0ED0E, $dev->block_size()*4, 4); 579 580ok($dev->finish(), 581 "finish device after append") 582 or diag($dev->error_or_status()); 583 584# try reading the third file back, creating a new device 585# object first, and skipping the read-label step. 586 587$dev = undef; 588$dev = Amanda::Device->new($dev_name); 589is($dev->status(), $DEVICE_STATUS_SUCCESS, 590 "$dev_name: re-create successful") 591 or diag($dev->error_or_status()); 592 593ok($dev->start($ACCESS_READ, undef, undef), 594 "start in read mode") 595 or diag($dev->error_or_status()); 596 597verify_file(0x2FACE, $dev->block_size()*10+17, 3); 598 599ok($dev->finish(), 600 "finish device after read") 601 or diag($dev->error_or_status()); 602 603ok($dev->start($ACCESS_READ, undef, undef), 604 "start in read mode after missing volume") 605 or diag($dev->error_or_status()); 606 607# corrupt the device somehow and hope it keeps working 608rmtree("$taperoot/1"); 609 610verify_file(0x2FACE, $dev->block_size()*10+17, 3); 611verify_file(0xD0ED0E, $dev->block_size()*4, 4); 612verify_file(0x2FACE, $dev->block_size()*10+17, 2); 613 614ok($dev->finish(), 615 "finish device read after missing volume") 616 or diag($dev->error_or_status()); 617 618ok(!($dev->start($ACCESS_WRITE, "TESTCONF29", undef)), 619 "start in write mode fails with missing volume") 620 or diag($dev->error_or_status()); 621 622undef $dev; 623 624$dev_name = "rait:{file:$vtape2,MISSING}"; 625$dev = Amanda::Device->new($dev_name); 626 627ok($dev->start($ACCESS_READ, undef, undef), 628 "start in read mode with MISSING") 629 or diag($dev->error_or_status()); 630 631verify_file(0x2FACE, $dev->block_size()*10+17, 3); 632verify_file(0xD0ED0E, $dev->block_size()*4, 4); 633verify_file(0x2FACE, $dev->block_size()*10+17, 2); 634 635ok($dev->finish(), 636 "finish device read with MISSING") 637 or diag($dev->error_or_status()); 638 639ok(!($dev->start($ACCESS_WRITE, "TESTCONF29", undef)), 640 "start in write mode fails with MISSING") 641 or diag($dev->error_or_status()); 642 643undef $dev; 644 645$dev = Amanda::Device->new_rait_from_children( 646 Amanda::Device->new("file:$vtape2"), undef); 647 648ok(!($dev->start($ACCESS_WRITE, "TESTCONF29", undef)), 649 "start a RAIT device in write mode fails, when created with 'undef'") 650 or diag($dev->error_or_status()); 651 652# Make two devices with different labels, should get a 653# message accordingly. 654($vtape1, $vtape2) = (mkvtape(1), mkvtape(2)); 655 656my $n = 13; 657for $dev_name ("file:$vtape1", "file:$vtape2") { 658 my $dev = Amanda::Device->new($dev_name); 659 is($dev->status(), $DEVICE_STATUS_SUCCESS, 660 "$dev_name: Open successful") 661 or diag($dev->error_or_status()); 662 ok($dev->start($ACCESS_WRITE, "TESTCONF$n", undef), 663 "wrote label 'TESTCONF$n'"); 664 ok($dev->finish(), "finished device"); 665 $n++; 666} 667 668$dev = Amanda::Device->new_rait_from_children( 669 Amanda::Device->new("file:$vtape1"), 670 Amanda::Device->new("file:$vtape2")); 671is($dev->status(), $DEVICE_STATUS_SUCCESS, 672 "new_rait_from_children: Open successful") 673 or diag($dev->error_or_status()); 674 675$dev->read_label(); 676ok($dev->status() & $DEVICE_STATUS_VOLUME_ERROR, 677 "Label mismatch error handled correctly") 678 or diag($dev->error_or_status()); 679 680# Use some config to set a block size on a child device 681($vtape1, $vtape2) = (mkvtape(1), mkvtape(2)); 682$dev_name = "rait:{file:$vtape1,mytape2}"; 683 684$testconf = Installcheck::Config->new(); 685$testconf->add_device("mytape2", [ 686 "tapedev" => "\"file:$vtape2\"", 687 "device_property" => "\"BLOCK_SIZE\" \"64k\"" 688]); 689$testconf->write(); 690config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF') == $CFGERR_OK 691 or die("Could not load configuration"); 692 693$dev = Amanda::Device->new($dev_name); 694is($dev->status(), $DEVICE_STATUS_SUCCESS, 695 "$dev_name: create successful") 696 or diag($dev->error_or_status()); 697 698ok($dev->configure(1), "configure device"); 699 700is($dev->property_get("block_size"), 65536, 701 "rait device calculates a block size from its children correctly"); 702 703# Test an S3 device if the proper environment variables are set 704my $S3_SECRET_KEY = $ENV{'INSTALLCHECK_S3_SECRET_KEY'}; 705my $S3_ACCESS_KEY = $ENV{'INSTALLCHECK_S3_ACCESS_KEY'}; 706my $DEVPAY_SECRET_KEY = $ENV{'INSTALLCHECK_DEVPAY_SECRET_KEY'}; 707my $DEVPAY_ACCESS_KEY = $ENV{'INSTALLCHECK_DEVPAY_ACCESS_KEY'}; 708my $DEVPAY_USER_TOKEN = $ENV{'INSTALLCHECK_DEVPAY_USER_TOKEN'}; 709 710my $run_s3_tests = defined $S3_SECRET_KEY && defined $S3_ACCESS_KEY; 711my $run_devpay_tests = defined $DEVPAY_SECRET_KEY && 712 defined $DEVPAY_ACCESS_KEY && $DEVPAY_USER_TOKEN; 713 714my $s3_make_device_count = 7; 715sub s3_make_device($$) { 716 my ($dev_name, $kind) = @_; 717 $dev = Amanda::Device->new($dev_name); 718 is($dev->status(), $DEVICE_STATUS_SUCCESS, 719 "$dev_name: create successful") 720 or diag($dev->error_or_status()); 721 722 my @s3_props = ( 's3_access_key', 's3_secret_key' ); 723 push @s3_props, 's3_user_token' if ($kind eq "devpay"); 724 properties_include([ $dev->property_list() ], [ @common_properties, @s3_props ], 725 "necessary properties listed on s3 device"); 726 727 ok($dev->property_set('BLOCK_SIZE', 32768*2), 728 "set block size") 729 or diag($dev->error_or_status()); 730 731 # might as well save a few cents while testing this property.. 732 ok($dev->property_set('S3_STORAGE_CLASS', 'REDUCED_REDUNDANCY'), 733 "set storage class") 734 or diag($dev->error_or_status()); 735 736 if ($kind eq "s3") { 737 # use regular S3 credentials 738 ok($dev->property_set('S3_ACCESS_KEY', $S3_ACCESS_KEY), 739 "set S3 access key") 740 or diag($dev->error_or_status()); 741 742 ok($dev->property_set('S3_SECRET_KEY', $S3_SECRET_KEY), 743 "set S3 secret key") 744 or diag($dev->error_or_status()); 745 746 pass("(placeholder)"); 747 } elsif ($kind eq "devpay") { 748 # use devpay credentials 749 ok($dev->property_set('S3_ACCESS_KEY', $DEVPAY_ACCESS_KEY), 750 "set devpay access key") 751 or diag($dev->error_or_status()); 752 753 ok($dev->property_set('S3_SECRET_KEY', $DEVPAY_SECRET_KEY), 754 "set devpay secret key") 755 or diag($dev->error_or_status()); 756 757 ok($dev->property_set('S3_USER_TOKEN', $DEVPAY_USER_TOKEN), 758 "set devpay user token") 759 or diag($dev->error_or_status()); 760 } else { 761 croak("didn't recognize the device kind, so no credentials were set"); 762 } 763 return $dev; 764} 765 766my $base_name; 767 768SKIP: { 769 skip "define \$INSTALLCHECK_S3_{SECRET,ACCESS}_KEY to run S3 tests", 770 103 + 771 1 * $verify_file_count + 772 7 * $write_file_count + 773 13 * $s3_make_device_count 774 unless $run_s3_tests; 775 776 $dev_name = "s3:"; 777 $dev = Amanda::Device->new($dev_name); 778 isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 779 "creating $dev_name fails miserably"); 780 781 $dev_name = "s3:foo"; 782 $dev = Amanda::Device->new($dev_name); 783 784 ok($dev->property_get("full_deletion"), 785 "property_get(full_deletion) on s3 device"); 786 787 ok($dev->property_get("leom"), 788 "property_get(leom) on s3 device"); 789 790 # test parsing of boolean values 791 # (s3 is the only device driver that has a writable boolean property at the 792 # moment) 793 794 my @verbose_vals = ( 795 {'val' => '1', 'true' => 1}, 796 {'val' => '0', 'true' => 0}, 797 {'val' => 't', 'true' => 1}, 798 {'val' => 'true', 'true' => 1}, 799 {'val' => 'f', 'true' => 0}, 800 {'val' => 'false', 'true' => 0}, 801 {'val' => 'y', 'true' => 1}, 802 {'val' => 'yes', 'true' => 1}, 803 {'val' => 'n', 'true' => 0}, 804 {'val' => 'no', 'true' => 0}, 805 {'val' => 'on', 'true' => 1}, 806 {'val' => 'off', 'true' => 0}, 807 {'val' => 'oFf', 'true' => 0}, 808 ); 809 810 foreach my $v (@verbose_vals) { 811 $dev_name = "s3:foo"; 812 $dev = Amanda::Device->new($dev_name); 813 814 $testconf = Installcheck::Config->new(); 815 $testconf->add_param("device_property", "\"verbose\" \"$v->{'val'}\""); 816 $testconf->write(); 817 config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF') == $CFGERR_OK 818 or die("Could not load configuration"); 819 820 ok($dev->configure(1), 821 "configured device with verbose set to $v->{'val'}") 822 or diag($dev->error_or_status()); 823 824 my $get_val = $dev->property_get('verbose'); 825 # see if truth-iness matches 826 my $expec = $v->{'true'}? "true" : "false"; 827 is(!!$dev->property_get('verbose'), !!$v->{'true'}, 828 "device_property 'VERBOSE' '$v->{'val'}' => property_get(verbose) returning $expec"); 829 } 830 831 # test unparsable property 832 $dev_name = "s3:foo"; 833 $dev = Amanda::Device->new($dev_name); 834 835 $testconf = Installcheck::Config->new(); 836 $testconf->add_param("device_property", "\"verbose\" \"foo\""); 837 $testconf->write(); 838 config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF') == $CFGERR_OK 839 or die("Could not load configuration"); 840 841 ok(!$dev->configure(1), 842 "failed to configure device with verbose set to foo"); 843 844 like($dev->error_or_status(), qr/'verbose'/, 845 "error message mentions property name"); 846 847 like($dev->error_or_status(), qr/'foo'/, 848 "error message mentions property value"); 849 850 like($dev->error_or_status(), qr/gboolean/, 851 "error message mentions property type"); 852 853 my $hostname = hostname(); 854 $hostname =~ s/\./-/g; 855 $base_name = "$S3_ACCESS_KEY-installcheck-$hostname"; 856 $dev_name = "s3:$base_name-s3-1"; 857 $dev = s3_make_device($dev_name, "s3"); 858 $dev->read_label(); 859 my $status = $dev->status(); 860 # this test appears very liberal, but catches the case where setup_handle fails without 861 # giving false positives 862 ok(($status == $DEVICE_STATUS_SUCCESS) || (($status & $DEVICE_STATUS_VOLUME_UNLABELED) != 0), 863 "status is either OK or possibly unlabeled") 864 or diag($dev->error_or_status()); 865 866 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 867 "start in write mode") 868 or diag($dev->error_or_status()); 869 870 ok(!($dev->status() & $DEVICE_STATUS_VOLUME_UNLABELED), 871 "it's labeled now") 872 or diag($dev->error_or_status()); 873 874 for (my $i = 1; $i <= 3; $i++) { 875 write_file(0x2FACE, $dev->block_size()*10, $i); 876 } 877 878 ok($dev->finish(), 879 "finish device after write") 880 or diag($dev->error_or_status()); 881 882 $dev->read_label(); 883 ok(!($dev->status()), 884 "no error, at all, from read_label") 885 or diag($dev->error_or_status()); 886 887 # append one more copy, to test ACCESS_APPEND 888 889 ok($dev->start($ACCESS_APPEND, undef, undef), 890 "start in append mode") 891 or diag($dev->error_or_status()); 892 893 write_file(0xD0ED0E, $dev->block_size()*10, 4); 894 895 ok($dev->finish(), 896 "finish device after append") 897 or diag($dev->error_or_status()); 898 899 # try reading the third file back 900 901 ok($dev->start($ACCESS_READ, undef, undef), 902 "start in read mode") 903 or diag($dev->error_or_status()); 904 905 verify_file(0x2FACE, $dev->block_size()*10, 3); 906 907 # test EOT indications on reading 908 my $hdr = $dev->seek_file(4); 909 is($hdr->{'type'}, $Amanda::Header::F_DUMPFILE, 910 "file 4 has correct type F_DUMPFILE"); 911 912 $hdr = $dev->seek_file(5); 913 is($hdr->{'type'}, $Amanda::Header::F_TAPEEND, 914 "file 5 has correct type F_TAPEEND"); 915 916 $hdr = $dev->seek_file(6); 917 is($hdr, undef, "seek_file returns undef for file 6"); 918 919 ok($dev->finish(), 920 "finish device after read") 921 or diag($dev->error_or_status()); # (note: we don't use write_max_size here, 922 # as the maximum for S3 is very large) 923 924 ok($dev->erase(), 925 "erase device") 926 or diag($dev->error_or_status()); 927 928 ok($dev->erase(), 929 "erase device (again)") 930 or diag($dev->error_or_status()); 931 932 ok($dev->finish(), 933 "finish device after erase") 934 or diag($dev->error_or_status()); 935 936 $dev->read_label(); 937 $status = $dev->status(); 938 ok($status & $DEVICE_STATUS_VOLUME_UNLABELED, 939 "status is unlabeled after an erase") 940 or diag($dev->error_or_status()); 941 942 ok($dev->erase(), 943 "erase device") 944 or diag($dev->error_or_status()); 945 946 $dev_name = "s3:$base_name-s3-2"; 947 $dev = s3_make_device($dev_name, "s3"); 948 949 ok($dev->erase(), 950 "erase device right after creation") 951 or diag($dev->error_or_status()); 952 953 $dev_name = "s3:$base_name-s3-3"; 954 $dev = s3_make_device($dev_name, "s3"); 955 956 # set MAX_VOLUME_USAGE, LEOM=true, ENFORCE_MAX_VOLUME_USAGE=false 957 ok($dev->property_set('MAX_VOLUME_USAGE', "512k"), 958 "set MAX_VOLUME_USAGE to test LEOM"); 959 960 ok($dev->property_set("LEOM", 1), 961 "set LEOM"); 962 963 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 964 "start in write mode") 965 or diag($dev->error_or_status()); 966 967 write_file(0x2FACE, 440*1024, 1); 968 969 ok(!$dev->is_eom, 970 "device does not indicate LEOM after writing as property ENFORCE_MAX_VOLUME_USAGE not set and its default value is false"); 971 972 ok($dev->finish(), 973 "finish device after LEOM test") 974 or diag($dev->error_or_status()); 975 976 ok($dev->erase(), 977 "erase device") 978 or diag($dev->error_or_status()); 979 980 $dev_name = "s3:$base_name-s3-4"; 981 $dev = s3_make_device($dev_name, "s3"); 982 983 # set MAX_VOLUME_USAGE, LEOM=true, ENFORCE_MAX_VOLUME_USAGE=true 984 ok($dev->property_set('MAX_VOLUME_USAGE', "512k"), 985 "set MAX_VOLUME_USAGE to test LEOM"); 986 987 ok($dev->property_set('ENFORCE_MAX_VOLUME_USAGE', 1 ), 988 "set ENFORCE_MAX_VOLUME_USAGE"); 989 990 ok($dev->property_set("LEOM", 1), 991 "set LEOM"); 992 993 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 994 "start in write mode") 995 or diag($dev->error_or_status()); 996 997 write_file(0x2FACE, 440*1024, 1); 998 999 ok($dev->is_eom, 1000 "device indicates LEOM after writing, when property ENFORCE_MAX_VOLUME_USAGE set to true"); 1001 1002 ok($dev->finish(), 1003 "finish device after LEOM test") 1004 or diag($dev->error_or_status()); 1005 1006 ok($dev->erase(), 1007 "erase device") 1008 or diag($dev->error_or_status()); 1009 1010 $dev_name = "s3:$base_name-s3-5"; 1011 $dev = s3_make_device($dev_name, "s3"); 1012 1013 # set MAX_VOLUME_USAGE, LEOM=true, ENFORCE_MAX_VOLUME_USAGE=false 1014 ok($dev->property_set('MAX_VOLUME_USAGE', "512k"), 1015 "set MAX_VOLUME_USAGE to test LEOM"); 1016 1017 ok($dev->property_set('ENFORCE_MAX_VOLUME_USAGE', 0 ), 1018 "set ENFORCE_MAX_VOLUME_USAGE"); 1019 1020 ok($dev->property_set("LEOM", 1), 1021 "set LEOM"); 1022 1023 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 1024 "start in write mode") 1025 or diag($dev->error_or_status()); 1026 1027 write_file(0x2FACE, 440*1024, 1); 1028 1029 ok(!$dev->is_eom, 1030 "device does not indicate LEOM after writing, when property ENFORCE_MAX_VOLUME_USAGE set to false"); 1031 1032 ok($dev->finish(), 1033 "finish device after LEOM test") 1034 or diag($dev->error_or_status()); 1035 1036 ok($dev->erase(), 1037 "erase device") 1038 or diag($dev->error_or_status()); 1039 1040 # try with empty user token 1041 $dev_name = lc("s3:$base_name-s3-6"); 1042 $dev = s3_make_device($dev_name, "s3"); 1043 ok($dev->property_set('S3_USER_TOKEN', ''), 1044 "set devpay user token") 1045 or diag($dev->error_or_status()); 1046 1047 $dev->read_label(); 1048 $status = $dev->status(); 1049 ok(($status == $DEVICE_STATUS_SUCCESS) || (($status & $DEVICE_STATUS_VOLUME_UNLABELED) != 0), 1050 "status is either OK or possibly unlabeled") 1051 or diag($dev->error_or_status()); 1052 1053 $dev->finish(); 1054 1055 ok($dev->erase(), 1056 "erase device") 1057 or diag($dev->error_or_status()); 1058 1059 # try a eu-constrained bucket 1060 $dev_name = lc("s3:$base_name-s3-eu"); 1061 $dev = s3_make_device($dev_name, "s3"); 1062 ok($dev->property_set('S3_BUCKET_LOCATION', 'EU'), 1063 "set S3 bucket location to 'EU'") 1064 or diag($dev->error_or_status()); 1065 1066 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 1067 "start in write mode") 1068 or diag($dev->error_or_status()); 1069 1070 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1071 "status is OK") 1072 or diag($dev->error_or_status()); 1073 1074 $dev->finish(); 1075 1076 ok($dev->erase(), 1077 "erase device") 1078 or diag($dev->error_or_status()); 1079 1080 # try a wildcard-constrained bucket 1081 $dev_name = lc("s3:$base_name-s3-wild"); 1082 $dev = s3_make_device($dev_name, "s3"); 1083 ok($dev->property_set('S3_BUCKET_LOCATION', '*'), 1084 "set S3 bucket location to '*'") 1085 or diag($dev->error_or_status()); 1086 1087 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 1088 "start in write mode") 1089 or diag($dev->error_or_status()); 1090 1091 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1092 "status is OK") 1093 or diag($dev->error_or_status()); 1094 1095 $dev->finish(); 1096 ok($dev->erase(), 1097 "erase device") 1098 or diag($dev->error_or_status()); 1099 1100 # test again with invalid ca_info 1101 $dev_name = lc("s3:$base_name-s3-ca"); 1102 $dev = s3_make_device($dev_name, "s3"); 1103 SKIP: { 1104 skip "SSL not supported; can't check SSL_CA_INFO", 2 1105 unless $dev->property_get('S3_SSL'); 1106 1107 ok($dev->property_set('SSL_CA_INFO', '/dev/null'), 1108 "set invalid SSL/TLS CA certificate") 1109 or diag($dev->error_or_status()); 1110 1111 ok(!$dev->start($ACCESS_WRITE, "TESTCONF13", undef), 1112 "start in write mode") 1113 or diag($dev->error_or_status()); 1114 1115 isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 1116 "status is OK") 1117 or diag($dev->error_or_status()); 1118 1119 $dev->finish(); 1120 } 1121 1122 # test again with our own CA bundle 1123 $dev_name = lc("s3:$base_name-s3-oca"); 1124 $dev = s3_make_device($dev_name, "s3"); 1125 SKIP: { 1126 skip "SSL not supported; can't check SSL_CA_INFO", 4 1127 unless $dev->property_get('S3_SSL'); 1128 ok($dev->property_set('SSL_CA_INFO', "$srcdir/data/aws-bundle.crt"), 1129 "set our own SSL/TLS CA certificate bundle") 1130 or diag($dev->error_or_status()); 1131 1132 ok($dev->erase(), 1133 "erase device") 1134 or diag($dev->error_or_status()); 1135 1136 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 1137 "start in write mode") 1138 or diag($dev->error_or_status()); 1139 1140 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1141 "status is OK") 1142 or diag($dev->error_or_status()); 1143 1144 $dev->finish(); 1145 } 1146 1147 ok($dev->erase(), 1148 "erase device") 1149 or diag($dev->error_or_status()); 1150 1151 # bucket names incompatible with location constraint 1152 $dev_name = "s3:-$base_name-s3-eu-2"; 1153 $dev = s3_make_device($dev_name, "s3"); 1154 1155 ok($dev->property_set('S3_BUCKET_LOCATION', ''), 1156 "should be able to set an empty S3 bucket location with an incompatible name") 1157 or diag($dev->error_or_status()); 1158 1159 $dev_name = "s3:$base_name-s3.eu-3"; 1160 $dev = s3_make_device($dev_name, "s3"); 1161 1162 ok($dev->property_set('S3_BUCKET_LOCATION', ''), 1163 "should be able to set an empty S3 bucket location with an incompatible name") 1164 or diag($dev->error_or_status()); 1165 1166 $dev_name = "s3:-$base_name-s3-eu"; 1167 $dev = s3_make_device($dev_name, "s3"); 1168 1169 ok(!$dev->property_set('S3_BUCKET_LOCATION', 'EU'), 1170 "should not be able to set S3 bucket location with an incompatible name") 1171 or diag($dev->error_or_status()); 1172 1173 $dev_name = lc("s3:$base_name-s3-eu-4"); 1174 $dev = s3_make_device($dev_name, "s3"); 1175 ok($dev->property_set('S3_BUCKET_LOCATION', 'XYZ'), 1176 "should be able to set S3 bucket location with a compatible name") 1177 or diag($dev->error_or_status()); 1178 $dev->read_label(); 1179 $status = $dev->status(); 1180 ok(($status == $DEVICE_STATUS_DEVICE_ERROR), 1181 "status is DEVICE_STATUS_DEVICE_ERROR") 1182 or diag($dev->error_or_status()); 1183 my $error_msg = $dev->error_or_status(); 1184 ok(($dev->error_or_status() == "While creating new S3 bucket: The specified location-constraint is not valid (Unknown) (HTTP 400)"), 1185 "invalid location-constraint") 1186 or diag("bad error: " . $dev->error_or_status()); 1187 1188} 1189 1190SKIP: { 1191 # in this case, most of our code has already been exercised 1192 # just make sure that authentication works as a basic sanity check 1193 skip "skipping abbreviated devpay tests", $s3_make_device_count + 1 1194 unless $run_devpay_tests; 1195 $dev_name = "s3:$base_name-devpay"; 1196 $dev = s3_make_device($dev_name, "devpay"); 1197 $dev->read_label(); 1198 my $status = $dev->status(); 1199 # this test appears very liberal, but catches the case where setup_handle fails without 1200 # giving false positives 1201 ok(($status == 0) || (($status & $DEVICE_STATUS_VOLUME_UNLABELED) != 0), 1202 "status is either OK or possibly unlabeled") 1203 or diag($dev->error_or_status()); 1204} 1205 1206# Test a tape device if the proper environment variables are set 1207my $TAPE_DEVICE = $ENV{'INSTALLCHECK_TAPE_DEVICE'}; 1208my $run_tape_tests = defined $TAPE_DEVICE; 1209SKIP: { 1210 skip "define \$INSTALLCHECK_TAPE_DEVICE to run tape tests", 1211 30 + 1212 7 * $verify_file_count + 1213 5 * $write_file_count 1214 unless $run_tape_tests; 1215 1216 $dev_name = "tape:$TAPE_DEVICE"; 1217 $dev = Amanda::Device->new($dev_name); 1218 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1219 "$dev_name: create successful") 1220 or diag($dev->error_or_status()); 1221 1222 my $status = $dev->read_label(); 1223 ok(($status == $DEVICE_STATUS_SUCCESS) || (($status & $DEVICE_STATUS_VOLUME_UNLABELED) != 0), 1224 "status is either OK or possibly unlabeled") 1225 or diag($dev->error_or_status()); 1226 1227 ok($dev->start($ACCESS_WRITE, "TESTCONF13", undef), 1228 "start in write mode") 1229 or diag($dev->error_or_status()); 1230 1231 ok(!($dev->status() & $DEVICE_STATUS_VOLUME_UNLABELED), 1232 "not unlabeled anymore") 1233 or diag($dev->error_or_status()); 1234 1235 for (my $i = 1; $i <= 4; $i++) { 1236 write_file(0x2FACE+$i, $dev->block_size()*10+17, $i); 1237 } 1238 1239 ok($dev->finish(), 1240 "finish device after write") 1241 or diag($dev->error_or_status()); 1242 1243 $dev->read_label(); 1244 ok(!($dev->status()), 1245 "no error, at all, from read_label") 1246 or diag($dev->error_or_status()); 1247 1248 is($dev->volume_label(), "TESTCONF13", 1249 "read_label reads the correct label") 1250 or diag($dev->error_or_status()); 1251 1252 # append one more copy, to test ACCESS_APPEND 1253 1254 # if final_filemarks is 1, then the tape device will use F_NOOP, 1255 # inserting an extra file, and we'll be appending at file number 6. 1256 my $append_fileno = ($dev->property_get("FINAL_FILEMARKS") == 2)? 5:6; 1257 1258 SKIP: { 1259 skip "APPEND not supported", $write_file_count + 2 1260 unless $dev->property_get("APPENDABLE"); 1261 1262 ok($dev->start($ACCESS_APPEND, undef, undef), 1263 "start in append mode") 1264 or diag($dev->error_or_status()); 1265 1266 write_file(0xD0ED0E, $dev->block_size()*4, $append_fileno); 1267 1268 ok($dev->finish(), 1269 "finish device after append") 1270 or diag($dev->error_or_status()); 1271 } 1272 1273 # try reading the second and third files back, creating a new 1274 # device object first, and skipping the read-label step. 1275 1276 $dev = undef; 1277 $dev = Amanda::Device->new($dev_name); 1278 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1279 "$dev_name: re-create successful") 1280 or diag($dev->error_or_status()); 1281 1282 # use a big read_block_size, checking that it's also settable 1283 # via read_buffer_size 1284 ok($dev->property_set("read_buffer_size", 256*1024), 1285 "can set read_buffer_size"); 1286 is($dev->property_get("read_block_size"), 256*1024, 1287 "and its value is reflected in read_block_size"); 1288 ok($dev->property_set("read_block_size", 32*1024), 1289 "can set read_block_size"); 1290 1291 ok($dev->start($ACCESS_READ, undef, undef), 1292 "start in read mode") 1293 or diag($dev->error_or_status()); 1294 1295 # now verify those files in a particular order to trigger all of the 1296 # seeking edge cases 1297 1298 verify_file(0x2FACE+1, $dev->block_size()*10+17, 1); 1299 verify_file(0x2FACE+2, $dev->block_size()*10+17, 2); 1300 verify_file(0x2FACE+4, $dev->block_size()*10+17, 4); 1301 verify_file(0x2FACE+3, $dev->block_size()*10+17, 3); 1302 verify_file(0x2FACE+1, $dev->block_size()*10+17, 1); 1303 1304 # try re-seeking to the same file 1305 ok(header_for($dev->seek_file(2), 2), "seek to file 2 the first time"); 1306 verify_file(0x2FACE+2, $dev->block_size()*10+17, 2); 1307 ok(header_for($dev->seek_file(2), 2), "seek to file 2 the third time"); 1308 1309 # and seek through the same pattern *without* reading to EOF 1310 ok(header_for($dev->seek_file(1), 1), "seek to file 1"); 1311 ok(header_for($dev->seek_file(2), 2), "seek to file 2"); 1312 ok(header_for($dev->seek_file(4), 4), "seek to file 4"); 1313 ok(header_for($dev->seek_file(3), 3), "seek to file 3"); 1314 ok(header_for($dev->seek_file(1), 1), "seek to file 1"); 1315 1316 SKIP: { 1317 skip "APPEND not supported", $verify_file_count 1318 unless $dev->property_get("APPENDABLE"); 1319 verify_file(0xD0ED0E, $dev->block_size()*4, $append_fileno); 1320 } 1321 1322 ok($dev->finish(), 1323 "finish device after read") 1324 or diag($dev->error_or_status()); 1325 1326 # tickle a regression in improperly closing fd's 1327 ok($dev->finish(), 1328 "finish device again after read") 1329 or diag($dev->error_or_status()); 1330 1331 ok($dev->read_label() == $DEVICE_STATUS_SUCCESS, 1332 "read_label after second finish (used to fail)") 1333 or diag($dev->error_or_status()); 1334 1335 # finally, run the device with FSF and BSF set to "no", to test the 1336 # fallback schemes for this condition 1337 1338 $dev = undef; 1339 $dev = Amanda::Device->new($dev_name); 1340 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1341 "$dev_name: re-create successful") 1342 or diag($dev->error_or_status()); 1343 $dev->property_set("fsf", "no"); 1344 $dev->property_set("bsf", "no"); 1345 1346 ok($dev->start($ACCESS_READ, undef, undef), 1347 "start in read mode") 1348 or diag($dev->error_or_status()); 1349 1350 ok(header_for($dev->seek_file(1), 1), "seek to file 1"); 1351 ok(header_for($dev->seek_file(4), 4), "seek to file 4"); 1352 ok(header_for($dev->seek_file(2), 2), "seek to file 2"); 1353 1354 ok($dev->finish(), 1355 "finish device after read") 1356 or diag($dev->error_or_status()); 1357} 1358 1359SKIP: { 1360 skip "not built with ndmp and server", 26 unless 1361 Amanda::Util::built_with_component("ndmp") and 1362 Amanda::Util::built_with_component("server"); 1363 1364 my $dev; 1365 my $testconf = Installcheck::Config->new(); 1366 $testconf->write(); 1367 1368 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); 1369 if ($cfg_result != $CFGERR_OK) { 1370 my ($level, @errors) = Amanda::Config::config_errors(); 1371 die(join "\n", @errors); 1372 } 1373 1374 my $ndmp = Installcheck::Mock::NdmpServer->new(); 1375 my $ndmp_port = $ndmp->{'port'}; 1376 my $drive = $ndmp->{'drive'}; 1377 pass("started ndmjob in daemon mode"); 1378 1379 # set up a header for use below 1380 my $hdr = Amanda::Header->new(); 1381 $hdr->{type} = $Amanda::Header::F_DUMPFILE; 1382 $hdr->{datestamp} = "20070102030405"; 1383 $hdr->{dumplevel} = 0; 1384 $hdr->{compressed} = 1; 1385 $hdr->{name} = "localhost"; 1386 $hdr->{disk} = "/home"; 1387 $hdr->{program} = "INSTALLCHECK"; 1388 1389 $dev = Amanda::Device->new("ndmp:127.0.0.1:9i1\@foo"); 1390 isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 1391 "creation of an ndmp device fails with invalid port"); 1392 1393 $dev = Amanda::Device->new("ndmp:127.0.0.1:90000\@foo"); 1394 isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 1395 "creation of an ndmp device fails with too-large port"); 1396 1397 $dev = Amanda::Device->new("ndmp:127.0.0.1:$ndmp_port"); 1398 isnt($dev->status(), $DEVICE_STATUS_SUCCESS, 1399 "creation of an ndmp device fails without ..\@device_name"); 1400 1401 $dev = Amanda::Device->new("ndmp:127.0.0.1:$ndmp_port\@$drive"); 1402 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1403 "creation of an ndmp device succeeds with correct syntax"); 1404 1405 ok($dev->property_set("ndmp_username", "foo"), 1406 "set ndmp_username property"); 1407 is($dev->property_get("ndmp_username"), "foo", 1408 "..and get the value back"); 1409 ok($dev->property_set("ndmp_password", "bar"), 1410 "set ndmp_password property"); 1411 is($dev->property_get("ndmp_password"), "bar", 1412 "..and get the value back"); 1413 1414 ok($dev->property_set("verbose", 1), 1415 "set VERBOSE"); 1416 1417 # set 'em back to the defaults 1418 $dev->property_set("ndmp_username", "ndmp"); 1419 $dev->property_set("ndmp_password", "ndmp"); 1420 1421 # use a big read_block_size, checking that it's also settable 1422 # via read_buffer_size 1423 ok($dev->property_set("read_block_size", 256*1024), 1424 "can set read_block_size"); 1425 is($dev->property_get("read_block_size"), 256*1024, 1426 "and its value is reflected"); 1427 ok($dev->property_set("read_block_size", 64*1024), 1428 "set read_block_size back to something smaller"); 1429 1430 # ok, let's fire the thing up 1431 ok($dev->start($ACCESS_WRITE, "TEST1", "20090915000000"), 1432 "start device in write mode") 1433 or diag $dev->error_or_status(); 1434 1435 ok($dev->start_file($hdr), 1436 "start_file"); 1437 1438 { # write to the file 1439 my $xfer = Amanda::Xfer->new([ 1440 Amanda::Xfer::Source::Random->new(32768*21, 0xBEEFEE00), 1441 Amanda::Xfer::Dest::Device->new($dev, 0) ]); 1442 $xfer->start(make_cb(xmsg_cb => sub { 1443 my ($src, $msg, $xfer) = @_; 1444 if ($msg->{'type'} == $XMSG_ERROR) { 1445 die $msg->{'elt'} . " failed: " . $msg->{'message'}; 1446 } elsif ($msg->{'type'} == $XMSG_DONE) { 1447 Amanda::MainLoop::quit(); 1448 } 1449 })); 1450 1451 Amanda::MainLoop::run(); 1452 pass("wrote 21 blocks"); 1453 } 1454 1455 ok($dev->finish(), 1456 "finish device") 1457 or diag $dev->error_or_status(); 1458 1459 is($dev->read_label(), $DEVICE_STATUS_SUCCESS, 1460 "read label from (same) device") 1461 or diag $dev->error_or_status(); 1462 1463 is($dev->volume_label, "TEST1", 1464 "volume label read back correctly"); 1465 1466 ## label a device and check the label, but open a new device in between 1467 1468 # Write a label 1469 $dev = Amanda::Device->new("ndmp:127.0.0.1:$ndmp_port\@$drive"); 1470 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1471 "creation of an ndmp device succeeds with correct syntax"); 1472 $dev->property_set("ndmp_username", "ndmp"); 1473 $dev->property_set("ndmp_password", "ndmp"); 1474 $dev->property_set("verbose", 1); 1475 1476 # Write the label 1477 ok($dev->start($ACCESS_WRITE, "TEST2", "20090915000000"), 1478 "start device in write mode") 1479 or diag $dev->error_or_status(); 1480 ok($dev->finish(), 1481 "finish device") 1482 or diag $dev->error_or_status(); 1483 1484 # Read the label with a new device. 1485 $dev = Amanda::Device->new("ndmp:127.0.0.1:$ndmp_port\@$drive"); 1486 is($dev->status(), $DEVICE_STATUS_SUCCESS, 1487 "creation of an ndmp device succeeds with correct syntax"); 1488 $dev->property_set("ndmp_username", "ndmp"); 1489 $dev->property_set("ndmp_password", "ndmp"); 1490 $dev->property_set("verbose", 1); 1491 1492 # read the label 1493 is($dev->read_label(), $DEVICE_STATUS_SUCCESS, 1494 "read label from device") 1495 or diag $dev->error_or_status(); 1496 is($dev->volume_label, "TEST2", 1497 "volume label read back correctly"); 1498 ok($dev->finish(), 1499 "finish device") 1500 or diag $dev->error_or_status(); 1501 1502 1503 $ndmp->cleanup(); 1504} 1505unlink($input_filename); 1506unlink($output_filename); 1507rmtree($taperoot); 1508