Skip to content
Extraits de code Groupes Projets
VisitTest.php 17,3 ko
Newer Older
  • Learn to ignore specific revisions
  • sgiehl's avatar
    sgiehl a validé
    <?php
    /**
    
     * Piwik - free/libre analytics platform
    
    sgiehl's avatar
    sgiehl a validé
     *
     * @link http://piwik.org
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
     */
    
    namespace Piwik\Tests\Integration\Tracker;
    
    
    use Piwik\Cache;
    use Piwik\CacheId;
    
    use Piwik\Plugin\Manager;
    
    use Piwik\Tests\Framework\Mock\FakeAccess;
    
    use Piwik\Tracker\Request;
    
    mattab's avatar
    mattab a validé
    use Piwik\Tracker\VisitExcluded;
    
    use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
    
    class VisitTest extends IntegrationTestCase
    
    sgiehl's avatar
    sgiehl a validé
    {
        public function setUp()
        {
            parent::setUp();
    
            // setup the access layer
            $pseudoMockAccess = new FakeAccess;
            FakeAccess::$superUser = true;
    
            Access::setSingletonInstance($pseudoMockAccess);
    
            Manager::getInstance()->loadTrackerPlugins();
            Manager::getInstance()->loadPlugin('SitesManager');
    
    sgiehl's avatar
    sgiehl a validé
        }
    
        /**
         * Dataprovider
         */
        public function getExcludedIpTestData()
        {
            return array(
                array('12.12.12.12', array(
    
                    '12.12.12.12'     => true,
                    '12.12.12.11'     => false,
                    '12.12.12.13'     => false,
                    '0.0.0.0'         => false,
    
    sgiehl's avatar
    sgiehl a validé
                    '255.255.255.255' => false
                )),
                array('12.12.12.12/32', array(
    
                    '12.12.12.12'     => true,
                    '12.12.12.11'     => false,
                    '12.12.12.13'     => false,
                    '0.0.0.0'         => false,
    
    sgiehl's avatar
    sgiehl a validé
                    '255.255.255.255' => false
                )),
                array('12.12.12.*', array(
    
                    '12.12.12.0'      => true,
                    '12.12.12.255'    => true,
                    '12.12.12.12'     => true,
                    '12.12.11.255'    => false,
                    '12.12.13.0'      => false,
                    '0.0.0.0'         => false,
    
    sgiehl's avatar
    sgiehl a validé
                    '255.255.255.255' => false,
                )),
                array('12.12.12.0/24', array(
    
                    '12.12.12.0'      => true,
                    '12.12.12.255'    => true,
                    '12.12.12.12'     => true,
                    '12.12.11.255'    => false,
                    '12.12.13.0'      => false,
                    '0.0.0.0'         => false,
    
    sgiehl's avatar
    sgiehl a validé
                    '255.255.255.255' => false,
                )),
                // add some ipv6 addresses!
            );
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * @dataProvider getExcludedIpTestData
         */
    
        public function testIsVisitorIpExcluded($excludedIp, $tests)
    
    sgiehl's avatar
    sgiehl a validé
        {
    
            $idsite = API::getInstance()->addSite("name", "http://piwik.net/", $ecommerce = 0,
    
                $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $excludedIp);
    
            $request = new Request(array('idsite' => $idsite));
    
    sgiehl's avatar
    sgiehl a validé
    
            // test that IPs within the range, or the given IP, are excluded
    
            foreach ($tests as $ip => $expected) {
    
                $testIpIsExcluded = IPUtils::stringToBinaryIP($ip);
    
                $excluded = new VisitExcluded_public($request, $testIpIsExcluded);
    
                $this->assertSame($expected, $excluded->public_isVisitorIpExcluded($testIpIsExcluded));
    
    sgiehl's avatar
    sgiehl a validé
            }
        }
    
        /**
         * Dataprovider for testIsVisitorUserAgentExcluded.
         */
        public function getExcludedUserAgentTestData()
        {
    
            return array(
                array('', array(
                    'whatever'        => false,
                    ''                => false,
                    'nlksdjfsldkjfsa' => false,
                )),
                array('mozilla', array(
                    'this has mozilla in it' => true,
                    'this doesn\'t'          => false,
                    'partial presence: mozi' => false,
                )),
                array('cHrOmE,notinthere,&^%', array(
                    'chrome is here' => true,
                    'CHROME is here' => true,
                    '12&^%345'       => true,
                    'sfasdf'         => false,
                )),
            );
        }
    
        /**
         * @dataProvider getExcludedUserAgentTestData
         */
        public function testIsVisitorUserAgentExcluded($excludedUserAgent, $tests)
        {
    
            API::getInstance()->setSiteSpecificUserAgentExcludeEnabled(true);
    
            $idsite = API::getInstance()->addSite("name", "http://piwik.net/", $ecommerce = 0,
    
                $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $excludedIp = null,
                $excludedQueryParameters = null, $timezone = null, $currency = null, $group = null, $startDate = null,
                $excludedUserAgent);
    
    
            $request = new Request(array('idsite' => $idsite));
    
            // test that user agents that contain excluded user agent strings are excluded
            foreach ($tests as $ua => $expected) {
    
                $excluded = new VisitExcluded_public($request, $ip = false, $ua);
    
                $this->assertSame($expected, $excluded->public_isUserAgentExcluded(), "Result if isUserAgentExcluded('$ua') was not " . ($expected ? 'true' : 'false') . ".");
            }
        }
    
        /**
         * @group referrerIsKnownSpam
         */
        public function testIsVisitor_referrerIsKnownSpam()
        {
            $knownSpammers = array(
                'http://semalt.com' => true,
                'http://semalt.com/random/sub/page' => true,
                'http://semalt.com/out/of/here?mate' => true,
    
    mattab's avatar
    mattab a validé
                'http://buttons-for-website.com/out/of/here?mate' => true,
                'https://buttons-for-website.com' => true,
    
                'https://make-money-online.7makemoneyonline.com' => true,
    
    mattab's avatar
    mattab a validé
                'https://7makemoneyonline.com' => true,
    
                'http://valid.domain/' => false,
                'http://valid.domain/page' => false,
    
    mattab's avatar
    mattab a validé
                'https://valid.domain/page' => false,
    
            );
            API::getInstance()->setSiteSpecificUserAgentExcludeEnabled(true);
    
            $idsite = API::getInstance()->addSite("name", "http://piwik.net/");
    
            // test that user agents that contain excluded user agent strings are excluded
            foreach ($knownSpammers as $spamUrl => $expectedIsReferrerSpam) {
                $spamUrl = urlencode($spamUrl);
                $request = new Request(array(
                    'idsite' => $idsite,
                    'urlref' => $spamUrl
                ));
                $excluded = new VisitExcluded_public($request);
    
                $this->assertSame($expectedIsReferrerSpam, $excluded->public_isReferrerSpamExcluded(), $spamUrl);
    
        /**
         * @group IpIsKnownBot
         */
        public function testIsVisitor_ipIsKnownBot()
        {
            $isIpBot = array(
                // Source: http://forum.piwik.org/read.php?3,108926
                '66.249.85.36' => true,
                '66.249.91.150' => true,
                '64.233.172.1' => true,
    
                '64.233.172.200' => true,
                '66.249.88.216' => true,
                '66.249.83.204' => true,
                '64.233.172.6' => true,
    
    
                // ddos bot
                '1.202.218.8' => true,
    
                // Not bots
                '66.248.91.150' => false,
                '66.250.91.150' => false,
    
                // almost google range but not google
                '66.249.2.1' => false,
                '66.249.60.1' => false,
    
            );
    
            $idsite = API::getInstance()->addSite("name", "http://piwik.net/");
            $request = new Request(array('idsite' => $idsite, 'bots' => 0));
    
            foreach ($isIpBot as $ip => $isBot) {
    
                $excluded = new VisitExcluded_public($request, IPUtils::stringToBinaryIP($ip));
    
    
                $this->assertSame($isBot, $excluded->public_isNonHumanBot(), $ip);
            }
        }
    
    
        /**
         * @group UserAgentIsKnownBot
         */
        public function testIsVisitor_userAgentIsKnownBot()
        {
            $isUserAgentBot = array(
    
                'bingbot' => true,
                'BINGBOT' => true,
                'x BingBot x' => true,
                'BingPreview' => true,
    
                'Mozilla/5.0 (compatible; CloudFlare-AlwaysOnline/1.0; +http://www.cloudflare.com/always-online) XXXX' => true,
                'Pingdom.com_bot_version_1.4_(http://www.pingdom.com/)' => true,
                'Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)' => true,
                'Exabot/2.0' => true,
                'sogou spider' => true,
                'Mozilla/5.0(compatible;Sosospider/2.0;+http://help.soso.com/webspider.htm)' => true,
    
                'AdsBot-Google (+http://www.google.com/adsbot.html)' => true,
                'Google Page Speed Insights' => true,
                // Web snippets
                'Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 Google (+https://developers.google.com/+/web/snippet/)' => true,
                // Google Web Preview
                'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.51 (KHTML, like Gecko; Google Web Preview) Chrome/12.0.742 Safari/534.51' => true,
                'Googlebot-Video/1.0' => true,
                'Googlebot' => true,
    
    
                'random' => false,
                'hello world' => false,
                'this is a user agent' => false,
                'Mozilla' => false,
            );
    
            $idsite = API::getInstance()->addSite("name", "http://piwik.net/");
    
            foreach ($isUserAgentBot as $userAgent => $isBot) {
                $request = new Request(array(
                    'idsite' => $idsite,
                    'bots' => 0,
                    'ua' => $userAgent,
                ));
    
                $excluded = new VisitExcluded_public($request);
    
                $this->assertSame($isBot, $excluded->public_isNonHumanBot(), $userAgent);
            }
        }
    
    
        public function test_isVisitNew_ReturnsFalse_IfLastActionTimestampIsWithinVisitTimeLength_AndNoDimensionForcesVisit_AndVisitorKnown()
        {
            $this->setDimensionsWithOnNewVisit(array(false, false, false));
    
            /** @var Visit $visit */
            list($visit, $visitor, $action) = $this->makeVisitorAndAction(
                $lastActionTime = '2012-01-02 08:08:34', $thisActionTime = '2012-01-02 08:12:45', $isVisitorKnown = true);
    
            $result = $visit->isVisitNew($visitor, $action);
    
            $this->assertFalse($result);
        }
    
    
        public function test_isVisitNew_ReturnsTrue_IfLastActionTimestampWasYesterday()
        {
            $this->setDimensionsWithOnNewVisit(array(false, false, false));
    
            // test same day
            /** @var Visit $visit */
            list($visit, $visitor, $action) = $this->makeVisitorAndAction(
                $lastActionTime = '2012-01-01 23:59:58', $thisActionTime = '2012-01-01 23:59:59', $isVisitorKnown = true);
            $result = $visit->isVisitNew($visitor, $action);
            $this->assertFalse($result);
    
            // test different day
            list($visit, $visitor, $action) = $this->makeVisitorAndAction(
            $lastActionTime = '2012-01-01 23:59:58', $thisActionTime = '2012-01-02 00:00:01', $isVisitorKnown = true);
            $result = $visit->isVisitNew($visitor, $action);
            $this->assertTrue($result);
        }
    
    
        public function test_markArchivedReportsAsInvalidIfArchiveAlreadyFinished_ShouldRemember_IfRequestWasDoneLongAgo()
        {
            $currentActionTime = '2012-01-02 08:12:45';
            $idsite = API::getInstance()->addSite('name', 'http://piwik.net/');
    
            $expectedRemembered = array('2012-01-02' => array($idsite));
    
            $this->assertRememberedArchivedReportsThatShouldBeInvalidated($idsite, $currentActionTime, $expectedRemembered);
        }
    
        public function test_markArchivedReportsAsInvalidIfArchiveAlreadyFinished_ShouldNotRemember_IfRequestWasDoneJustAtStartOfTheDay()
        {
            $currentActionTime = Date::today()->getDatetime();
            $idsite = API::getInstance()->addSite('name', 'http://piwik.net/');
    
            $expectedRemembered = array();
    
            $this->assertRememberedArchivedReportsThatShouldBeInvalidated($idsite, $currentActionTime, $expectedRemembered);
        }
    
        public function test_markArchivedReportsAsInvalidIfArchiveAlreadyFinished_ShouldRemember_IfRequestWasDoneAt11PMTheDayBefore()
        {
            $currentActionTime = Date::today()->subHour(1)->getDatetime();
            $idsite = API::getInstance()->addSite('name', 'http://piwik.net/');
    
            $expectedRemembered = array(
                substr($currentActionTime, 0, 10) => array($idsite)
            );
    
            $this->assertRememberedArchivedReportsThatShouldBeInvalidated($idsite, $currentActionTime, $expectedRemembered);
        }
    
        public function test_markArchivedReportsAsInvalidIfArchiveAlreadyFinished_shouldConsiderWebsitesTimezone()
        {
            $timezone1 = 'UTC+4';
            $timezone2 = 'UTC+6';
    
            $currentActionTime1 = Date::today()->setTimezone($timezone1)->getDatetime();
            $currentActionTime2 = Date::today()->setTimezone($timezone2)->getDatetime();
            $idsite = API::getInstance()->addSite('name', 'http://piwik.net/', $ecommerce = null,
                $siteSearch = null,
                $searchKeywordParameters = null,
                $searchCategoryParameters = null,
                $excludedIps = null,
                $excludedQueryParameters = null,
                $timezone = 'UTC+5');
    
            $expectedRemembered = array(
                substr($currentActionTime1, 0, 10) => array($idsite)
            );
    
            // if website timezone was von considered both would be today (expected = array())
            $this->assertRememberedArchivedReportsThatShouldBeInvalidated($idsite, $currentActionTime1, array());
            $this->assertRememberedArchivedReportsThatShouldBeInvalidated($idsite, $currentActionTime2, $expectedRemembered);
        }
    
        private function assertRememberedArchivedReportsThatShouldBeInvalidated($idsite, $requestDate, $expectedRemeberedArchivedReports)
        {
            /** @var Visit $visit */
            list($visit) = $this->prepareVisitWithRequest(array(
                'idsite' => $idsite,
                'rec' => 1,
                'cip' => '156.146.156.146',
                'token_auth' => Fixture::getTokenAuth()
            ), $requestDate);
    
            $visit->handle();
    
            $archive = new ArchiveInvalidator();
            $remembered = $archive->getRememberedArchivedReportsThatShouldBeInvalidated();
    
            $this->assertSame($expectedRemeberedArchivedReports, $remembered);
        }
    
        private function prepareVisitWithRequest($requestParams, $requestDate)
        {
            $request = new Request($requestParams);
            $request->setCurrentTimestamp(Date::factory($requestDate)->getTimestamp());
    
            $visit = new Visit();
            $visit->setRequest($request);
    
            $visit->handle();
    
            return array($visit, $request);
        }
    
    
        public function test_isVisitNew_ReturnsTrue_IfLastActionTimestampIsNotWithinVisitTimeLength_AndNoDimensionForcesVisit_AndVisitorNotKnown()
        {
            $this->setDimensionsWithOnNewVisit(array(false, false, false));
    
            /** @var Visit $visit */
            list($visit, $visitor, $action) = $this->makeVisitorAndAction($lastActionTime = '2012-01-02 08:08:34', $thisActionTime = '2012-01-02 09:12:45');
    
            $result = $visit->isVisitNew($visitor, $action);
    
            $this->assertTrue($result);
        }
    
        public function test_isVisitNew_ReturnsTrue_IfLastActionTimestampIsWithinVisitTimeLength_AndDimensionForcesVisit()
        {
            $this->setDimensionsWithOnNewVisit(array(false, false, true));
    
            /** @var Visit $visit */
            list($visit, $visitor, $action) = $this->makeVisitorAndAction($lastActionTime = '2012-01-02 08:08:34', $thisActionTime = '2012-01-02 08:12:45');
    
            $result = $visit->isVisitNew($visitor, $action);
    
            $this->assertTrue($result);
        }
    
    
        public function test_isVisitNew_ReturnsTrue_IfDimensionForcesVisit_AndVisitorKnown()
    
        {
            $this->setDimensionsWithOnNewVisit(array(false, false, true));
    
            /** @var Visit $visit */
            list($visit, $visitor, $action) = $this->makeVisitorAndAction($lastActionTime = '2012-01-02 08:08:34', $thisActionTime = '2012-01-02 08:12:45');
    
            $result = $visit->isVisitNew($visitor, $action);
    
            $this->assertTrue($result);
        }
    
        private function makeVisitorAndAction($lastActionTimestamp, $currentActionTime, $isVisitorKnown = false)
        {
            $idsite = API::getInstance()->addSite("name", "http://piwik.net/");
    
    
            list($visit, $request) = $this->prepareVisitWithRequest(array('idsite' => $idsite), $currentActionTime);
    
    
            $visitor = new Visitor($request, 'configid', array('visit_last_action_time' => Date::factory($lastActionTimestamp)->getTimestamp()));
            $visitor->setIsVisitorKnown($isVisitorKnown);
    
            $action = new ActionPageview($request);
    
            return array($visit, $visitor, $action);
        }
    
        private function setDimensionsWithOnNewVisit($dimensionOnNewVisitResults)
        {
            $dimensions = array();
            foreach ($dimensionOnNewVisitResults as $onNewVisitResult) {
                $dim = $this->getMock('Piwik\\Plugin\\Dimension', array('shouldForceNewVisit', 'getColumnName'));
                $dim->expects($this->any())->method('shouldForceNewVisit')->will($this->returnValue($onNewVisitResult));
                $dimensions[] = $dim;
            }
    
    
            $cache = Cache::getTransientCache();
            $cache->save(CacheId::pluginAware('VisitDimensions'), $dimensions);
    
    class VisitExcluded_public extends VisitExcluded
    
    {
        public function public_isVisitorIpExcluded($ip)
        {
            return $this->isVisitorIpExcluded($ip);
        }
    
    
        public function public_isUserAgentExcluded()
        {
            return $this->isUserAgentExcluded();
        }
        public function public_isReferrerSpamExcluded()
    
            return $this->isReferrerSpamExcluded();
    
        public function public_isNonHumanBot()
        {
            return $this->isNonHumanBot();
        }
    
    sgiehl's avatar
    sgiehl a validé
    }