The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w
#
# test the command queue class

use strict;
use Test::More qw(no_plan);

use SRS::EPP::Command;
use SRS::EPP::Response;
BEGIN {
	use_ok("SRS::EPP::Session::CmdQ");
}

# the command queue - queues SRS::EPP::Command objects, and their
# SRS::EPP::Response partners

{
	package Mock::Anything;
	sub isa { 1 }  # trump most type constraints :->
	sub new {
		my $class = shift;
		bless { @_ }, $class;
	}
	our $AUTOLOAD;
	sub AUTOLOAD {
		my $self = shift;
		$AUTOLOAD=~/.*::(.*)/;
		if ( @_ ) {
			$self->{$1} = shift;
		}
		else {
			$self->{$1};
		}
	}
}

# here's the abstract model: a *single* EPP command,
my $command = SRS::EPP::Command->new(
	message => Mock::Anything->new(
		name => "login",
		message => Mock::Anything->new(),
	       ),
       );

# is answered by a *single* EPP response
my $response = SRS::EPP::Response->new(
	code => 1000,
	message => Mock::Anything->new(
		response => 1,
		name => "greeting",
	       ),
       );

# Ad infinitum
my @commands = qw(check1 info create1 transfer1 delete1 transfer2
		  delete2 create2 check2);

my @command_rq = map {
	SRS::EPP::Command->new(
		message => Mock::Anything->new(
			name => $_,
			message => Mock::Anything->new(),
		       ),
	       );
} @commands;

my @command_rs = map {
	SRS::EPP::Response->new(
		code => 1000,
		message => Mock::Anything->new(
			name => $_,
			request => 1,
			message => Mock::Anything->new(),
		       ),
	       );
} @commands;

# ok.  we've got some data, construct our test object.
my $cq = SRS::EPP::Session::CmdQ->new();
isa_ok($cq, "SRS::EPP::Session::CmdQ",
       "SRS::EPP::Session::CmdQ->new()");

# some basic tests
is($cq->commands_queued, 0, "->commands_queued (null)");
ok(!$cq->response_ready, "->response_ready (null)");

# data in: enqueue the command and SRS Request objects
$cq->queue_command( $command );

is($cq->commands_queued, 1, "->commands_queued (added rq)");

# state change: grab requests to begin processing
my $rq = $cq->next_command;

is($cq->commands_queued, 1, "->commands_queued (sent rq)");
ok(!$cq->response_ready, "->response_ready (sent rq)");
ok(!$cq->next_command, "->next_command (empty q)");

# state change: back-end returns with response.
$cq->add_command_response($response, $command);

is($cq->commands_queued, 1, "->commands_queued (got rs)");
ok($cq->response_ready, "->response_ready (got rs)");

# dequeue
my $rs = $cq->dequeue_response;
is($rs, $response, "->dequeue_response (got rs)");
is($cq->commands_queued, 0, "->commands_queued (dequeued rs)");
ok(!$cq->response_ready, "->response_ready (dequeued rs)");

# now throw the rest at it!
my @rq_q = @command_rq;
my @rs_q = @command_rs;
srand 1042;
my @output_q;
while ( @rq_q or @rs_q ) {
	if ( @rq_q and rand(1) < 0.5 ) {
		$cq->queue_command(shift @rq_q);
	}
	if ( @rs_q > @rq_q and rand(1) < 0.4 ) {
		my $rs = shift @rs_q;
		$cq->add_command_response($rs);
	}
	if ( rand(1) < 0.6 and $cq->response_ready ) {
		my @output = $cq->dequeue_response;
		if ( @output ) {
			push @output_q, \@output;
		}
	}
}
push @output_q, [ $cq->dequeue_response ]
	while $cq->response_ready;

ok(!(grep{
	my $rv = (
	!$output_q[$_]
		or
	!$output_q[$_][0]->message->request
		or
	$output_q[$_][1]->message->request
		or
	$output_q[$_][0] != $command_rs[$_]
		or
	$output_q[$_][1] != $command_rq[$_]
       );
	#$DB::single = 1 if $rv;
	$rv;
} 0..$#command_rq),
   "got results back in correct order") or do {
	   require Data::Dumper;
	   diag("results: ".Data::Dumper::Dumper(\@output_q));
   };

# Copyright (C) 2009  NZ Registry Services
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the Artistic License 2.0 or later.
#
# 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
# Artistic License 2.0 for more details.
#
# You should have received a copy of the Artistic License the file
# COPYING.txt.  If not, see
# <http://www.perlfoundation.org/artistic_license_2_0>