Skip to content

Commit 4bdc6a7

Browse files
author
alessandro
committed
Fixes #19 and improves coverage
1 parent 8d369d7 commit 4bdc6a7

9 files changed

+217
-11
lines changed

Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ FROM php:7.4-cli
22
ARG DEBIAN_FRONTEND=noninteractive
33
WORKDIR /app
44

5+
ENV XDEBUG_MODE=coverage
6+
57
RUN apt-get -y upgrade && \
68
apt-get - dist-upgrade && \
79
apt-get update && \

src/DateTimeUtils.php

+2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ public static function dateTimeFromTimestampWithMs(int $timestamp) : DateTimeInt
1313
{
1414
$dateTime = DateTimeImmutable::createFromFormat('U.u', sprintf('%.03f', $timestamp / 1000));
1515
if ($dateTime === false) {
16+
// @codeCoverageIgnoreStart
1617
throw new TimestampParsingException(sprintf("Unable to parse timestamp: %d", $timestamp));
18+
// @codeCoverageIgnoreEnd
1719
}
1820
return $dateTime;
1921
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Palicao\PhpRedisTimeSeries\Exception;
5+
6+
use InvalidArgumentException;
7+
8+
class InvalidDuplicatePolicyException extends InvalidArgumentException
9+
{
10+
}

src/TimeSeries.php

+80-4
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,29 @@
55

66
use DateTimeInterface;
77
use Palicao\PhpRedisTimeSeries\Client\RedisClientInterface;
8+
use Palicao\PhpRedisTimeSeries\Exception\InvalidDuplicatePolicyException;
89
use Palicao\PhpRedisTimeSeries\Exception\RedisClientException;
910
use RedisException;
1011

1112
final class TimeSeries
1213
{
14+
public const DUPLICATE_POLICY_BLOCK = 'BLOCK';
15+
public const DUPLICATE_POLICY_FIRST = 'FIRST';
16+
public const DUPLICATE_POLICY_LAST = 'LAST';
17+
public const DUPLICATE_POLICY_MIN = 'MIN';
18+
public const DUPLICATE_POLICY_MAX = 'MAX';
19+
public const DUPLICATE_POLICY_SUM = 'SUM';
20+
21+
private const DUPLICATE_POLICIES = [
22+
self::DUPLICATE_POLICY_BLOCK,
23+
self::DUPLICATE_POLICY_FIRST,
24+
self::DUPLICATE_POLICY_LAST,
25+
self::DUPLICATE_POLICY_MIN,
26+
self::DUPLICATE_POLICY_MAX,
27+
self::DUPLICATE_POLICY_SUM
28+
];
29+
30+
1331
/** @var RedisClientInterface */
1432
private $redis;
1533

@@ -27,15 +45,44 @@ public function __construct(RedisClientInterface $redis)
2745
* @param string $key
2846
* @param int|null $retentionMs
2947
* @param Label[] $labels
48+
* @param bool $uncompressed
49+
* @param int|null $chunkSize
50+
* @param string|null $duplicatePolicy
3051
* @return void
31-
* @throws RedisClientException
3252
* @throws RedisException
3353
*/
34-
public function create(string $key, ?int $retentionMs = null, array $labels = []): void
54+
public function create(
55+
string $key,
56+
?int $retentionMs = null,
57+
array $labels = [],
58+
bool $uncompressed = false,
59+
?int $chunkSize = null,
60+
?string $duplicatePolicy = null
61+
): void
3562
{
63+
$params = [];
64+
65+
if ($uncompressed === true) {
66+
$params[] = 'UNCOMPRESSED';
67+
}
68+
69+
if ($chunkSize !== null) {
70+
$params[] = 'CHUNK_SIZE';
71+
$params[] = (string) $chunkSize;
72+
}
73+
74+
if ($duplicatePolicy !== null) {
75+
if (!in_array($duplicatePolicy, self::DUPLICATE_POLICIES)) {
76+
throw new InvalidDuplicatePolicyException(sprintf("Duplicate policy %s is invalid", $duplicatePolicy));
77+
}
78+
$params[] = 'DUPLICATE_POLICY';
79+
$params[] = $duplicatePolicy;
80+
}
81+
3682
$this->redis->executeCommand(array_merge(
3783
['TS.CREATE', $key],
3884
$this->getRetentionParams($retentionMs),
85+
$params,
3986
$this->getLabelsParams(...$labels)
4087
));
4188
}
@@ -65,15 +112,44 @@ public function alter(string $key, ?int $retentionMs = null, array $labels = [])
65112
* @param Sample $sample
66113
* @param int|null $retentionMs
67114
* @param Label[] $labels
115+
* @param bool $uncompressed
116+
* @param int|null $chunkSize
117+
* @param string|null $duplicatePolicy
68118
* @return Sample
69-
* @throws RedisClientException
70119
* @throws RedisException
71120
*/
72-
public function add(Sample $sample, ?int $retentionMs = null, array $labels = []): Sample
121+
public function add(
122+
Sample $sample,
123+
?int $retentionMs = null,
124+
array $labels = [],
125+
bool $uncompressed = false,
126+
?int $chunkSize = null,
127+
?string $duplicatePolicy = null
128+
): Sample
73129
{
130+
$params = [];
131+
132+
if ($uncompressed === true) {
133+
$params[] = 'UNCOMPRESSED';
134+
}
135+
136+
if ($chunkSize !== null) {
137+
$params[] = 'CHUNK_SIZE';
138+
$params[] = (string) $chunkSize;
139+
}
140+
141+
if ($duplicatePolicy !== null) {
142+
if (!in_array($duplicatePolicy, self::DUPLICATE_POLICIES)) {
143+
throw new InvalidDuplicatePolicyException(sprintf("Duplicate policy %s is invalid", $duplicatePolicy));
144+
}
145+
$params[] = 'ON_DUPLICATE';
146+
$params[] = $duplicatePolicy;
147+
}
148+
74149
$timestamp = (int)$this->redis->executeCommand(array_merge(
75150
['TS.ADD'],
76151
$sample->toRedisParams(),
152+
$params,
77153
$this->getRetentionParams($retentionMs),
78154
$this->getLabelsParams(...$labels)
79155
));

tests/Integration/IntegrationTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@ public function testAddAndRetrieveAsRange(): void
6969
self::assertEquals($expectedRange, $range);
7070
}
7171

72+
public function testAddAndRetrieveWithDuplicatePolicySum(): void
73+
{
74+
$dt = new DateTimeImmutable('2019-11-06 20:34:17.000');
75+
$this->sut->create(
76+
'temperature:3:11',
77+
6000,
78+
[new Label('sensor_id', '2'), new Label('area_id', '32')],
79+
false,
80+
null,
81+
TimeSeries::DUPLICATE_POLICY_SUM
82+
);
83+
84+
$this->sut->add(new Sample('temperature:3:11', 10.0, $dt));
85+
$this->sut->add(new Sample('temperature:3:11', 20.0, $dt));
86+
87+
$result = $this->sut->range('temperature:3:11', $dt, $dt);
88+
89+
self::assertEquals([new Sample('temperature:3:11', 30.0, $dt)], $result);
90+
}
91+
7292
public function testAddAndRetrieveAsMultirangeWithLabelsReverse(): void
7393
{
7494
$this->sut->create(

tests/Unit/DateTimeUtilsTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ public function testTimestampWithMsFromDateTimeConvertsCorrectly() : void
2323
$expected = 1548149181000;
2424
self::assertEquals($expected, $result);
2525
}
26-
}
26+
}

tests/Unit/RedisClientTest.php

+41
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,45 @@ public function testFailureToConnectThrowsException(): void
7272
$sut = new RedisClient($redisMock, $connectionParams);
7373
$sut->executeCommand(['MY', 'command']);
7474
}
75+
76+
public function testConnectionWithPassword(): void
77+
{
78+
$redisMock = $this->createMock(Redis::class);
79+
$redisMock->expects(self::once())->method('isConnected')->willReturn(false);
80+
$redisMock->expects(self::once())->method('connect')->with(
81+
'127.0.0.1',
82+
6379,
83+
0,
84+
0,
85+
0.0
86+
);
87+
$redisMock->expects(self::once())
88+
->method('auth')
89+
->with('pass');
90+
$connectionParams = new RedisConnectionParams('127.0.0.1', 6379, null, 'pass');
91+
$sut = new RedisClient($redisMock, $connectionParams);
92+
$sut->executeCommand(['MY', 'command']);
93+
}
94+
95+
public function testConnectionWithUseranameAndPassword(): void
96+
{
97+
$redisMock = $this->createMock(Redis::class);
98+
$redisMock->expects(self::once())->method('isConnected')->willReturn(false);
99+
$redisMock->expects(self::once())->method('connect')->with(
100+
'127.0.0.1',
101+
6379,
102+
0,
103+
0,
104+
0.0
105+
);
106+
$redisMock->expects(self::exactly(2))
107+
->method('rawCommand')
108+
->withConsecutive(
109+
['AUTH', 'username', 'pass'],
110+
['MY', 'command']
111+
);
112+
$connectionParams = new RedisConnectionParams('127.0.0.1', 6379, 'username', 'pass');
113+
$sut = new RedisClient($redisMock, $connectionParams);
114+
$sut->executeCommand(['MY', 'command']);
115+
}
75116
}

