#!/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
#
# LVM script for testing region creates and deletes.
#
# Test1: Create a region. Specify only the name, which should use all the
#        available freespace.
# Test2: Delete the region that we just created.
# Test3: Create a region, specifying number of extents.
# Test4: Create a region, specifying the size.
# Test5: Create a region, specifying a size which is not a multiple of the
#        extent size.
# Test6: Create a region, specifying a size larger than the available freespace.
# Test7: Delete all regions created so far.
# Test8: Create a striped region across all PVs in the container. Default size
#        and stripe-size.
# Test9: Create a striped region, specifying size and stripe-size. The size
#        will not be a multiple of (number of stripes * extent-size), and
#        should be rounded appropriately.

use strict;
use warnings;

use Evms::Common;
use Evms::Log;
use Evms::DM;
use Evms::Object;
use Evms::Dos;
use Evms::Lvm;

my $container_name = "MiddleEarth";
my $container_pe_size = "4MB";

# Setup
# Create an LVM container with four DOS segments.
sub Setup
{
	my $disk = $_[0];
	my @pvs = ($disk."5", $disk."6", $disk."7", $disk."8");
	my %options;
	my $rc;

	log_info("Creating 4 DOS segments.\n");

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

	$options{"name"} = $container_name;
	$options{"pe_size"} = $container_pe_size;

	log_info("Creating LVM container $container_name\n");

	$rc = create_lvm_container(\%options, @pvs);
	if ($rc) {
		log_error("Error creating LVM container.\n");
		goto out;
	}

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

# Test1
# Create a region. Specify only the name, which should use all the
# available freespace.
sub Test1
{
	my $name = "TheShire";
	my $region_name = $container_name . "/" . $name;
	my %options;
	my @output;
	my $size;
	my $rc;

	$options{"name"} = $name;

	log_info("Test creating an LVM region.\n");

	log_info("1. Creating an LVM region $region_name. " .
		 "All default options.\n");

	$rc = create_lvm_region($container_name, \%options);
	if ($rc) {
		log_error("Error creating region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying creation of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (!@output) {
		log_error("Error getting details for region $region_name.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying region $region_name is active in the kernel.\n");

	@output = dm_info("lvm|" . $container_name . "|" . $name);
	if (!@output) {
		log_error("Error: region $region_name not found " .
			  "in the kernel.\n");
		$rc = 1;
		goto out;
	}

	log_info("4. Verifying all freespace used in container " .
		 "$container_name.\n");

	$size = get_object_size("lvm/" . $container_name . "/Freespace");

	$rc = compare_sizes($size, "0KB", 0);
	if ($rc) {
		log_error("Error: Container $container_name has " .
			  "non-zero freespace.\n");
		goto out;
	}

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

# Test2
# Delete the region that we just created.
sub Test2
{
	my $name = "TheShire";
	my $region_name = $container_name . "/" . $name;
	my @output;
	my $rc;

	log_info("Test deleting an LVM region.\n");

	log_info("1. Deleting region $region_name.\n");

	$rc = delete_lvm_region($region_name);
	if ($rc) {
		log_error("Error deleting region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying deletion of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (@output) {
		log_error("Error: region $region_name still exists.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying region $region_name has been deactivated\n");
	log_info("   from the kernel.\n");
	@output = dm_info("lvm|" . $container_name . "|" . $name);
	if (@output) {
		log_error("Error: region $region_name still active in " .
			  "the kernel.\n");
		$rc = 1;
		goto out;
	}

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

# Test3
# Create a region, specifying number of extents.
sub Test3
{
	my $name = "Gondor";
	my $region_name = $container_name . "/" . $name;
	my $extents = 100;
	my %options;
	my @output;
	my $size;
	my $rc;

	log_info("Test creating an LVM region.\n");

	log_info("1. Creating an LVM region $region_name with " .
		 "$extents extents.\n");

	$options{"name"} = $name;
	$options{"extents"} = $extents;

	$rc = create_lvm_region($container_name, \%options);
	if ($rc) {
		log_error("Error creating region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying creation of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (!@output) {
		log_error("Error getting details for region $region_name.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying size of region $region_name.\n");

	$size = get_object_size("lvm/" . $region_name);

	$rc = compare_sectors($extents * size_to_sectors($container_pe_size),
			      size_to_sectors($size), 0);
	if ($rc) {
		log_error("Error: region $region_name has incorrect size.\n");
		goto out;
	}

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

# Test4
# Create a region, specifying the size.
sub Test4
{
	my $name = "Rohan";
	my $region_name = $container_name . "/" . $name;
	my $size = "200MB";
	my $real_size;
	my %options;
	my @output;
	my $rc;

	log_info("Test creating an LVM region.\n");

	log_info("1. Creating an LVM region $region_name with size $size.\n");

	$options{"name"} = $name;
	$options{"size"} = $size;

	$rc = create_lvm_region($container_name, \%options);
	if ($rc) {
		log_error("Error creating region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying creation of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (!@output) {
		log_error("Error getting details for region $region_name.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying size of region $region_name.\n");

	$real_size = get_object_size("lvm/" . $region_name);

	$rc = compare_sizes($size, $real_size, 0);
	if ($rc) {
		log_error("Error: region $region_name has incorrect size.\n");
		goto out;
	}

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

# Test5
# Create a region, specifying a size which is not a multiple of the extent size.
sub Test5
{
	my $name = "Rivendell";
	my $region_name = $container_name . "/" . $name;
	my $size = "298MB";
	my $real_size;
	my %options;
	my @output;
	my $rc;

	log_info("Test creating an LVM region.\n");

	log_info("1. Creating an LVM region $region_name with size $size,\n");
	log_info("   which is not a multiple of the container extent size.\n");

	$options{"name"} = $name;
	$options{"size"} = $size;

	$rc = create_lvm_region($container_name, \%options);
	if ($rc) {
		log_error("Error creating region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying creation of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (!@output) {
		log_error("Error getting details for region $region_name.\n");
		$rc = 1;
		goto out;
	}

	$size = "300MB";

	log_info("3. Verifying size of region $region_name was correctly\n");
	log_info("   rounded up to $size.\n");

	$real_size = get_object_size("lvm/" . $region_name);

	$rc = compare_sizes($size, $real_size, 0);
	if ($rc) {
		log_error("Error: region $region_name has incorrect size.\n");
		goto out;
	}

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

# Test6
# Create a region, specifying a size larger than the available freespace.
sub Test6
{
	my $name = "Mordor";
	my $region_name = $container_name . "/" . $name;
	my $size = "2GB";
	my $freespace_size;
	my $real_size;
	my %options;
	my @output;
	my $rc;

	$freespace_size = get_object_size("lvm/".$container_name."/Freespace");

	log_info("Test creating an LVM region.\n");

	log_info("1. Creating an LVM region $region_name with size $size,\n");
	log_info("   which is larger than the available freespace.\n");

	$options{"name"} = $name;
	$options{"size"} = $size;

	$rc = create_lvm_region($container_name, \%options);
	if ($rc) {
		log_error("Error creating region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying creation of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (!@output) {
		log_error("Error getting details for region $region_name.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying size of region $region_name was correctly\n");
	log_info("   rounded down to $freespace_size.\n");

	$real_size = get_object_size("lvm/" . $region_name);

	$rc = compare_sizes($freespace_size, $real_size, 0);
	if ($rc) {
		log_error("Error: region $region_name has incorrect size.\n");
		goto out;
	}

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

# Test7
# Delete all regions created so far.
sub Test7
{
	my @names = ("Gondor", "Rohan", "Rivendell", "Mordor");
	my @output;
	my ($name, $region_name);
	my ($rc, $i);

	log_info("Test deleting several LVM regions.\n");

	$i = 1;
	foreach $name (@names) {
		$region_name = $container_name . "/" . $name;

		log_info("$i. Deleting region $region_name.\n");

		$rc = delete_lvm_region($region_name);
		if ($rc) {
			log_error("Error deleting region $region_name.\n");
			goto out;
		}
		$i++;

		log_info("$i. Verifying deletion of region $region_name.\n");

		@output = query_lvm_region($region_name);
		if (@output) {
			log_error("Error: region $region_name still exists.\n");
			$rc = 1;
			goto out;
		}
		$i++;
	}

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

# Test8
# Create a striped region across all PVs in the container. Default size
# and stripe-size.
sub Test8
{
	my $name = "Mirkwood";
	my $region_name = $container_name . "/" . $name;
	my $stripes = 4;
	my ($size, $real_stripes);
	my %options;
	my @output;
	my $rc;

	log_info("Test creating an LVM striped region.\n");

	log_info("1. Creating an LVM striped region $region_name across\n");
	log_info("   all four segments in the container.\n");

	$options{"name"} = $name;
	$options{"stripes"} = $stripes;

	$rc = create_lvm_region($container_name, \%options);
	if ($rc) {
		log_error("Error creating region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying creation of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (!@output) {
		log_error("Error getting details for region $region_name.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying region $region_name is active in the kernel.\n");

	@output = dm_info("lvm|" . $container_name . "|" . $name);
	if (!@output) {
		log_error("Error: region $region_name not found " .
			  "in the kernel.\n");
		$rc = 1;
		goto out;
	}

	log_info("4. Verifying number of stripes in region $region_name.\n");

	@output = extended_query_object("lvm/" . $region_name);
	$real_stripes = get_extended_info_value("Stripes", \@output);
	if ($stripes != $real_stripes) {
		log_error("Error: region $region_name has $stripes stripes.\n");
		$rc = 1;
		goto out;
	}

	log_info("5. Verifying all freespace used in container " .
		 "$container_name.\n");

	$size = get_object_size("lvm/" . $container_name . "/Freespace");

	$rc = compare_sizes($size, "0KB", 0);
	if ($rc) {
		log_error("Error: container $container_name has " .
			  "non-zero freespace.\n");
		goto out;
	}

	delete_lvm_region($region_name);

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

# Test9
# Create a striped region, specifying size and stripe-size. The size will not
# be a multiple of (number of stripes * extent-size), and should be rounded
# appropriately.
sub Test9
{
	my $name = "Lorien";
	my $region_name = $container_name . "/" . $name;
	my $stripes = 3;
	my $stripe_size = "64KB";
	my $size = "100MB";
	my ($real_stripes, $real_size);
	my %options;
	my @output;
	my $rc;

	log_info("Test creating an LVM striped region.\n");

	log_info("1. Creating an LVM striped region $region_name\n");
	log_info("      Size: $size\n");
	log_info("      Stripes: $stripes\n");
	log_info("      Stripe-size: $stripe_size\n");

	$options{"name"} = $name;
	$options{"size"} = $size;
	$options{"stripes"} = $stripes;
	$options{"stripe_size"} = $stripe_size;

	$rc = create_lvm_region($container_name, \%options);
	if ($rc) {
		log_error("Error creating region $region_name.\n");
		goto out;
	}

	log_info("2. Verifying creation of region $region_name.\n");

	@output = query_lvm_region($region_name);
	if (!@output) {
		log_error("Error getting details for region $region_name.\n");
		$rc = 1;
		goto out;
	}

	log_info("4. Verifying number of stripes in region $region_name.\n");

	@output = extended_query_object("lvm/" . $region_name);
	$real_stripes = get_extended_info_value("Stripes", \@output);
	if ($stripes != $real_stripes) {
		log_error("Error: region $region_name has $stripes stripes.\n");
		$rc = 1;
		goto out;
	}

	log_info("5. Verifying stripe-size for region $region_name.\n");
	$real_size = get_extended_info_value("Stripe_Size", \@output);
	$real_size =~ s/(\d+)\s+sectors/$1/;
	$rc = compare_sectors(size_to_sectors($stripe_size), $real_size, 0);
	if ($rc) {
		log_error("Error: region $region_name has wrong stripe-size.\n");
		goto out;
	}

	$size = "108MB";
	log_info("6. Verifying size of region $region_name was rounded to a\n");
	log_info("   multiple of num_stripes * extent_size ($size).\n");

	$real_size = get_object_size("lvm/" . $region_name);

	$rc = compare_sizes($size, $real_size, 0);
	if ($rc) {
		log_error("Error: region $region_name has the wrong size.\n");
		goto out;
	}

	delete_lvm_region($region_name);

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, "2GB");
	if ($rc) {
		goto finish;
	}

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

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

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

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

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

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

	$rc = Test6();
	if ($rc) {
		goto finish;
	}

	$rc = Test7();
	if ($rc) {
		goto finish;
	}

	$rc = Test8();
	if ($rc) {
		goto finish;
	}

	$rc = Test9();
	if ($rc) {
		goto finish;
	}

finish:
}

