#!/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: Create a drive link.  Delete it.
# Test2: Create a drive link with the maximun number of children.
# Test3: Create a drive link with (max-children - 1) children.  Should fail.
# Test4: Expand a drive link.
# Test5: Shrink a drive link.

use strict;
use warnings;

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

my $max_drive_link_kids = 60;

# Setup
# Assign the DOS Segment Manager to the disk.
# Make 61 segments 100MB each.
sub Setup
{
	my $disk = $_[0];
	my $rc;
	my $freespace;
	my $size = "100MB";
	my @commands;

	log_info("Assign DOS Segment Manager to disk $disk.\n");
	$rc = assign_dos_plugin($disk);
	if ($rc) {
		log_error("Error assigning DOS Segment Manager to disk $disk.\n");
		goto setup_out;
	}

	# Build a list of commands to be done at once rather than calling
	# create_dos_logical_segment() 61 times.  Each call to
	# create_dos_logical_segment() opens and closes the Engine.

	log_info("Create " . ($max_drive_link_kids + 1) . " $size segments.\n");

	# First segment comes from freespace1.
	$freespace = "$disk" . "_freespace1";
	$commands[0] = "create:segment,$freespace,Size=$size,Primary=FALSE";

	# Next segments come from freespace 2.
	$freespace = "$disk" . "_freespace2";

	for (my $i = 1; $i <= $max_drive_link_kids + 1; $i++) {
		$commands[$i] = "create:segment,$freespace,Size=$size,Primary=FALSE";
	}

	$rc = run_evms_commands(\@commands);
	if ($rc) {
		log_error("Error creating " . ($max_drive_link_kids + 1) . " DOS segments.  Return code was $rc.\n");
	}

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

# Test1
# Create a drive link.
sub Test1
{
	my @objects = @_;
	my $object_list;
	my $rc;
	my $drive_link_name = "Rat";
	my $drive_link;
	my $plugin = "DriveLink";
	my %create_options = ("name" => $drive_link_name);
	my @output;
	my $line;
	my $child = "";
	my $parent = "";
	my @lines;
	my %children;

	log_info("Test creating a drive link.\n");

	if (@objects < 1) {
		log_error(" This test requires at least one object to make a drive link.\n");
		$rc = 1;
		goto test1_out;
	}

	foreach my $thing (@objects) {
		$object_list .= "$thing ";
	}
	chop $object_list;

	log_info("1. Create a drive link named $drive_link_name from $object_list.\n");
	($drive_link) = create_object($plugin, \@objects, \%create_options);

	if (!defined($drive_link) || ($drive_link ne $drive_link_name)) {
		log_error("Failed to create drive link object.\n");
		$rc = 1;
		goto test1_out;
	}

	log_info("2. Verify drive link $drive_link_name was created.\n");
	@output = query_object($drive_link_name);
	if (@output == 0) {
		log_error("$drive_link_name was not created.\n");
		$rc = 1;
		goto test1_out;
	}

	log_info("3. Verify drive link $drive_link_name has all the objects as its children.\n");
	$rc = run_evms_command("query:children,$drive_link_name", \@output);
	if ($rc) {
		log_error("Error getting the children of $drive_link_name.  Return code was $rc.\n");
		goto test1_out;
	}
	foreach $child (@objects) {
		$children{$child} = "";
	}
	@lines = grep(/Name:/, @output);
	foreach $line (@lines) {
		$child = "";
		if ($line =~ /Name:\s+(\S+)/) {
			$child = $1;
		}
		if ($child eq "") {
			log_error("Output line does not have an object name.\n");
			$rc = 1;
			goto test1_out;
		}

		if (exists $children{$child}) {
			# Remove it from the hash.
			delete $children{$child};

		} else {
			# Extra child of the drive link
			log_error("Object $child is part of drive link $drive_link_name but was not one of the objects used to create the drive link.\n");
			$rc = 1;
			goto test1_out;
		}
	}

	if (%children) {
		log_error("The following child(ren) is/are not part of drive link $drive_link_name:\n");
		foreach $child (keys %children) {
			log_error("  $child\n");
		}
		$rc = 1;
		goto test1_out;
	}

	log_info("4. Verify that each of the object(s) has drive link $drive_link_name as its parent.\n");
	foreach $child (@objects) {
		$rc = run_evms_command("query:parent,$child", \@output);
		if ($rc) {
			log_error("Error getting the parent of $child.  Return code was $rc.\n");
			goto test1_out;
		}

		($line) = grep(/Name:/, @output);
		if ($line =~ /Name:\s+(\S+)/) {
			$parent = $1;
		}

		if ($parent eq "") {
			log_error("Could not find the line with the parent object name in the query children output.\n");
			$rc = 1;
			goto test1_out;
		}

		if ($parent ne "$drive_link_name") {
			log_error("$child does not have $drive_link_name as its parent.  It has $parent instead.\n");
			$rc = 1;
			goto test1_out;
		}
	}

	log_info("5. Delete drive link $drive_link_name.\n");
	$rc = run_evms_command("delete:$drive_link_name", \@output);
	if ($rc) {
		log_error("Error deleting $drive_link_name.  Return code was $rc.\n");
		goto test1_out;
	}

	log_info("6. Verify drive link $drive_link_name is gone.\n");
	@output = query_object($drive_link_name);
	if (@output) {
		$rc = 1;
		log_error("$drive_link_name was not deleted.\n");
		goto test1_out;
	}

	log_info("Cleanup objects.\n");
	clean_objects(@objects);

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


# Test2
# Create a drive link with the maximum number of children.
sub Test2
{
	my @objects = @_;
	my $rc;
	my $drive_link_name = "Pig";
	my $drive_link;
	my $plugin = "DriveLink";
	my %create_options = ("name" => $drive_link_name);
	my @output;
	my $line;
	my $child = "";
	my $parent = "";
	my @lines;
	my %children;

	log_info("Create a drive link with the maximum number of children.\n");

	if (@objects != $max_drive_link_kids) {
		log_error(" This test requires $max_drive_link_kids objects to make a drive link.\n");
		$rc = 1;
		goto test2_out;
	}

	log_info("1. Create a drive link named $drive_link_name from " . @objects . " objects.\n");
	($drive_link) = create_object($plugin, \@objects, \%create_options);

	if (!defined($drive_link) || ($drive_link ne $drive_link_name)) {
		log_error("Failed to create drive link object.\n");
		$rc = 1;
		goto test2_out;
	}

	log_info("2. Verify drive link $drive_link_name was created.\n");
	@output = query_object($drive_link_name);
	if (@output == 0) {
		log_error("$drive_link_name was not created.\n");
		$rc = 1;
		goto test2_out;
	}

	log_info("3. Verify drive link $drive_link_name has all " . @objects . " objects as its children.\n");
	$rc = run_evms_command("query:children,$drive_link_name", \@output);
	if ($rc) {
		log_error("Error getting the children of $drive_link_name.  Return code was $rc.\n");
		goto test2_out;
	}
	foreach $child (@objects) {
		$children{$child} = "";
	}
	@lines = grep(/Name:/, @output);
	foreach $line (@lines) {
		$child = "";
		if ($line =~ /Name:\s+(\S+)/) {
			$child = $1;
		}
		if ($child eq "") {
			log_error("Output line does not have an object name.\n");
			$rc = 1;
			goto test2_out;
		}

		if (exists $children{$child}) {
			# Remove it from the hash.
			delete $children{$child};

		} else {
			# Extra child of the drive link
			log_error("Object $child is part of drive link $drive_link_name but was not one of the objects used to create the drive link.\n");
			$rc = 1;
			goto test2_out;
		}
	}

	if (%children) {
		log_error("The following child(ren) is/are not part of drive link $drive_link_name:\n");
		foreach $child (keys %children) {
			log_error("  $child\n");
		}
		$rc = 1;
		goto test2_out;
	}

	log_info("4. Verify that each of the " . @objects . " objects has drive link $drive_link_name as its parent.\n");
	log_info("   This may take a while.\n");
	foreach $child (@objects) {
		$rc = run_evms_command("query:parent,$child", \@output);
		if ($rc) {
			log_error("Error getting the parent of $child.  Return code was $rc.\n");
			goto test2_out;
		}

		($line) = grep(/Name:/, @output);
		if ($line =~ /Name:\s+(\S+)/) {
			$parent = $1;
		}

		if ($parent eq "") {
			log_error("Could not find the line with the parent object name in the query children output.\n");
			$rc = 1;
			goto test2_out;
		}

		if ($parent ne "$drive_link_name") {
			log_error("$child does not have $drive_link_name as its parent.  It has $parent instead.\n");
			$rc = 1;
			goto test2_out;
		}
	}

	log_info("Cleanup objects.\n");
	clean_objects(@objects);

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


# Test3
# Try to create a drive link with more than the maximum number of children.
sub Test3
{
	my @objects = @_;
	my $rc;
	my $drive_link_name = "Pigita";
	my $drive_link;
	my $plugin = "DriveLink";
	my %create_options = ("name" => $drive_link_name);
	my @output;
	my $line;
	my $child = "";
	my $parent = "";
	my @lines;
	my %children;

	log_info("Try to create a drive link with more than the maximum number of children.\n");

	if (@objects < $max_drive_link_kids + 1) {
		log_error(" This test requires more than $max_drive_link_kids objects to make a drive link.\n");
		$rc = 1;
		goto test3_out;
	}

	log_info("1. Create a drive link named $drive_link_name from " . @objects . " objects.\n");
	($drive_link) = create_object($plugin, \@objects, \%create_options);

	if (defined($drive_link)) {
		log_error("Drive link creation succeeded.  It should have failed.\n");
		$rc = 1;
		goto test3_out;
	}

	log_info("2. Verify drive link $drive_link_name was not created.\n");
	@output = query_object($drive_link_name);
	if (@output != 0) {
		log_error("$drive_link_name was created.\n");
		$rc = 1;
		goto test3_out;
	}

	if ($rc) {
		log_info("Cleanup objects.\n");
		clean_objects(@objects);
	}

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


# Test4
# Expand a drive link.
sub Test4
{
	my @objects = @_;
	my $object_list;
	my $expand_object;
	my $rc;
	my $drive_link_name = "Zebra";
	my $drive_link;
	my $plugin = "DriveLink";
	my %create_options = ("name" => $drive_link_name);
	my @output;
	my $line;
	my $child = "";
	my $parent = "";
	my @lines;

	log_info("Test expanding a drive link.\n");

	if (@objects < 2) {
		log_error(" This test requires at least one object to make a drive link and another object to expand it.\n");
		$rc = 1;
		goto test4_out;
	}

	$expand_object = pop(@objects);

	foreach my $thing (@objects) {
		$object_list .= "$thing ";
	}
	chop $object_list;

	log_info("1. Create a drive link named $drive_link_name from $object_list.\n");
	($drive_link) = create_object($plugin, \@objects, \%create_options);

	if (!defined($drive_link) || ($drive_link ne $drive_link_name)) {
		log_error("Failed to create drive link object.\n");
		$rc = 1;
		goto test4_out;
	}

	log_info("2. Verify drive link $drive_link_name was created.\n");
	@output = query_object($drive_link_name);
	if (@output == 0) {
		log_error("$drive_link_name was not created.\n");
		$rc = 1;
		goto test4_out;
	}

	log_info("3. Expand drive link $drive_link_name by adding object $expand_object.\n");
	$rc = run_evms_command("expand:$drive_link_name,$expand_object", \@output);
	if ($rc) {
		log_error("Error expanding $drive_link_name.  Return code was $rc.\n");
		goto test4_out;
	}


	log_info("4. Verify that $expand_object is a child of drive link $drive_link_name.\n");
	$rc = run_evms_command("query:children,$drive_link_name", \@output);
	if ($rc) {
		log_error("Error getting the children of $drive_link_name.  Return code was $rc.\n");
		goto test4_out;
	}
	@lines = grep(/Name:/, @output);
	foreach $line (@lines) {
		if ($line =~ /Name:\s+(\S+)/) {
			$child = $1;
		}
		if ($child eq $expand_object) {
			last;
		}
	}

	if ($child ne $expand_object) {
		log_error("$expand_object was not found in the list of children of drive link $drive_link_name.\n");
		goto test4_out;
	}

	log_info("5. Verify that $expand_object has drive link $drive_link_name as its parent.\n");
	$rc = run_evms_command("query:parent,$expand_object", \@output);
	if ($rc) {
		log_error("Error getting the parent of $expand_object.  Return code was $rc.\n");
		goto test4_out;
	}

	($line) = grep(/Name:/, @output);
	if ($line =~ /Name:\s+(\S+)/) {
		$parent = $1;
	}

	if ($parent ne "$drive_link_name") {
		log_error("$expand_object does not have $drive_link_name as its parent.  It has $parent instead.\n");
		$rc = 1;
		goto test4_out;
	}

	log_info("Cleanup objects.\n");
	$rc = clean_objects(@objects);

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

# Test5
# Shrink a drive link.
sub Test5
{
	my @objects = @_;
	my $object_list;
	my $shrink_object;
	my $rc;
	my $drive_link_name = "Goat";
	my $drive_link;
	my $plugin = "DriveLink";
	my %create_options = ("name" => $drive_link_name);
	my @output;
	my $line;
	my $child = "";
	my $parent = "";
	my @lines;

	log_info("Test shrinking a drive link.\n");

	if (@objects < 2) {
		log_error(" This test requires at least two objects to make a drive link that can be shrunk.\n");
		$rc = 1;
		goto test5_out;
	}

	foreach my $thing (@objects) {
		$object_list .= "$thing ";
	}
	chop $object_list;

	log_info("1. Create a drive link named $drive_link_name from $object_list.\n");
	($drive_link) = create_object($plugin, \@objects, \%create_options);

	if (!defined($drive_link) || ($drive_link ne $drive_link_name)) {
		log_error("Failed to create drive link object.\n");
		$rc = 1;
		goto test5_out;
	}

	log_info("2. Verify drive link $drive_link_name was created.\n");
	@output = query_object($drive_link_name);
	if (@output == 0) {
		log_error("$drive_link_name was not created.\n");
		$rc = 1;
		goto test5_out;
	}

	# The shrink object is the last object in the drive link.
	$rc = run_evms_command("query:children,$drive_link_name", \@output);
	if ($rc) {
		log_error("Error getting the children of $drive_link_name.  Return code was $rc.\n");
		goto test5_out;
	}
	@lines = grep(/Name:/, @output);
	foreach $line (@lines) {
		if ($line =~ /Name:\s+(\S+)/) {
			$shrink_object = $1;
		}
        }
	if (!defined $shrink_object) {
		log_error("Error finding the last child of $drive_link_name.\n");
		$rc = 1;
		goto test5_out;
	}

	log_info("2. Shrink drive link $drive_link_name by removing object $shrink_object.\n");
	$rc = run_evms_command("shrink:$drive_link_name,$shrink_object", \@output);
	if ($rc) {
		log_error("Error shrinking $drive_link_name.  Return code was $rc.\n");
		goto test5_out;
	}


	log_info("3. Verify that $shrink_object is not a child of drive link $drive_link_name.\n");
	$rc = run_evms_command("query:children,$drive_link_name", \@output);
	if ($rc) {
		log_error("Error getting the children of $drive_link_name.  Return code was $rc.\n");
		goto test5_out;
	}
	@lines = grep(/Name:/, @output);
	foreach $line (@lines) {
		if ($line =~ /Name:\s+(\S+)/) {
			$child = $1;
		}
		if ($child eq $shrink_object) {
			last;
		}
	}

	if ($child eq $shrink_object) {
		log_error("$shrink_object was found in the list of children of drive link $drive_link_name.\n");
		goto test5_out;
	}

	log_info("4. Verify that $shrink_object does not have drive link $drive_link_name as its parent.\n");
	$rc = run_evms_command("query:parent,$shrink_object", \@output);
	if ($rc) {
		log_error("Error getting the parent of $shrink_object.  Return code was $rc.\n");
		goto test5_out;
	}

	($line) = grep(/Name:/, @output);
	if (defined $line) {
		if ($line =~ /Name:\s+(\S+)/) {
			$parent = $1;
		}
	}

	if ($parent eq "$drive_link_name") {
		log_error("$shrink_object has $drive_link_name as its parent.\n");
		$rc = 1;
		goto test5_out;
	}

	log_info("Cleanup objects.\n");
	clean_objects(@objects);

test5_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");

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

	$rc = Test1($disk.5, $disk.6, $disk.7, $disk.8);
	if ($rc) {
		goto finish;
	}

	$rc = Test2($disk.5,  $disk.6,  $disk.7,  $disk.8,  $disk.9,  $disk.10, $disk.11, $disk.12, $disk.13, $disk.14,
		    $disk.15, $disk.16, $disk.17, $disk.18, $disk.19, $disk.20, $disk.21, $disk.22, $disk.23, $disk.24,
		    $disk.25, $disk.26, $disk.27, $disk.28, $disk.29, $disk.30, $disk.31, $disk.32, $disk.33, $disk.34,
		    $disk.35, $disk.36, $disk.37, $disk.38, $disk.39, $disk.40, $disk.41, $disk.42, $disk.43, $disk.44,
		    $disk.45, $disk.46, $disk.47, $disk.48, $disk.49, $disk.50, $disk.51, $disk.52, $disk.53, $disk.54,
		    $disk.55, $disk.56, $disk.57, $disk.58, $disk.59, $disk.60, $disk.61, $disk.62, $disk.63, $disk.64);
	if ($rc) {
		goto finish;
	}

	$rc = Test3($disk.5,  $disk.6,  $disk.7,  $disk.8,  $disk.9,  $disk.10, $disk.11, $disk.12, $disk.13, $disk.14,
		    $disk.15, $disk.16, $disk.17, $disk.18, $disk.19, $disk.20, $disk.21, $disk.22, $disk.23, $disk.24,
		    $disk.25, $disk.26, $disk.27, $disk.28, $disk.29, $disk.30, $disk.31, $disk.32, $disk.33, $disk.34,
		    $disk.35, $disk.36, $disk.37, $disk.38, $disk.39, $disk.40, $disk.41, $disk.42, $disk.43, $disk.44,
		    $disk.45, $disk.46, $disk.47, $disk.48, $disk.49, $disk.50, $disk.51, $disk.52, $disk.53, $disk.54,
		    $disk.55, $disk.56, $disk.57, $disk.58, $disk.59, $disk.60, $disk.61, $disk.62, $disk.63, $disk.64,
		    $disk.65);
	if ($rc) {
		goto finish;
	}

	$rc = Test4($disk.5, $disk.6, $disk.7, $disk.8);
	if ($rc) {
		goto finish;
	}

	$rc = Test5($disk.5, $disk.6, $disk.7, $disk.8);
	if ($rc) {
		goto finish;
	}

	clean_object($disk);

finish:
}