tests/Unit/SampleWithLabelsTest.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Palicao\PhpRedisTimeSeries\Tests\Unit;
5+
6+
use DateTimeImmutable;
7+
use Palicao\PhpRedisTimeSeries\Label;
8+
use Palicao\PhpRedisTimeSeries\SampleWithLabels;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class SampleWithLabelsTest extends TestCase
12+
{
13+
public function testLabelsCanBeRetrieved(): void
14+
{
15+
$sample = new SampleWithLabels(
16+
'a',
17+
1,
18+
new DateTimeImmutable('2017-01-01T20.01.06.234'),
19+
[new Label('a','10'), new Label('b', '20')]
20+
);
21+
22+
self::assertEquals([new Label('a','10'), new Label('b', '20')], $sample->getLabels());
23+
}
24+
}

tests/Unit/TimeSeriesTest.php

+37-6
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function setUp(): void
3737
/**
3838
* @dataProvider createDataProvider
3939
*/
40-
public function testCreate($params, $expectedParams): void
40+
public function testCreate(array $params, array $expectedParams): void
4141
{
4242
$this->redisClientMock
4343
->expects(self::once())
@@ -49,7 +49,40 @@ public function testCreate($params, $expectedParams): void
4949
public function createDataProvider(): array
5050
{
5151
return [
52-
'full' => [['a', 10, [new Label('l1', 'v1'), new Label('l2', 'v2')]], ['TS.CREATE', 'a', 'RETENTION', 10, 'LABELS', 'l1', 'v1', 'l2', 'v2']],
52+
'full' => [
53+
[
54+
'a',
55+
10,
56+
[new Label('l1', 'v1'), new Label('l2', 'v2')],
57+
true,
58+
10000,
59+
TimeSeries::DUPLICATE_POLICY_SUM
60+
],
61+
[
62+
'TS.CREATE',
63+
'a',
64+
'RETENTION',
65+
10,
66+
'UNCOMPRESSED',
67+
'CHUNK_SIZE',
68+
'10000',
69+
'DUPLICATE_POLICY',
70+
'SUM',
71+
'LABELS',
72+
'l1',
73+
'v1',
74+
'l2',
75+
'v2'
76+
],
77+
],
78+
'most common' => [
79+
[
80+
'a',
81+
10,
82+
[new Label('l1', 'v1'), new Label('l2', 'v2')]
83+
],
84+
['TS.CREATE', 'a', 'RETENTION', 10, 'LABELS', 'l1', 'v1', 'l2', 'v2']
85+
],
5386
'no labels' => [['a', 10], ['TS.CREATE', 'a', 'RETENTION', 10]],
5487
'minimal' => [['a'], ['TS.CREATE', 'a']]
5588
];
@@ -71,7 +104,7 @@ public function testAlter(): void
71104
/**
72105
* @dataProvider addDataProvider
73106
*/
74-
public function testAdd($params, $expectedParams): void
107+
public function testAdd(array $params, array $expectedParams): void
75108
{
76109
$this->redisClientMock
77110
->expects(self::once())
@@ -279,8 +312,7 @@ public function testInfo(): void
279312

280313
self::assertEquals($expected, $returned);
281314
}
282-
283-
315+
284316
public function testGetLastSample(): void
285317
{
286318
$this->redisClientMock
@@ -293,7 +325,6 @@ public function testGetLastSample(): void
293325
self::assertEquals($expected, $response);
294326
}
295327

296-
297328
public function testGetLastSamples(): void
298329
{
299330
$this->redisClientMock

0 commit comments

Comments
 (0)