Skip to content

Commit ba6aaa4

Browse files
authored
Tests for PostgreSQL (laravel-workflow#31)
* Update php.yml * Add Y encoder * Add rector, phpstan, ECS
1 parent 47e4df6 commit ba6aaa4

16 files changed

+284
-55
lines changed

.github/workflows/php.yml

+31-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ jobs:
1919
ports:
2020
- 3306:3306
2121

22+
postgres:
23+
image: postgres
24+
env:
25+
POSTGRES_USER: root
26+
POSTGRES_PASSWORD: password
27+
POSTGRES_DB: testbench
28+
ports:
29+
- 5432:5432
30+
2231
redis:
2332
image: redis
2433
ports:
@@ -42,10 +51,16 @@ jobs:
4251
- name: Install dependencies
4352
run: composer install --prefer-dist --no-progress
4453

54+
- name: Check coding style via ECS
55+
run: vendor/bin/ecs check
56+
57+
- name: Run static analysis via PHPStan
58+
run: vendor/bin/phpstan --xdebug analyse src
59+
4560
- name: Create database
4661
run: mysql -e 'CREATE DATABASE testbench' -h127.0.0.1 -uroot -ppassword -P ${{ job.services.mysql.ports[3306] }}
4762

48-
- name: Run test suite
63+
- name: Run test suite (MySQL)
4964
run: composer run-script test
5065
env:
5166
APP_KEY: base64:i3g6f+dV8FfsIkcxqd7gbiPn2oXk5r00sTmdD6V5utI=
@@ -59,3 +74,18 @@ jobs:
5974
REDIS_HOST: 127.0.0.1
6075
REDIS_PASSWORD:
6176
REDIS_PORT: 6379
77+
78+
- name: Run test suite (PostgreSQL)
79+
run: composer run-script test
80+
env:
81+
APP_KEY: base64:i3g6f+dV8FfsIkcxqd7gbiPn2oXk5r00sTmdD6V5utI=
82+
DB_CONNECTION: pgsql
83+
DB_DATABASE: testbench
84+
DB_HOST: 127.0.0.1
85+
DB_PORT: 5432
86+
DB_USERNAME: root
87+
DB_PASSWORD: password
88+
QUEUE_CONNECTION: redis
89+
REDIS_HOST: 127.0.0.1
90+
REDIS_PASSWORD:
91+
REDIS_PORT: 6379

composer.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
}
1515
},
1616
"scripts": {
17+
"rector": "vendor/bin/rector",
18+
"ecs": "vendor/bin/ecs check --fix",
19+
"stan": "vendor/bin/phpstan analyse src tests",
1720
"test": "phpunit --testdox"
1821
},
1922
"authors": [
@@ -29,7 +32,10 @@
2932
"react/promise": "^2.9"
3033
},
3134
"require-dev": {
32-
"orchestra/testbench": "^7.1"
35+
"orchestra/testbench": "^7.1",
36+
"phpstan/phpstan": "^1.9",
37+
"rector/rector": "^0.15.1",
38+
"symplify/easy-coding-standard": "^11.1"
3339
},
3440
"extra": {
3541
"laravel": {

ecs.php

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\AssignmentInConditionSniff;
6+
use PhpCsFixer\Fixer\FunctionNotation\FunctionTypehintSpaceFixer;
7+
use PhpCsFixer\Fixer\FunctionNotation\StaticLambdaFixer;
8+
use PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer;
9+
use PhpCsFixer\Fixer\Phpdoc\NoSuperfluousPhpdocTagsFixer;
10+
use PhpCsFixer\Fixer\Phpdoc\PhpdocNoEmptyReturnFixer;
11+
use PhpCsFixer\Fixer\Phpdoc\PhpdocTypesFixer;
12+
use PhpCsFixer\Fixer\PhpUnit\PhpUnitStrictFixer;
13+
use Symplify\CodingStandard\Fixer\LineLength\DocBlockLineLengthFixer;
14+
use Symplify\EasyCodingStandard\Config\ECSConfig;
15+
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
16+
17+
return static function (ECSConfig $ecsConfig): void {
18+
$ecsConfig->sets([SetList::PSR_12, SetList::SYMPLIFY, SetList::COMMON, SetList::CLEAN_CODE]);
19+
20+
$ecsConfig->paths([
21+
__DIR__ . '/src',
22+
__DIR__ . '/tests',
23+
]);
24+
25+
$ecsConfig->ruleWithConfiguration(NoSuperfluousPhpdocTagsFixer::class, [
26+
'allow_mixed' => true,
27+
]);
28+
29+
$ecsConfig->ruleWithConfiguration(GeneralPhpdocAnnotationRemoveFixer::class, [
30+
'annotations' => [
31+
'throw',
32+
'throws',
33+
'author',
34+
'authors',
35+
'package',
36+
'group',
37+
'required',
38+
'phpstan-ignore-line',
39+
'phpstan-ignore-next-line',
40+
],
41+
]);
42+
43+
$ecsConfig->rule(StaticLambdaFixer::class);
44+
45+
$ecsConfig->skip([
46+
'*/Source/*',
47+
'*/Fixture/*',
48+
'*/Expected/*',
49+
50+
// buggy - @todo fix on Symplify master
51+
DocBlockLineLengthFixer::class,
52+
53+
PhpdocTypesFixer::class => [
54+
// double to Double false positive
55+
__DIR__ . '/rules/Php74/Rector/Double/RealToFloatTypeCastRector.php',
56+
// skip for enum types
57+
__DIR__ . '/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php',
58+
],
59+
60+
// breaking and handled better by Rector PHPUnit code quality set, removed in symplify dev-main
61+
PhpUnitStrictFixer::class,
62+
63+
// skip add space on &$variable
64+
FunctionTypehintSpaceFixer::class => [
65+
__DIR__ . '/src/PhpParser/Printer/BetterStandardPrinter.php',
66+
__DIR__ . '/src/DependencyInjection/Loader/Configurator/RectorServiceConfigurator.php',
67+
__DIR__ . '/rules/Php70/EregToPcreTransformer.php',
68+
],
69+
70+
AssignmentInConditionSniff::class . '.FoundInWhileCondition',
71+
72+
// null on purpose as no change
73+
PhpdocNoEmptyReturnFixer::class => [
74+
__DIR__ . '/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php',
75+
],
76+
]);
77+
};

rector.php

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Core\ValueObject\PhpVersion;
7+
use Rector\Set\ValueObject\LevelSetList;
8+
use Rector\Set\ValueObject\SetList;
9+
10+
return static function (RectorConfig $rectorConfig): void {
11+
$rectorConfig->paths([
12+
__DIR__ . '/src',
13+
__DIR__ . '/tests'
14+
]);
15+
16+
$rectorConfig->parallel(240);
17+
18+
$rectorConfig->phpVersion(PhpVersion::PHP_81);
19+
20+
$rectorConfig->sets([
21+
LevelSetList::UP_TO_PHP_81,
22+
SetList::CODE_QUALITY,
23+
SetList::DEAD_CODE,
24+
SetList::PRIVATIZATION,
25+
SetList::NAMING,
26+
SetList::TYPE_DECLARATION,
27+
SetList::EARLY_RETURN,
28+
SetList::CODING_STYLE,
29+
]);
30+
};

src/Activity.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Workflow\Middleware\WithoutOverlappingMiddleware;
1616
use Workflow\Middleware\WorkflowMiddleware;
1717
use Workflow\Models\StoredWorkflow;
18+
use Workflow\Serializers\Y;
1819

1920
class Activity implements ShouldBeEncrypted, ShouldQueue
2021
{
@@ -75,7 +76,7 @@ public function handle()
7576
$this->storedWorkflow->exceptions()
7677
->create([
7778
'class' => $this::class,
78-
'exception' => serialize($throwable),
79+
'exception' => Y::serialize($throwable),
7980
]);
8081

8182
throw $throwable;
@@ -84,7 +85,6 @@ public function handle()
8485

8586
public function middleware()
8687
{
87-
8888
return [
8989
new WithoutOverlappingMiddleware($this->storedWorkflow->id, WithoutOverlappingMiddleware::ACTIVITY),
9090
new WorkflowMiddleware(),

src/ActivityStub.php

+15-15
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
namespace Workflow;
66

7+
use function React\Promise\all;
78
use React\Promise\Deferred;
89
use React\Promise\PromiseInterface;
9-
use function React\Promise\all;
1010
use function React\Promise\resolve;
11+
use Workflow\Serializers\Y;
1112

1213
final class ActivityStub
1314
{
@@ -36,24 +37,23 @@ public static function make($activity, ...$arguments): PromiseInterface
3637
if ($log) {
3738
++$context->index;
3839
WorkflowStub::setContext($context);
39-
return resolve(unserialize($log->result));
40-
} else {
41-
$current = new self($activity, ...$arguments);
40+
return resolve(Y::unserialize($log->result));
41+
}
42+
$current = new self($activity, ...$arguments);
4243

43-
$current->activity()::dispatch(
44-
$context->index,
45-
$context->now,
46-
$context->storedWorkflow,
47-
...$current->arguments()
48-
);
44+
$current->activity()::dispatch(
45+
$context->index,
46+
$context->now,
47+
$context->storedWorkflow,
48+
...$current->arguments()
49+
);
4950

50-
++$context->index;
51-
WorkflowStub::setContext($context);
51+
++$context->index;
52+
WorkflowStub::setContext($context);
5253

53-
$deferred = new Deferred();
54+
$deferred = new Deferred();
5455

55-
return $deferred->promise();
56-
}
56+
return $deferred->promise();
5757
}
5858

5959
public function activity()

src/Middleware/WithoutOverlappingMiddleware.php

+34-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class WithoutOverlappingMiddleware
1313
use InteractsWithTime;
1414

1515
public const WORKFLOW = 1;
16+
1617
public const ACTIVITY = 2;
1718

1819
public string $key;
@@ -43,14 +44,24 @@ public function handle($job, $next)
4344
case self::WORKFLOW:
4445
$locked = false;
4546
if ($workflowSemaphore === 0 && $activitySemaphore === 0) {
46-
$locked = $this->compareAndSet($cache, $this->getWorkflowSemaphoreKey(), $workflowSemaphore, $workflowSemaphore + 1);
47+
$locked = $this->compareAndSet(
48+
$cache,
49+
$this->getWorkflowSemaphoreKey(),
50+
$workflowSemaphore,
51+
$workflowSemaphore + 1
52+
);
4753
}
4854
break;
4955

5056
case self::ACTIVITY:
5157
$locked = false;
5258
if ($workflowSemaphore === 0) {
53-
$locked = $this->compareAndSet($cache, $this->getActivitySemaphoreKey(), $activitySemaphore, $activitySemaphore + 1);
59+
$locked = $this->compareAndSet(
60+
$cache,
61+
$this->getActivitySemaphoreKey(),
62+
$activitySemaphore,
63+
$activitySemaphore + 1
64+
);
5465
}
5566
break;
5667

@@ -68,48 +79,58 @@ public function handle($job, $next)
6879
$unlocked = false;
6980
while (! $unlocked) {
7081
$workflowSemaphore = (int) $cache->get($this->getWorkflowSemaphoreKey());
71-
$unlocked = $this->compareAndSet($cache, $this->getWorkflowSemaphoreKey(), $workflowSemaphore, max($workflowSemaphore - 1, 0));
82+
$unlocked = $this->compareAndSet(
83+
$cache,
84+
$this->getWorkflowSemaphoreKey(),
85+
$workflowSemaphore,
86+
max($workflowSemaphore - 1, 0)
87+
);
7288
}
7389
break;
74-
90+
7591
case self::ACTIVITY:
7692
$unlocked = false;
7793
while (! $unlocked) {
7894
$activitySemaphore = (int) $cache->get($this->getActivitySemaphoreKey());
79-
$unlocked = $this->compareAndSet($cache, $this->getActivitySemaphoreKey(), $activitySemaphore, max($activitySemaphore - 1, 0));
95+
$unlocked = $this->compareAndSet(
96+
$cache,
97+
$this->getActivitySemaphoreKey(),
98+
$activitySemaphore,
99+
max($activitySemaphore - 1, 0)
100+
);
80101
}
81102
break;
82-
}
103+
}
83104
}
84-
} elseif (! is_null($this->releaseAfter)) {
105+
} elseif ($this->releaseAfter !== null) {
85106
$job->release($this->releaseAfter);
86107
}
87108
}
88109

89110
public function getLockKey()
90111
{
91-
return $this->prefix.$this->key;
112+
return $this->prefix . $this->key;
92113
}
93114

94115
public function getWorkflowSemaphoreKey()
95116
{
96-
return $this->getLockKey().':workflow';
117+
return $this->getLockKey() . ':workflow';
97118
}
98119

99120
public function getActivitySemaphoreKey()
100121
{
101-
return $this->getLockKey().':activity';
122+
return $this->getLockKey() . ':activity';
102123
}
103124

104125
private function compareAndSet($cache, $key, $expectedValue, $newValue)
105126
{
106127
$lock = $cache->lock($this->getLockKey(), $this->expiresAfter);
107-
128+
108129
if ($lock->get()) {
109130
try {
110131
$currentValue = (int) $cache->get($key, null);
111-
112-
if ($currentValue == $expectedValue) {
132+
133+
if ($currentValue === $expectedValue) {
113134
$cache->put($key, (int) $newValue);
114135
return true;
115136
}

src/QueryMethod.php

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace Workflow;
66

7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_METHOD)]
710
final class QueryMethod
811
{
912
}

0 commit comments

Comments
 (0)