currentDate = (new DateTime())->format('Y-m-d'); $this->statsAnrService = $this->getApplicationServiceLocator()->get(StatsAnrService::class); } protected function configureServiceManager(ServiceManager $serviceManager) { $serviceManager->setAllowOverride(true); $serviceLocator = $this->getApplicationServiceLocator(); $config = ['statsApi' => ['baseUrl' => 'http://url.com', 'apiKey' => 'token12345']]; $this->statsApiMockHandler = new MockHandler(); $statsApiProvider = new StatsApiProvider($config, $this->statsApiMockHandler); $serviceManager->setService(StatsApiProvider::class, $statsApiProvider); $this->connectedUserService = $this->createMock(ConnectedUserService::class); $serviceManager->setService(ConnectedUserService::class, $this->connectedUserService); $statsAnrService = new StatsAnrService( $serviceLocator->get(AnrTable::class), $serviceLocator->get(ScaleTable::class), $serviceLocator->get(InstanceRiskTable::class), $serviceLocator->get(InstanceRiskOpTable::class), $serviceLocator->get(ReferentialTable::class), $serviceLocator->get(SoaTable::class), $serviceLocator->get(StatsApiProvider::class), $this->connectedUserService, $serviceLocator->get(UserTable::class), $serviceLocator->get(SnapshotTable::class), $serviceLocator->get(SettingTable::class), $config ); $serviceManager->setService(StatsAnrService::class, $statsAnrService); $serviceManager->setAllowOverride(false); } public function testItThrowsTheErrorWhenTheTheStatsAlreadyGeneratedForToday() { $this->expectException(StatsAlreadyCollectedException::class); $this->expectExceptionMessage('The stats is already collected for today.'); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse([ new StatsDataObject([ 'type' => StatsDataObject::TYPE_RISK, 'anr' => '1232-31abcd-213efgh-123klmp', 'data' => [ 'total' => [ [ 'label' => 'Low risks', 'value' => 50, ], [ 'label' => 'Medium risks', 'value' => 30, ], [ 'label' => 'High risks', 'value' => 10, ], ], ], ]) ]))); $this->statsAnrService->collectStats(); } public function testItDoesNotSendTheStatsWhenTheDataIsEmpty() { $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsAnrService->collectStats([99, 78]); $this->assertEquals('GET', $this->statsApiMockHandler->getLastRequest()->getMethod()); } public function testItCanGenerateTheStatsForAllTheAnrs() { /** @var AnrTable $anrTable */ $anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class); $anrs = $anrTable->findAll(); $anrUuids = []; foreach ($anrs as $anr) { $anrUuids[] = $anr->getUuid(); } $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsApiMockHandler->append(new Response(201, [], '{"status": "ok"}')); $this->statsAnrService->collectStats(); $this->assertJsonStringEqualsJsonString( $this->getExpectedStatsDataJson($anrUuids), $this->statsApiMockHandler->getLastRequest()->getBody()->getContents() ); } public function testItGenerateTheStatsOnlyForPassedAnrs() { $anrIdsToGenerateTheStats = [1, 2, 3]; /** @var AnrTable $anrTable */ $anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class); $anrs = $anrTable->findByIds($anrIdsToGenerateTheStats); $anrUuids = []; foreach ($anrs as $num => $anr) { $anrUuids[] = $anr->getUuid(); } $this->assertCount(\count($anrIdsToGenerateTheStats), $anrUuids); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsApiMockHandler->append(new Response(201, [], '{"status": "ok"}')); $this->statsAnrService->collectStats($anrIdsToGenerateTheStats); $this->assertJsonStringEqualsJsonString( $this->getExpectedStatsDataJson($anrUuids), $this->statsApiMockHandler->getLastRequest()->getBody()->getContents() ); } public function testItThrowsTheExceptionIfUserIsNotLoggedIn() { $this->expectException(UserNotAuthorizedException::class); $this->expectExceptionMessage('User not authorized.'); $this->statsAnrService->getStats([]); } public function testItThrowsTheExceptionIfUserDoesNotHaveTheRightsToGetTheStats() { $this->expectException(AccessForbiddenException::class); $this->expectExceptionMessage('User does not have an access to the action.'); $user = $this->createMock(User::class); $user->expects($this->once())->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(false); $user->method('getUserAnrs')->willReturn(new ArrayCollection()); $this->connectedUserService ->expects($this->once()) ->method('getConnectedUser') ->willReturn($user); $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_CARTOGRAPHY, 'anrs' => []]); } public function testItThrowsLogicExceptionIfTypeIsNotPassed() { $this->expectException(LogicException::class); $this->expectExceptionMessage('Filter parameter \'type\' is mandatory to get the stats.'); $user = $this->createMock(User::class); $this->connectedUserService ->expects($this->once()) ->method('getConnectedUser') ->willReturn($user); $this->statsAnrService->getStats([]); } public function testItAddsToTheFilterAllowedForTheUserAnrUuids() { $user = $this->createMock(User::class); $user->expects($this->exactly(2))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(false); /** @var Anr $anr1 */ $anr1 = (new Anr())->setId(1); /** @var Anr $anr2 */ $anr2 = (new Anr())->setId(2); /** @var Anr $anr3 */ $anr3 = (new Anr())->setId(3); $user->method('getUserAnrs')->willReturn(new ArrayCollection([ (new UserAnr())->setAnr($anr1->generateAndSetUuid()), (new UserAnr())->setAnr($anr2->generateAndSetUuid()), (new UserAnr())->setAnr($anr3->generateAndSetUuid()), ])); $this->connectedUserService->expects($this->exactly(2))->method('getConnectedUser')->willReturn($user); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $stats = $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_COMPLIANCE]); $this->assertEmpty($stats); $defaultDates = [ 'date_from' => (new DateTime())->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'), 'date_to' => (new DateTime())->format('Y-m-d'), ]; $queryParams = []; parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals( array_merge([ 'anrs' => [$anr1->getUuid(), $anr2->getUuid(), $anr3->getUuid()], 'type' => StatsDataObject::TYPE_COMPLIANCE, 'get_last' => 0, ], $defaultDates), $queryParams ); $statsResponse = $this->getStatsResponse([ new StatsDataObject([ 'type' => StatsDataObject::TYPE_RISK, 'anr' => '1232-31abcd-213efgh-123klmp', 'data' => [ 'risks' => [], 'total' => [], ], ]) ]); $this->statsApiMockHandler->append(new Response(200, [], $statsResponse)); $stats = $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_RISK, 'anrs' => [1, 3, 7]]); $this->assertEquals($this->getStatsResponse($stats), $this->getStatsResponse()); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals( array_merge([ 'anrs' => [$anr1->getUuid(), $anr3->getUuid()], 'type' => StatsDataObject::TYPE_RISK, 'get_last' => 0, ], $defaultDates), $queryParams ); } public function testItAllowsToFilterBySpecificAnrsForCeoRoleOrGetItWithoutLimitations() { $user = $this->createMock(User::class); $user->expects($this->exactly(2))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(true); $user->expects($this->never())->method('getUserAnrs'); $this->connectedUserService->expects($this->exactly(2))->method('getConnectedUser')->willReturn($user); /** @var AnrTable $anrTable */ $anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class); $anrUuids = []; foreach ($anrTable->findByIds([1, 2, 3]) as $anr) { $anrUuids[] = $anr->getUuid(); } $defaultDates = [ 'date_from' => (new DateTime())->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'), 'date_to' => (new DateTime())->format('Y-m-d'), ]; $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsAnrService->getStats([ 'type' => StatsDataObject::TYPE_RISK, 'anrs' => [1, 2, 3, 99] // anr ID = 99 is not in thew db. ]); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals(array_merge([ 'anrs' => $anrUuids, 'type' => StatsDataObject::TYPE_RISK, 'get_last' => 0, ], $defaultDates), $queryParams); $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_VULNERABILITY]); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals( array_merge(['type' => StatsDataObject::TYPE_VULNERABILITY], $defaultDates + ['get_last' => 0]), $queryParams ); } public function testItCanSendDifferentParamsToGetTheStats() { $user = $this->createMock(User::class); $user->expects($this->exactly(3))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(true); $user->expects($this->never())->method('getUserAnrs'); $this->connectedUserService->expects($this->exactly(3))->method('getConnectedUser')->willReturn($user); /** @var AnrTable $anrTable */ $anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class); $anrUuids = []; foreach ($anrTable->findByIds([1, 2, 3, 4]) as $anr) { $anrUuids[] = $anr->getUuid(); } $datesRange = [ 'dateFrom' => (new DateTime())->modify('-1 year')->format('Y-m-d'), 'dateTo' => (new DateTime())->format('Y-m-d'), ]; $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsAnrService->getStats(array_merge([ 'anrs' => [1, 2, 3, 4], 'aggregationPeriod' => 'month', 'type' => StatsDataObject::TYPE_COMPLIANCE ], $datesRange)); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals(array_merge([ 'anrs' => $anrUuids, 'aggregation_period' => 'month', 'type' => StatsDataObject::TYPE_COMPLIANCE, 'get_last' => 0, ], [ 'date_from' => $datesRange['dateFrom'], 'date_to' => $datesRange['dateTo'], ]), $queryParams); $this->statsAnrService->getStats(array_merge([ 'aggregationPeriod' => 'week', 'type' => StatsDataObject::TYPE_VULNERABILITY ], $datesRange)); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals(array_merge([ 'aggregation_period' => 'week', 'get_last' => 0, 'type' => StatsDataObject::TYPE_VULNERABILITY ], [ 'date_from' => $datesRange['dateFrom'], 'date_to' => $datesRange['dateTo'], ]), $queryParams); $this->statsAnrService->getStats(array_merge([ 'getLast' => true, 'type' => StatsDataObject::TYPE_CARTOGRAPHY, ], $datesRange)); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals(array_merge([ 'get_last' => 1, 'type' => StatsDataObject::TYPE_CARTOGRAPHY ]), $queryParams); } public function testItFetchesStatsForDefaultPeriodIfFromAndToDatesAreNotPassed() { $user = $this->createMock(User::class); $user->expects($this->exactly(3))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(true); $user->expects($this->never())->method('getUserAnrs'); $this->connectedUserService->expects($this->exactly(3))->method('getConnectedUser')->willReturn($user); $defaultDates = [ 'dateFrom' => (new DateTime())->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'), 'dateTo' => (new DateTime())->format('Y-m-d'), ]; $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse())); $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_THREAT]); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals([ 'date_from' => $defaultDates['dateFrom'], 'date_to' => $defaultDates['dateTo'], 'type' => StatsDataObject::TYPE_THREAT, 'get_last' => 0, ], $queryParams); $this->statsAnrService->getStats([ 'type' => StatsDataObject::TYPE_THREAT, 'dateFrom' => (new DateTime())->modify('-6 months')->format('Y-m-d') ]); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals([ 'date_from' => (new DateTime())->modify('-6 months')->format('Y-m-d'), 'date_to' => $defaultDates['dateTo'], 'type' => StatsDataObject::TYPE_THREAT, 'get_last' => 0, ], $queryParams); $dateTo = (new DateTimeImmutable())->modify('-6 months'); $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_THREAT, 'dateTo' => $dateTo->format('Y-m-d')]); parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams); $this->assertEquals([ 'type' => StatsDataObject::TYPE_THREAT, 'date_from' => $dateTo->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'), 'date_to' => $dateTo->format('Y-m-d'), 'get_last' => 0, ], $queryParams); } private function getStatsResponse(array $results = []): string { return json_encode([ 'metadata' => [ 'count' => \count($results), 'offset' => 0, 'limit' => 0, ], 'data' => $results, ]); } private function getExpectedStatsDataJson(array $anrUuids): string { $statsData = json_decode( file_get_contents($this->testPath . '/data/expected_stats_data_for_my_print.json'), true ); $expectedStats = []; foreach ($anrUuids as $num => $anrUuid) { foreach ($statsData as $data) { $data['anr'] = $anrUuid; $data['date'] = $this->currentDate; $expectedStats[] = $data; } } return json_encode($expectedStats); } }