Skip to content

Commit d1c14bc

Browse files
TD-CLI-003: dw workflow:start has no test coverage for new priority / fairness dispatch fields (#28)
1 parent 548b08e commit d1c14bc

1 file changed

Lines changed: 199 additions & 0 deletions

File tree

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Commands;
6+
7+
use DurableWorkflow\Cli\Commands\WorkflowCommand\StartCommand;
8+
use DurableWorkflow\Cli\Support\ServerClient;
9+
use PHPUnit\Framework\TestCase;
10+
use Symfony\Component\Console\Command\Command;
11+
use Symfony\Component\Console\Tester\CommandTester;
12+
13+
/**
14+
* Coverage for the dispatch-shaping options on `dw workflow:start`
15+
* (`--priority`, `--fairness-key`, `--fairness-weight`).
16+
*
17+
* These options shape how the server orders and rebalances pending
18+
* starts under contention. The command must:
19+
* - forward each option as the typed JSON field the server expects
20+
* (`priority` int, `fairness_key` string, `fairness_weight` int)
21+
* - omit any unset option from the request body so older servers
22+
* that don't yet model these fields keep working
23+
* - preserve `priority: 0` as a valid value (lowest dispatch
24+
* priority, distinct from "field absent")
25+
* - drop a blank fairness key rather than send an empty string
26+
* that would conflict with the 1..64-char server contract
27+
*/
28+
final class WorkflowStartCommandTest extends TestCase
29+
{
30+
public function test_priority_is_forwarded_as_integer(): void
31+
{
32+
$client = $this->newClient();
33+
$tester = $this->newTester($client);
34+
35+
self::assertSame(Command::SUCCESS, $tester->execute([
36+
'--type' => 'orders.process',
37+
'--priority' => '3',
38+
]));
39+
40+
self::assertSame('POST', $client->lastMethod);
41+
self::assertSame('/workflows', $client->lastPath);
42+
self::assertArrayHasKey('priority', $client->lastBody);
43+
self::assertSame(3, $client->lastBody['priority']);
44+
}
45+
46+
public function test_priority_zero_is_preserved_in_body(): void
47+
{
48+
$client = $this->newClient();
49+
$tester = $this->newTester($client);
50+
51+
self::assertSame(Command::SUCCESS, $tester->execute([
52+
'--type' => 'orders.process',
53+
'--priority' => '0',
54+
]));
55+
56+
self::assertArrayHasKey('priority', $client->lastBody);
57+
self::assertSame(0, $client->lastBody['priority']);
58+
}
59+
60+
public function test_fairness_key_is_forwarded_as_string(): void
61+
{
62+
$client = $this->newClient();
63+
$tester = $this->newTester($client);
64+
65+
self::assertSame(Command::SUCCESS, $tester->execute([
66+
'--type' => 'orders.process',
67+
'--fairness-key' => 'tenant-acme',
68+
]));
69+
70+
self::assertArrayHasKey('fairness_key', $client->lastBody);
71+
self::assertSame('tenant-acme', $client->lastBody['fairness_key']);
72+
}
73+
74+
public function test_blank_fairness_key_is_dropped_from_body(): void
75+
{
76+
$client = $this->newClient();
77+
$tester = $this->newTester($client);
78+
79+
self::assertSame(Command::SUCCESS, $tester->execute([
80+
'--type' => 'orders.process',
81+
'--fairness-key' => ' ',
82+
]));
83+
84+
self::assertArrayNotHasKey(
85+
'fairness_key',
86+
$client->lastBody,
87+
'Whitespace-only --fairness-key must not be sent: it would violate the 1..64 URL-safe-char server contract.',
88+
);
89+
}
90+
91+
public function test_fairness_weight_is_forwarded_as_integer(): void
92+
{
93+
$client = $this->newClient();
94+
$tester = $this->newTester($client);
95+
96+
self::assertSame(Command::SUCCESS, $tester->execute([
97+
'--type' => 'orders.process',
98+
'--fairness-weight' => '250',
99+
]));
100+
101+
self::assertArrayHasKey('fairness_weight', $client->lastBody);
102+
self::assertSame(250, $client->lastBody['fairness_weight']);
103+
}
104+
105+
public function test_priority_and_fairness_can_be_set_together(): void
106+
{
107+
$client = $this->newClient();
108+
$tester = $this->newTester($client);
109+
110+
self::assertSame(Command::SUCCESS, $tester->execute([
111+
'--type' => 'orders.process',
112+
'--priority' => '1',
113+
'--fairness-key' => 'tier-gold',
114+
'--fairness-weight' => '750',
115+
]));
116+
117+
self::assertSame(1, $client->lastBody['priority']);
118+
self::assertSame('tier-gold', $client->lastBody['fairness_key']);
119+
self::assertSame(750, $client->lastBody['fairness_weight']);
120+
}
121+
122+
public function test_priority_and_fairness_fields_are_omitted_when_unset(): void
123+
{
124+
$client = $this->newClient();
125+
$tester = $this->newTester($client);
126+
127+
self::assertSame(Command::SUCCESS, $tester->execute([
128+
'--type' => 'orders.process',
129+
]));
130+
131+
self::assertArrayNotHasKey('priority', $client->lastBody);
132+
self::assertArrayNotHasKey('fairness_key', $client->lastBody);
133+
self::assertArrayNotHasKey('fairness_weight', $client->lastBody);
134+
}
135+
136+
public function test_command_exposes_dispatch_options_in_definition(): void
137+
{
138+
$command = new StartCommand();
139+
$definition = $command->getDefinition();
140+
141+
self::assertTrue($definition->hasOption('priority'));
142+
self::assertTrue($definition->hasOption('fairness-key'));
143+
self::assertTrue($definition->hasOption('fairness-weight'));
144+
145+
self::assertTrue(
146+
$definition->getOption('priority')->isValueRequired(),
147+
'--priority must require a value (it is meaningful only when explicitly set).',
148+
);
149+
self::assertTrue(
150+
$definition->getOption('fairness-key')->isValueRequired(),
151+
'--fairness-key must require a value.',
152+
);
153+
self::assertTrue(
154+
$definition->getOption('fairness-weight')->isValueRequired(),
155+
'--fairness-weight must require a value.',
156+
);
157+
}
158+
159+
private function newClient(): WorkflowStartFakeServerClient
160+
{
161+
return new WorkflowStartFakeServerClient();
162+
}
163+
164+
private function newTester(WorkflowStartFakeServerClient $client): CommandTester
165+
{
166+
$command = new StartCommand();
167+
$command->setServerClient($client);
168+
169+
return new CommandTester($command);
170+
}
171+
}
172+
173+
final class WorkflowStartFakeServerClient extends ServerClient
174+
{
175+
public ?string $lastMethod = null;
176+
177+
public ?string $lastPath = null;
178+
179+
/**
180+
* @var array<string, mixed>
181+
*/
182+
public array $lastBody = [];
183+
184+
public function __construct() {}
185+
186+
public function post(string $path, array $body = []): array
187+
{
188+
$this->lastMethod = 'POST';
189+
$this->lastPath = $path;
190+
$this->lastBody = $body;
191+
192+
return [
193+
'workflow_id' => $body['workflow_id'] ?? 'wf-test',
194+
'run_id' => 'run-test',
195+
'workflow_type' => $body['workflow_type'] ?? 'orders.process',
196+
'outcome' => 'started_new',
197+
];
198+
}
199+
}

0 commit comments

Comments
 (0)