notFoundType = $this->prophesize(NotFoundType::class); $this->visitsTracker = $this->prophesize(VisitsTrackerInterface::class); $this->requestTracker = new RequestTracker( $this->visitsTracker->reveal(), new TrackingOptions([ 'disable_track_param' => 'foobar', 'disable_tracking_from' => ['80.90.100.110', '192.168.10.0/24', '1.2.*.*'], ]), ); $this->request = ServerRequestFactory::fromGlobals()->withAttribute( NotFoundType::class, $this->notFoundType->reveal(), ); } /** * @test * @dataProvider provideNonTrackingRequests */ public function trackingIsDisabledWhenRequestDoesNotMeetConditions(ServerRequestInterface $request): void { $shortUrl = ShortUrl::withLongUrl(self::LONG_URL); $this->requestTracker->trackIfApplicable($shortUrl, $request); $this->visitsTracker->track(Argument::cetera())->shouldNotHaveBeenCalled(); } public function provideNonTrackingRequests(): iterable { yield 'forwarded from head' => [ServerRequestFactory::fromGlobals()->withAttribute( ImplicitHeadMiddleware::FORWARDED_HTTP_METHOD_ATTRIBUTE, RequestMethodInterface::METHOD_HEAD, )]; yield 'disable track param' => [ServerRequestFactory::fromGlobals()->withQueryParams(['foobar' => 'foo'])]; yield 'disable track param as null' => [ ServerRequestFactory::fromGlobals()->withQueryParams(['foobar' => null]), ]; yield 'exact remote address' => [ServerRequestFactory::fromGlobals()->withAttribute( IpAddressMiddlewareFactory::REQUEST_ATTR, '80.90.100.110', )]; yield 'matching wildcard remote address' => [ServerRequestFactory::fromGlobals()->withAttribute( IpAddressMiddlewareFactory::REQUEST_ATTR, '1.2.3.4', )]; yield 'matching CIDR block remote address' => [ServerRequestFactory::fromGlobals()->withAttribute( IpAddressMiddlewareFactory::REQUEST_ATTR, '192.168.10.100', )]; } /** @test */ public function trackingHappensOverShortUrlsWhenRequestMeetsConditions(): void { $shortUrl = ShortUrl::withLongUrl(self::LONG_URL); $this->requestTracker->trackIfApplicable($shortUrl, $this->request); $this->visitsTracker->track($shortUrl, Argument::type(Visitor::class))->shouldHaveBeenCalledOnce(); } /** @test */ public function baseUrlErrorIsTracked(): void { $isBaseUrl = $this->notFoundType->isBaseUrl()->willReturn(true); $isRegularNotFound = $this->notFoundType->isRegularNotFound()->willReturn(false); $isInvalidShortUrl = $this->notFoundType->isInvalidShortUrl()->willReturn(false); $this->requestTracker->trackNotFoundIfApplicable($this->request); $isBaseUrl->shouldHaveBeenCalledOnce(); $isRegularNotFound->shouldNotHaveBeenCalled(); $isInvalidShortUrl->shouldNotHaveBeenCalled(); $this->visitsTracker->trackBaseUrlVisit(Argument::type(Visitor::class))->shouldHaveBeenCalledOnce(); $this->visitsTracker->trackRegularNotFoundVisit(Argument::type(Visitor::class))->shouldNotHaveBeenCalled(); $this->visitsTracker->trackInvalidShortUrlVisit(Argument::type(Visitor::class))->shouldNotHaveBeenCalled(); } /** @test */ public function regularNotFoundErrorIsTracked(): void { $isBaseUrl = $this->notFoundType->isBaseUrl()->willReturn(false); $isRegularNotFound = $this->notFoundType->isRegularNotFound()->willReturn(true); $isInvalidShortUrl = $this->notFoundType->isInvalidShortUrl()->willReturn(false); $this->requestTracker->trackNotFoundIfApplicable($this->request); $isBaseUrl->shouldHaveBeenCalledOnce(); $isRegularNotFound->shouldHaveBeenCalledOnce(); $isInvalidShortUrl->shouldNotHaveBeenCalled(); $this->visitsTracker->trackBaseUrlVisit(Argument::type(Visitor::class))->shouldNotHaveBeenCalled(); $this->visitsTracker->trackRegularNotFoundVisit(Argument::type(Visitor::class))->shouldHaveBeenCalledOnce(); $this->visitsTracker->trackInvalidShortUrlVisit(Argument::type(Visitor::class))->shouldNotHaveBeenCalled(); } /** @test */ public function invalidShortUrlErrorIsTracked(): void { $isBaseUrl = $this->notFoundType->isBaseUrl()->willReturn(false); $isRegularNotFound = $this->notFoundType->isRegularNotFound()->willReturn(false); $isInvalidShortUrl = $this->notFoundType->isInvalidShortUrl()->willReturn(true); $this->requestTracker->trackNotFoundIfApplicable($this->request); $isBaseUrl->shouldHaveBeenCalledOnce(); $isRegularNotFound->shouldHaveBeenCalledOnce(); $isInvalidShortUrl->shouldHaveBeenCalledOnce(); $this->visitsTracker->trackBaseUrlVisit(Argument::type(Visitor::class))->shouldNotHaveBeenCalled(); $this->visitsTracker->trackRegularNotFoundVisit(Argument::type(Visitor::class))->shouldNotHaveBeenCalled(); $this->visitsTracker->trackInvalidShortUrlVisit(Argument::type(Visitor::class))->shouldHaveBeenCalledOnce(); } /** * @test * @dataProvider provideNonTrackingRequests */ public function notFoundIsNotTrackedIfRequestDoesNotMeetConditions(ServerRequestInterface $request): void { $this->requestTracker->trackNotFoundIfApplicable($request); $this->visitsTracker->trackBaseUrlVisit(Argument::cetera())->shouldNotHaveBeenCalled(); $this->visitsTracker->trackRegularNotFoundVisit(Argument::cetera())->shouldNotHaveBeenCalled(); $this->visitsTracker->trackInvalidShortUrlVisit(Argument::cetera())->shouldNotHaveBeenCalled(); } }