ManagerTest.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace OCA\WorkflowEngine\Tests;
  7. use OC\Files\Config\UserMountCache;
  8. use OC\L10N\L10N;
  9. use OCA\WorkflowEngine\Entity\File;
  10. use OCA\WorkflowEngine\Helper\ScopeContext;
  11. use OCA\WorkflowEngine\Manager;
  12. use OCP\AppFramework\QueryException;
  13. use OCP\EventDispatcher\IEventDispatcher;
  14. use OCP\Files\Events\Node\NodeCreatedEvent;
  15. use OCP\Files\IRootFolder;
  16. use OCP\Files\Mount\IMountManager;
  17. use OCP\ICache;
  18. use OCP\ICacheFactory;
  19. use OCP\IConfig;
  20. use OCP\IDBConnection;
  21. use OCP\IL10N;
  22. use OCP\IServerContainer;
  23. use OCP\IURLGenerator;
  24. use OCP\IUserManager;
  25. use OCP\IUserSession;
  26. use OCP\SystemTag\ISystemTagManager;
  27. use OCP\WorkflowEngine\Events\RegisterEntitiesEvent;
  28. use OCP\WorkflowEngine\ICheck;
  29. use OCP\WorkflowEngine\IEntity;
  30. use OCP\WorkflowEngine\IEntityEvent;
  31. use OCP\WorkflowEngine\IManager;
  32. use OCP\WorkflowEngine\IOperation;
  33. use PHPUnit\Framework\MockObject\MockObject;
  34. use Psr\Log\LoggerInterface;
  35. use Test\TestCase;
  36. /**
  37. * Class ManagerTest
  38. *
  39. * @package OCA\WorkflowEngine\Tests
  40. * @group DB
  41. */
  42. class ManagerTest extends TestCase {
  43. /** @var Manager */
  44. protected $manager;
  45. /** @var MockObject|IDBConnection */
  46. protected $db;
  47. /** @var \PHPUnit\Framework\MockObject\MockObject|LoggerInterface */
  48. protected $logger;
  49. /** @var MockObject|IServerContainer */
  50. protected $container;
  51. /** @var MockObject|IUserSession */
  52. protected $session;
  53. /** @var MockObject|L10N */
  54. protected $l;
  55. /** @var MockObject|IEventDispatcher */
  56. protected $dispatcher;
  57. /** @var MockObject|IConfig */
  58. protected $config;
  59. /** @var MockObject|ICacheFactory */
  60. protected $cacheFactory;
  61. protected function setUp(): void {
  62. parent::setUp();
  63. $this->db = \OC::$server->getDatabaseConnection();
  64. $this->container = $this->createMock(IServerContainer::class);
  65. /** @var IL10N|MockObject $l */
  66. $this->l = $this->createMock(IL10N::class);
  67. $this->l->method('t')
  68. ->willReturnCallback(function ($text, $parameters = []) {
  69. return vsprintf($text, $parameters);
  70. });
  71. $this->logger = $this->createMock(LoggerInterface::class);
  72. $this->session = $this->createMock(IUserSession::class);
  73. $this->dispatcher = $this->createMock(IEventDispatcher::class);
  74. $this->config = $this->createMock(IConfig::class);
  75. $this->cacheFactory = $this->createMock(ICacheFactory::class);
  76. $this->manager = new Manager(
  77. \OC::$server->getDatabaseConnection(),
  78. $this->container,
  79. $this->l,
  80. $this->logger,
  81. $this->session,
  82. $this->dispatcher,
  83. $this->config,
  84. $this->cacheFactory
  85. );
  86. $this->clearTables();
  87. }
  88. protected function tearDown(): void {
  89. $this->clearTables();
  90. parent::tearDown();
  91. }
  92. /**
  93. * @return MockObject|ScopeContext
  94. */
  95. protected function buildScope(?string $scopeId = null): MockObject {
  96. $scopeContext = $this->createMock(ScopeContext::class);
  97. $scopeContext->expects($this->any())
  98. ->method('getScope')
  99. ->willReturn($scopeId ? IManager::SCOPE_USER : IManager::SCOPE_ADMIN);
  100. $scopeContext->expects($this->any())
  101. ->method('getScopeId')
  102. ->willReturn($scopeId ?? '');
  103. $scopeContext->expects($this->any())
  104. ->method('getHash')
  105. ->willReturn(md5($scopeId ?? ''));
  106. return $scopeContext;
  107. }
  108. public function clearTables() {
  109. $query = $this->db->getQueryBuilder();
  110. foreach (['flow_checks', 'flow_operations', 'flow_operations_scope'] as $table) {
  111. $query->delete($table)
  112. ->execute();
  113. }
  114. }
  115. public function testChecks(): void {
  116. $check1 = $this->invokePrivate($this->manager, 'addCheck', ['Test', 'equal', 1]);
  117. $check2 = $this->invokePrivate($this->manager, 'addCheck', ['Test', '!equal', 2]);
  118. $data = $this->manager->getChecks([$check1]);
  119. $this->assertArrayHasKey($check1, $data);
  120. $this->assertArrayNotHasKey($check2, $data);
  121. $data = $this->manager->getChecks([$check1, $check2]);
  122. $this->assertArrayHasKey($check1, $data);
  123. $this->assertArrayHasKey($check2, $data);
  124. $data = $this->manager->getChecks([$check2, $check1]);
  125. $this->assertArrayHasKey($check1, $data);
  126. $this->assertArrayHasKey($check2, $data);
  127. $data = $this->manager->getChecks([$check2]);
  128. $this->assertArrayNotHasKey($check1, $data);
  129. $this->assertArrayHasKey($check2, $data);
  130. }
  131. public function testScope(): void {
  132. $adminScope = $this->buildScope();
  133. $userScope = $this->buildScope('jackie');
  134. $entity = File::class;
  135. $opId1 = $this->invokePrivate(
  136. $this->manager,
  137. 'insertOperation',
  138. ['OCA\WFE\TestOp', 'Test01', [11, 22], 'foo', $entity, []]
  139. );
  140. $this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
  141. $opId2 = $this->invokePrivate(
  142. $this->manager,
  143. 'insertOperation',
  144. ['OCA\WFE\TestOp', 'Test02', [33, 22], 'bar', $entity, []]
  145. );
  146. $this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
  147. $opId3 = $this->invokePrivate(
  148. $this->manager,
  149. 'insertOperation',
  150. ['OCA\WFE\TestOp', 'Test03', [11, 44], 'foobar', $entity, []]
  151. );
  152. $this->invokePrivate($this->manager, 'addScope', [$opId3, $userScope]);
  153. $this->assertTrue($this->invokePrivate($this->manager, 'canModify', [$opId1, $adminScope]));
  154. $this->assertFalse($this->invokePrivate($this->manager, 'canModify', [$opId2, $adminScope]));
  155. $this->assertFalse($this->invokePrivate($this->manager, 'canModify', [$opId3, $adminScope]));
  156. $this->assertFalse($this->invokePrivate($this->manager, 'canModify', [$opId1, $userScope]));
  157. $this->assertTrue($this->invokePrivate($this->manager, 'canModify', [$opId2, $userScope]));
  158. $this->assertTrue($this->invokePrivate($this->manager, 'canModify', [$opId3, $userScope]));
  159. }
  160. public function testGetAllOperations(): void {
  161. $adminScope = $this->buildScope();
  162. $userScope = $this->buildScope('jackie');
  163. $entity = File::class;
  164. $adminOperation = $this->createMock(IOperation::class);
  165. $adminOperation->expects($this->any())
  166. ->method('isAvailableForScope')
  167. ->willReturnMap([
  168. [IManager::SCOPE_ADMIN, true],
  169. [IManager::SCOPE_USER, false],
  170. ]);
  171. $userOperation = $this->createMock(IOperation::class);
  172. $userOperation->expects($this->any())
  173. ->method('isAvailableForScope')
  174. ->willReturnMap([
  175. [IManager::SCOPE_ADMIN, false],
  176. [IManager::SCOPE_USER, true],
  177. ]);
  178. $this->container->expects($this->any())
  179. ->method('query')
  180. ->willReturnCallback(function ($className) use ($adminOperation, $userOperation) {
  181. switch ($className) {
  182. case 'OCA\WFE\TestAdminOp':
  183. return $adminOperation;
  184. case 'OCA\WFE\TestUserOp':
  185. return $userOperation;
  186. }
  187. });
  188. $opId1 = $this->invokePrivate(
  189. $this->manager,
  190. 'insertOperation',
  191. ['OCA\WFE\TestAdminOp', 'Test01', [11, 22], 'foo', $entity, []]
  192. );
  193. $this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
  194. $opId2 = $this->invokePrivate(
  195. $this->manager,
  196. 'insertOperation',
  197. ['OCA\WFE\TestUserOp', 'Test02', [33, 22], 'bar', $entity, []]
  198. );
  199. $this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
  200. $opId3 = $this->invokePrivate(
  201. $this->manager,
  202. 'insertOperation',
  203. ['OCA\WFE\TestUserOp', 'Test03', [11, 44], 'foobar', $entity, []]
  204. );
  205. $this->invokePrivate($this->manager, 'addScope', [$opId3, $userScope]);
  206. $opId4 = $this->invokePrivate(
  207. $this->manager,
  208. 'insertOperation',
  209. ['OCA\WFE\TestAdminOp', 'Test04', [41, 10, 4], 'NoBar', $entity, []]
  210. );
  211. $this->invokePrivate($this->manager, 'addScope', [$opId4, $userScope]);
  212. $adminOps = $this->manager->getAllOperations($adminScope);
  213. $userOps = $this->manager->getAllOperations($userScope);
  214. $this->assertSame(1, count($adminOps));
  215. $this->assertTrue(array_key_exists('OCA\WFE\TestAdminOp', $adminOps));
  216. $this->assertFalse(array_key_exists('OCA\WFE\TestUserOp', $adminOps));
  217. $this->assertSame(1, count($userOps));
  218. $this->assertFalse(array_key_exists('OCA\WFE\TestAdminOp', $userOps));
  219. $this->assertTrue(array_key_exists('OCA\WFE\TestUserOp', $userOps));
  220. $this->assertSame(2, count($userOps['OCA\WFE\TestUserOp']));
  221. }
  222. public function testGetOperations(): void {
  223. $adminScope = $this->buildScope();
  224. $userScope = $this->buildScope('jackie');
  225. $entity = File::class;
  226. $opId1 = $this->invokePrivate(
  227. $this->manager,
  228. 'insertOperation',
  229. ['OCA\WFE\TestOp', 'Test01', [11, 22], 'foo', $entity, []]
  230. );
  231. $this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
  232. $opId4 = $this->invokePrivate(
  233. $this->manager,
  234. 'insertOperation',
  235. ['OCA\WFE\OtherTestOp', 'Test04', [5], 'foo', $entity, []]
  236. );
  237. $this->invokePrivate($this->manager, 'addScope', [$opId4, $adminScope]);
  238. $opId2 = $this->invokePrivate(
  239. $this->manager,
  240. 'insertOperation',
  241. ['OCA\WFE\TestOp', 'Test02', [33, 22], 'bar', $entity, []]
  242. );
  243. $this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
  244. $opId3 = $this->invokePrivate(
  245. $this->manager,
  246. 'insertOperation',
  247. ['OCA\WFE\TestOp', 'Test03', [11, 44], 'foobar', $entity, []]
  248. );
  249. $this->invokePrivate($this->manager, 'addScope', [$opId3, $userScope]);
  250. $opId5 = $this->invokePrivate(
  251. $this->manager,
  252. 'insertOperation',
  253. ['OCA\WFE\OtherTestOp', 'Test05', [5], 'foobar', $entity, []]
  254. );
  255. $this->invokePrivate($this->manager, 'addScope', [$opId5, $userScope]);
  256. $operation = $this->createMock(IOperation::class);
  257. $operation->expects($this->any())
  258. ->method('isAvailableForScope')
  259. ->willReturnMap([
  260. [IManager::SCOPE_ADMIN, true],
  261. [IManager::SCOPE_USER, true],
  262. ]);
  263. $this->container->expects($this->any())
  264. ->method('query')
  265. ->willReturnCallback(function ($className) use ($operation) {
  266. switch ($className) {
  267. case 'OCA\WFE\TestOp':
  268. return $operation;
  269. case 'OCA\WFE\OtherTestOp':
  270. throw new QueryException();
  271. }
  272. });
  273. $adminOps = $this->manager->getOperations('OCA\WFE\TestOp', $adminScope);
  274. $userOps = $this->manager->getOperations('OCA\WFE\TestOp', $userScope);
  275. $this->assertSame(1, count($adminOps));
  276. array_walk($adminOps, function ($op) {
  277. $this->assertTrue($op['class'] === 'OCA\WFE\TestOp');
  278. });
  279. $this->assertSame(2, count($userOps));
  280. array_walk($userOps, function ($op) {
  281. $this->assertTrue($op['class'] === 'OCA\WFE\TestOp');
  282. });
  283. }
  284. public function testGetAllConfiguredEvents(): void {
  285. $adminScope = $this->buildScope();
  286. $userScope = $this->buildScope('jackie');
  287. $entity = File::class;
  288. $opId5 = $this->invokePrivate(
  289. $this->manager,
  290. 'insertOperation',
  291. ['OCA\WFE\OtherTestOp', 'Test04', [], 'foo', $entity, [NodeCreatedEvent::class]]
  292. );
  293. $this->invokePrivate($this->manager, 'addScope', [$opId5, $userScope]);
  294. $allOperations = null;
  295. $cache = $this->createMock(ICache::class);
  296. $cache
  297. ->method('get')
  298. ->willReturnCallback(function () use (&$allOperations) {
  299. if ($allOperations) {
  300. return $allOperations;
  301. }
  302. return null;
  303. });
  304. $this->cacheFactory->method('createDistributed')->willReturn($cache);
  305. $allOperations = $this->manager->getAllConfiguredEvents();
  306. $this->assertCount(1, $allOperations);
  307. $allOperationsCached = $this->manager->getAllConfiguredEvents();
  308. $this->assertCount(1, $allOperationsCached);
  309. $this->assertEquals($allOperationsCached, $allOperations);
  310. }
  311. public function testUpdateOperation(): void {
  312. $adminScope = $this->buildScope();
  313. $userScope = $this->buildScope('jackie');
  314. $entity = File::class;
  315. $cache = $this->createMock(ICache::class);
  316. $cache->expects($this->exactly(4))
  317. ->method('remove')
  318. ->with('events');
  319. $this->cacheFactory->method('createDistributed')->willReturn($cache);
  320. $operationMock = $this->createMock(IOperation::class);
  321. $operationMock->expects($this->any())
  322. ->method('isAvailableForScope')
  323. ->withConsecutive(
  324. [IManager::SCOPE_ADMIN],
  325. [IManager::SCOPE_USER]
  326. )
  327. ->willReturn(true);
  328. $this->container->expects($this->any())
  329. ->method('query')
  330. ->willReturnCallback(function ($class) use ($operationMock) {
  331. if (substr($class, -2) === 'Op') {
  332. return $operationMock;
  333. } elseif ($class === File::class) {
  334. return $this->getMockBuilder(File::class)
  335. ->setConstructorArgs([
  336. $this->l,
  337. $this->createMock(IURLGenerator::class),
  338. $this->createMock(IRootFolder::class),
  339. $this->createMock(IUserSession::class),
  340. $this->createMock(ISystemTagManager::class),
  341. $this->createMock(IUserManager::class),
  342. $this->createMock(UserMountCache::class),
  343. $this->createMock(IMountManager::class),
  344. ])
  345. ->setMethodsExcept(['getEvents'])
  346. ->getMock();
  347. }
  348. return $this->createMock(ICheck::class);
  349. });
  350. $opId1 = $this->invokePrivate(
  351. $this->manager,
  352. 'insertOperation',
  353. ['OCA\WFE\TestAdminOp', 'Test01', [11, 22], 'foo', $entity, []]
  354. );
  355. $this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
  356. $opId2 = $this->invokePrivate(
  357. $this->manager,
  358. 'insertOperation',
  359. ['OCA\WFE\TestUserOp', 'Test02', [33, 22], 'bar', $entity, []]
  360. );
  361. $this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
  362. $check1 = ['class' => 'OCA\WFE\C22', 'operator' => 'eq', 'value' => 'asdf'];
  363. $check2 = ['class' => 'OCA\WFE\C33', 'operator' => 'eq', 'value' => 23456];
  364. /** @noinspection PhpUnhandledExceptionInspection */
  365. $op = $this->manager->updateOperation($opId1, 'Test01a', [$check1, $check2], 'foohur', $adminScope, $entity, ['\OCP\Files::postDelete']);
  366. $this->assertSame('Test01a', $op['name']);
  367. $this->assertSame('foohur', $op['operation']);
  368. /** @noinspection PhpUnhandledExceptionInspection */
  369. $op = $this->manager->updateOperation($opId2, 'Test02a', [$check1], 'barfoo', $userScope, $entity, ['\OCP\Files::postDelete']);
  370. $this->assertSame('Test02a', $op['name']);
  371. $this->assertSame('barfoo', $op['operation']);
  372. foreach ([[$adminScope, $opId2], [$userScope, $opId1]] as $run) {
  373. try {
  374. /** @noinspection PhpUnhandledExceptionInspection */
  375. $this->manager->updateOperation($run[1], 'Evil', [$check2], 'hackx0r', $run[0], $entity, []);
  376. $this->assertTrue(false, 'DomainException not thrown');
  377. } catch (\DomainException $e) {
  378. $this->assertTrue(true);
  379. }
  380. }
  381. }
  382. public function testDeleteOperation(): void {
  383. $adminScope = $this->buildScope();
  384. $userScope = $this->buildScope('jackie');
  385. $entity = File::class;
  386. $cache = $this->createMock(ICache::class);
  387. $cache->expects($this->exactly(4))
  388. ->method('remove')
  389. ->with('events');
  390. $this->cacheFactory->method('createDistributed')->willReturn($cache);
  391. $opId1 = $this->invokePrivate(
  392. $this->manager,
  393. 'insertOperation',
  394. ['OCA\WFE\TestAdminOp', 'Test01', [11, 22], 'foo', $entity, []]
  395. );
  396. $this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
  397. $opId2 = $this->invokePrivate(
  398. $this->manager,
  399. 'insertOperation',
  400. ['OCA\WFE\TestUserOp', 'Test02', [33, 22], 'bar', $entity, []]
  401. );
  402. $this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
  403. foreach ([[$adminScope, $opId2], [$userScope, $opId1]] as $run) {
  404. try {
  405. /** @noinspection PhpUnhandledExceptionInspection */
  406. $this->manager->deleteOperation($run[1], $run[0]);
  407. $this->assertTrue(false, 'DomainException not thrown');
  408. } catch (\Exception $e) {
  409. $this->assertInstanceOf(\DomainException::class, $e);
  410. }
  411. }
  412. /** @noinspection PhpUnhandledExceptionInspection */
  413. $this->manager->deleteOperation($opId1, $adminScope);
  414. /** @noinspection PhpUnhandledExceptionInspection */
  415. $this->manager->deleteOperation($opId2, $userScope);
  416. foreach ([$opId1, $opId2] as $opId) {
  417. try {
  418. $this->invokePrivate($this->manager, 'getOperation', [$opId]);
  419. $this->assertTrue(false, 'UnexpectedValueException not thrown');
  420. } catch (\Exception $e) {
  421. $this->assertInstanceOf(\UnexpectedValueException::class, $e);
  422. }
  423. }
  424. }
  425. public function testGetEntitiesListBuildInOnly(): void {
  426. $fileEntityMock = $this->createMock(File::class);
  427. $this->container->expects($this->once())
  428. ->method('query')
  429. ->with(File::class)
  430. ->willReturn($fileEntityMock);
  431. $entities = $this->manager->getEntitiesList();
  432. $this->assertCount(1, $entities);
  433. $this->assertInstanceOf(IEntity::class, $entities[0]);
  434. }
  435. public function testGetEntitiesList(): void {
  436. $fileEntityMock = $this->createMock(File::class);
  437. $this->container->expects($this->once())
  438. ->method('query')
  439. ->with(File::class)
  440. ->willReturn($fileEntityMock);
  441. /** @var MockObject|IEntity $extraEntity */
  442. $extraEntity = $this->createMock(IEntity::class);
  443. $this->dispatcher->expects($this->once())
  444. ->method('dispatchTyped')
  445. ->willReturnCallback(function (RegisterEntitiesEvent $e) use ($extraEntity) {
  446. $this->manager->registerEntity($extraEntity);
  447. });
  448. $entities = $this->manager->getEntitiesList();
  449. $this->assertCount(2, $entities);
  450. $entityTypeCounts = array_reduce($entities, function (array $carry, IEntity $entity) {
  451. if ($entity instanceof File) {
  452. $carry[0]++;
  453. } elseif ($entity instanceof IEntity) {
  454. $carry[1]++;
  455. }
  456. return $carry;
  457. }, [0, 0]);
  458. $this->assertSame(1, $entityTypeCounts[0]);
  459. $this->assertSame(1, $entityTypeCounts[1]);
  460. }
  461. public function testValidateOperationOK(): void {
  462. $check = [
  463. 'class' => ICheck::class,
  464. 'operator' => 'is',
  465. 'value' => 'barfoo',
  466. ];
  467. $operationMock = $this->createMock(IOperation::class);
  468. $entityMock = $this->createMock(IEntity::class);
  469. $eventEntityMock = $this->createMock(IEntityEvent::class);
  470. $checkMock = $this->createMock(ICheck::class);
  471. $scopeMock = $this->createMock(ScopeContext::class);
  472. $scopeMock->expects($this->any())
  473. ->method('getScope')
  474. ->willReturn(IManager::SCOPE_ADMIN);
  475. $operationMock->expects($this->once())
  476. ->method('isAvailableForScope')
  477. ->with(IManager::SCOPE_ADMIN)
  478. ->willReturn(true);
  479. $operationMock->expects($this->once())
  480. ->method('validateOperation')
  481. ->with('test', [$check], 'operationData');
  482. $entityMock->expects($this->any())
  483. ->method('getEvents')
  484. ->willReturn([$eventEntityMock]);
  485. $eventEntityMock->expects($this->any())
  486. ->method('getEventName')
  487. ->willReturn('MyEvent');
  488. $checkMock->expects($this->any())
  489. ->method('supportedEntities')
  490. ->willReturn([IEntity::class]);
  491. $checkMock->expects($this->atLeastOnce())
  492. ->method('validateCheck');
  493. $this->container->expects($this->any())
  494. ->method('query')
  495. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  496. switch ($className) {
  497. case IOperation::class:
  498. return $operationMock;
  499. case IEntity::class:
  500. return $entityMock;
  501. case IEntityEvent::class:
  502. return $eventEntityMock;
  503. case ICheck::class:
  504. return $checkMock;
  505. default:
  506. return $this->createMock($className);
  507. }
  508. });
  509. $this->manager->validateOperation(IOperation::class, 'test', [$check], 'operationData', $scopeMock, IEntity::class, ['MyEvent']);
  510. }
  511. public function testValidateOperationCheckInputLengthError(): void {
  512. $check = [
  513. 'class' => ICheck::class,
  514. 'operator' => 'is',
  515. 'value' => str_pad('', IManager::MAX_CHECK_VALUE_BYTES + 1, 'FooBar'),
  516. ];
  517. $operationMock = $this->createMock(IOperation::class);
  518. $entityMock = $this->createMock(IEntity::class);
  519. $eventEntityMock = $this->createMock(IEntityEvent::class);
  520. $checkMock = $this->createMock(ICheck::class);
  521. $scopeMock = $this->createMock(ScopeContext::class);
  522. $scopeMock->expects($this->any())
  523. ->method('getScope')
  524. ->willReturn(IManager::SCOPE_ADMIN);
  525. $operationMock->expects($this->once())
  526. ->method('isAvailableForScope')
  527. ->with(IManager::SCOPE_ADMIN)
  528. ->willReturn(true);
  529. $operationMock->expects($this->once())
  530. ->method('validateOperation')
  531. ->with('test', [$check], 'operationData');
  532. $entityMock->expects($this->any())
  533. ->method('getEvents')
  534. ->willReturn([$eventEntityMock]);
  535. $eventEntityMock->expects($this->any())
  536. ->method('getEventName')
  537. ->willReturn('MyEvent');
  538. $checkMock->expects($this->any())
  539. ->method('supportedEntities')
  540. ->willReturn([IEntity::class]);
  541. $checkMock->expects($this->never())
  542. ->method('validateCheck');
  543. $this->container->expects($this->any())
  544. ->method('query')
  545. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  546. switch ($className) {
  547. case IOperation::class:
  548. return $operationMock;
  549. case IEntity::class:
  550. return $entityMock;
  551. case IEntityEvent::class:
  552. return $eventEntityMock;
  553. case ICheck::class:
  554. return $checkMock;
  555. default:
  556. return $this->createMock($className);
  557. }
  558. });
  559. try {
  560. $this->manager->validateOperation(IOperation::class, 'test', [$check], 'operationData', $scopeMock, IEntity::class, ['MyEvent']);
  561. } catch (\UnexpectedValueException $e) {
  562. $this->assertSame('The provided check value is too long', $e->getMessage());
  563. }
  564. }
  565. public function testValidateOperationDataLengthError(): void {
  566. $check = [
  567. 'class' => ICheck::class,
  568. 'operator' => 'is',
  569. 'value' => 'barfoo',
  570. ];
  571. $operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES + 1, 'FooBar');
  572. $operationMock = $this->createMock(IOperation::class);
  573. $entityMock = $this->createMock(IEntity::class);
  574. $eventEntityMock = $this->createMock(IEntityEvent::class);
  575. $checkMock = $this->createMock(ICheck::class);
  576. $scopeMock = $this->createMock(ScopeContext::class);
  577. $scopeMock->expects($this->any())
  578. ->method('getScope')
  579. ->willReturn(IManager::SCOPE_ADMIN);
  580. $operationMock->expects($this->once())
  581. ->method('isAvailableForScope')
  582. ->with(IManager::SCOPE_ADMIN)
  583. ->willReturn(true);
  584. $operationMock->expects($this->never())
  585. ->method('validateOperation');
  586. $entityMock->expects($this->any())
  587. ->method('getEvents')
  588. ->willReturn([$eventEntityMock]);
  589. $eventEntityMock->expects($this->any())
  590. ->method('getEventName')
  591. ->willReturn('MyEvent');
  592. $checkMock->expects($this->any())
  593. ->method('supportedEntities')
  594. ->willReturn([IEntity::class]);
  595. $checkMock->expects($this->never())
  596. ->method('validateCheck');
  597. $this->container->expects($this->any())
  598. ->method('query')
  599. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  600. switch ($className) {
  601. case IOperation::class:
  602. return $operationMock;
  603. case IEntity::class:
  604. return $entityMock;
  605. case IEntityEvent::class:
  606. return $eventEntityMock;
  607. case ICheck::class:
  608. return $checkMock;
  609. default:
  610. return $this->createMock($className);
  611. }
  612. });
  613. try {
  614. $this->manager->validateOperation(IOperation::class, 'test', [$check], $operationData, $scopeMock, IEntity::class, ['MyEvent']);
  615. } catch (\UnexpectedValueException $e) {
  616. $this->assertSame('The provided operation data is too long', $e->getMessage());
  617. }
  618. }
  619. public function testValidateOperationScopeNotAvailable(): void {
  620. $check = [
  621. 'class' => ICheck::class,
  622. 'operator' => 'is',
  623. 'value' => 'barfoo',
  624. ];
  625. $operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES + 1, 'FooBar');
  626. $operationMock = $this->createMock(IOperation::class);
  627. $entityMock = $this->createMock(IEntity::class);
  628. $eventEntityMock = $this->createMock(IEntityEvent::class);
  629. $checkMock = $this->createMock(ICheck::class);
  630. $scopeMock = $this->createMock(ScopeContext::class);
  631. $scopeMock->expects($this->any())
  632. ->method('getScope')
  633. ->willReturn(IManager::SCOPE_ADMIN);
  634. $operationMock->expects($this->once())
  635. ->method('isAvailableForScope')
  636. ->with(IManager::SCOPE_ADMIN)
  637. ->willReturn(false);
  638. $operationMock->expects($this->never())
  639. ->method('validateOperation');
  640. $entityMock->expects($this->any())
  641. ->method('getEvents')
  642. ->willReturn([$eventEntityMock]);
  643. $eventEntityMock->expects($this->any())
  644. ->method('getEventName')
  645. ->willReturn('MyEvent');
  646. $checkMock->expects($this->any())
  647. ->method('supportedEntities')
  648. ->willReturn([IEntity::class]);
  649. $checkMock->expects($this->never())
  650. ->method('validateCheck');
  651. $this->container->expects($this->any())
  652. ->method('query')
  653. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  654. switch ($className) {
  655. case IOperation::class:
  656. return $operationMock;
  657. case IEntity::class:
  658. return $entityMock;
  659. case IEntityEvent::class:
  660. return $eventEntityMock;
  661. case ICheck::class:
  662. return $checkMock;
  663. default:
  664. return $this->createMock($className);
  665. }
  666. });
  667. try {
  668. $this->manager->validateOperation(IOperation::class, 'test', [$check], $operationData, $scopeMock, IEntity::class, ['MyEvent']);
  669. } catch (\UnexpectedValueException $e) {
  670. $this->assertSame('Operation OCP\WorkflowEngine\IOperation is invalid', $e->getMessage());
  671. }
  672. }
  673. }