#!/bin/perl
# **********************************************************************
#
# Copyright (c) 2000 
# Object Oriented Concepts, Inc.
# Billerica, MA, USA
#
# All Rights Reserved
#
# **********************************************************************

package Tests;

use TestSuiteUtilities;
use strict;
use Exporter;

use vars qw(%test_params
	    $current_test_type
	    $status
	    $current_indent
	    $service_started
	    $service_type
	    $con_admin
   	    $sup_admin
   	    $multiple
	    @ISA 
	    @EXPORT);

@ISA = qw(Exporter);

@EXPORT = qw(&getStatus
	     &MultipleProxies
	     &MultipleTypedProxies
	     &SendEvents
	     &SendTypedEvents
	     &printLastMessage);


#########################################################################
#
# Private helper methods.
#
#########################################################################

#
# Start the event service.
#
sub startEventService()
{
    if($service_type eq "typed")
    {
        &startTypedService();
	
	$service_started = "true";
	my $channel = &obtainTypedChannel();
	if($channel eq -1)
	{
	    &shutdownTypedService();
	    print "Channel undefined, exiting\n";
	    exit();
	}
	
	$con_admin = &obtainTypedConsumerAdmin($channel);
	$sup_admin = &obtainTypedSupplierAdmin($channel);
    }
    elsif($service_type eq "untyped") 
    {
        &startService();

	$service_started = "true";
	my $channel = &obtainChannel();
	if($channel eq -1)
	{
	    &shutdownService();
	    print "Channel undefined, exiting\n";
	    exit();
	}
	
	$con_admin = &obtainConsumerAdmin($channel);
	$sup_admin = &obtainSupplierAdmin($channel);
    }
    else
    {
        print "Error: Service Type is neither typed nor untyped\n";
	exit();
    }
}

#
# The current_test_type variable holds the type of the test that is being 
# tested.  If it changes, then the previous test type passed.
#
# The test types will have * markers in it.  For each string before a 
# marker that does match the previous test type, the output will be
# indented two spaces.  When a difference is found, the previous test
# must have succeeded, and a new test is started.
#
sub changeTestType($)
{ 
    my $new = shift;
    $| = 1;

    if($new eq "Last")
    {
        print "OK!\n";
	return;
    }
    
    if($current_test_type eq "")
    {

        #
	# This is the first test executed
	#
	startEventService();
	$current_test_type = $new;
	my @tokens = split("[\*]", $current_test_type);
        my $indent = 0;
        
        for(my $i = 0 ; $i < scalar(@tokens) - 1 ; $i++)
        {
            for(my $j = 0 ; $j < $indent ; $j++)
            {
                print " ";
            }
            $indent += 2;
            print "$tokens[$i]\n";
        }
        for(my $j = 0 ; $j < $indent ; $j++)
        {
	    print " ";
        }
        my $j = scalar(@tokens) - 1;
        print "$tokens[$j] ... ";
	$current_indent = $indent;
	return;
    }
  
    print "OK!\n";

    if($current_test_type eq $new)
    { 
	for(my $j = 0 ; $j < $current_indent ; $j++)
	{
	    print " ";
	}
	my @tokens = split("[\*]", $current_test_type);
	my $j = scalar(@tokens) - 1;
	print "$tokens[$j] ... ";
	return;
    }

    my @old_tokens = split("[\*]", $current_test_type);
    my @new_tokens = split("[\*]", $new);
    my $indent = 0;
    $current_test_type = $new;   
    
    for(my $i = 0 ; $i < scalar(@new_tokens) ; $i++)
    {
        if($old_tokens[$i] eq $new_tokens[$i])
	{
	    $indent += 2;
        }
	else
	{
	    for(my $j = $i ; $j < scalar(@new_tokens) - 1 ; $j++)
            { 
	        for(my $k = 0 ; $k < $indent ; $k++)
		{
                    print " ";
		}
                $indent += 2;
                print "$new_tokens[$j]\n";
	    }
	    for(my $k = 0 ; $k < $indent ; $k++)
	    {
                print " ";
	    }
	    my $j = scalar(@new_tokens) - 1;
            print "$new_tokens[$j] ... ";
	    $current_indent = $indent;
            return;
        }
    }
}

#
# The test parameters hash is use to dictate to the individual running of 
# a test what settings to make to the system.  The hash is cleaned 
# before each running of the test.
#
sub cleanTestHash()
{
    $test_params{"datafile"} = "";
    $test_params{"proxy_consumer"} = "";
    $test_params{"proxy_supplier"} = "";
    $test_params{"sleep_time"} = "0";
    $test_params{"supplier_count"} = "1";
    $test_params{"consumer_count"} = "1";
    $test_params{"shutdown"} = "false";
}

