#!/usr/bin/perl
#
# (C) Copyright IBM Corp. 2004
#
# This program is free software;  you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Script for testing RAID-5 resize.
#
# Setup: Create a RAID-5 with three segments and create a compatibility volume.
# Test1: Expand the RAID-5 region with another segment.
# Test2: Expand the RAID-5 region with two segments.
# Test3: Shrink the RAID-5 region by removing the one segment.
# Test4: Shrink the RAID-5 region by removing the last two segments.

use strict;
use warnings;

use Evms::Common;
use Evms::Log;
use Evms::Object;
use Evms::Dos;
use Evms::Volume;
use Evms::MD;

my $raid5_name;
my $dev_name;

# Setup
# Create 6 segments to test with. Create a RAID-5 region with the first
# two segments.
sub Setup
{
	my $disk = $_[0];
	my @objects = ($disk . "7", $disk . "6", $disk . "5");
	my @none;
	my $rc;

	log_info("1. Creating 6 DOS segments.\n");

	$rc = create_dos_segments($disk, 6, "100MB");
	if ($rc) {
		log_error("Error creating DOS segments.\n");
		goto out;
	}

	log_info("2. Creating RAID-5 region with $objects[0], " .
		 "$objects[1], and $objects[2].\n");

	$rc = create_md_region("MDRaid5RegMgr", \@objects,
			       \@none, $raid5_name);
	if ($rc) {
		log_error("Error creating RAID-5 region.\n");
		goto out;
	}
	$dev_name = "/dev/evms/.nodes/" . $raid5_name;

	log_info("3. Waiting for RAID-5 region $raid5_name to sync.\n");

	$rc = wait_for_md_resync($raid5_name);
	if ($rc) {
		log_error("Error waiting for resync.\n");
		goto out;
	}

out:
	log_result($rc);
	return $rc;
}

# Test1
# Expand the RAID-5 region by adding one segment.
sub Test1($)
{
	my $disk = $_[0];
	my @objects = ($disk . "8");
	my @object_sectors;
	my ($region_sectors_before, $region_sectors_after);
	my $rc;

	log_info("Testing expand of RAID-5 $raid5_name with " .
		 "one segment.\n");

	log_info("1. Getting size of region $raid5_name before the expand.\n");

	$object_sectors[0] = get_blkdev_sectors($objects[0]);
	$region_sectors_before = get_blkdev_sectors($raid5_name);

	log_info("2. Writing initial pattern to region $raid5_name.\n");

	$rc = write_sequence($dev_name, $region_sectors_before);
	if ($rc) {
		log_error("Error initializing pattern.\n");
		goto out;
	}

	log_info("3. Expanding region $raid5_name using " .
		 "segment $objects[0].\n");

	$rc = expand_md_region($raid5_name, \@objects);
	if ($rc) {
		log_error("Error expanding region.\n");
		goto out;
	}

	log_info("4. Getting size of region $raid5_name after the expand.\n");

	$region_sectors_after = get_blkdev_sectors($raid5_name);

	log_info("5. Checking that region $raid5_name expanded by " .
		 "correct amount.\n");

	$rc = compare_sectors($region_sectors_before + $object_sectors[0],
			      $region_sectors_after, 1);
	if ($rc) {
		log_error("Region did not expand by correct size.\n");
		goto out;
	}

	log_info("6. Verifying pattern on expanded region $raid5_name.\n");

	$rc = validate_sequence($dev_name, $region_sectors_before);
	if ($rc) {
		log_error("Error validating pattern on region.\n");
		goto out;
	}

out:
	log_result($rc);
	return $rc;
}

# Test2
# Expand the RAID-5 region by adding two segments.
sub Test2($)
{
	my $disk = $_[0];
	my @objects = ($disk . "10", $disk . "9");
	my @object_sectors;
	my ($region_sectors_before, $region_sectors_after);
	my $rc;

	log_info("Testing expand of RAID-5 $raid5_name with " .
		 "two segments.\n");

	log_info("1. Getting size of region $raid5_name before the expand.\n");

	$object_sectors[0] = get_blkdev_sectors($objects[0]);
	$object_sectors[1] = get_blkdev_sectors($objects[1]);
	$region_sectors_before = get_blkdev_sectors($raid5_name);

	log_info("2. Writing initial pattern to region $raid5_name.\n");

	$rc = write_sequence($dev_name, $region_sectors_before);
	if ($rc) {
		log_error("Error initializing pattern.\n");
		goto out;
	}

	log_info("3. Expanding region $raid5_name using " .
		 "segments $objects[0] and $objects[1].\n");

	$rc = expand_md_region($raid5_name, \@objects);
	if ($rc) {
		log_error("Error expanding region.\n");
		goto out;
	}

	log_info("4. Getting size of region $raid5_name after the expand.\n");

	$region_sectors_after = get_blkdev_sectors($raid5_name);

	log_info("5. Checking that region $raid5_name expanded by " .
		 "correct amount.\n");

	$rc = compare_sectors($region_sectors_before + $object_sectors[0] +
			      $object_sectors[1], $region_sectors_after, 1);
	if ($rc) {
		log_error("Region did not expand by correct size.\n");
		goto out;
	}

	log_info("6. Verifying pattern on expanded region $raid5_name.\n");

	$rc = validate_sequence($dev_name, $region_sectors_before);
	if ($rc) {
		log_error("Error validating pattern on region.\n");
		goto out;
	}

out:
	log_result($rc);
	return $rc;
}

