#!/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
#
# Basic tests of snapshotting without any filesystems.
# Test1: Write a pattern to the origin. Create a snapshot. Verify the
#        pattern on the snapshot matches the pattern from the origin.
# Test2: Write a different pattern to the origin. Verify the pattern on the
#        snapshot has not changed from Test1.
# Test3: Reset the snapshot. Verify the pattern on the snapshot now matches
#        the new pattern on the origin from Test2.
# Test4: Repeat Test2 with yet a different pattern on the origin.
# Test5: Rollback the snapshot. Verify the patterns on the origin and the
#        snapshot match the pattern from Test2.

use strict;
use warnings;

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

my $snapshot_name = "Snapshot1";
my $origin_name = "Origin1";
my $snapshot_vol = "/dev/evms/" . $snapshot_name;
my $origin_vol = "/dev/evms/" . $origin_name;
my $snapshot_obj = "snap_obj1";
my $origin_sectors;
my $pattern = 0;

# Setup
# Create two DOS segments to work with. The second will be slightly larger,
# so the snapshot does not get invalidated during these tests. Then create
# the origin volume.
sub Setup
{
	my $disk = $_[0];
	my $freespace = $disk . "_freespace1";
	my $origin_seg = $disk . "1";
	my $snapshot_seg = $disk . "2";
	my %options;
	my $rc;

	log_info("1. Assigning DOS to disk $disk.\n");

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

	log_info("2. Creating two DOS primary segments on disk $disk.\n");

	$rc = create_dos_primary_segment($freespace, "250MB");
	if ($rc) {
		log_error("Error creating first DOS segment on disk $disk.\n");
		goto out;
	}

	$rc = create_dos_primary_segment($freespace, "300MB");
	if ($rc) {
		log_error("Error creating second DOS segment on disk $disk.\n");
		goto out;
	}

	log_info("3. Creating volume $origin_vol on segment $origin_seg.\n");

	$rc = create_evms_volume($origin_seg, $origin_name);
	if ($rc) {
		log_error("Error creating volume $origin_vol.\n");
		goto out;
	}

	log_info("4. Getting size of volume $origin_vol.\n");

	$origin_sectors = get_blkdev_sectors($origin_vol);
	if ($origin_sectors <= 0) {
		log_error("Error getting size of volume $origin_vol.\n");
		$rc = 1;
		goto out;
	}

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

# Test1
# Write a pattern to the origin. Create a snapshot. Verify that the pattern on
# the snapshot matches the pattern from the origin.
sub Test1
{
	my $disk = $_[0];
	my $snapshot_seg = $disk . "2";
	my %options;
	my $rc;

	log_info("Test correctness of snapshot data.\n");

	# Write pattern to the origin and verify.
	log_info("1. Writing pattern $pattern to volume $origin_vol.\n");

	$rc = write_sequence($origin_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error writing pattern $pattern to " .
			  "volume $origin_vol.\n");
		goto out;
	}

	log_info("2. Validating pattern $pattern on volume $origin_vol.\n");

	$rc = validate_sequence($origin_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $origin_vol.\n");
		goto out;
	}

	# Create the snapshot volume.
	log_info("3. Creating snapshot volume $snapshot_vol of\n");
	log_info("   origin volume $origin_vol.\n");

	$options{"original"} = $origin_vol;
	$options{"snapshot"} = $snapshot_obj;
	$rc = create_snapshot($snapshot_seg, \%options);
	if ($rc) {
		log_error("Error creating snapshot object $snapshot_obj " .
			  "on segment $snapshot_seg.\n");
		goto out;
	}

	$rc = create_evms_volume($snapshot_obj, $snapshot_name);
	if ($rc) {
		log_error("Error creating volume from object $snapshot_obj.\n");
		goto out;
	}

	# Verify the pattern on the snapshot.
	log_info("4. Validating pattern $pattern on volume $snapshot_vol.\n");

	$rc = validate_sequence($snapshot_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $snapshot_vol.\n");
		goto out;
	}

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

# Test2
# Write a different pattern to the origin. Verify the pattern on the
# snapshot has not changed from Test1.
sub Test2
{
	my $rc;

	log_info("Test correctness of snapshot data after modifying origin.\n");

	# Write new pattern to the origin and verify.
	$pattern = 1;
	log_info("1. Writing pattern $pattern to volume $origin_vol.\n");

	$rc = write_sequence($origin_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error writing pattern $pattern to " .
			  "volume $origin_vol.\n");
		goto out;
	}

	log_info("2. Validating pattern $pattern on volume $origin_vol.\n");

	$rc = validate_sequence($origin_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $origin_vol.\n");
		goto out;
	}

	# Verify the old pattern on the snapshot.
	$pattern = 0;
	log_info("4. Validating pattern $pattern on volume $snapshot_vol.\n");

	$rc = validate_sequence($snapshot_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $snapshot_vol.\n");
		goto out;
	}

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

# Test3
# Reset the snapshot. Verify the pattern on the snapshot now matches
# the new pattern on the origin from Test2.
sub Test3
{
	my $rc;

	log_info("Test resetting the snapshot.\n");

	log_info("1. Resetting snapshot object $snapshot_obj.\n");

	$rc = reset_snapshot($snapshot_obj);
	if ($rc) {
		log_error("Error resetting snapshot object $snapshot_obj.\n");
		goto out;
	}

	# Verify the pattern on the snapshot now matches the origin.
	$pattern = 1;
	log_info("2. Validating pattern $pattern on volume $snapshot_vol.\n");

	$rc = validate_sequence($snapshot_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $snapshot_vol.\n");
		goto out;
	}

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

# Test4
# Repeat Test2 with yet a different pattern on the origin.
sub Test4
{
	my $rc;

	log_info("Test correctness of snapshot data after modifying origin.\n");

	# Write new pattern to the origin and verify.
	$pattern = 2;
	log_info("1. Writing pattern $pattern to volume $origin_vol.\n");

	$rc = write_sequence($origin_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error writing pattern $pattern to " .
			  "volume $origin_vol.\n");
		goto out;
	}

	log_info("2. Validating pattern $pattern on volume $origin_vol.\n");

	$rc = validate_sequence($origin_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $origin_vol.\n");
		goto out;
	}

	# Verify the old pattern on the snapshot.
	$pattern = 1;
	log_info("4. Validating pattern $pattern on volume $snapshot_vol.\n");

	$rc = validate_sequence($snapshot_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $snapshot_vol.\n");
		goto out;
	}

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

# Test5
# Rollback the snapshot. Verify the patterns on the origin and the
# snapshot match the pattern from Test2.
sub Test5
{
	my $rc;

	log_info("Test rolling-back the snapshot.\n");

	log_info("1. Rolling-back snapshot object $snapshot_obj.\n");

	$rc = rollback_snapshot($snapshot_obj);
	if ($rc) {
		log_error("Error rolling-back snapshot object $snapshot_obj.\n");
		goto out;
	}

	# Verify the patterns on the origin and the snapshot.
	$pattern = 1;
	log_info("2. Validating pattern $pattern on volume $origin_vol.\n");

	$rc = validate_sequence($origin_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $origin_vol.\n");
		goto out;
	}

	log_info("3. Validating pattern $pattern on volume $snapshot_vol.\n");

	$rc = validate_sequence($snapshot_vol, $origin_sectors, 0, $pattern);
	if ($rc) {
		log_error("Error validating pattern $pattern on " .
			  "volume $snapshot_vol.\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;
	}

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

finish:
	# Delete the snapshot volume and object.
	delete_thing($snapshot_vol);
	delete_thing($snapshot_obj);
}