#
# Here we are interested in reading the data contained after the
# set: and the use: markers in the datafile.
#
sub readDataFileSettings()
{
    my $IN = new FileHandle;

    #
    # Read the events from the data file.
    #
    open(IN, $test_params{"datafile"}) or
	die "Could not open file $test_params{\"datafile\"}\n;";
   
    #
    # Look for "set:" and "use:" 
    #
    while(<IN>)
    {
	$_ =~ s/^\s+//;
	$_ =~ s/\s+$//;
	if(/set:/) 
	{

	    #
	    # Have QoS setting commands
	    #
	    while(<IN>)
	    {        
		$_ =~ s/^\s+//;
		$_ =~ s/\s+$//;
		if(/Sleep_Time: (.*)/) 
		{ 
		    $test_params{"sleep_time"} = $1;
		}
		elsif(/Type_Reference: (.*)/) 
		{ 
		    $test_params{"reference"} = $1;
		}
		elsif(/Shutdown: (.*)/) 
		{ 
		    $test_params{"shutdown"} = $1;
		}
		elsif(/Supplier_Count: (.*)/) 
		{   
		    if($multiple eq "true")
		    {
		        $test_params{"supplier_count"} = $1;
		    }
		}
		elsif(/Consumer_Count: (.*)/) 
		{ 
		    if($multiple eq "true")
		    {
		        $test_params{"consumer_count"} = $1;
		    }
		}
		else 
		{ 
		    last; 
		}
	    }
	}
	elsif(/use:/) 
	{

	    #
	    # Have proxy objects defined. (have to trim the newlines) 
	    #
	    while(<IN>)
	    {        
		$_ =~ s/^\s+//;
		$_ =~ s/\s+$//;
		if(/.*Supplier/) 
		{ 
		   $_ =~ s/\n//;
		   $test_params{"proxy_supplier"} = $_;
		}
		elsif(/.*Consumer/) 
		{ 
		   $_ =~ s/\n//;
		   $test_params{"proxy_consumer"} = $_;
		}
		else 
		{ 
		    last; 
		}
	    }
	}
    }
    close(IN);
}

#
# This is the generic untyped Event Service test.  The method sets up the 
# service with the desired proxies, causes events to be sent and then
# received, and finally inspects the results to determine if the test
# passed.
#
sub Run_Event_Service_Tests()
{
    if($service_started eq "false")
    {
	startEventService();
    }

    #
    # Read the data file for settings that need to be made.
    #
    readDataFileSettings();

    my $i;	
    my @consumer_proxy;
    my @supplier_proxy;
    my $consumer_proxy_model;
    my $supplier_proxy_model;
    
    if(index($test_params{"proxy_consumer"}, "Push") == -1)
    {
	$consumer_proxy_model = "pull";
	for($i = 0 ; $i < $test_params{"supplier_count"} ; $i++)
	{
	    $consumer_proxy[$i] = &obtainPullConsumer($sup_admin); 
	}
    }
    else
    {
	$consumer_proxy_model = "push";
	for($i = 0 ; $i < $test_params{"supplier_count"} ; $i++)
	{
	    $consumer_proxy[$i] = &obtainPushConsumer($sup_admin); 
	}
    }
    if(index($test_params{"proxy_supplier"}, "Push") == -1)
    {
	$supplier_proxy_model = "pull";
	for($i = 0 ; $i < $test_params{"consumer_count"} ; $i++)
	{
	    $supplier_proxy[$i] = &obtainPullSupplier($con_admin); 
	}
    }
    else
    {
	$supplier_proxy_model = "push";
	for($i = 0 ; $i < $test_params{"consumer_count"} ; $i++)
	{
	    $supplier_proxy[$i] = &obtainPushSupplier($con_admin); 
	}
    }

    for($i = 0 ; $i < $test_params{"consumer_count"} ; $i++)
    {
        &makeConnected($supplier_proxy[$i], $supplier_proxy_model, $i);
    }

    #
    # Now we can send events as described in the datafile
    #
    for($i = 0 ; $i < $test_params{"supplier_count"} ; $i++)
    {
	&sendEvents($consumer_proxy[$i], $consumer_proxy_model, 
	            $test_params{"datafile"});
    }

    #
    # Now we can receive the events
    #
    for($i = 0 ; $i < $test_params{"consumer_count"} ; $i++)
    {
	&receiveEvents($supplier_proxy[$i], $supplier_proxy_model, 
		       $test_params{"sleep_time"}, $test_params{"datafile"}, 
		       $i);
	
	#
	# If the output matches what we expect then the test succeeds.
	# Otherwise it fails.
	#
	if(!&verifyOutput($test_params{"datafile"}))
	{
	    $service_started = "false";
	    &shutdownService();
	    return 0;
	}
    }

    if($test_params{"shutdown"} eq "true")
    {
	$service_started = "false";
	&shutdownService();
    }
    return 1;
}

