#!/usr/bin/perl

use strict;
use warnings;
use Cache::Memcached;
use Cache::Memcached::Fast;

# Constants
my $memcached_class   = 'Cache::Memcached';
my $memcached_servers = [
  '127.0.0.1:11211'
 ];
my $reconnect_on_fail = 1;
my $loops             = 10000;
my $op_attempts       = 10;
my $die_on_error      = 0;

# Globals
my $memcached         = undef;
my $data              = undef;

# Connect to Memcached.
memcached_connect();

foreach my $loop (1..$loops) {

  my $attempt_add = 1;
  my $attempt_get = 1;
  my $attempt_del = 1;

  my $key         = 'test_key_' . $$;
  my $value       = 'test_value_' . $$ . '_' . $loop;

  # Add
  while (not $memcached->add($key, $value, 1)) {
    if ($attempt_add++ == $op_attempts) {
      handle_error ('Failed to add data on loop ' . $loop . ' in ' . $op_attempts . ' attempts');
    }
    memcached_connect()
      if ($reconnect_on_fail);
  }
  if ($attempt_add > 1) {
    warn ('Required ' . $attempt_add . ' attempts to add data on loop ' . $loop);
  }

  # Get
  while (not defined($data = $memcached->get($key))) {
    if ($attempt_get++ == $op_attempts) {
      handle_error ('Failed to get data on loop ' . $loop . ' in ' . $op_attempts . ' attempts');
    }
    memcached_connect()
      if ($reconnect_on_fail);
  }
  if ($attempt_get > 1) {
    warn ('Required ' . $attempt_get . ' attempts to get data on loop ' . $loop);
  }
  if ($data ne $value) {
    handle_error ('Data invalid on loop ' . $loop);
  }

  # Delete
  while (not $memcached->delete($key)) {
    if ($attempt_del++ == $op_attempts) {
      handle_error ('Failed to delete data on loop ' . $loop . ' in ' . $op_attempts . ' attempts');
    }
    memcached_connect()
      if ($reconnect_on_fail);
  }
  if ($attempt_del > 1) {
    warn ('Required ' . $attempt_del . ' attempts to delete data on loop ' . $loop);
  }

}

print 'Test completed' . "\n";


sub memcached_connect {

  $memcached = undef;
  $memcached = $memcached_class->new({
    servers => $memcached_servers
  });

  if (not (defined($memcached) && $memcached->set('connect_test_key_' . $$, 'test_' . $$) && $memcached->delete('connect_test_key_' . $$))) {
    die ('Failed to connect to Memcached and test successfully');
  }

}

sub handle_error {

  my $errstr = shift || die('Required argument not supplied');
  if ($die_on_error) {
    die($errstr);
  } else {
    warn($errstr);
  }

}
