share(function ($DI) { return $this->loadApp($this->getApplicationPath()); }); self::$DI['cli'] = self::$DI->share(function ($DI) { return $this->loadCLI(); }); self::$DI['local-guzzle'] = self::$DI->share(function ($DI) { return new Guzzle(self::$DI['app']['conf']->get('servername')); }); self::$DI['client'] = self::$DI->share(function ($DI) { return new Client($DI['app'], []); }); self::$DI['feed_public'] = self::$DI->share(function ($DI) { return $DI['app']['repo.feeds']->find(self::$fixtureIds['feed']['public']['feed']); }); self::$DI['feed_public_entry'] = self::$DI->share(function ($DI) { return $DI['app']['repo.feed-entries']->find(self::$fixtureIds['feed']['public']['entry']); }); self::$DI['feed_public_token'] = self::$DI->share(function ($DI) { return $DI['app']['repo.feed-tokens']->find(self::$fixtureIds['feed']['public']['token']); }); self::$DI['feed_private'] = self::$DI->share(function ($DI) { return $DI['app']['repo.feeds']->find(self::$fixtureIds['feed']['private']['feed']); }); self::$DI['feed_private_entry'] = self::$DI->share(function ($DI) { return $DI['app']['repo.feed-entries']->find(self::$fixtureIds['feed']['private']['entry']); }); self::$DI['feed_private_token'] = self::$DI->share(function ($DI) { return $DI['app']['repo.feed-tokens']->find(self::$fixtureIds['feed']['private']['token']); }); self::$DI['basket_1'] = self::$DI->share(function ($DI) { return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_1']); }); self::$DI['basket_2'] = self::$DI->share(function ($DI) { return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_2']); }); self::$DI['basket_3'] = self::$DI->share(function ($DI) { return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_3']); }); self::$DI['basket_4'] = self::$DI->share(function ($DI) { return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_4']); }); self::$DI['token_1'] = self::$DI->share(function ($DI) { return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_1']); }); self::$DI['token_2'] = self::$DI->share(function ($DI) { return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_2']); }); self::$DI['token_invalid'] = self::$DI->share(function ($DI) { return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_invalid']); }); self::$DI['token_validation'] = self::$DI->share(function ($DI) { return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_validation']); }); $users = [ 'user' => 'test_phpunit', 'user_1' => 'user_1', 'user_2' => 'user_2', 'user_3' => 'user_3', 'user_guest' => 'user_guest', 'user_notAdmin' => 'test_phpunit_not_admin', 'user_alt1' => 'test_phpunit_alt1', 'user_alt2' => 'test_phpunit_alt2', 'user_template' => 'user_template', ]; $userFactory = function ($fixtureName) { if ('user_guest' === $fixtureName) { return function ($DI) use ($fixtureName) { return $DI['app']['repo.users']->find(self::$fixtureIds['user'][$fixtureName]); }; } return function ($DI) use ($fixtureName) { $user = $DI['app']['repo.users']->find(self::$fixtureIds['user'][$fixtureName]); self::resetUsersRights($DI['app'], $user); return $user; }; }; foreach ($users as $name => $fixtureName) { self::$DI[$name] = self::$DI->share($userFactory($fixtureName)); } self::$DI['registration_1'] = self::$DI->share(function ($DI) { return $DI['app']['repo.registrations']->find(self::$fixtureIds['registrations']['registration_1']); }); self::$DI['registration_2'] = self::$DI->share(function ($DI) { return $DI['app']['repo.registrations']->find(self::$fixtureIds['registrations']['registration_2']); }); self::$DI['registration_3'] = self::$DI->share(function ($DI) { return $DI['app']['repo.registrations']->find(self::$fixtureIds['registrations']['registration_3']); }); self::$DI['oauth2-app-user'] = self::$DI->share(function ($DI) { return $DI['app']['repo.api-applications']->find(self::$fixtureIds['oauth']['user']); }); self::$DI['oauth2-app-user1'] = self::$DI->share(function ($DI) { return $DI['app']['repo.api-applications']->find(self::$fixtureIds['oauth']['user1']); }); self::$DI['webhook-event'] = self::$DI->share(function ($DI) { return $DI['app']['repo.webhook-event']->find(self::$fixtureIds['webhook']['event']); }); self::$DI['oauth2-app-user-not-admin'] = self::$DI->share(function ($DI) { return $DI['app']['repo.api-applications']->find(self::$fixtureIds['oauth']['user-not-admin']); }); self::$DI['oauth2-app-acc-user'] = self::$DI->share(function ($DI) { return $DI['app']['repo.api-accounts']->find(self::$fixtureIds['oauth']['acc-user']); }); self::$DI['oauth2-app-acc-user-not-admin'] = self::$DI->share(function ($DI) { return $DI['app']['repo.api-accounts']->find(self::$fixtureIds['oauth']['acc-user-not-admin']); }); self::$DI['logger'] = self::$DI->share(function () { $logger = new Logger('tests'); $logger->pushHandler(new NullHandler()); return $logger; }); self::$DI['collection'] = self::$DI->share(function ($DI) { return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll']); }); self::$DI['collectionReference'] = self::$DI->share(function ($DI) { /** @var \Alchemy\Phrasea\Collection\Reference\DbalCollectionReferenceRepository $repo */ $repo = self::$DI['app']['repo.collection-references']; return $repo->find(self::$fixtureIds['collection']['coll']); }); self::$DI['collection_no_access'] = self::$DI->share(function ($DI) { return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll_no_access']); }); self::$DI['collection_no_access_by_status'] = self::$DI->share(function ($DI) { return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll_no_status']); }); self::$DI['lazaret_1'] = self::$DI->share(function ($DI) { return $DI['app']['orm.em']->find('Phraseanet:LazaretFile', self::$fixtureIds['lazaret']['lazaret_1']); }); foreach (range(1, 7) as $i) { self::$DI['record_' . $i] = self::$DI->share(function ($DI) use ($i) { return new \record_adapter($DI['app'], self::$fixtureIds['databox']['records'], self::$fixtureIds['record']['record_'.$i]); }); } foreach (range(1, 3) as $i) { self::$DI['record_story_' . $i] = self::$DI->share(function ($DI) use ($i) { return new \record_adapter($DI['app'], self::$fixtureIds['databox']['records'], self::$fixtureIds['record']['record_story_'.$i]); }); } self::$DI['record_no_access_resolver'] = self::$DI->protect(function () { $id = 'no_access'; if (isset(self::$fixtureIds['records'][$id])) { return self::$fixtureIds['records'][$id]; } self::$recordsInitialized[] = $id; $file = new File(self::$DI['app'], self::$DI['app']['mediavorus']->guess(__DIR__ . '/../files/cestlafete.jpg'), self::$DI['collection_no_access']); $record = record_adapter::createFromFile($file, self::$DI['app']); self::$DI['app']['subdef.generator']->generateSubdefs($record); self::$fixtureIds['records'][$id] = $record->getRecordId(); return self::$fixtureIds['records'][$id]; }); self::$DI['record_no_access_by_status_resolver'] = self::$DI->protect(function () { $id = 'no_access_by_status'; if (isset(self::$fixtureIds['records'][$id])) { return self::$fixtureIds['records'][$id]; } self::$recordsInitialized[] = $id; $file = new File(self::$DI['app'], self::$DI['app']['mediavorus']->guess(__DIR__ . '/../files/cestlafete.jpg'), self::$DI['collection_no_access_by_status']); $record = record_adapter::createFromFile($file, self::$DI['app']); self::$DI['app']['subdef.generator']->generateSubdefs($record); self::$fixtureIds['records'][$id] = $record->getRecordId(); return self::$fixtureIds['records'][$id]; }); self::$DI['record_no_access'] = self::$DI->share(function ($DI) { return new \record_adapter($DI['app'], self::$fixtureIds['databox']['records'], $DI['record_no_access_resolver']()); }); self::$DI['record_no_access_by_status'] = self::$DI->share(function ($DI) { return new \record_adapter($DI['app'], self::$fixtureIds['databox']['records'], $DI['record_no_access_by_status_resolver']()); }); static $decodedFixtureIds; if (is_null($decodedFixtureIds)) { $decodedFixtureIds = json_decode(file_get_contents(sys_get_temp_dir().'/fixtures.json'), true); } self::$fixtureIds = $decodedFixtureIds; } /** * @return Application */ public function getApplication() { return self::$DI['app']; } /** * @return databox */ public function getFirstDatabox(Application $app) { $databoxes = $app->getDataboxes(); return reset($databoxes); } /** * @return Client */ public function getClient() { return self::$DI['client']; } /** * @return record_adapter */ public function getRecord1() { return self::$DI['record_1']; } /** * @return record_adapter */ public function getRecord2() { return self::$DI['record_2']; } /** * @return record_adapter */ public function getRecordStory1() { return self::$DI['record_story_1']; } /** * @return collection */ public function getCollection() { return self::$DI['collection']; } /** * @return CollectionReference */ public function getCollectionReference() { return self::$DI['collectionReference']; } public static function tearDownAfterClass() { gc_collect_cycles(); parent::tearDownAfterClass(); } protected function loadCLI($environment = Application::ENV_TEST) { $cli = new CLI('cli test', null, $environment); $this->addMocks($cli); $this->addAppCacheFlush($cli); return $cli; } /** * @param null|string $path * @param string $environment * @return Application */ protected function loadApp($path = null, $environment = Application::ENV_TEST) { if (null !== $path) { $app = require __DIR__ . '/../../' . $path; } else { $app = new Application($environment); } $this->addAppCacheFlush($app); $this->loadDb($app); $this->addMocks($app); $app->boot(); return $app; } protected function addAppCacheFlush(Application $app) { $app['phraseanet.cache-service'] = $app->share($app->extend('phraseanet.cache-service', function (CacheManager $cache) { $cache->flushAll(); return $cache; })); } protected function loadDb($app) { // copy db.ref.sqlite to db.sqlite to re-initialize db with empty values $app['filesystem']->copy($app['db.fixture.info']['path'], $app['db.test.info']['path'], true); } protected function addMocks(Application $app) { $app['form.csrf_provider'] = $app->share(function () { return new CsrfTestProvider(); }); $app['url_generator'] = $app->share($app->extend('url_generator', function ($generator, $app) { $host = parse_url($app['conf']->get('servername'), PHP_URL_HOST); $generator->setContext(new RequestContext('', 'GET', $host ?: $app['conf']->get('servername'))); return $generator; })); $app['task-manager.notifier'] = $app->share($app->extend('task-manager.notifier', function (Notifier $notifier) { $notifier->setTimeout(0.0001); return $notifier; })); $app['translator'] = $this->createTranslatorMock(); $app['phraseanet.SE.subscriber'] = new PhraseanetSeTestSubscriber(); $app['orm.em'] = $app->extend('orm.em', function($em, $app) { return $app['orm.ems'][$app['db.test.hash.key']]; }); $app['browser'] = $app->share($app->extend('browser', function ($browser) { $browser->setUserAgent(self::USER_AGENT_FIREFOX8MAC); return $browser; })); $app['notification.deliverer'] = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer') ->disableOriginalConstructor() ->getMock(); $app['notification.deliverer']->expects($this->any()) ->method('deliver') ->willReturn(0); } public function tearDown() { ACLProvider::purge(); \collection::purge(); \databox::purge(); \caption_field::purge(); \caption_Field_Value::purge(); \databox_field::purge(); \thesaurus_xpath::purge(); self::deleteResources(); // close all connection self::$DI['app']['connection.pool.manager']->closeAll(); /** * Kris Wallsmith pro-tip * @see http://kriswallsmith.net/post/18029585104/faster-phpunit */ $refl = new ReflectionObject($this); foreach ($refl->getProperties() as $prop) { if (!$prop->isStatic() && 0 !== strpos($prop->getDeclaringClass()->getName(), 'PHPUnit_') && 0 !== strpos($prop->getDeclaringClass()->getName(), 'Phraseanet')) { $prop->setAccessible(true); $prop->setValue($this, null); } } $refl = null; parent::tearDown(); //In case some executed script modify 'max_execution_time' ini var //Initialize set_time_limit(0) which is the default value for PHP CLI set_time_limit(0); } protected function assertForbiddenResponse(Response $response) { $this->assertEquals(403, $response->getStatusCode()); $this->assertTrue(false !== stripos($response->getContent(), 'Sorry, you do have access to the page you are looking for')); } protected function assertBadResponse(Response $response) { $this->assertEquals(400, $response->getStatusCode()); $this->assertTrue(false !== stripos($response->getContent(), 'bad request')); } protected function assertNotFoundResponse(Response $response) { $this->assertEquals(404, $response->getStatusCode()); $this->assertTrue(false !== stripos($response->getContent(), 'Sorry, the page you are looking for could not be found')); } protected function assertDateAtom($date) { return $this->assertRegExp('/\d{4}[-]\d{2}[-]\d{2}[T]\d{2}[:]\d{2}[:]\d{2}[+]\d{2}[:]\d{2}/', $date); } protected function set_user_agent($user_agent, Application $app) { $app['browser']->setUserAgent($user_agent); $app->register(new \Silex\Provider\TwigServiceProvider()); $app->register(new \Alchemy\Phrasea\Core\Provider\TwigServiceProvider()); self::$DI['client'] = self::$DI->share(function ($DI) use ($app) { return new Client($app, []); }); } /** * @param string $method * @param string $uri * @param array $parameters * @param array $server * @param string $content * * @return Response */ protected function request($method, $uri, array $parameters = [], array $server = [], $content = null) { $client = $this->getClient(); $client->request($method, $uri, $parameters, [], $server, $content); return $client->getResponse(); } /** * Calls a URI as XMLHTTP request. * * @param string $method The request method * @param string $uri The URI to fetch * @param array $parameters The Request parameters * @param string $httpAccept Contents of the Accept header * * @return Response */ protected function XMLHTTPRequest($method, $uri, array $parameters = [], $httpAccept = 'application/json') { return $this->request($method, $uri, $parameters, [ 'HTTP_ACCEPT' => $httpAccept, 'HTTP_X-Requested-With' => 'XMLHttpRequest', ]); } protected static function resetUsersRights(Application $app, User $user) { switch ($user->getId()) { case self::$fixtureIds['user']['test_phpunit']: self::giveRightsToUser($app, $user); $app->getAclForUser($user)->set_admin(true); $app->getAclForUser($user)->revoke_access_from_bases([self::$DI['collection_no_access']->get_base_id()]); $app->getAclForUser($user)->set_masks_on_base(self::$DI['collection_no_access_by_status']->get_base_id(), '00000000000000000000000000010000', '00000000000000000000000000010000', '00000000000000000000000000010000', '00000000000000000000000000010000'); break; case self::$fixtureIds['user']['user_1']: case self::$fixtureIds['user']['user_2']: case self::$fixtureIds['user']['user_3']: case self::$fixtureIds['user']['test_phpunit_not_admin']: case self::$fixtureIds['user']['test_phpunit_alt1']: case self::$fixtureIds['user']['test_phpunit_alt2']: case self::$fixtureIds['user']['user_template']: self::giveRightsToUser($app, $user); $app->getAclForUser($user)->set_admin(false); $app->getAclForUser($user)->revoke_access_from_bases([self::$DI['collection_no_access']->get_base_id()]); $app->getAclForUser($user)->set_masks_on_base(self::$DI['collection_no_access_by_status']->get_base_id(), '00000000000000000000000000010000', '00000000000000000000000000010000', '00000000000000000000000000010000', '00000000000000000000000000010000'); break; default: throw new \InvalidArgumentException(sprintf('User %s not found', $user->getLogin())); } } /** * Gives Bases Rights to User. * * @param User $user */ public static function giveRightsToUser(Application $app, User $user, $base_ids = null, $force = false) { $app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_GLOBAL_RIGHTS); $app->getAclForUser($user)->delete_data_from_cache(databox::CACHE_COLLECTIONS); $app->getAclForUser($user)->give_access_to_sbas(array_keys($app->getDataboxes())); foreach ($app->getDataboxes() as $databox) { $app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_SBAS); $app->getAclForUser($user)->update_rights_to_sbas( $databox->get_sbas_id(), [ \ACL::BAS_MANAGE => true, \ACL::BAS_MODIFY_STRUCT => true, \ACL::BAS_MODIF_TH => true, \ACL::BAS_CHUPUB => true ] ); foreach ($databox->get_collections() as $collection) { if (null !== $base_ids && !in_array($collection->get_base_id(), (array) $base_ids, true)) { continue; } $base_id = $collection->get_base_id(); if ($app->getAclForUser($user)->has_access_to_base($base_id) && false === $force) { continue; } $app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_BAS); $app->getAclForUser($user)->give_access_to_base([$base_id]); $app->getAclForUser($user)->update_rights_to_base( $base_id, [ \ACL::ORDER_MASTER => true ] ); $app->getAclForUser($user)->update_rights_to_base( $collection->get_base_id(), [ 'creationdate' => '1', // todo : wtf \ACL::CANPUTINALBUM => true, \ACL::CANDWNLDHD => true, \ACL::NOWATERMARK => true, \ACL::CANDWNLDPREVIEW => true, \ACL::CANCMD => true, \ACL::CANADMIN => true, \ACL::CANREPORT => true, \ACL::CANPUSH => true, \ACL::CANADDRECORD => true, \ACL::CANMODIFRECORD => true, \ACL::CANDELETERECORD => true, \ACL::CHGSTATUS => true, \ACL::IMGTOOLS => true, \ACL::COLL_MANAGE => true, \ACL::COLL_MODIFY_STRUCT => true, \ACL::BAS_MODIFY_STRUCT => true ] ); } } } /** * Deletes previously created Resources. */ private static function deleteResources() { if (!empty(self::$recordsInitialized)) { foreach (self::$recordsInitialized as $i) { self::$DI['record_' . $i]->delete(); } self::$recordsInitialized = []; } // Clear fixtures self::$fixtureIds = []; } /** * Authenticates self::['user'] against application. * * @param Application $app * @param User $user */ protected function authenticate(Application $app, User $user = null) { /** @var User $user */ $user = $user ?: self::$DI['user']; $app['session']->clear(); $app['session']->set('usr_id', $user->getId()); $session = new Session(); $session->setUser($user); $session->setUserAgent(''); $app['orm.em']->persist($session); $app['orm.em']->flush(); $app['session']->set('session_id', $session->getId()); $app->getAuthenticator()->reinitUser(); } /** * Logout authenticated user from application. * * @param Application $app */ protected function logout(Application $app) { $app['session']->clear(); $app->getAuthenticator()->reinitUser(); } protected function assertXMLHTTPBadJsonResponse(Response $response) { $this->assertEquals(200, $response->getStatusCode()); $data = json_decode($response->getContent(), true); $this->assertTrue(is_array($data)); $this->assertFalse($data['success']); } protected function mockNotificationDeliverer($expectedMail, $qty = 1, $receipt = null) { $app = $this->getApplication(); $delivererMock = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer') ->disableOriginalConstructor() ->getMock(); $delivererMock->expects($this->exactly($qty)) ->method('deliver') ->with($this->isInstanceOf($expectedMail), $this->equalTo($receipt)); $app['notification.deliverer'] = $delivererMock; } protected function mockUserNotificationSettings($notificationName, $returnValue = true) { $app = $this->getApplication(); if (false === $app['settings'] instanceof \PHPUnit_Framework_MockObject_MockObject) { $app['settings'] = $this->getMockBuilder('Alchemy\Phrasea\Core\Configuration\DisplaySettingService') ->disableOriginalConstructor() ->getMock(); } $app['settings'] ->expects($this->any()) ->method('getUserNotificationSetting') ->with( $this->isInstanceOf('Alchemy\Phrasea\Model\Entities\User'), $this->equalTo($notificationName) ) ->will($this->returnValue($returnValue)); $app['setting'] = 'toto'; } public function createGeneratorMock() { return $this->getMockBuilder('Randomlib\Generator') ->disableOriginalConstructor() ->getMock(); } public function createAppboxMock() { return $this->getMockBuilder('appbox') ->disableOriginalConstructor() ->getMock(); } public function createUserMock() { return $this->getMock('Alchemy\Phrasea\Model\Entities\User'); } public function removeUser(Application $app, User $user) { $app['orm.em']->remove($user); $app['orm.em']->flush(); } protected function createLoggerMock() { return $this->getMock('Psr\Log\LoggerInterface'); } protected function createMonologMock() { return $this->getMockBuilder('Monolog\Logger') ->disableOriginalConstructor() ->getMock(); } protected function createEntityRepositoryMock() { return $this->getMockBuilder('Doctrine\ORM\EntityRepository') ->disableOriginalConstructor() ->getMock(); } protected function createEntityManagerMock() { return $this->getMockBuilder('Doctrine\ORM\EntityManager') ->disableOriginalConstructor() ->getMock(); } protected function assertDateNear($expected, $tested, $precision = 1) { $tested = $tested instanceof \DateTime ? $tested : new \DateTime($tested); $expected = $expected instanceof \DateTime ? $expected : new \DateTime($expected); $this->assertLessThanOrEqual($precision, abs($expected->format('U') - $tested->format('U'))); } protected function createSearchEngineMock() { $mock = $this->getMock(SearchEngineInterface::class); $mock->expects($this->any()) ->method('getStatus') ->will($this->returnValue([])); return $mock; } protected function setSessionFormToken($formName) { $randomValue = bin2hex(random_bytes(35)); self::$DI['app']['session']->set($formName.'_token', $randomValue); return $randomValue; } }