@@ -33,14 +33,15 @@ public function setUp(): void
3333 {
3434 parent ::setUp ();
3535
36+ Fixture::createSuperUser ();
3637 $ this ->setSuperUser ();
3738 Fixture::createWebsite ('2010-01-01 ' );
3839 }
3940
4041 public function testGetStandAndEndDateUsesNowWhenDateOutOfRange ()
4142 {
4243 $ model = new Model ();
43- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'year ' , (date ('Y ' ) + 1 ) . '-01-01 ' );
44+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'year ' , (date ('Y ' ) + 1 ) . '-01-01 ' );
4445
4546 $ validDates = $ this ->getValidNowDates ();
4647
@@ -52,7 +53,7 @@ public function testGetStandAndEndDateUsesNowWhenDateOutOfRange()
5253 public function testGetStandAndEndDateUsesNowWhenEndDateOutOfRange ()
5354 {
5455 $ model = new Model ();
55- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'year ' , date ('Y ' ) . '-01-01 ' );
56+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'year ' , date ('Y ' ) . '-01-01 ' );
5657
5758 $ validDates = $ this ->getValidNowDates ();
5859
@@ -157,7 +158,7 @@ public function testQueryAdjacentVisitorIdMaxExecutionTime()
157158 public function testGetStandAndEndDate ()
158159 {
159160 $ model = new Model ();
160- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'year ' , '2018-02-01 ' );
161+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'year ' , '2018-02-01 ' );
161162
162163 $ this ->assertEquals ('2018-01-01 00:00:00 ' , $ dateStart ->getDatetime ());
163164 $ this ->assertEquals ('2019-01-01 00:00:00 ' , $ dateEnd ->getDatetime ());
@@ -214,8 +215,8 @@ public function testIsLookingAtMoreThanOneDayWhenStartAndEndDateIsSetMoreThanOne
214215 public function testMakeLogVisitsQueryString ()
215216 {
216217 $ model = new Model ();
217- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
218- list ( $ sql , $ bind) = $ model ->makeLogVisitsQueryString (
218+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
219+ [ $ sql , $ bind] = $ model ->makeLogVisitsQueryString (
219220 $ idSite = 1 ,
220221 $ dateStart ,
221222 $ dateEnd ,
@@ -249,8 +250,8 @@ public function testMakeLogVisitsQueryStringWithMultipleIdSites()
249250 });
250251
251252 $ model = new Model ();
252- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
253- list ( $ sql , $ bind) = $ model ->makeLogVisitsQueryString (
253+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
254+ [ $ sql , $ bind] = $ model ->makeLogVisitsQueryString (
254255 $ idSite = 1 ,
255256 $ dateStart ,
256257 $ dateEnd ,
@@ -283,8 +284,8 @@ public function testMakeLogVisitsQueryStringWithOffset()
283284 {
284285 $ model = new Model ();
285286
286- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
287- list ( $ sql , $ bind) = $ model ->makeLogVisitsQueryString (
287+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
288+ [ $ sql , $ bind] = $ model ->makeLogVisitsQueryString (
288289 $ idSite = 1 ,
289290 $ dateStart ,
290291 $ dateEnd ,
@@ -315,8 +316,8 @@ public function testMakeLogVisitsQueryStringWithOffset()
315316 public function testMakeLogVisitsQueryStringWhenSegment ()
316317 {
317318 $ model = new Model ();
318- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
319- list ( $ sql , $ bind) = $ model ->makeLogVisitsQueryString (
319+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
320+ [ $ sql , $ bind] = $ model ->makeLogVisitsQueryString (
320321 $ idSite = 1 ,
321322 $ dateStart ,
322323 $ dateEnd ,
@@ -357,8 +358,8 @@ public function testMakeLogVisitsQueryStringAddsMaxExecutionHintIfConfigured()
357358 Db \Schema::unsetInstance ();
358359
359360 $ model = new Model ();
360- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
361- list ( $ sql , $ bind) = $ model ->makeLogVisitsQueryString (
361+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
362+ [ $ sql , $ bind] = $ model ->makeLogVisitsQueryString (
362363 $ idSite = 1 ,
363364 $ dateStart ,
364365 $ dateEnd ,
@@ -382,8 +383,8 @@ public function testMakeLogVisitsQueryStringDoesNotAddsMaxExecutionHintForVisito
382383 $ this ->setMaxExecutionTime (30 );
383384
384385 $ model = new Model ();
385- list ( $ dateStart , $ dateEnd) = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
386- list ( $ sql , $ bind) = $ model ->makeLogVisitsQueryString (
386+ [ $ dateStart , $ dateEnd] = $ model ->getStartAndEndDate ($ idSite = 1 , 'month ' , '2010-01-01 ' );
387+ [ $ sql , $ bind] = $ model ->makeLogVisitsQueryString (
387388 $ idSite = 1 ,
388389 $ dateStart ,
389390 $ dateEnd ,
@@ -523,6 +524,230 @@ private function splitDatesIntoMultipleQueries($startDate, $endDate, $limit, $of
523524 }, $ queries );
524525 }
525526
527+ public function testQueryLogVisitsSkipsOffsetAcrossSplitDateRanges ()
528+ {
529+ // build visits across 3 days so the query will be split into multiple ranges
530+ $ this ->trackVisitAtTime ('2010-01-01 03:00:00 ' );
531+ $ this ->trackVisitAtTime ('2010-01-01 06:10:00 ' );
532+ $ this ->trackVisitAtTime ('2010-01-01 09:20:00 ' );
533+ $ this ->trackVisitAtTime ('2010-01-02 03:00:00 ' );
534+ $ this ->trackVisitAtTime ('2010-01-02 06:10:00 ' );
535+ $ this ->trackVisitAtTime ('2010-01-03 03:00:00 ' );
536+ $ this ->trackVisitAtTime ('2010-01-03 06:10:00 ' );
537+ $ this ->trackVisitAtTime ('2010-01-03 09:20:00 ' );
538+
539+ $ this ->assertEquals (8 , $ this ->countVisitsBetween ('2010-01-01 00:00:00 ' , '2010-01-04 00:00:00 ' ));
540+
541+ $ model = new Model ();
542+
543+ // sanity check: without offset we see all visits
544+ $ allVisits = $ model ->queryLogVisits (
545+ 1 ,
546+ 'range ' ,
547+ '2010-01-01,2010-01-03 ' ,
548+ $ segment = '' ,
549+ $ offset = 0 ,
550+ $ limit = 10 ,
551+ $ visitorId = false ,
552+ $ minTimestamp = false ,
553+ $ filterSortOrder = 'desc '
554+ );
555+ $ this ->assertCount (8 , $ allVisits );
556+
557+ $ visits = $ model ->queryLogVisits (
558+ 1 ,
559+ 'range ' ,
560+ '2010-01-01,2010-01-03 ' ,
561+ $ segment = '' ,
562+ $ offset = 6 ,
563+ $ limit = 2 ,
564+ $ visitorId = false ,
565+ $ minTimestamp = false ,
566+ $ filterSortOrder = 'desc '
567+ );
568+
569+ $ this ->assertCount (2 , $ visits );
570+ $ this ->assertEquals ('2010-01-01 06:10:00 ' , $ visits [0 ]['visit_last_action_time ' ]);
571+ $ this ->assertEquals ('2010-01-01 03:00:00 ' , $ visits [1 ]['visit_last_action_time ' ]);
572+ }
573+
574+ public function testQueryLogVisitsOffsetAcrossSplitDateRangesAscending ()
575+ {
576+ $ this ->trackVisitAtTime ('2010-02-01 03:00:00 ' );
577+ $ this ->trackVisitAtTime ('2010-02-01 06:10:00 ' );
578+ $ this ->trackVisitAtTime ('2010-02-01 09:20:00 ' );
579+ $ this ->trackVisitAtTime ('2010-02-02 03:00:00 ' );
580+ $ this ->trackVisitAtTime ('2010-02-02 06:10:00 ' );
581+ $ this ->trackVisitAtTime ('2010-02-03 03:00:00 ' );
582+ $ this ->trackVisitAtTime ('2010-02-03 06:10:00 ' );
583+ $ this ->trackVisitAtTime ('2010-02-03 09:20:00 ' );
584+
585+ $ this ->assertEquals (8 , $ this ->countVisitsBetween ('2010-02-01 00:00:00 ' , '2010-02-04 00:00:00 ' ));
586+
587+ $ model = new Model ();
588+
589+ $ visits = $ model ->queryLogVisits (
590+ 1 ,
591+ 'range ' ,
592+ '2010-02-01,2010-02-03 ' ,
593+ $ segment = '' ,
594+ $ offset = 6 ,
595+ $ limit = 2 ,
596+ $ visitorId = false ,
597+ $ minTimestamp = false ,
598+ $ filterSortOrder = 'asc '
599+ );
600+
601+ $ this ->assertCount (2 , $ visits );
602+ $ this ->assertEquals ('2010-02-03 06:10:00 ' , $ visits [0 ]['visit_last_action_time ' ]);
603+ $ this ->assertEquals ('2010-02-03 09:20:00 ' , $ visits [1 ]['visit_last_action_time ' ]);
604+ }
605+
606+ public function testQueryLogVisitsOffsetAcrossYearRange ()
607+ {
608+ $ dates = [
609+ '2010-01-01 03:00:00 ' ,
610+ '2010-02-01 03:00:00 ' ,
611+ '2010-03-01 03:00:00 ' ,
612+ '2010-04-01 03:00:00 ' ,
613+ '2010-05-01 03:00:00 ' ,
614+ '2010-06-01 03:00:00 ' ,
615+ '2010-07-01 03:00:00 ' ,
616+ '2010-08-01 03:00:00 ' ,
617+ '2010-09-01 03:00:00 ' ,
618+ '2010-10-01 03:00:00 ' ,
619+ '2010-11-01 03:00:00 ' ,
620+ '2010-12-01 03:00:00 ' ,
621+ '2011-01-01 03:00:00 ' ,
622+ ];
623+
624+ foreach ($ dates as $ dateTime ) {
625+ $ this ->trackVisitAtTime ($ dateTime );
626+ }
627+
628+ $ this ->assertEquals (13 , $ this ->countVisitsBetween ('2010-01-01 00:00:00 ' , '2011-02-01 00:00:00 ' ));
629+
630+ $ model = new Model ();
631+ $ visits = $ model ->queryLogVisits (
632+ 1 ,
633+ 'range ' ,
634+ '2010-01-01,2011-01-01 ' ,
635+ $ segment = '' ,
636+ $ offset = 10 ,
637+ $ limit = 2 ,
638+ $ visitorId = false ,
639+ $ minTimestamp = false ,
640+ $ filterSortOrder = 'desc '
641+ );
642+
643+ $ this ->assertCount (2 , $ visits );
644+ $ this ->assertEquals ('2010-03-01 03:00:00 ' , $ visits [0 ]['visit_last_action_time ' ]);
645+ $ this ->assertEquals ('2010-02-01 03:00:00 ' , $ visits [1 ]['visit_last_action_time ' ]);
646+ }
647+
648+ public function testQueryLogVisitsOffsetBeyondTotalReturnsEmpty ()
649+ {
650+ $ this ->trackVisitAtTime ('2010-04-01 03:00:00 ' );
651+ $ this ->trackVisitAtTime ('2010-04-01 06:10:00 ' );
652+ $ this ->trackVisitAtTime ('2010-04-02 03:00:00 ' );
653+
654+ $ this ->assertEquals (3 , $ this ->countVisitsBetween ('2010-04-01 00:00:00 ' , '2010-04-03 00:00:00 ' ));
655+
656+ $ model = new Model ();
657+ $ visits = $ model ->queryLogVisits (
658+ 1 ,
659+ 'range ' ,
660+ '2010-04-01,2010-04-02 ' ,
661+ $ segment = '' ,
662+ $ offset = 10 ,
663+ $ limit = 5 ,
664+ $ visitorId = false ,
665+ $ minTimestamp = false ,
666+ $ filterSortOrder = 'desc '
667+ );
668+
669+ $ this ->assertSame ([], $ visits );
670+ }
671+
672+ public function testQueryLogVisitsOffsetWeekPeriod ()
673+ {
674+ $ this ->trackVisitAtTime ('2010-01-05 01:00:00 ' );
675+ $ this ->trackVisitAtTime ('2010-01-06 01:00:00 ' );
676+ $ this ->trackVisitAtTime ('2010-01-07 01:00:00 ' );
677+
678+ $ this ->assertEquals (3 , $ this ->countVisitsBetween ('2010-01-04 00:00:00 ' , '2010-01-08 00:00:00 ' ));
679+
680+ $ model = new Model ();
681+ $ visits = $ model ->queryLogVisits (
682+ 1 ,
683+ 'week ' ,
684+ '2010-01-05 ' ,
685+ $ segment = '' ,
686+ $ offset = 1 ,
687+ $ limit = 1 ,
688+ $ visitorId = false ,
689+ $ minTimestamp = false ,
690+ $ filterSortOrder = 'desc '
691+ );
692+
693+ $ this ->assertCount (1 , $ visits );
694+ $ this ->assertEquals ('2010-01-06 01:00:00 ' , $ visits [0 ]['visit_last_action_time ' ]);
695+ }
696+
697+ public function testQueryLogVisitsOffsetMonthPeriod ()
698+ {
699+ $ this ->trackVisitAtTime ('2010-06-05 01:00:00 ' );
700+ $ this ->trackVisitAtTime ('2010-06-10 01:00:00 ' );
701+ $ this ->trackVisitAtTime ('2010-06-20 01:00:00 ' );
702+ $ this ->trackVisitAtTime ('2010-06-25 01:00:00 ' );
703+
704+ $ this ->assertEquals (4 , $ this ->countVisitsBetween ('2010-06-01 00:00:00 ' , '2010-07-01 00:00:00 ' ));
705+
706+ $ model = new Model ();
707+ $ visits = $ model ->queryLogVisits (
708+ 1 ,
709+ 'month ' ,
710+ '2010-06-15 ' ,
711+ $ segment = '' ,
712+ $ offset = 2 ,
713+ $ limit = 1 ,
714+ $ visitorId = false ,
715+ $ minTimestamp = false ,
716+ $ filterSortOrder = 'desc '
717+ );
718+
719+ $ this ->assertCount (1 , $ visits );
720+ $ this ->assertEquals ('2010-06-10 01:00:00 ' , $ visits [0 ]['visit_last_action_time ' ]);
721+ }
722+
723+ public function testQueryLogVisitsOffsetYearPeriod ()
724+ {
725+ $ this ->trackVisitAtTime ('2011-01-01 03:00:00 ' );
726+ $ this ->trackVisitAtTime ('2011-03-01 03:00:00 ' );
727+ $ this ->trackVisitAtTime ('2011-06-01 03:00:00 ' );
728+ $ this ->trackVisitAtTime ('2011-09-01 03:00:00 ' );
729+ $ this ->trackVisitAtTime ('2011-12-01 03:00:00 ' );
730+
731+ $ this ->assertEquals (5 , $ this ->countVisitsBetween ('2011-01-01 00:00:00 ' , '2012-01-01 00:00:00 ' ));
732+
733+ $ model = new Model ();
734+ $ visits = $ model ->queryLogVisits (
735+ 1 ,
736+ 'year ' ,
737+ '2011-01-01 ' ,
738+ $ segment = '' ,
739+ $ offset = 3 ,
740+ $ limit = 2 ,
741+ $ visitorId = false ,
742+ $ minTimestamp = false ,
743+ $ filterSortOrder = 'desc '
744+ );
745+
746+ $ this ->assertCount (2 , $ visits );
747+ $ this ->assertEquals ('2011-03-01 03:00:00 ' , $ visits [0 ]['visit_last_action_time ' ]);
748+ $ this ->assertEquals ('2011-01-01 03:00:00 ' , $ visits [1 ]['visit_last_action_time ' ]);
749+ }
750+
526751 protected function setSuperUser ()
527752 {
528753 FakeAccess::$ superUser = true ;
@@ -557,4 +782,22 @@ private function trackPageView(): void
557782 $ t ->setVisitorId (substr (sha1 ('X4F66G776HGI ' ), 0 , 16 ));
558783 $ t ->doTrackPageView ('foo ' );
559784 }
785+
786+ private function trackVisitAtTime (string $ dateTime ): void
787+ {
788+ $ t = Fixture::getTracker (1 , $ dateTime , $ defaultInit = true );
789+ $ t ->setTokenAuth (Fixture::getTokenAuth ());
790+ $ t ->setNewVisitorId ();
791+ $ t ->setForceVisitDateTime ($ dateTime );
792+ $ t ->setUrl ('http://example.org/ ' . str_replace ([' ' , ': ' ], '- ' , $ dateTime ));
793+ Fixture::checkResponse ($ t ->doTrackPageView ('Visit at ' . $ dateTime ));
794+ }
795+
796+ private function countVisitsBetween (string $ startDate , string $ endDate ): int
797+ {
798+ return (int ) Db::fetchOne (
799+ 'SELECT COUNT(*) FROM ' . Common::prefixTable ('log_visit ' ) . ' WHERE visit_last_action_time >= ? AND visit_last_action_time <= ? AND idsite = ? ' ,
800+ [$ startDate , $ endDate , 1 ]
801+ );
802+ }
560803}
0 commit comments