#!/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 assign, create, and delete of DOS segments.
#
# Test1: Assign the DOS plugin to the disk.
# Test2: Create a primary segment.
# Test3: Create a logical segment.
# Test4: Delete the primary and logical segments.
# Test5: Create a primary segment with several other options.
# Test6: Create four primary segments. Make sure a fifth primary segment
#        or any logical segments cannot be created.
# Test7: Create a lot of logical segments.
# Test8: Unassign the DOS plugin from the disk.

use strict;
use warnings;

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

# Test1
# Assign DOS to the disk.
sub Test1
{
	my $disk = $_[0];
	my @query_output;
	my $mbr = $disk . "_mbr";
	my $rc;

	log_info("Test assigning the DOS plugin to a disk.\n");

	log_info("1. Assigning DOS plugin to disk $disk.\n");
	$rc = assign_dos_plugin($disk);
	if ($rc) {
		log_error("Error assigning DOS plugin to disk $disk.\n");
		goto out;
	}

	log_info("2. Verifying assignment of plugin to disk $disk.\n");

	@query_output = query_object($mbr);
	if (@query_output == 0) {
		log_error("Error getting details for MBR on disk $disk.\n");
		$rc = 1;
		goto out;
	}

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

# Test2
# Create a primary segment.
sub Test2
{
	my $disk = $_[0];
	my $freespace = $disk . "_freespace1";
	my $segment = $disk . "1";
	my $size = "500MB";
	my @query_output;
	my $rc;

	log_info("Test creating a primary segment.\n");

	log_info("1. Creating $size primary segment on disk $disk.\n");

	$rc = create_dos_primary_segment($freespace, $size);
	if ($rc) {
		log_error("Error creating primary segment.\n");
		goto out;
	}

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

	@query_output = query_object($segment);
	if (@query_output == 0) {
		log_error("Error verifying existence of segment $segment.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying segment $segment is active in kernel.\n");

	$rc = dm_device_exists($segment);
	if ($rc) {
		log_error("Error getting kernel info for segment $segment.\n");
		$rc = 1;
		goto out;
	}

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

# Test3
# Create a logical segment.
sub Test3
{
	my $disk = $_[0];
	my $freespace = $disk . "_freespace1";
	my $segment = $disk . "5";
	my $size = "500MB";
	my @query_output;
	my $rc;

	log_info("Test creating a logical segment.\n");

	log_info("1. Creating $size logical segment on disk $disk.\n");

	$rc = create_dos_logical_segment($freespace, $size);
	if ($rc) {
		log_error("Error creating logical segment.\n");
		goto out;
	}

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

	@query_output = query_object($segment);
	if (@query_output == 0) {
		log_error("Error verifying existence of segment $segment.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying segment $segment is active in kernel.\n");

	$rc = dm_device_exists($segment);
	if ($rc) {
		log_error("Error getting kernel info for segment $segment.\n");
		$rc = 1;
		goto out;
	}

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

# Test4
# Delete the primary and logical segments from Test2 and Test3.
sub Test4
{
	my $disk = $_[0];
	my $primary = $disk . "1";
	my $logical = $disk . "5";
	my @query_output;
	my $rc;

	log_info("Test deleting segments.\n");

	log_info("1. Deleting the segments $primary and $logical " .
		 "from disk $disk.\n");

	$rc = delete_thing($primary);
	if ($rc) {
		log_error("Error deleting segment $primary.\n");
		goto out;
	}

	$rc = delete_thing($logical);
	if ($rc) {
		log_error("Error deleting segment $logical.\n");
		goto out;
	}

	log_info("2. Verifying deletion of segments $primary and $logical.\n");

	@query_output = query_object($primary);
	if (@query_output != 0) {
		log_error("Error: segment $primary still exists.\n");
		$rc = 1;
		goto out;
	}

	@query_output = query_object($logical);
	if (@query_output != 0) {
		log_error("Error: segment $logical still exists.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying deactivation of segments in kernel.\n");

	$rc = dm_device_exists($primary);
	if (!$rc) {
		log_error("Error: segment $primary still active in kernel.\n");
		$rc = 1;
		goto out;
	}

	$rc = dm_device_exists($logical);
	if (!$rc) {
		log_error("Error: segment $logical still active in kernel.\n");
		$rc = 1;
		goto out;
	}

	$rc = 0;

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

# Test5
# Create a segment with extra options.
sub Test5
{
	my $disk = $_[0];
	my $freespace = $disk . "_freespace1";
	my $segment = $disk . "1";
	my %options;
	my @query_output;
	my $value;
	my $rc;

	$options{"Size"} = "1GB";
	$options{"Primary"} = "TRUE";
	$options{"Offset"} = "1GB";
	$options{"Bootable"} = "TRUE";
	$options{"TypeByNumber"} = "142";

	log_info("Test creating segments with extra DOS options.\n");

	log_info("1. Creating primary segment on disk $disk with options:\n");
	log_info("     size = $options{'Size'}\n");
	log_info("     primary = $options{'Primary'}\n");
	log_info("     offset = $options{'Offset'}\n");
	log_info("     bootable = $options{'Bootable'}\n");
	log_info("     type = $options{'TypeByNumber'}\n");

	$rc = create_dos_segment($freespace, \%options);
	if ($rc) {
		log_error("Error creating segment.\n");
		goto out;
	}

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

	@query_output = query_object($segment);
	if (@query_output == 0) {
		log_error("Error verifying existence of segment $segment.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying extra options on segment $segment.\n");

	@query_output = extended_query_object($segment);
	if (@query_output == 0) {
		log_error("Error getting extended info for segment $segment.\n");
		$rc = 1;
		goto out;
	}

	$value = get_extended_info_value("Size", \@query_output);
	$value =~ s/(\d+)\s+sectors/$1/;
	$rc = compare_sectors($value, size_to_sectors($options{"Size"}), 5);
	if ($rc) {
		log_error("Error verifying size of segment $segment.\n");
		goto out;
	}

	$value = get_extended_info_value("Start", \@query_output);
	$rc = compare_sectors($value, size_to_sectors($options{"Offset"}), 5);
	if ($rc) {
		log_error("Error verifying starting offset of " .
			  "segment $segment.\n");
		goto out;
	}

	$value = get_extended_info_value("Flag", \@query_output);
	if ($value ne "Yes") {
		log_error("Error verifying primary/logical flag for " .
			  "segment $segment.\n");
		$rc = 1;
		goto out;
	}

	# KMC: Compare other extended info values!!!

	# Delete the segment now that we're done.
	delete_thing($segment);

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

# Test6
# Create four primary segments. Then try to create a fifth and make sure it
# fails. Then try to create a logical segment and make sure it fails.
sub Test6
{
	my $disk = $_[0];
	my $freespace = $disk . "_freespace1";
	my $size = 250;
	my @query_output;
	my ($rc, $i);

	log_info("Test limit of four primary segments per disk.\n");

	log_info("1. Creating four primary segments on disk $disk.\n");

	for ($i = 1; $i < 5; $i++) {
		$rc = create_dos_primary_segment($freespace, $size * $i . "MB");
		if ($rc) {
			log_error("Error creating primary segment $disk$i.\n");
			goto out;
		}
	}

	log_info("2. Attempting to create a fifth primary segment on disk $disk.\n");

	$rc = create_dos_primary_segment($freespace, $size . "MB");
	if (!$rc) {
		log_error("Error: created a fifth primary segment.\n");
		$rc = 1;
		goto out;
	}

	log_info("3. Verifying fifth primary segment was *not* created.\n");

	@query_output = query_object($disk . "5");
	if (@query_output != 0) {
		log_error("Error: segment ${disk}5 exists.\n");
		$rc = 1;
		goto out;
	}

	log_info("4. Attempting to create a logical segment on disk $disk.\n");

	$rc = create_dos_logical_segment($freespace, $size . "MB");
	if (!$rc) {
		log_error("Error: created a logical segment.\n");
		$rc = 1;
		goto out;
	}

	log_info("5. Verifying logical segment was *not* created.\n");

	@query_output = query_object($disk . "5");
	if (@query_output != 0) {
		log_error("Error: segment ${disk}5 exists.\n");
		$rc = 1;
		goto out;
	}

	delete_thing($disk . "1");
	delete_thing($disk . "2");
	delete_thing($disk . "3");
	delete_thing($disk . "4");
	$rc = 0;

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

# Test7
# Create a lot of logical segments on the disk.
sub Test7
{
	my $disk = $_[0];
	my $freespace = $disk . "_freespace1";
	my $segment;
	my $count = 25;
	my $size = "50MB";
	my $sectors;
	my ($rc, $i);

	log_info("Test creating large number of logical segments on a disk.\n");

	log_info("1. Creating $count logical segments on disk $disk.\n");

	for ($i = 0; $i < $count; $i++) {
		$rc = create_dos_logical_segment($freespace, $size);
		if ($rc) {
			log_error("Error creating logical segment $i.\n");
			goto out;
		}
		$freespace = $disk . "_freespace2";
	}

	log_info("2. Verifying all $count segments are active in the kernel.\n");

	for ($i = 0; $i < $count; $i++) {
		$segment = $i + 5;
		$segment = $disk . $segment;
		$rc = dm_device_exists($segment);
		if ($rc) {
			log_error("Error: segment $segment not found in " .
				  "the kernel.\n");
			goto out;
		}

		$sectors = get_blkdev_sectors($segment);
		$rc = compare_sectors($sectors, size_to_sectors($size), 10);
		if ($rc) {
			log_error("Error verifying number of sectors in " .
				  "segment $segment.\n");
			goto out;
		}
	}

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

# Test8
# Unassign DOS from the disk.
sub Test8
{
	my $disk = $_[0];
	my $mbr = $disk . "_mbr";
	my @query_output;
	my $rc;

	log_info("Testing unassigning the DOS plugin from a disk.\n");

	log_info("1. Removing the DOS plugin from disk $disk.\n");

	$rc = unassign_dos_plugin($disk);
	if ($rc) {
		log_error("Error removing DOS plugin from disk $disk.\n");
		goto out;
	}

	log_info("2. Verifying removal of DOS plugin.\n");

	@query_output = query_object($mbr);
	if (@query_output != 0) {
		log_error("Error: DOS plugin was not removed from disk $disk.\n");
		$rc = 1;
		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, "1.5GB");
	if ($rc) {
		die("Disk $disk isn't large enough for this test.\n");
	}

	# No setup required, as long as $disk is already clean.

	$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;
	}

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

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

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

finish:
}

