#!/usr/bin/perl use strict; use Test::More 'no_plan'; use lib "$ENV{LJHOME}/cgi-bin"; require 'ljlib.pl'; no warnings 'redefine'; use LJ::Test qw (temp_user memcache_stress); use Class::Autouse qw ( LJ::SMS::Message ); # fork child processes to test races? my $dofork = 0; # make time() be overridable in the future at runtime, rather than be an opcode: BEGIN { *CORE::GLOBAL::time = sub { time() }; } # kill children on exit my %children; # pid -> 1 my $parent = $$; END { if ($$ == $parent) { my @pids = keys %children; kill 9, @pids if @pids; } } # use local time instead of db time, so it can be overridden by the # locally defined CORE::time() $LJ::_T_SMS_QUOTA_TIME = 1; # don't actually send messages $LJ::_T_SMS_SEND = sub { }; my ($paidcapbit) = grep { $LJ::CAP{$_}{_key} eq 'paid' } keys %LJ::CAP; # TODO: simulate races sub run_tests { my $u = temp_user(); my $sms_num; for (1..100) { $sms_num = '+1'; $sms_num .= int(rand(10)) foreach (1..10); next if LJ::SMS->num_to_uid($sms_num, verified_only => 0); $u->set_sms_number($sms_num, verified => 'Y'); last; } # test message my $msg = LJ::SMS::Message->new( owner => $u, type => 'outgoing', body_text => 'test', to => $u, ); # test that free user gets no quota and has no messages remaining { ok(! $u->sms_quota_remaining, "No messages remaining for free user"); # give the user some free messages $u->add_sms_quota(5, 'free'); check_message_counts($u, 5, 0, 0, "Add 5 free messages"); } # add user to paid class, test they got correct quota { $LJ::CAP{$paidcapbit}->{sms_message_quota} = 10; # paid $u->add_to_class('paid'); # make sure we got the right counts check_message_counts($u, 5, 0, 10, "Got correct cap quota"); } # add some paid messages { $u->add_sms_quota(1, 'paid'); # make sure we got the right counts check_message_counts($u, 5, 1, 10, "Added paid message"); # send a message, make sure it decreases from paid first $u->send_sms($msg); # make sure we got the right counts check_message_counts($u, 5, 0, 10, "Sending message decreased paid count"); } # test quota decreasing { # send another, make sure now dipping into free count $u->send_sms($msg); check_message_counts($u, 4, 0, 10, "Sending message decreased free count"); # send a bunch more, make sure we decrease ok $u->send_sms($msg) for 1..4; check_message_counts($u, 0, 0, 10, "Decreased when sending messages OK"); # send one, make sure decreases from cap quota ok $u->send_sms($msg); check_message_counts($u, 0, 0, 9, "Decrease from cap quota"); # send a few more to use up the cap quota $u->send_sms($msg) for 1..5; check_message_counts($u, 0, 0, 4, "Decreased from cap quota"); } # warp into the future! { my $future = 60 * 60 * 24 * 7 * 5; # 5 weeks local *CORE::GLOBAL::time = sub { CORE::time() + $future }; # see if quota reset check_message_counts($u, 0, 0, 10, "Got quota refil a month later"); # send some messages to use up cap quota $u->send_sms($msg) for 1..5; check_message_counts($u, 0, 0, 5, "Decreased cap quota"); # go into the future some more, make sure quota refilled again $future *= 2; # see if quota reset check_message_counts($u, 0, 0, 10, "Got quota refil a month later"); } } sub check_message_counts { my ($u, $free, $paid, $quota, $msg) = @_; is($u->sms_quota_remaining, $free + $paid + $quota, "$msg:\tTotal messages remaining"); is($u->sms_quota_remaining('free'), $free, "$msg:\tFree messages remaining"); is($u->sms_quota_remaining('paid'), $paid, "$msg:\tPaid messages remaining"); is($u->sms_quota_remaining('cap'), $quota, "$msg:\tCap messages remaining"); } # simluate races! if ($dofork) { for (1..3) { if (my $childpid = fork()) { $children{$childpid} = 1; } } } memcache_stress ( sub { run_tests(); });