Completed
Push — master ( cc41b9...0dfb70 )
by Jorge
01:59
created

TimeBackoffTest::it_tracks_attempts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 0
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace JVelasco\CircuitBreaker\AvailabilityStrategy;
4
5
use PHPUnit\Framework\TestCase;
6
use Prophecy\Argument;
7
use Prophecy\Prophecy\ObjectProphecy;
8
9
final class TimeBackoffTest extends TestCase
10
{
11
    const SERVICE_NAME = 'service name';
12
    const LAST_ATTEMPT_KEY = "last_attempt";
13
    const MAX_FAILURES = 1;
14
    const BASE_WAIT_TIME = 200; // 200 ms
15
    const MAX_WAIT_TIME = 30000; // 30 secs
16
17
    /** @var InMemoryStorage */
18
    private $storage;
19
    /** @var TimeBackoff */
20
    private $sut;
21
    /** @var BackoffStrategy|ObjectProphecy */
22
    private $backoffStrategy;
23
24
    protected function setUp()
25
    {
26
        $this->storage = new InMemoryStorage();
27
        $this->backoffStrategy = $this->prophesize(BackoffStrategy::class);
28
        $this->backoffStrategy->id()->willReturn("test_backoff");
29
        $this->sut = new TimeBackoff(
30
            $this->storage,
31
            $this->backoffStrategy->reveal(),
32
            self::MAX_FAILURES,
33
            self::BASE_WAIT_TIME,
34
            self::MAX_WAIT_TIME
35
        );
36
    }
37
38
    /** @test */
39
    public function it_report_as_available_when_failures_is_under_threshold()
40
    {
41
        $this->failuresAreUnderThreshold();
42
        $this->assertTrue($this->sut->isAvailable(self::SERVICE_NAME));
43
    }
44
45
    /** @test */
46
    public function it_reports_as_non_available_between_attempts()
47
    {
48
        $this->storage->saveStrategyData(
49
            $this->sut,
50
            self::SERVICE_NAME,
51
            self::LAST_ATTEMPT_KEY,
52
            floor(microtime(true) * 1000)
53
        );
54
        $this->setFailuresToMaxAllowed($this->storage);
0 ignored issues
show
Unused Code introduced by
The call to JVelasco\CircuitBreaker\...tFailuresToMaxAllowed() has too many arguments starting with $this->storage. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

54
        $this->/** @scrutinizer ignore-call */ 
55
               setFailuresToMaxAllowed($this->storage);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
55
        $this->backoffStrategy->waitTime(Argument::any(), self::BASE_WAIT_TIME)
0 ignored issues
show
Bug introduced by
Prophecy\Argument::any() of type Prophecy\Argument\Token\AnyValueToken is incompatible with the type integer expected by parameter $attempt of JVelasco\CircuitBreaker\...offStrategy::waitTime(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

55
        $this->backoffStrategy->waitTime(/** @scrutinizer ignore-type */ Argument::any(), self::BASE_WAIT_TIME)
Loading history...
56
            ->willReturn(100);
57
        $this->assertFalse($this->sut->isAvailable(self::SERVICE_NAME));
58
    }
59
60
    /** @test */
61
    public function it_closes_the_circuit_after_timeout()
62
    {
63
        $this->setFailuresToMaxAllowed();
64
        $oneSecAndOneMillisecond = floor((microtime(true) * 1000)) - self::BASE_WAIT_TIME - 1;
65
        $this->storage->saveStrategyData(
66
            $this->sut,
67
            self::SERVICE_NAME,
68
            self::LAST_ATTEMPT_KEY,
69
            (string) $oneSecAndOneMillisecond
70
        );
71
72
        $this->backoffStrategy->waitTime(Argument::any(), self::BASE_WAIT_TIME)
0 ignored issues
show
Bug introduced by
Prophecy\Argument::any() of type Prophecy\Argument\Token\AnyValueToken is incompatible with the type integer expected by parameter $attempt of JVelasco\CircuitBreaker\...offStrategy::waitTime(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

72
        $this->backoffStrategy->waitTime(/** @scrutinizer ignore-type */ Argument::any(), self::BASE_WAIT_TIME)
Loading history...
73
            ->willReturn(self::BASE_WAIT_TIME);
74
75
        $this->assertTrue($this->sut->isAvailable(self::SERVICE_NAME));
76
        $this->assertEquals(0, $this->storage->numberOfFailures(self::SERVICE_NAME));
77
    }
78
79
    /** @test */
80
    public function it_reports_as_available_on_storage_failures()
81
    {
82
        $this->storage->throwExceptionInNumberOfFailures();
83
        $this->assertTrue($this->sut->isAvailable(self::SERVICE_NAME));
84
    }
85
86
87
    /** @test */
88
    public function it_tracks_attempts()
89
    {
90
        $this->setFailuresToMaxAllowed();
91
        $this->waitTimeHaveOccurred();
92
93
        $this->sut->isAvailable(self::SERVICE_NAME);
94
        $this->assertEquals(1, $this->storage->getStrategyData($this->sut, self::SERVICE_NAME, "attempts"));
95
96
        $this->setFailuresToMaxAllowed();
97
        $this->waitTimeHaveOccurred();
98
99
        $this->sut->isAvailable(self::SERVICE_NAME);
100
        $this->assertEquals(2, $this->storage->getStrategyData($this->sut, self::SERVICE_NAME, "attempts"));
101
    }
102
103
    private function setFailuresToMaxAllowed()
104
    {
105
        $this->storage->setNumberOfFailures(
106
            self::SERVICE_NAME,
107
            self::MAX_FAILURES
108
        );
109
    }
110
111
    private function failuresAreUnderThreshold()
112
    {
113
        $this->storage->setNumberOfFailures(
114
            self::SERVICE_NAME,
115
            self::MAX_FAILURES - 1
116
        );
117
    }
118
119
    private function waitTimeHaveOccurred()
120
    {
121
        $this->backoffStrategy->waitTime(Argument::any(), Argument::any())
0 ignored issues
show
Bug introduced by
Prophecy\Argument::any() of type Prophecy\Argument\Token\AnyValueToken is incompatible with the type integer expected by parameter $baseTime of JVelasco\CircuitBreaker\...offStrategy::waitTime(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
        $this->backoffStrategy->waitTime(Argument::any(), /** @scrutinizer ignore-type */ Argument::any())
Loading history...
Bug introduced by
Prophecy\Argument::any() of type Prophecy\Argument\Token\AnyValueToken is incompatible with the type integer expected by parameter $attempt of JVelasco\CircuitBreaker\...offStrategy::waitTime(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
        $this->backoffStrategy->waitTime(/** @scrutinizer ignore-type */ Argument::any(), Argument::any())
Loading history...
122
            ->willReturn(0);
123
        $this->storage->saveStrategyData(
124
            $this->sut,
125
            self::SERVICE_NAME,
126
            self::LAST_ATTEMPT_KEY,
127
            floor(microtime(true) * 1000) - 1);
128
    }
129
}
130