#
# This is the generic Typed Event Service test.  The method sets up the 
# service with the desired proxies, causes events to be sent and then
# received,  and finally inspects the results to determine if the test
# passed.
#
sub Run_Event_Service_Typed_Tests()
{
    if($service_started eq "false")
    {
	startEventService();
    }

    #
    # Read the data file for settings that need to be made.
    #
    readDataFileSettings();

    my $i;	
    my @consumer_proxy;
    my @supplier_proxy;
    my $consumer_proxy_model;
    my $supplier_proxy_model;
    
    for($i = 0; $i < $test_params{"supplier_count"} ; $i++)
    {
	$consumer_proxy[$i] = &obtainTypedPushConsumer($sup_admin,
				  $test_params{"reference"}); 
    }
    for($i = 0 ; $i < $test_params{"consumer_count"} ; $i++)
    {
	$supplier_proxy[$i] = &obtainTypedPushSupplier($con_admin,
				  $test_params{"reference"}); 
    }
    for($i = 0 ; $i < $test_params{"consumer_count"} ; $i++)
    {
        &makeConnectedTyped($supplier_proxy[$i], $i);
    }

    #
    # Now we can send events as described in the datafile
    #
    for($i = 0 ; $i < $test_params{"supplier_count"} ; $i++)
    {
	&sendTypedEvents($consumer_proxy[$i], $test_params{"datafile"});
    }

    #
    # Now we can receive the events
    #
    for($i = 0 ; $i < $test_params{"consumer_count"} ; $i++)
    {
	&receiveTypedEvents($supplier_proxy[$i], $test_params{"sleep_time"}, 
			      $test_params{"datafile"}, $i);
	
	#
	# If the output matches what we expect then the test succeeds.
	# Otherwise it fails.
	#
	if(!&verifyOutput($test_params{"datafile"}))
	{
	    $service_started = "false";
	    &shutdownTypedService();
	    return 0;
	}
    }

    if($test_params{"shutdown"} eq "true")
    {
	$service_started = "false";
	&shutdownTypedService();
    }
    return 1;
}

#########################################################################
#
# Public methods.
#
#########################################################################

#
# No more tests to be run, show last success message
#
sub printLastMessage()
{
    &changeTestType("Last");

    #
    # Want to shutdown the service if it is running	
    #
    if($service_started eq "true")
    {
	if($service_type eq "typed")
	{
	    &shutdownTypedService();
	}
	else
	{
	    &shutdownService();
	}
    }
} 

#
# Return the current status of the test suite.
#
sub getStatus()
{
    return $status;
}

sub SendEvents($)
{
    my $args = shift;

    $multiple = "false";
    if($service_type eq "typed")
    {  
	if($service_started eq "true")
	{
	    $service_started = "false";
	    &shutdownTypedService();
	}
    }
    $service_type = "untyped";
   
    cleanTestHash();
    $test_params{"datafile"} = $args;
  
    my $test_type = "Event Service Tests*Sending Events*$args";
    &changeTestType($test_type);

    if(Run_Event_Service_Tests() == 0)
    {
	print "Failed\n";
	&printErrorMessage();
	$status = 0;
	return; 
    }
    $status = 1;
    return;
}

sub MultipleProxies($)
{

    my $args = shift;
    $multiple = "true";
    if($service_type eq "typed")
    {  
	if($service_started eq "true")
	{
	    $service_started = "false";
	    &shutdownTypedService();
	}
    }
    $service_type = "untyped";
   
    cleanTestHash();
    $test_params{"datafile"} = $args;
  
    my $test_type = "Event Service Tests*Multiple Consumers and " .
	            "Suppliers*$args";
    &changeTestType($test_type);

    if(Run_Event_Service_Tests() == 0)
    {
	print "Failed\n";
	&printErrorMessage();
	$status = 0;
	return; 
    }
    $status = 1;
    return;
}

sub MultipleTypedProxies($)
{
    my $args = shift;

    $multiple = "true";
    if($service_type eq "untyped")
    {  
	if($service_started eq "true")
	{
	    $service_started = "false";
	    &shutdownService();
	}
    }
    $service_type = "typed";
   
    cleanTestHash();
    $test_params{"datafile"} = $args;
  
    my $test_type = "Event Service Tests*Typed Multiple Consumers and " .
	            "Suppliers*$args";
    &changeTestType($test_type);

    if(Run_Event_Service_Typed_Tests() == 0)
    {
	print "Failed\n";
	&printErrorMessage();
	$status = 0;
	return; 
    }
    $status = 1;
    return;
}

sub SendTypedEvents($)
{
    my $args = shift;

    $multiple = "false";
    if($service_type eq "untyped")
    {  
	if($service_started eq "true")
	{
	    $service_started = "false";
	    &shutdownService();
	}
    }
    $service_type = "typed";

    cleanTestHash();
    $test_params{"datafile"} = $args;
  
    my $test_type = "Event Service Tests*Sending Typed Events*$args";
    &changeTestType($test_type);

    if(Run_Event_Service_Typed_Tests() == 0)
    {
	print "Failed\n";
	&printErrorMessage();
	$status = 0;
	return; 
    }
    $status = 1;
    return;
}

