#!/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-Linear resize.
#
# Setup: Create a RAID-Linear with two segments.
# Test1: Expand the linear region with another segment.
# Test2: Expand the Linear region with two segments.
# Test3: Shrink the Linear region by removing the last segment.
# Test4: Attempt to shrink the Linear region by removing a segment that isn't
#        the last segment in the region.
# Test5: Shrink the Linear 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 $linear_name;

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

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

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

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

	$rc = create_md_region("MDLinearRegMgr", \@objects,
			       \@none, $linear_name);
	if ($rc) {
		log_error("Error creating RAID-Linear region.\n");
		goto out;
	}

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

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

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

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

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

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

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

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

	$region_sectors_after = get_blkdev_sectors($linear_name);

	log_info("4. Checking that region $linear_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;
	}

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

# Test2
# Expand the Linear region by adding two segments at the same time.
sub Test2($)
{
	my $disk = $_[0];
	my @objects = ($disk . "9", $disk . "8");
	my ($region_sectors_before, $region_sectors_after);
	my @object_sectors;
	my $rc;

	log_info("Testing expand of RAID-Linear $linear_name with " .
		 "multiple segments.\n");

	log_info("1. Getting size of region $linear_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($linear_name);

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

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

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

	$region_sectors_after = get_blkdev_sectors($linear_name);

	log_info("4. Checking that region $linear_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;
	}

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

# Test3
# Shrink the Linear region by removing the last segment.
sub Test3($)
{
	my $disk = $_[0];
	my @objects = ($disk . "9");
	my ($region_sectors_before, $region_sectors_after);
	my @object_sectors;
	my $rc;

	log_info("Testing shrink of RAID-Linear $linear_name with " .
		 "one segment.\n");

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

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

	log_info("2. Shrinking region $linear_name by removing " .
		 "segment $objects[0].\n");

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

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

	$region_sectors_after = get_blkdev_sectors($linear_name);

	log_info("4. Checking that region $linear_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;
	}

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

# Test4
# Attempt to shrink the Linear region by removing a segment that isn't the
# last child.
sub Test4($)
{
	my $disk = $_[0];
	my @objects = ($disk . "5");
	my ($region_sectors_before, $region_sectors_after);
	my $rc;

	log_info("Testing shrink of RAID-Linear $linear_name with segment\n");
	log_info("that isn't the last child, which is not allowed.\n");

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

	$region_sectors_before = get_blkdev_sectors($linear_name);

	log_info("2. Attempting to shrink region $linear_name by " .
		 "removing segment $objects[0].\n");

	$rc = shrink_md_region($linear_name, \@objects);
	if (!$rc) {
		log_error("Error: region successfully shrunk.\n");
		$rc = 1;
		goto out;
	}

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

	$region_sectors_after = get_blkdev_sectors($linear_name);

	log_info("4. Checking that region $linear_name did *NOT* shrink.\n");

	$rc = compare_sectors($region_sectors_before, $region_sectors_after, 0);
	if ($rc) {
		log_error("Region is not the same size.\n");
		goto out;
	}

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

# Test5
# Shrink the Linear region by removing the last two segments.
sub Test5($)
{
	my $disk = $_[0];
	my @objects = ($disk . "8", $disk . "7");
	my ($region_sectors_before, $region_sectors_after);
	my @object_sectors;
	my $rc;

	log_info("Testing shrink of RAID-Linear $linear_name with " .
		 "multiple segments.\n");

	log_info("1. Getting size of region $linear_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($linear_name);

	log_info("2. Shrinking region $linear_name by removing " .
		 "segments $objects[0] and $objects[1].\n");

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

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

	$region_sectors_after = get_blkdev_sectors($linear_name);

	log_info("4. Checking that region $linear_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;
	}

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, "1GB");
	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;
	}

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

finish:
}

