ManagerTest.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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): void {
  277. $this->assertTrue($op['class'] === 'OCA\WFE\TestOp');
  278. });
  279. $this->assertSame(2, count($userOps));
  280. array_walk($userOps, function ($op): void {
  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')
  320. ->willReturn($cache);
  321. $expectedCalls = [
  322. [IManager::SCOPE_ADMIN],
  323. [IManager::SCOPE_USER],
  324. ];
  325. $i = 0;
  326. $operationMock = $this->createMock(IOperation::class);
  327. $operationMock->expects($this->any())
  328. ->method('isAvailableForScope')
  329. ->willReturnCallback(function () use (&$expectedCalls, &$i): bool {
  330. $this->assertEquals($expectedCalls[$i], func_get_args());
  331. $i++;
  332. return true;
  333. });
  334. $this->container->expects($this->any())
  335. ->method('query')
  336. ->willReturnCallback(function ($class) use ($operationMock) {
  337. if (substr($class, -2) === 'Op') {
  338. return $operationMock;
  339. } elseif ($class === File::class) {
  340. return $this->getMockBuilder(File::class)
  341. ->setConstructorArgs([
  342. $this->l,
  343. $this->createMock(IURLGenerator::class),
  344. $this->createMock(IRootFolder::class),
  345. $this->createMock(IUserSession::class),
  346. $this->createMock(ISystemTagManager::class),
  347. $this->createMock(IUserManager::class),
  348. $this->createMock(UserMountCache::class),
  349. $this->createMock(IMountManager::class),
  350. ])
  351. ->onlyMethods($this->filterClassMethods(File::class, ['getEvents']))
  352. ->getMock();
  353. }
  354. return $this->createMock(ICheck::class);
  355. });
  356. $opId1 = $this->invokePrivate(
  357. $this->manager,
  358. 'insertOperation',
  359. ['OCA\WFE\TestAdminOp', 'Test01', [11, 22], 'foo', $entity, []]
  360. );
  361. $this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
  362. $opId2 = $this->invokePrivate(
  363. $this->manager,
  364. 'insertOperation',
  365. ['OCA\WFE\TestUserOp', 'Test02', [33, 22], 'bar', $entity, []]
  366. );
  367. $this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
  368. $check1 = ['class' => 'OCA\WFE\C22', 'operator' => 'eq', 'value' => 'asdf'];
  369. $check2 = ['class' => 'OCA\WFE\C33', 'operator' => 'eq', 'value' => 23456];
  370. /** @noinspection PhpUnhandledExceptionInspection */
  371. $op = $this->manager->updateOperation($opId1, 'Test01a', [$check1, $check2], 'foohur', $adminScope, $entity, ['\OCP\Files::postDelete']);
  372. $this->assertSame('Test01a', $op['name']);
  373. $this->assertSame('foohur', $op['operation']);
  374. /** @noinspection PhpUnhandledExceptionInspection */
  375. $op = $this->manager->updateOperation($opId2, 'Test02a', [$check1], 'barfoo', $userScope, $entity, ['\OCP\Files::postDelete']);
  376. $this->assertSame('Test02a', $op['name']);
  377. $this->assertSame('barfoo', $op['operation']);
  378. foreach ([[$adminScope, $opId2], [$userScope, $opId1]] as $run) {
  379. try {
  380. /** @noinspection PhpUnhandledExceptionInspection */
  381. $this->manager->updateOperation($run[1], 'Evil', [$check2], 'hackx0r', $run[0], $entity, []);
  382. $this->assertTrue(false, 'DomainException not thrown');
  383. } catch (\DomainException $e) {
  384. $this->assertTrue(true);
  385. }
  386. }
  387. }
  388. public function testDeleteOperation(): void {
  389. $adminScope = $this->buildScope();
  390. $userScope = $this->buildScope('jackie');
  391. $entity = File::class;
  392. $cache = $this->createMock(ICache::class);
  393. $cache->expects($this->exactly(4))
  394. ->method('remove')
  395. ->with('events');
  396. $this->cacheFactory->method('createDistributed')->willReturn($cache);
  397. $opId1 = $this->invokePrivate(
  398. $this->manager,
  399. 'insertOperation',
  400. ['OCA\WFE\TestAdminOp', 'Test01', [11, 22], 'foo', $entity, []]
  401. );
  402. $this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
  403. $opId2 = $this->invokePrivate(
  404. $this->manager,
  405. 'insertOperation',
  406. ['OCA\WFE\TestUserOp', 'Test02', [33, 22], 'bar', $entity, []]
  407. );
  408. $this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
  409. foreach ([[$adminScope, $opId2], [$userScope, $opId1]] as $run) {
  410. try {
  411. /** @noinspection PhpUnhandledExceptionInspection */
  412. $this->manager->deleteOperation($run[1], $run[0]);
  413. $this->assertTrue(false, 'DomainException not thrown');
  414. } catch (\Exception $e) {
  415. $this->assertInstanceOf(\DomainException::class, $e);
  416. }
  417. }
  418. /** @noinspection PhpUnhandledExceptionInspection */
  419. $this->manager->deleteOperation($opId1, $adminScope);
  420. /** @noinspection PhpUnhandledExceptionInspection */
  421. $this->manager->deleteOperation($opId2, $userScope);
  422. foreach ([$opId1, $opId2] as $opId) {
  423. try {
  424. $this->invokePrivate($this->manager, 'getOperation', [$opId]);
  425. $this->assertTrue(false, 'UnexpectedValueException not thrown');
  426. } catch (\Exception $e) {
  427. $this->assertInstanceOf(\UnexpectedValueException::class, $e);
  428. }
  429. }
  430. }
  431. public function testGetEntitiesListBuildInOnly(): void {
  432. $fileEntityMock = $this->createMock(File::class);
  433. $this->container->expects($this->once())
  434. ->method('query')
  435. ->with(File::class)
  436. ->willReturn($fileEntityMock);
  437. $entities = $this->manager->getEntitiesList();
  438. $this->assertCount(1, $entities);
  439. $this->assertInstanceOf(IEntity::class, $entities[0]);
  440. }
  441. public function testGetEntitiesList(): void {
  442. $fileEntityMock = $this->createMock(File::class);
  443. $this->container->expects($this->once())
  444. ->method('query')
  445. ->with(File::class)
  446. ->willReturn($fileEntityMock);
  447. /** @var MockObject|IEntity $extraEntity */
  448. $extraEntity = $this->createMock(IEntity::class);
  449. $this->dispatcher->expects($this->once())
  450. ->method('dispatchTyped')
  451. ->willReturnCallback(function (RegisterEntitiesEvent $e) use ($extraEntity): void {
  452. $this->manager->registerEntity($extraEntity);
  453. });
  454. $entities = $this->manager->getEntitiesList();
  455. $this->assertCount(2, $entities);
  456. $entityTypeCounts = array_reduce($entities, function (array $carry, IEntity $entity) {
  457. if ($entity instanceof File) {
  458. $carry[0]++;
  459. } elseif ($entity instanceof IEntity) {
  460. $carry[1]++;
  461. }
  462. return $carry;
  463. }, [0, 0]);
  464. $this->assertSame(1, $entityTypeCounts[0]);
  465. $this->assertSame(1, $entityTypeCounts[1]);
  466. }
  467. public function testValidateOperationOK(): void {
  468. $check = [
  469. 'class' => ICheck::class,
  470. 'operator' => 'is',
  471. 'value' => 'barfoo',
  472. ];
  473. $operationMock = $this->createMock(IOperation::class);
  474. $entityMock = $this->createMock(IEntity::class);
  475. $eventEntityMock = $this->createMock(IEntityEvent::class);
  476. $checkMock = $this->createMock(ICheck::class);
  477. $scopeMock = $this->createMock(ScopeContext::class);
  478. $scopeMock->expects($this->any())
  479. ->method('getScope')
  480. ->willReturn(IManager::SCOPE_ADMIN);
  481. $operationMock->expects($this->once())
  482. ->method('isAvailableForScope')
  483. ->with(IManager::SCOPE_ADMIN)
  484. ->willReturn(true);
  485. $operationMock->expects($this->once())
  486. ->method('validateOperation')
  487. ->with('test', [$check], 'operationData');
  488. $entityMock->expects($this->any())
  489. ->method('getEvents')
  490. ->willReturn([$eventEntityMock]);
  491. $eventEntityMock->expects($this->any())
  492. ->method('getEventName')
  493. ->willReturn('MyEvent');
  494. $checkMock->expects($this->any())
  495. ->method('supportedEntities')
  496. ->willReturn([IEntity::class]);
  497. $checkMock->expects($this->atLeastOnce())
  498. ->method('validateCheck');
  499. $this->container->expects($this->any())
  500. ->method('query')
  501. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  502. switch ($className) {
  503. case IOperation::class:
  504. return $operationMock;
  505. case IEntity::class:
  506. return $entityMock;
  507. case IEntityEvent::class:
  508. return $eventEntityMock;
  509. case ICheck::class:
  510. return $checkMock;
  511. default:
  512. return $this->createMock($className);
  513. }
  514. });
  515. $this->manager->validateOperation(IOperation::class, 'test', [$check], 'operationData', $scopeMock, IEntity::class, ['MyEvent']);
  516. }
  517. public function testValidateOperationCheckInputLengthError(): void {
  518. $check = [
  519. 'class' => ICheck::class,
  520. 'operator' => 'is',
  521. 'value' => str_pad('', IManager::MAX_CHECK_VALUE_BYTES + 1, 'FooBar'),
  522. ];
  523. $operationMock = $this->createMock(IOperation::class);
  524. $entityMock = $this->createMock(IEntity::class);
  525. $eventEntityMock = $this->createMock(IEntityEvent::class);
  526. $checkMock = $this->createMock(ICheck::class);
  527. $scopeMock = $this->createMock(ScopeContext::class);
  528. $scopeMock->expects($this->any())
  529. ->method('getScope')
  530. ->willReturn(IManager::SCOPE_ADMIN);
  531. $operationMock->expects($this->once())
  532. ->method('isAvailableForScope')
  533. ->with(IManager::SCOPE_ADMIN)
  534. ->willReturn(true);
  535. $operationMock->expects($this->once())
  536. ->method('validateOperation')
  537. ->with('test', [$check], 'operationData');
  538. $entityMock->expects($this->any())
  539. ->method('getEvents')
  540. ->willReturn([$eventEntityMock]);
  541. $eventEntityMock->expects($this->any())
  542. ->method('getEventName')
  543. ->willReturn('MyEvent');
  544. $checkMock->expects($this->any())
  545. ->method('supportedEntities')
  546. ->willReturn([IEntity::class]);
  547. $checkMock->expects($this->never())
  548. ->method('validateCheck');
  549. $this->container->expects($this->any())
  550. ->method('query')
  551. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  552. switch ($className) {
  553. case IOperation::class:
  554. return $operationMock;
  555. case IEntity::class:
  556. return $entityMock;
  557. case IEntityEvent::class:
  558. return $eventEntityMock;
  559. case ICheck::class:
  560. return $checkMock;
  561. default:
  562. return $this->createMock($className);
  563. }
  564. });
  565. try {
  566. $this->manager->validateOperation(IOperation::class, 'test', [$check], 'operationData', $scopeMock, IEntity::class, ['MyEvent']);
  567. } catch (\UnexpectedValueException $e) {
  568. $this->assertSame('The provided check value is too long', $e->getMessage());
  569. }
  570. }
  571. public function testValidateOperationDataLengthError(): void {
  572. $check = [
  573. 'class' => ICheck::class,
  574. 'operator' => 'is',
  575. 'value' => 'barfoo',
  576. ];
  577. $operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES + 1, 'FooBar');
  578. $operationMock = $this->createMock(IOperation::class);
  579. $entityMock = $this->createMock(IEntity::class);
  580. $eventEntityMock = $this->createMock(IEntityEvent::class);
  581. $checkMock = $this->createMock(ICheck::class);
  582. $scopeMock = $this->createMock(ScopeContext::class);
  583. $scopeMock->expects($this->any())
  584. ->method('getScope')
  585. ->willReturn(IManager::SCOPE_ADMIN);
  586. $operationMock->expects($this->once())
  587. ->method('isAvailableForScope')
  588. ->with(IManager::SCOPE_ADMIN)
  589. ->willReturn(true);
  590. $operationMock->expects($this->never())
  591. ->method('validateOperation');
  592. $entityMock->expects($this->any())
  593. ->method('getEvents')
  594. ->willReturn([$eventEntityMock]);
  595. $eventEntityMock->expects($this->any())
  596. ->method('getEventName')
  597. ->willReturn('MyEvent');
  598. $checkMock->expects($this->any())
  599. ->method('supportedEntities')
  600. ->willReturn([IEntity::class]);
  601. $checkMock->expects($this->never())
  602. ->method('validateCheck');
  603. $this->container->expects($this->any())
  604. ->method('query')
  605. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  606. switch ($className) {
  607. case IOperation::class:
  608. return $operationMock;
  609. case IEntity::class:
  610. return $entityMock;
  611. case IEntityEvent::class:
  612. return $eventEntityMock;
  613. case ICheck::class:
  614. return $checkMock;
  615. default:
  616. return $this->createMock($className);
  617. }
  618. });
  619. try {
  620. $this->manager->validateOperation(IOperation::class, 'test', [$check], $operationData, $scopeMock, IEntity::class, ['MyEvent']);
  621. } catch (\UnexpectedValueException $e) {
  622. $this->assertSame('The provided operation data is too long', $e->getMessage());
  623. }
  624. }
  625. public function testValidateOperationScopeNotAvailable(): void {
  626. $check = [
  627. 'class' => ICheck::class,
  628. 'operator' => 'is',
  629. 'value' => 'barfoo',
  630. ];
  631. $operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES + 1, 'FooBar');
  632. $operationMock = $this->createMock(IOperation::class);
  633. $entityMock = $this->createMock(IEntity::class);
  634. $eventEntityMock = $this->createMock(IEntityEvent::class);
  635. $checkMock = $this->createMock(ICheck::class);
  636. $scopeMock = $this->createMock(ScopeContext::class);
  637. $scopeMock->expects($this->any())
  638. ->method('getScope')
  639. ->willReturn(IManager::SCOPE_ADMIN);
  640. $operationMock->expects($this->once())
  641. ->method('isAvailableForScope')
  642. ->with(IManager::SCOPE_ADMIN)
  643. ->willReturn(false);
  644. $operationMock->expects($this->never())
  645. ->method('validateOperation');
  646. $entityMock->expects($this->any())
  647. ->method('getEvents')
  648. ->willReturn([$eventEntityMock]);
  649. $eventEntityMock->expects($this->any())
  650. ->method('getEventName')
  651. ->willReturn('MyEvent');
  652. $checkMock->expects($this->any())
  653. ->method('supportedEntities')
  654. ->willReturn([IEntity::class]);
  655. $checkMock->expects($this->never())
  656. ->method('validateCheck');
  657. $this->container->expects($this->any())
  658. ->method('query')
  659. ->willReturnCallback(function ($className) use ($operationMock, $entityMock, $eventEntityMock, $checkMock) {
  660. switch ($className) {
  661. case IOperation::class:
  662. return $operationMock;
  663. case IEntity::class:
  664. return $entityMock;
  665. case IEntityEvent::class:
  666. return $eventEntityMock;
  667. case ICheck::class:
  668. return $checkMock;
  669. default:
  670. return $this->createMock($className);
  671. }
  672. });
  673. try {
  674. $this->manager->validateOperation(IOperation::class, 'test', [$check], $operationData, $scopeMock, IEntity::class, ['MyEvent']);
  675. } catch (\UnexpectedValueException $e) {
  676. $this->assertSame('Operation OCP\WorkflowEngine\IOperation is invalid', $e->getMessage());
  677. }
  678. }
  679. }