# Test3
# Shrink the RAID-5 region by removing one segment.
sub Test3($)
{
	my $disk = $_[0];
	my @objects = ($disk . "6");
	my @object_sectors;
	my ($region_sectors_before, $region_sectors_after);
	my $rc;

	log_info("Testing shrink of RAID-5 $raid5_name by removing " .
		 "one segment.\n");

	log_info("1. Getting size of region $raid5_name before the shrink.\n");

	$object_sectors[0] = get_blkdev_sectors($objects[0]);
	$region_sectors_before = get_blkdev_sectors($raid5_name);

	log_info("2. Writing initial pattern to region $raid5_name.\n");

	$rc = write_sequence($dev_name, $region_sectors_before);
	if ($rc) {
		log_error("Error initializing pattern.\n");
		goto out;
	}

	log_info("3. Shrinking region $raid5_name using " .
		 "segment $objects[0].\n");

	$rc = shrink_md_region($raid5_name, \@objects);
	if ($rc) {
		log_error("Error shrinking region.\n");
		goto out;
	}

	log_info("4. Getting size of region $raid5_name after the shrink.\n");

	$region_sectors_after = get_blkdev_sectors($raid5_name);

	log_info("5. Checking that region $raid5_name shrunk by " .
		 "correct amount.\n");

	$rc = compare_sectors($region_sectors_before - $object_sectors[0],
			      $region_sectors_after, 1);
	if ($rc) {
		log_error("Region did not shrink by correct size.\n");
		goto out;
	}

	log_info("6. Verifying pattern on shrunk region $raid5_name.\n");

	$rc = validate_sequence($dev_name, $region_sectors_after);
	if ($rc) {
		log_error("Error validating pattern on region.\n");
		goto out;
	}

out:
	log_result($rc);
	return $rc;
}

# Test4
# Shrink the RAID-5 region by removing two segments.
sub Test4($)
{
	my $disk = $_[0];
	my @objects = ($disk . "5", $disk . "9");
	my @object_sectors;
	my ($region_sectors_before, $region_sectors_after);
	my $rc;

	log_info("Testing shrink of RAID-5 $raid5_name by removing " .
		 "two segments.\n");

	log_info("1. Getting size of region $raid5_name before the shrink.\n");

	$object_sectors[0] = get_blkdev_sectors($objects[0]);
	$object_sectors[1] = get_blkdev_sectors($objects[1]);
	$region_sectors_before = get_blkdev_sectors($raid5_name);

	log_info("2. Writing initial pattern to region $raid5_name.\n");

	$rc = write_sequence($dev_name, $region_sectors_before);
	if ($rc) {
		log_error("Error initializing pattern.\n");
		goto out;
	}

	log_info("3. Shrinking region $raid5_name using " .
		 "segments $objects[0] and $objects[1].\n");

	$rc = shrink_md_region($raid5_name, \@objects);
	if ($rc) {
		log_error("Error shrinking region.\n");
		goto out;
	}

	log_info("4. Getting size of region $raid5_name after the shrink.\n");

	$region_sectors_after = get_blkdev_sectors($raid5_name);

	log_info("5. Checking that region $raid5_name shrunk by " .
		 "correct amount.\n");

	$rc = compare_sectors($region_sectors_before - $object_sectors[0] -
			      $object_sectors[1], $region_sectors_after, 1);
	if ($rc) {
		log_error("Region did not shrink by correct size.\n");
		goto out;
	}

	log_info("6. Verifying pattern on shrunk region $raid5_name.\n");

	$rc = validate_sequence($dev_name, $region_sectors_after);
	if ($rc) {
		log_error("Error validating pattern on region.\n");
		goto out;
	}

out:
	log_result($rc);
	return $rc;
}

MAIN:
{
	my $disk;
	my $rc;

	# Only use the first disk specified.
	$disk = $ARGV[0];
	$disk || die("USAGE: $0 <disk>\n");

	# Check for minimum-sized disk.
	$rc = check_minimum_object_size($disk, "600MB");
	if ($rc) {
		goto finish;
	}

	$rc = Setup($disk);
	if ($rc) {
		goto finish;
	}

	$rc = Test1($disk);
	if ($rc) {
		goto finish;
	}

	$rc = Test2($disk);
	if ($rc) {
		goto finish;
	}

	$rc = Test3($disk);
	if ($rc) {
		goto finish;
	}

	$rc = Test4($disk);
	if ($rc) {
		goto finish;
	}

finish:
}

