Completed
Push — master ( 3d8b1a...c926fb )
by Dmitry
03:03
created

TarantoolTest::testSelectUsageWithCompositeKeys()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 49
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 49
rs 9.2258
c 0
b 0
f 0
cc 3
eloc 33
nc 4
nop 0
1
<?php
2
3
namespace Test;
4
5
use Basis\Filesystem;
6
use Basis\Job;
7
use Basis\Procedure\Select;
8
use Basis\Test;
9
use Exception;
10
use Procedure\Greet;
11
use ReflectionClass;
12
use Repository\Note;
13
use Tarantool\Mapper\Bootstrap;
14
use Tarantool\Mapper\Mapper;
15
use Tarantool\Mapper\Pool;
16
17
class TarantoolTest extends Test
18
{
19
    public $data = [
20
        'guard.session' => [],
21
        'web.services' => [
22
            ['id' => 1, 'name' => 'tester'],
23
            ['id' => 2, 'name' => 'basis'],
24
            ['id' => 3, 'name' => 'web'],
25
        ],
26
        'tester.data' => [
27
            ['id' => 3, 'value' => 'test'],
28
            ['id' => 4, 'value' => 'test'],
29
        ],
30
    ];
31
32
    public $mocks = [
33
        ['web.services', [], ['services' => ['web', 'tester', 'basis']]]
34
    ];
35
36
    public function testPool()
37
    {
38
        $web = $this->get(Pool::class)->get('web');
39
        $this->assertCount(3, $web->find('services'));
40
        $this->assertCount(1, $web->find('services', ['name' => 'web']));
41
42
        $tester = $this->get(Pool::class)->get('tester');
43
        $this->assertCount(0, $tester->find('data', ['id' => 2]));
44
        $this->assertCount(1, $tester->find('data', ['id' => 3]));
45
        $this->assertCount(2, $tester->find('data', ['value' => 'test']));
46
47
        $this->data['web.services'][] = ['id' => 4, 'name' => 'guard'];
48
        $this->assertCount(4, $web->find('services'));
49
50
        $this->assertSame($tester->findOne('data', ['value' => 'test'])->id, 3);
51
        $this->assertSame($tester->findOrFail('data', ['value' => 'test'])->id, 3);
52
        $this->assertNull($tester->findOne('data', ['id' => 1]));
53
54
        $this->expectException(Exception::class);
55
        $tester->findOrFail('data', ['id' => 1]);
56
    }
57
58
    public function tearDown()
59
    {
60
        $fs = $this->app->get(Filesystem::class);
61
        $classes = $fs->listClasses('Migration');
62
63
        $dirs = [];
64
        foreach ($classes as $class) {
65
            $filename = $fs->getPath('php/'.str_replace('\\', '/', $class).'.php');
66
            unlink($filename);
67
            $dirs[dirname($filename)] = true;
68
        }
69
        foreach ($dirs as $dir => $_) {
70
            rmdir($dir);
71
        }
72
73
        parent::tearDown();
74
    }
75
76
    public function testProcedureRegistration()
77
    {
78
        $this->assertSame($this->app->get(Greet::class)('Dmitry'), 'Hello, Dmitry!');
79
    }
80
81
    public function testMigrationOrder()
82
    {
83
        $migration = $this->app->dispatch('generate.migration', [
84
            'name' => 'b',
85
        ]);
86
        $contents = file_get_contents($migration->filename);
87
        $contents = str_replace('throw', '//throw', $contents);
88
        file_put_contents($migration->filename, $contents);
89
90
        sleep(1);
91
92
        $migration = $this->app->dispatch('generate.migration', [
93
            'name' => 'a',
94
        ]);
95
96
        $contents = file_get_contents($migration->filename);
97
        $contents = str_replace('throw', '//throw', $contents);
98
        file_put_contents($migration->filename, $contents);
99
100
        $this->app->dispatch('tarantool.migrate');
101
102
        $bootstrap = $this->app->get(Bootstrap::class);
103
104
        $reflection = new ReflectionClass(Bootstrap::class);
105
        $property = $reflection->getProperty('migrations');
106
        $property->setAccessible(true);
107
108
        $migrations = $property->getValue($bootstrap);
109
110
        $this->assertCount(2, $migrations);
111
112
        $order = [];
113
        foreach ($migrations as $migration) {
114
            $order[] = substr($migration, -1);
115
        }
116
        $this->assertSame(['B', 'A'], $order);
117
    }
118
119
    public function testMigrationGenerator()
120
    {
121
        $fs = $this->app->get(Filesystem::class);
122
123
        $classes = $fs->listClasses('Migration');
124
        $this->assertCount(0, $classes);
125
126
        $this->app->dispatch('generate.migration', [
127
            'name' => 'my migration created at ' . time(),
128
        ]);
129
130
        $classes = $fs->listClasses('Migration');
131
        $this->assertCount(1, $classes);
132
    }
133
134
    public function testEntity()
135
    {
136
        $mapper = $this->app->get(Mapper::class);
137
        $mapper->getRepository('note')->truncate();
138
        $note = $mapper->getRepository('note')->create('zzz');
139
        $this->assertSame($note->message, 'zzz');
140
141
        $note->message = 'test';
142
        $note->save();
143
144
        $this->assertNotNull($note->id);
145
        $this->assertSame($note->message, 'test');
146
147
        $this->assertSame($note->app, $this->app);
148
149
        ob_start();
150
        var_dump($note);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($note); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
151
        $contents = ob_get_clean();
152
153
        $this->assertNotContains("app", $contents);
154
    }
155
156
    public function testRepositoryRegistration()
157
    {
158
        $repository = $this->app->get(Note::class);
159
        $this->assertSame($this->app->get(Mapper::class), $repository->getMapper());
160
    }
161
162
    public function testJobShortcuts()
163
    {
164
        $job = new class($this->app) extends Job {
165
            public function run(TarantoolTest $test)
166
            {
167
                // dispatch shortcut
168
                $result = $this->dispatch('test.hello');
169
                $test->assertSame($result->message, 'hello world!');
170
171
                // get instance shortcut
172
                $mapper = $this->get(Mapper::class);
173
                $mapper->getRepository('note')->truncate();
174
175
                // find shortcut
176
                $test->assertCount(0, $this->find('note'));
177
                $note = $this->create('note', ['message' => 'hello world']);
178
                $test->assertCount(1, $this->find('note'));
179
                // find one shortcut
180
                $test->assertNotNull($this->findOne('note', ['id' => $note->id]));
0 ignored issues
show
Bug introduced by
The property id does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
181
                $test->assertSame([$note], $this->find('note'));
182
183
                // find or create shortcut
184
                $testing = $this->findOrCreate('note', ['id' => $note->id]);
185
                $test->assertSame($note, $testing);
186
187
                $testing = $this->findOrCreate('note', ['id' => $note->id+1]);
188
                $test->assertCount(2, $this->find('note'));
189
190
                // find or fail shortcut
191
                $this->findOrFail('note', $testing->id);
192
193
                // remove shortcut
194
                $this->remove('note', ['id' => $testing->id]);
195
196
                $test->assertNull($this->findOne('note', ['id' => $testing->id]));
197
198
                $test->expectException(Exception::class);
199
                $this->findOrFail('note', $testing->id);
200
            }
201
        };
202
203
        $job->run($this);
204
205
        ob_start();
206
        var_dump($job);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($job); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
207
        $contents = ob_get_clean();
208
209
        $this->assertNotContains("app", $contents);
210
    }
211
212
    public function testPoolConfiguration()
213
    {
214
        $pool = $this->get(Pool::class);
215
216
        $this->mock('web.services')->willReturn(['services' => ['guard']]);
217
        $this->assertSame('guard', $pool->get('guard')->serviceName);
218
219
        $this->expectException(Exception::class);
220
        $pool->get('gateway');
221
    }
222
223
    public function testSelectRegistration()
224
    {
225
        $this->dispatch('tarantool.clear');
226
        $this->dispatch('module.bootstrap');
227
228
        // procedure was registered
229
        $mapper = $this->getMapper();
230
        $result = $mapper->getClient()->evaluate("return basis_select(nil, nil, nil)")->getData();
231
        $this->assertNull($result[0]);
232
    }
233
234
    public function testSelectUsage()
235
    {
236
        $this->dispatch('tarantool.clear');
237
        $this->dispatch('module.bootstrap');
238
239
        $mapper = $this->getMapper();
240
        $mapper->getSchema()
241
            ->createSpace('tester', [
242
                'id' => 'unsigned',
243
                'name' => 'string',
244
            ])
245
            ->createIndex('id')
246
            ->createIndex('name');
247
248
        $nekufa = $mapper->create('tester', ['id' => 1, 'name' => 'nekufa']);
249
        $bazyaba = $mapper->create('tester', ['id' => 2, 'name' => 'bazyaba']);
250
251
        $result = $this->get(Select::class)
252
            ('tester', 'id', [$nekufa->id]);
253
254
        $this->assertCount(1, $result);
255
256
        $result = $this->get(Select::class)
257
            ('tester', 'id', [$nekufa->id, $nekufa->id]);
258
259
        $this->assertCount(1, $result);
260
261
        $result = $this->get(Select::class)
262
            ('tester', 'id', [$bazyaba->id, $nekufa->id, $nekufa->id]);
263
264
        $this->assertCount(2, $result);
265
266
        $result = $this->get(Select::class)
267
            ('tester', 'name', ['nekufa']);
268
269
        $this->assertCount(1, $result);
270
271
        $result = $this->get(Select::class)
272
            ('tester', 'name', ['nekufa', 'bazyaba']);
273
274
        $this->assertCount(2, $result);
275
276
        $result = $this->get(Select::class)
277
            ('tester', 'name', ['nekufa', 'bazyaba', 'nekufa', 'dmitry']);
278
279
        $this->assertCount(2, $result);
280
    }
281
282
    public function testSelectUsageWithCompositeKeys()
283
    {
284
        $this->dispatch('tarantool.clear');
285
        $this->dispatch('module.bootstrap');
286
287
        $mapper = $this->getMapper();
288
        $mapper->getSchema()
289
            ->createSpace('calendar', [
290
                'year' => 'unsigned',
291
                'month' => 'unsigned',
292
                'day' => 'unsigned',
293
            ])
294
            ->createIndex(['year', 'month', 'day']);
295
296
        $mapper->create('calendar', ['year' => 2018, 'month' => 4, 'day' => 1]);
297
        $mapper->create('calendar', ['year' => 2018, 'month' => 5, 'day' => 1]);
298
        $mapper->create('calendar', ['year' => 2018, 'month' => 5, 'day' => 2]);
299
        $mapper->create('calendar', ['year' => 2018, 'month' => 5, 'day' => 3]);
300
        $mapper->create('calendar', ['year' => 2018, 'month' => 5, 'day' => 5]);
301
        $mapper->create('calendar', ['year' => 2018, 'month' => 6, 'day' => 15]);
302
303
        $validations = [
304
            [4, [[2018, 5]]],
305
            [5, [[2018, 5], [2018, 6]]],
306
            [2, [[2018, 5, 1], [2018, 5, 2]]],
307
            [1, [[2018, 5, 3], [2018, 5, 4]]],
308
            [2, [[2018, 5, 3], [2018, 5, 4], [2018, 4]]],
309
            [2, [[2018, 5, 3], [2018, 5, 4], [2018, 4], [2018, 4]]],
310
        ];
311
312
        $select = function($key) {
313
            return $this->get(Select::class)('calendar', 'year_month_day', $key);
314
        };
315
316
        foreach ($validations as [$result, $keys]) {
317
            $this->assertCount($result, $select($keys));
0 ignored issues
show
Bug introduced by
The variable $result does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $keys does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
318
        }
319
320
        $spaceId = $mapper->getClient()->evaluate('return box.space.calendar.id')->getData()[0];
321
        $indexId = $mapper->getClient()->evaluate('return box.space.calendar.index.year_month_day.id')->getData()[0];
322
323
        $selectUsingSpaceAndIndexId = function($values) use ($spaceId, $indexId) {
324
            return $this->get(Select::class)($spaceId, $indexId, $values);
325
        };
326
327
        foreach ($validations as [$result, $keys]) {
328
            $this->assertCount($result, $selectUsingSpaceAndIndexId($keys));
329
        }
330
    }
331
332
    public function testSelectUsageWithNestedStructures()
333
    {
334
        $mapper = $this->getMapper();
335
        $mapper->getSchema()
336
            ->createSpace('sector', [
337
                'id' => 'unsigned',
338
            ])
339
            ->addProperty('parent', 'unsigned', false, 'sector')
340
            ->createIndex([
341
                'fields' => ['id'],
342
            ])
343
            ->createIndex([
344
                'fields' => ['parent'],
345
                'unique' => false,
346
            ]);
347
348
        $root = $this->create('sector', []);
349
        $moscow = $this->create('sector', ['parent' => $root]);
350
        $kaluga = $this->create('sector', ['parent' => $root]);
351
        $obninsk = $this->create('sector', ['parent' => $kaluga]);
352
353
        $select = function($values) {
354
            return $this->get(Select::class)('sector', 'id', $values);
355
        };
356
357
        $validations = [
358
            [1, [$obninsk->id]],
0 ignored issues
show
Bug introduced by
The property id does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
359
            [2, [$kaluga->id]],
360
            [3, [$kaluga->id, $moscow->id]],
361
            [4, [$obninsk->id, $root->id]],
362
        ];
363
364
        foreach ($validations as [$result, $input]) {
365
            $this->assertCount($result, $select($input));
0 ignored issues
show
Bug introduced by
The variable $result does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $input does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
366
        }
367
368
        $client = $mapper->getClient();
369
370
        $selectUsingNetBox = function($values) use ($client) {
371
            return $client->evaluate("
372
                return require('net.box').connect('tcp://localhost:3301')
373
                    :call('basis_select', {
374
                        'sector', 'id', ...
375
                    })
376
            ", [$values])->getData()[0];
377
        };
378
379
        foreach ($validations as [$result, $input]) {
380
            $this->assertCount($result, $selectUsingNetBox($input));
381
        }
382
383
        $spaceId = $client->evaluate("return box.space.sector.id")->getData()[0];
384
        $indexId = $client->evaluate("return box.space.sector.index.id.id")->getData()[0];
385
386
        $selectUsingNetBoxWithoutNames = function($values) use ($client, $spaceId, $indexId) {
387
            return $client->evaluate("
388
                return require('net.box').connect('tcp://localhost:3301')
389
                    :call('basis_select', {
390
                        $spaceId, $indexId, ...
391
                    })
392
            ", [$values])->getData()[0];
393
        };
394
395
        foreach ($validations as [$result, $input]) {
396
            $this->assertCount($result, $selectUsingNetBoxWithoutNames($input));
397
        }
398
    }
399
}
400
401