Skip to content

Commit 15d91f1

Browse files
committed
ACPT-1751: Enable Suspension of Cron-Triggered Indexer Operations
- Add unit test that covers indexer:set-status CLI command;
1 parent 55d61b4 commit 15d91f1

File tree

3 files changed

+275
-9
lines changed

3 files changed

+275
-9
lines changed

app/code/Magento/Indexer/Console/Command/IndexerSetStatusCommand.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,10 @@ private function validate(InputInterface $input): array
115115
StateInterface::STATUS_INVALID,
116116
StateInterface::STATUS_SUSPENDED,
117117
];
118-
$acceptedValuesString = '"' . implode('", "', $acceptedValues) . '"';
119118
$inputStatus = $input->getArgument(self::INPUT_KEY_STATUS);
120119

121-
if (!$inputStatus) {
122-
$errors[] = sprintf(
123-
'Missing argument "%s". Accepted values are %s.',
124-
self::INPUT_KEY_STATUS,
125-
$acceptedValuesString
126-
);
127-
} elseif (!in_array($inputStatus, $acceptedValues, true)) {
120+
if (!in_array($inputStatus, $acceptedValues, true)) {
121+
$acceptedValuesString = '"' . implode('", "', $acceptedValues) . '"';
128122
$errors[] = sprintf(
129123
'Invalid status "%s". Accepted values are %s.',
130124
$inputStatus,

app/code/Magento/Indexer/Model/ResourceModel/Indexer/State.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ protected function prepareDataForUpdate($object)
3535
'status IN (?)',
3636
[
3737
StateInterface::STATUS_WORKING,
38-
StateInterface::STATUS_SUSPENDED
38+
StateInterface::STATUS_SUSPENDED,
39+
StateInterface::STATUS_INVALID
3940
]
4041
);
4142
$data['status'] = $this->getConnection()->getCheckSql(
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Indexer\Test\Unit\Console\Command;
9+
10+
use Magento\Framework\Console\Cli;
11+
use Magento\Framework\Exception\AlreadyExistsException;
12+
use Magento\Framework\Indexer\StateInterface;
13+
use Magento\Indexer\Console\Command\IndexerSetStatusCommand;
14+
use Magento\Indexer\Model\Indexer\State;
15+
use Magento\Indexer\Model\ResourceModel\Indexer\State as StateResourceModel;
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
use Symfony\Component\Console\Tester\CommandTester;
18+
19+
class IndexerSetStatusCommandTest extends AbstractIndexerCommandCommonSetup
20+
{
21+
/**
22+
* Command being tested
23+
*
24+
* @var IndexerSetStatusCommand
25+
*/
26+
private $command;
27+
28+
/**
29+
* @var StateResourceModel|MockObject
30+
*/
31+
private $stateResourceModelMock;
32+
33+
/**
34+
* @var State|MockObject
35+
*/
36+
private $state;
37+
38+
protected function setUp(): void
39+
{
40+
parent::setUp();
41+
$this->stateResourceModelMock = $this->createMock(StateResourceModel::class);
42+
$this->state = $this->createMock(State::class);
43+
44+
$this->command = new IndexerSetStatusCommand(
45+
$this->stateResourceModelMock,
46+
$this->objectManagerFactory
47+
);
48+
}
49+
50+
public function testGetOptions()
51+
{
52+
$optionsList = $this->command->getInputList();
53+
$this->assertCount(2, $optionsList);
54+
$this->assertSame('status', $optionsList[0]->getName());
55+
$this->assertSame('index', $optionsList[1]->getName());
56+
}
57+
58+
public function testExecuteFailsDueToMissingStatusArgument()
59+
{
60+
$this->expectException('Symfony\Component\Console\Exception\RuntimeException');
61+
$this->expectExceptionMessage("Not enough arguments (missing: \"status\").");
62+
$commandTester = new CommandTester($this->command);
63+
$commandTester->execute([]);
64+
}
65+
66+
public function testExecuteInvalidStatus()
67+
{
68+
$this->expectException('InvalidArgumentException');
69+
$this->expectExceptionMessage(
70+
'Invalid status "wrong_status". Accepted values are "valid", "invalid", "suspended".'
71+
);
72+
$commandTester = new CommandTester($this->command);
73+
$commandTester->execute(['status' => 'wrong_status']);
74+
}
75+
76+
public function testExecuteAll()
77+
{
78+
$this->configureAdminArea();
79+
$indexerOne = $this->getIndexerMock(
80+
['getState'],
81+
['indexer_id' => 'indexer_1', 'title' => 'Indexer One Title']
82+
);
83+
84+
$this->state->method('setStatus')
85+
->willReturnCallback(function () {
86+
return $this->state;
87+
});
88+
$indexerOne->expects($this->once())->method('getState')->willReturn($this->state);
89+
$this->state->expects($this->exactly(2))
90+
->method('getStatus')
91+
->willReturnOnConsecutiveCalls(
92+
StateInterface::STATUS_VALID,
93+
StateInterface::STATUS_SUSPENDED
94+
);
95+
96+
$this->stateResourceModelMock->expects($this->once())
97+
->method('save')
98+
->with($this->state)
99+
->willReturnSelf();
100+
101+
$this->initIndexerCollectionByItems([$indexerOne]);
102+
103+
$commandTester = new CommandTester($this->command);
104+
$commandTester->execute(['status' => StateInterface::STATUS_SUSPENDED]);
105+
106+
$actualValue = $commandTester->getDisplay();
107+
$this->assertSame(
108+
sprintf(
109+
"Index status for Indexer 'Indexer One Title' was changed from '%s' to '%s'.%s",
110+
StateInterface::STATUS_VALID,
111+
StateInterface::STATUS_SUSPENDED,
112+
PHP_EOL
113+
),
114+
$actualValue
115+
);
116+
}
117+
118+
public function testExecuteAllWithoutStatusChange()
119+
{
120+
$this->configureAdminArea();
121+
$indexerOne = $this->getIndexerMock(
122+
['getState'],
123+
['indexer_id' => 'indexer_1', 'title' => 'Indexer One Title']
124+
);
125+
126+
$this->state->method('setStatus')
127+
->willReturnCallback(function () {
128+
return $this->state;
129+
});
130+
$indexerOne->expects($this->once())->method('getState')->willReturn($this->state);
131+
$this->state->expects($this->exactly(2))
132+
->method('getStatus')
133+
->willReturnOnConsecutiveCalls(
134+
StateInterface::STATUS_INVALID,
135+
StateInterface::STATUS_INVALID
136+
);
137+
138+
$this->stateResourceModelMock->expects($this->once())
139+
->method('save')
140+
->with($this->state)
141+
->willReturnSelf();
142+
143+
$this->initIndexerCollectionByItems([$indexerOne]);
144+
145+
$commandTester = new CommandTester($this->command);
146+
$commandTester->execute(['status' => StateInterface::STATUS_SUSPENDED]);
147+
148+
$actualValue = $commandTester->getDisplay();
149+
$this->assertSame(
150+
sprintf(
151+
"Index status for Indexer 'Indexer One Title' has not been changed.%s",
152+
PHP_EOL
153+
),
154+
$actualValue
155+
);
156+
}
157+
158+
/**
159+
* @param string $previousStatus
160+
* @param string $newStatus
161+
*
162+
* @dataProvider executeWithIndexDataProvider
163+
* @throws \Exception
164+
*/
165+
public function testExecuteWithIndex(string $previousStatus, string $newStatus)
166+
{
167+
$this->configureAdminArea();
168+
$indexerOne = $this->getIndexerMock(
169+
['getState'],
170+
['indexer_id' => 'indexer_1', 'title' => 'Indexer One Title']
171+
);
172+
173+
$this->state->method('setStatus')
174+
->willReturnCallback(function () {
175+
return $this->state;
176+
});
177+
$indexerOne->expects($this->once())->method('getState')->willReturn($this->state);
178+
$this->state->expects($this->exactly(2))
179+
->method('getStatus')
180+
->willReturnOnConsecutiveCalls(
181+
$previousStatus,
182+
$newStatus
183+
);
184+
185+
$this->stateResourceModelMock->expects($this->once())
186+
->method('save')
187+
->with($this->state)
188+
->willReturnSelf();
189+
190+
$this->initIndexerCollectionByItems([$indexerOne]);
191+
192+
$commandTester = new CommandTester($this->command);
193+
$commandTester->execute(['status' => $newStatus, 'index' => ['indexer_1']]);
194+
195+
$actualValue = $commandTester->getDisplay();
196+
$this->assertSame(
197+
sprintf(
198+
"Index status for Indexer 'Indexer One Title' was changed from '%s' to '%s'.%s",
199+
$previousStatus,
200+
$newStatus,
201+
PHP_EOL
202+
),
203+
$actualValue
204+
);
205+
}
206+
207+
public function executeWithIndexDataProvider(): array
208+
{
209+
return [
210+
[
211+
StateInterface::STATUS_SUSPENDED,
212+
StateInterface::STATUS_VALID,
213+
],
214+
[
215+
StateInterface::STATUS_VALID,
216+
StateInterface::STATUS_SUSPENDED,
217+
],
218+
[
219+
StateInterface::STATUS_VALID,
220+
StateInterface::STATUS_INVALID,
221+
],
222+
[
223+
StateInterface::STATUS_INVALID,
224+
StateInterface::STATUS_VALID
225+
],
226+
[
227+
StateInterface::STATUS_INVALID,
228+
StateInterface::STATUS_SUSPENDED
229+
],
230+
[
231+
StateInterface::STATUS_SUSPENDED,
232+
StateInterface::STATUS_INVALID
233+
]
234+
];
235+
}
236+
237+
public function testExecuteAllWithException()
238+
{
239+
$this->configureAdminArea();
240+
$indexerOne = $this->getIndexerMock(
241+
['getState'],
242+
['indexer_id' => 'indexer_1', 'title' => 'Indexer One Title']
243+
);
244+
245+
$this->state->method('setStatus')
246+
->willReturnCallback(function () {
247+
return $this->state;
248+
});
249+
$indexerOne->expects($this->once())->method('getState')->willReturn($this->state);
250+
251+
$this->stateResourceModelMock->expects($this->once())
252+
->method('save')
253+
->with($this->state)
254+
->willThrowException(new AlreadyExistsException(__('Exception while indexer status update.')));
255+
256+
$this->initIndexerCollectionByItems([$indexerOne]);
257+
258+
$commandTester = new CommandTester($this->command);
259+
$returnValue = $commandTester->execute(['status' => StateInterface::STATUS_SUSPENDED]);
260+
261+
$actualValue = $commandTester->getDisplay();
262+
$this->assertSame(
263+
sprintf(
264+
"Exception while indexer status update.%s",
265+
PHP_EOL
266+
),
267+
$actualValue
268+
);
269+
$this->assertSame(Cli::RETURN_FAILURE, $returnValue);
270+
}
271+
}

0 commit comments

Comments
 (0)