Skip to content

Commit df3ffb6

Browse files
committed
refactor concurrent tests
1 parent 8fe50f7 commit df3ffb6

5 files changed

Lines changed: 169 additions & 116 deletions

Spanner/composer.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,17 @@
6363
"@test-snippets",
6464
"@test-system"
6565
]
66+
},
67+
"repositories": {
68+
"local": {
69+
"type": "path",
70+
"url": "../Core",
71+
"options": {
72+
"versions": {
73+
"google/cloud-core": "1.100"
74+
}
75+
},
76+
"canonical": false
77+
}
6678
}
6779
}

Spanner/tests/System/SystemTestCaseTrait.php

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,20 @@
2727

2828
trait SystemTestCaseTrait
2929
{
30-
public const INSTANCE_NAME = 'google-cloud-php-system-tests';
31-
32-
protected const TESTING_PREFIX = 'gcloud_testing_';
33-
protected const TEST_TABLE_NAME = 'Users';
34-
protected const TEST_INDEX_NAME = 'uniqueIndex';
35-
30+
private const TESTING_PREFIX = 'gcloud_testing_';
31+
private const INSTANCE_NAME = 'google-cloud-php-system-tests';
32+
private const TEST_TABLE_NAME = 'Users';
33+
private const TEST_INDEX_NAME = 'uniqueIndex';
3634
private const DATABASE_ROLE = 'Reader';
3735
private const RESTRICTIVE_DATABASE_ROLE = 'RestrictiveReader';
3836

39-
protected static $client;
40-
protected static $instance;
41-
protected static $database;
42-
protected static $dbName;
43-
37+
private static $client;
38+
private static $instance;
39+
private static $database;
40+
private static $dbName;
4441
private static $hasSetUp = false;
4542

46-
protected static function getClient()
43+
private static function getClient()
4744
{
4845
if (self::$client) {
4946
return self::$client;
@@ -74,7 +71,7 @@ protected static function getClient()
7471
return self::$client = new SpannerClient($clientConfig);
7572
}
7673

77-
protected static function setUpTestDatabase(): void
74+
private static function setUpTestDatabase(): void
7875
{
7976
if (self::$hasSetUp) {
8077
return;
@@ -125,12 +122,12 @@ protected static function setUpTestDatabase(): void
125122
self::$hasSetUp = true;
126123
}
127124

128-
public static function getDatabaseInstance($dbName, $options = [])
125+
private static function getDatabaseInstance($dbName, $options = [])
129126
{
130-
return self::getClient()->connect(SystemTestCaseTrait::INSTANCE_NAME, $dbName, $options);
127+
return self::getClient()->connect(self::INSTANCE_NAME, $dbName, $options);
131128
}
132129

133-
public static function skipEmulatorTests()
130+
private static function skipEmulatorTests()
134131
{
135132
if (self::isEmulatorUsed()) {
136133
self::markTestSkipped('This test is not supported by the emulator.');
@@ -149,7 +146,7 @@ public static function isEmulatorUsed(): bool
149146
return (bool) getenv('SPANNER_EMULATOR_HOST');
150147
}
151148

152-
public static function getDbWithReaderRole()
149+
private static function getDbWithReaderRole()
153150
{
154151
return self::getDatabaseFromInstance(
155152
self::INSTANCE_NAME,
@@ -158,7 +155,7 @@ public static function getDbWithReaderRole()
158155
);
159156
}
160157

161-
public static function getDbWithRestrictiveRole()
158+
private static function getDbWithRestrictiveRole()
162159
{
163160
return self::getDatabaseFromInstance(
164161
self::INSTANCE_NAME,
@@ -173,7 +170,7 @@ private static function getDatabaseFromInstance($instance, $dbName, $options = [
173170
return $instance->database($dbName, $options);
174171
}
175172

176-
protected static function getCacheItemPool()
173+
private static function getCacheItemPool()
177174
{
178175
return new FilesystemAdapter(
179176
directory: __DIR__ . '/../../../.cache'

Spanner/tests/System/pcntl/AbortedErrorCausesRetry.php

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,48 +9,64 @@
99
list($dbName, $tableName, $id) = getInputArgs();
1010
$delay = 5000;
1111

12-
if ($childPID1 = pcntl_fork()) {
13-
usleep($delay);
14-
$iteration = 0;
15-
$db1 = SystemTestCaseTrait::getDatabaseInstance($dbName);
16-
$db1->runTransaction(function ($t) use ($id, $tableName, $delay, &$iteration) {
17-
$iteration++;
18-
usleep(2 * $delay);
19-
$row = $t->execute('SELECT id, number FROM ' . $tableName . ' WHERE ID = @id', [
20-
'parameters' => ['id' => (int) $id]
21-
])->rows()->current();
22-
23-
if ($iteration === 1) {
24-
throw new AbortedException('foo', 409, null, [
25-
[
26-
'retryDelay' => [
27-
'seconds' => 1,
28-
'nanos' => 0
29-
]
30-
]
31-
]);
32-
}
33-
34-
$row['number'] += 1;
35-
$t->update($tableName, $row);
36-
$t->commit();
37-
});
38-
39-
echo $iteration;
40-
pcntl_waitpid($childPID1, $status1);
41-
} else {
42-
$db2 = SystemTestCaseTrait::getDatabaseInstance($dbName);
43-
$db2->runTransaction(function ($t) use ($id, $tableName) {
44-
$row = $t->execute('SELECT id, number FROM ' . $tableName . ' WHERE ID = @id', [
45-
'parameters' => ['id' => (int) $id]
46-
])->rows()->current();
47-
48-
$row['number'] += 1;
49-
$t->update($tableName, $row);
50-
$t->commit();
51-
});
52-
53-
exit(0);
54-
}
55-
56-
exit(0);
12+
$abortedErrorRetry = new class($dbName, $tableName, $id, $delay) {
13+
use SystemTestCaseTrait;
14+
15+
public function __construct(
16+
string $dbName,
17+
private string $tableName,
18+
private int $id,
19+
private int $delay,
20+
) {
21+
self::$dbName = $dbName;
22+
}
23+
24+
public function run(): int
25+
{
26+
if ($childPID1 = pcntl_fork()) {
27+
usleep($this->delay);
28+
$iteration = 0;
29+
$db1 = self::getDatabaseInstance(self::$dbName);
30+
$db1->runTransaction(function ($t) use (&$iteration) {
31+
$iteration++;
32+
usleep(2 * $this->delay);
33+
$row = $t->execute('SELECT id, number FROM ' . $this->tableName . ' WHERE ID = @id', [
34+
'parameters' => ['id' => $this->id]
35+
])->rows()->current();
36+
37+
if ($iteration === 1) {
38+
throw new AbortedException('foo', 409, null, [
39+
[
40+
'retryDelay' => [
41+
'seconds' => 1,
42+
'nanos' => 0
43+
]
44+
]
45+
]);
46+
}
47+
$row['number'] += 1;
48+
$t->update($this->tableName, $row);
49+
$t->commit();
50+
});
51+
52+
echo $iteration;
53+
pcntl_waitpid($childPID1, $status1);
54+
} else {
55+
$db2 = self::getDatabaseInstance(self::$dbName);
56+
$db2->runTransaction(function ($t) {
57+
$row = $t->execute('SELECT id, number FROM ' . $this->tableName . ' WHERE ID = @id', [
58+
'parameters' => ['id' => $this->id]
59+
])->rows()->current();
60+
61+
$row['number'] += 1;
62+
$t->update($this->tableName, $row);
63+
$t->commit();
64+
});
65+
}
66+
67+
return 0;
68+
}
69+
};
70+
71+
exit($abortedErrorRetry->run());
72+

Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithExecute.php

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,51 +10,65 @@
1010
$tmpFile = sys_get_temp_dir() . '/ConcurrentTransactionsIncremementValueWithExecute.txt';
1111
setupIterationTracker($tmpFile);
1212

13-
$callable = function ($dbName, $tableName, $id) use ($tmpFile) {
14-
$iterations = 0;
15-
$db = SystemTestCaseTrait::getDatabaseInstance($dbName);
16-
if (SystemTestCaseTrait::isEmulatorUsed()) {
17-
// the emulator requires us to manually request a new session
18-
// presumably because multiplexed sessions aren't properly supported
19-
$db->session()->refresh();
13+
$concurrentExecute = new class($dbName, $tableName, $id, $tmpFile) {
14+
use SystemTestCaseTrait;
15+
16+
public function __construct(
17+
string $dbName,
18+
private string $tableName,
19+
private int $id,
20+
private string $tmpFile,
21+
) {
22+
self::$dbName = $dbName;
2023
}
21-
$db->runTransaction(function ($transaction) use ($id, $tableName, &$iterations) {
22-
$iterations++;
2324

24-
$row = $transaction->execute('SELECT * FROM ' . $tableName . ' WHERE id = @id', [
25-
'parameters' => [
26-
'id' => (int) $id
27-
]
28-
])->rows()->current();
29-
30-
$row['number'] += 1;
31-
32-
$transaction->update($tableName, $row);
33-
$transaction->commit();
34-
});
35-
36-
updateIterationTracker($tmpFile, $iterations);
25+
public function run(): int
26+
{
27+
$iterations = 0;
28+
$db = self::getDatabaseInstance(self::$dbName);
29+
if (self::isEmulatorUsed()) {
30+
// the emulator requires us to manually request a new session
31+
// presumably because multiplexed sessions aren't properly supported
32+
$db->session()->refresh();
33+
}
34+
$db->runTransaction(function ($transaction) use (&$iterations) {
35+
$iterations++;
36+
37+
$row = $transaction->execute('SELECT * FROM ' . $this->tableName . ' WHERE id = @id', [
38+
'parameters' => [
39+
'id' => $this->id,
40+
]
41+
])->rows()->current();
42+
43+
$row['number'] += 1;
44+
45+
$transaction->update($this->tableName, $row);
46+
$transaction->commit();
47+
});
48+
49+
updateIterationTracker($this->tmpFile, $iterations);
50+
51+
return 0;
52+
}
3753
};
3854

3955
$delay = 2000;
4056
$retryLimit = 100;
4157
if ($childPID1 = pcntl_fork()) {
4258
usleep($delay);
4359

44-
$callable($dbName, $tableName, $id);
60+
$status = $concurrentExecute->run();
4561

4662
while (pcntl_waitpid($childPID1, $status1, WNOHANG) == 0 && $retryLimit) {
4763
usleep(2 * $delay);
4864
$retryLimit--;
4965
}
66+
67+
echo file_get_contents($tmpFile);
68+
exit($status);
5069
} else {
5170
usleep(2 * $delay);
5271

53-
$callable($dbName, $tableName, $id);
54-
55-
exit(0);
72+
exit($concurrentExecute->run());
5673
}
5774

58-
echo file_get_contents($tmpFile);
59-
60-
exit(0);

Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithRead.php

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,60 @@
1414
$keyset = new KeySet(['keys' => [$id]]);
1515
$columns = ['id', 'number'];
1616

17-
$callable = function ($dbName, KeySet $keyset, array $columns, $tableName) use ($tmpFile) {
18-
$iterations = 0;
19-
$db = SystemTestCaseTrait::getDatabaseInstance($dbName);
20-
if (SystemTestCaseTrait::isEmulatorUsed()) {
21-
// the emulator requires us to manually request a new session
22-
// presumably because multiplexed sessions aren't properly supported
23-
$db->session()->refresh();
17+
$concurrentRead = new class($dbName, $keyset, $columns, $tableName, $tmpFile) {
18+
use SystemTestCaseTrait;
19+
20+
public function __construct(
21+
string $dbName,
22+
private KeySet $keyset,
23+
private array $columns,
24+
private string $tableName,
25+
private string $tmpFile
26+
) {
27+
self::$dbName = $dbName;
2428
}
25-
$db->runTransaction(function ($transaction) use ($keyset, $columns, $tableName, &$iterations) {
26-
$iterations++;
27-
$row = $transaction->read($tableName, $keyset, $columns)->rows()->current();
2829

29-
$row['number'] += 1;
30+
public function run(): int
31+
{
32+
$iterations = 0;
33+
$db = self::getDatabaseInstance(self::$dbName);
34+
if (self::isEmulatorUsed()) {
35+
// the emulator requires us to manually request a new session
36+
// presumably because multiplexed sessions aren't properly supported
37+
$db->session()->refresh();
38+
}
39+
$db->runTransaction(function ($transaction) use (&$iterations) {
40+
$iterations++;
41+
$row = $transaction->read($this->tableName, $this->keyset, $this->columns)->rows()->current();
3042

31-
$transaction->update($tableName, $row);
32-
$transaction->commit();
33-
});
43+
$row['number'] += 1;
3444

35-
updateIterationTracker($tmpFile, $iterations);
45+
$transaction->update($this->tableName, $row);
46+
$transaction->commit();
47+
});
48+
49+
updateIterationTracker($this->tmpFile, $iterations);
50+
51+
return 0;
52+
}
3653
};
3754

3855
$delay = 2000;
3956
$retryLimit = 100;
4057
if ($childPID1 = pcntl_fork()) {
4158
usleep($delay);
4259

43-
$callable($dbName, $keyset, $columns, $tableName);
60+
$status = $concurrentRead->run();
4461

4562
while (pcntl_waitpid($childPID1, $status1, WNOHANG) == 0 && $retryLimit) {
4663
usleep(2 * $delay);
4764
$retryLimit--;
4865
}
66+
67+
echo file_get_contents($tmpFile);
68+
exit($status);
4969
} else {
5070
usleep(2 * $delay);
5171

52-
$callable($dbName, $keyset, $columns, $tableName);
53-
54-
exit(0);
72+
exit($concurrentRead->run());
5573
}
56-
57-
echo file_get_contents($tmpFile);
58-
59-
exit(0);

0 commit comments

Comments
 (0)