diff options
-rwxr-xr-x | config/global.ini.php | 7 | ||||
-rw-r--r-- | core/ArchiveProcessor/Loader.php | 4 | ||||
-rw-r--r-- | core/ArchiveProcessor/Rules.php | 52 | ||||
-rw-r--r-- | core/Config/GeneralConfig.php | 48 | ||||
-rw-r--r-- | core/Plugin/Visualization.php | 18 | ||||
-rw-r--r-- | plugins/CoreHome/CoreHome.php | 1 | ||||
-rw-r--r-- | plugins/CoreHome/lang/en.json | 1 | ||||
-rw-r--r-- | plugins/CoreHome/templates/_dataTable.twig | 2 | ||||
-rw-r--r-- | tests/PHPUnit/Fixtures/DisablePluginArchive.php | 186 | ||||
-rw-r--r-- | tests/PHPUnit/Integration/ArchiveProcessor/LoaderTest.php | 50 | ||||
-rw-r--r-- | tests/PHPUnit/System/ArchiveInvalidationTest.php | 126 | ||||
-rw-r--r-- | tests/PHPUnit/Unit/ConfigTest.php | 310 | ||||
-rw-r--r-- | tests/UI/expected-screenshots/DisablePluginArchive_referrer_disabled.png | 3 | ||||
-rw-r--r-- | tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png | 4 | ||||
-rw-r--r-- | tests/UI/specs/DisablePluginArchive_spec.js | 27 |
15 files changed, 702 insertions, 137 deletions
diff --git a/config/global.ini.php b/config/global.ini.php index fbd0500424..aaf8fbd585 100755 --- a/config/global.ini.php +++ b/config/global.ini.php @@ -385,6 +385,11 @@ archiving_custom_ranges[] = ; This feature will not work with the MYSQLI extension. archiving_query_max_execution_time = 7200 + +; Allows you to disable archiving segments for selected plugins. For more details please see https://matomo.org/faq/how-to-disable-archiving-the-segment-reports-for-specific-plugins +; Here you can specify the comma separated list eg: "plugin1,plugin2" +disable_archiving_segment_for_plugins = "" + ; By default Matomo runs OPTIMIZE TABLE SQL queries to free spaces after deleting some data. ; If your Matomo tracks millions of pages, the OPTIMIZE TABLE queries might run for hours (seen in "SHOW FULL PROCESSLIST \g") ; so you can disable these special queries here: @@ -676,7 +681,7 @@ proxy_ip_read_last_in_list = 0 enable_trusted_host_check = 1 ; List of trusted hosts (eg domain or subdomain names) when generating absolute URLs. -; This only needs to be set for any hostnames that the Matomo UI will be accessed from. It is not necessary to set this +; This only needs to be set for any hostnames that the Matomo UI will be accessed from. It is not necessary to set this ; for other additional hostnames (For example tracking, API, etc.) ; Examples: ;trusted_hosts[] = example.com diff --git a/core/ArchiveProcessor/Loader.php b/core/ArchiveProcessor/Loader.php index d99a5ea0fb..00d834a8eb 100644 --- a/core/ArchiveProcessor/Loader.php +++ b/core/ArchiveProcessor/Loader.php @@ -468,6 +468,10 @@ class Loader return false; } + if (!empty($params->getRequestedPlugin()) && Rules::isSegmentPluginArchivingDisabled($params->getRequestedPlugin(), $params->getSite()->getId())) { + return true; + } + /** @var SegmentArchiving */ $segmentArchiving = StaticContainer::get(SegmentArchiving::class); $segmentInfo = $segmentArchiving->findSegmentForHash($params->getSegment()->getHash(), $params->getSite()->getId()); diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php index c31c3bf4fe..4f0fd85be6 100644 --- a/core/ArchiveProcessor/Rules.php +++ b/core/ArchiveProcessor/Rules.php @@ -11,6 +11,7 @@ namespace Piwik\ArchiveProcessor; use Exception; use Piwik\Common; use Piwik\Config; +use Piwik\Config\GeneralConfig; use Piwik\DataAccess\ArchiveWriter; use Piwik\DataAccess\Model; use Piwik\Date; @@ -58,7 +59,7 @@ class Rules public static function getDoneStringFlagFor(array $idSites, $segment, $periodLabel, $plugin) { if (!empty($plugin) - && !self::shouldProcessReportsAllPlugins($idSites, $segment, $periodLabel) + && !self::shouldProcessReportsAllPlugins($idSites, $segment, $periodLabel) ) { return self::getDoneFlagArchiveContainsOnePlugin($segment, $plugin); } @@ -101,7 +102,7 @@ class Rules public static function getDoneFlagArchiveContainsOnePlugin(Segment $segment, $plugin) { - return 'done' . $segment->getHash() . '.' . $plugin ; + return 'done' . $segment->getHash() . '.' . $plugin; } public static function getDoneFlagArchiveContainsAllPlugins(Segment $segment) @@ -131,8 +132,11 @@ class Rules } public static function getMinTimeProcessedForInProgressArchive( - Date $dateStart, \Piwik\Period $period, Segment $segment, Site $site) - { + Date $dateStart, + \Piwik\Period $period, + Segment $segment, + Site $site + ) { $todayArchiveTimeToLive = self::getPeriodArchiveTimeToLiveDefault($period->getLabel()); $now = time(); @@ -142,7 +146,7 @@ class Rules $isArchivingDisabled = Rules::isArchivingDisabledFor($idSites, $segment, $period->getLabel()); if ($isArchivingDisabled) { if ($period->getNumberOfSubperiods() == 0 - && $dateStart->getTimestamp() <= $now + && $dateStart->getTimestamp() <= $now ) { // Today: accept any recent enough archive $minimumArchiveTime = false; @@ -150,7 +154,8 @@ class Rules // This week, this month, this year: // accept any archive that was processed today after 00:00:01 this morning $timezone = $site->getTimezone(); - $minimumArchiveTime = Date::factory(Date::factory('now', $timezone)->getDateStartUTC())->setTimezone($timezone)->getTimestamp(); + $minimumArchiveTime = Date::factory(Date::factory('now', + $timezone)->getDateStartUTC())->setTimezone($timezone)->getTimestamp(); } } return $minimumArchiveTime; @@ -214,7 +219,7 @@ class Rules if ($periodLabel === 'range') { if (isset($generalConfig['archiving_range_force_on_browser_request']) - && $generalConfig['archiving_range_force_on_browser_request'] == false + && $generalConfig['archiving_range_force_on_browser_request'] == false ) { Log::debug("Not forcing archiving for range period."); return $isArchivingEnabled; @@ -229,8 +234,8 @@ class Rules } if (!$isArchivingEnabled - && (!self::isBrowserArchivingAvailableForSegments() || self::isSegmentPreProcessed($idSites, $segment)) - && !SettingsServer::isArchivePhpTriggered() // Only applies when we are not running core:archive command + && (!self::isBrowserArchivingAvailableForSegments() || self::isSegmentPreProcessed($idSites, $segment)) + && !SettingsServer::isArchivePhpTriggered() // Only applies when we are not running core:archive command ) { Log::debug("Archiving is disabled because of config setting browser_archiving_disabled_enforce=1 or because the segment is selected to be pre-processed."); return false; @@ -315,7 +320,7 @@ class Rules $segmentsToProcessUrlDecoded = array_map('urldecode', $segmentsToProcess); return in_array($segment, $segmentsToProcess) - || in_array($segment, $segmentsToProcessUrlDecoded); + || in_array($segment, $segmentsToProcessUrlDecoded); } /** @@ -323,8 +328,11 @@ class Rules * * @return string[] */ - public static function getSelectableDoneFlagValues($includeInvalidated = true, Parameters $params = null, $checkAuthorizedToArchive = true) - { + public static function getSelectableDoneFlagValues( + $includeInvalidated = true, + Parameters $params = null, + $checkAuthorizedToArchive = true + ) { $possibleValues = array(ArchiveWriter::DONE_OK, ArchiveWriter::DONE_OK_TEMPORARY); if ($includeInvalidated) { @@ -356,4 +364,24 @@ class Rules { return Config::getInstance()->General['rearchive_reports_in_past_exclude_segments'] != 1; } + + public static function isSegmentPluginArchivingDisabled($pluginName, $siteId = null) + { + $pluginArchivingSetting = GeneralConfig::getConfigValue('disable_archiving_segment_for_plugins', $siteId); + + if (empty($pluginArchivingSetting)) { + return false; + } + + if (is_string($pluginArchivingSetting)) { + $pluginArchivingSetting = explode(",", $pluginArchivingSetting); + $pluginArchivingSetting = array_filter($pluginArchivingSetting, function($plugin){ + return Manager::getInstance()->isValidPluginName($plugin); + }); + } + + $pluginArchivingSetting = array_map('strtolower', $pluginArchivingSetting); + + return in_array(strtolower($pluginName), $pluginArchivingSetting); + } } diff --git a/core/Config/GeneralConfig.php b/core/Config/GeneralConfig.php new file mode 100644 index 0000000000..89fe39ddb2 --- /dev/null +++ b/core/Config/GeneralConfig.php @@ -0,0 +1,48 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Config; + +use Piwik\Config; + +class GeneralConfig +{ + /** + * Update Archive config + * + * @param string $name Setting name + * @param mixed $value Value + */ + public static function setConfigValue($name, $value) + { + $section = self::getConfig(); + $section[$name] = $value; + Config::getInstance()->General = $section; + } + + public static function getConfigValue($name, $idSite = null) + { + $config = self::getConfig(); + if (!empty($idSite)) { + $siteSpecificConfig = self::getSiteSpecificConfig($idSite); + $config = array_merge($config, $siteSpecificConfig); + } + return $config[$name] ?? null; + } + + private static function getConfig() + { + return Config::getInstance()->General; + } + + private static function getSiteSpecificConfig($idSite) + { + $key = 'General_' . $idSite; + return Config::getInstance()->$key; + } +} diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php index 246a0a9cd2..dd99f5a5e8 100644 --- a/core/Plugin/Visualization.php +++ b/core/Plugin/Visualization.php @@ -14,6 +14,7 @@ use Piwik\API\Proxy; use Piwik\API\Request; use Piwik\API\Request as ApiRequest; use Piwik\API\ResponseBuilder; +use Piwik\ArchiveProcessor\Rules; use Piwik\Common; use Piwik\Container\StaticContainer; use Piwik\DataTable; @@ -232,6 +233,7 @@ class Visualization extends ViewDataTable // if it's likely that the report data for this data table has been purged, // set whether we should display a message to that effect. $view->showReportDataWasPurgedMessage = $this->hasReportBeenPurged(); + $view->showPluginArchiveDisabled = $this->hasReportSegmentDisabled(); $view->deleteReportsOlderThan = Option::get('delete_reports_older_than'); } @@ -601,6 +603,22 @@ class Visualization extends ViewDataTable } /** + * Return true if the config for the plug is disabled + * @return bool + */ + + private function hasReportSegmentDisabled() + { + $module = $this->requestConfig->getApiModuleToRequest(); + $rawSegment = \Piwik\API\Request::getRawSegmentFromRequest(); + + if (!empty($rawSegment) && Rules::isSegmentPluginArchivingDisabled($module)) { + return true; + } + return false; + } + + /** * Returns array of properties that should be visible to client side JavaScript. The data * will be available in the data-props HTML attribute of the .dataTable div. * diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php index f7d11586b3..c234997b6f 100644 --- a/plugins/CoreHome/CoreHome.php +++ b/plugins/CoreHome/CoreHome.php @@ -464,5 +464,6 @@ class CoreHome extends \Piwik\Plugin $translationKeys[] = 'CoreHome_TechDeprecationWarning'; $translationKeys[] = 'CoreHome_StartDate'; $translationKeys[] = 'CoreHome_EndDate'; + $translationKeys[] = 'CoreHome_DataForThisReportHasBeenDisabled'; } } diff --git a/plugins/CoreHome/lang/en.json b/plugins/CoreHome/lang/en.json index 44416ef59f..e49bcf7889 100644 --- a/plugins/CoreHome/lang/en.json +++ b/plugins/CoreHome/lang/en.json @@ -11,6 +11,7 @@ "CloseWidgetDirections": "You can close this widget by clicking on the 'X' icon at the top of the widget.", "ChooseX": "Choose %1$s", "DataForThisReportHasBeenPurged": "The data for this report is more than %s months old and has been purged.", + "DataForThisReportHasBeenDisabled": "Segmentation is currently disabled for this report. Please check %1$sthis FAQ%2$s for more details.", "DataTableExcludeAggregateRows": "Aggregate rows are shown %s Hide them", "DataTableIncludeAggregateRows": "Aggregate rows are hidden %s Show them", "DataTableHowToSearch": "Press enter or click the search icon to search", diff --git a/plugins/CoreHome/templates/_dataTable.twig b/plugins/CoreHome/templates/_dataTable.twig index d1a934c961..96dd9841dc 100644 --- a/plugins/CoreHome/templates/_dataTable.twig +++ b/plugins/CoreHome/templates/_dataTable.twig @@ -59,6 +59,8 @@ <div class="pk-emptyDataTable"> {% if showReportDataWasPurgedMessage is defined and showReportDataWasPurgedMessage %} {{ 'CoreHome_DataForThisReportHasBeenPurged'|translate(deleteReportsOlderThan) }} + {% elseif showPluginArchiveDisabled is defined and showPluginArchiveDisabled%} + {{ 'CoreHome_DataForThisReportHasBeenDisabled'|translate('<a target="_blank" href="'~'https://matomo.org/faq/how-to-disable-archiving-the-segment-reports-for-specific-plugins' ~'">', '</a>')|raw }} {% elseif properties.no_data_message %} {{ properties.no_data_message|raw }} {% else %} diff --git a/tests/PHPUnit/Fixtures/DisablePluginArchive.php b/tests/PHPUnit/Fixtures/DisablePluginArchive.php new file mode 100644 index 0000000000..ff7e720ca6 --- /dev/null +++ b/tests/PHPUnit/Fixtures/DisablePluginArchive.php @@ -0,0 +1,186 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +namespace Piwik\Tests\Fixtures; + +use MatomoTracker; +use Piwik\Date; +use Piwik\Plugins\Goals\API as APIGoals; +use Piwik\Plugins\SitesManager\API as APISitesManager; +use Piwik\Tests\Framework\Fixture; +use Exception; +use Piwik\Tracker\Cache; + +/** + * Add config disable archiving + */ +class DisablePluginArchive extends Fixture +{ + public $idSite = 1; + public $dateTime = '2009-01-04 00:11:42'; + + public $trackInvalidRequests = true; + + public function setUp(): void + { + $this->setUpWebsitesAndGoals(); + $this->setUpConfig(); + $this->trackVisits(); + } + + public function tearDown(): void + { + $this->removeConfig(); + } + + + private function setUpWebsitesAndGoals() + { + if (!self::siteCreated($idSite = 1)) { + self::createWebsite($this->dateTime); + } + } + + private function trackVisits() + { + $dateTime = $this->dateTime; + $idSite = $this->idSite; + + self::createSuperUser(); + $t = self::getTracker($idSite, $dateTime, $defaultInit = true); + + Cache::clearCacheGeneral(); + Cache::regenerateCacheWebsiteAttributes(array($idSite)); + + if ($this->useThirdPartyCookies) { + $t->DEBUG_APPEND_URL = '&forceUseThirdPartyCookie=1'; + } + + $t->disableCookieSupport(); + + $t->setUrlReferrer('http://referrer.com/page.htm?param=valuewith some spaces'); + + // testing URL excluded parameters + $parameterToExclude = 'excluded_parameter'; + APISitesManager::getInstance()->updateSite( + $idSite, + 'new name', + $url = array('http://site.com'), + $ecommerce = 0, + $siteSearch = $this->useSiteSearch ? 1 : 0, + $searchKeywordParameters = $this->useSiteSearch ? '' : null, + $searchCategoryParameters = $this->useSiteSearch ? 'notparam' : null, + $excludedIps = null, + $parameterToExclude . ',anotherParameter', + $timezone = null, + $currency = null, + $group = null, + $startDate = null + ); + + // Record 1st page view + $urlPage1 = 'http://example.org/index.htm?excluded_Parameter=SHOULD_NOT_DISPLAY¶meter=Should display'; + $t->setUrl($urlPage1); + $t->setPerformanceTimings(33, 105, 205, 1325, 390, 222); + self::checkResponse($t->doTrackPageView('incredible title!')); + + // testing that / and index.htm above record with different URLs + // Recording the 2nd page after 3 minutes + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.05)->getDatetime()); + $t->setUrl('http://example.org/'); + $t->setPerformanceTimings(62, 198, 253, 1559, 222, 152); + self::checkResponse($t->doTrackPageView('Second page view - should be registered as URL /')); + + // Click on external link after 6 minutes (3rd action) + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.1)->getDatetime()); + + // Testing Outlink that contains a URL Fragment + self::checkResponse($t->doTrackAction('https://outlinks.org/#!outlink-with-fragment-<script>', 'link')); + + // Click on file download after 12 minutes (4th action) + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.2)->getDatetime()); + self::checkResponse($t->doTrackAction('http://piwik.org/path/again/latest.zip', 'download')); + + // Click on two more external links, one the same as before (5th & 6th actions) + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.22)->getDateTime()); + self::checkResponse($t->doTrackAction('http://outlinks.org/other_outlink#fragment&pk_campaign=Open%20partnership', 'link')); + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.25)->getDateTime()); + self::checkResponse($t->doTrackAction('http://dev.piwik.org/svn', 'link')); + + // Create Goal 1: Triggered by JS, after 18 minutes + $idGoal = 1; + if (!self::goalExists($idSite, $idGoal)) { + $idGoal = APIGoals::getInstance()->addGoal($idSite, 'triggered js', 'manually', '', ''); + } + + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.3)->getDatetime()); + + // Change to Thai browser to ensure the conversion is credited to FR instead (the visitor initial country) + $t->setBrowserLanguage('th'); + self::checkResponse($t->doTrackGoal($idGoal, $revenue = 42)); + + // Track same Goal twice (after 24 minutes), should only be tracked once + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.4)->getDatetime()); + self::checkResponse($t->doTrackGoal($idGoal, $revenue = 42)); + + $t->setBrowserLanguage('fr'); + + if ($this->useSiteSearch) { + // Site Search request + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.42)->getDatetime()); + $t->setUrl('http://example.org/index.htm?q=Banks Own The World'); + $t->setPerformanceTimings(17, 236, 385, 1025, 199, 266); + self::checkResponse($t->doTrackPageView('Site Search request')); + + // Final page view (after 27 min) + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.45)->getDatetime()); + $t->setUrl('http://example.org/index.htm'); + $t->setPerformanceTimings(42, 96, 200, 955, 566, 200); + self::checkResponse($t->doTrackPageView('Looking at homepage after site search...')); + } else { + // Final page view (after 27 min) + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.45)->getDatetime()); + $t->setUrl('http://example.org/index.htm#ignoredFragment#'); + $t->setPerformanceTimings(0, 222, 333, 1111, 666, 333); + self::checkResponse($t->doTrackPageView('Looking at homepage (again)...')); + } + + // - + // End of first visit: 24min + + // Create Goal 2: Matching on URL + if (!self::goalExists($idSite, $idGoal = 2)) { + APIGoals::getInstance()->addGoal($idSite, 'matching purchase.htm', 'url', '(.*)store\/purchase\.(.*)', 'regex', false, $revenue = 1); + } + + // - + // Start of returning visit, 1 hour after first page view + $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(1)->getDatetime()); + $t->setUrl('http://example.org/store/purchase.htm'); + $t->setUrlReferrer('http://search.yahoo.com/search?p=purchase'); + + // Goal Tracking URL matching, testing custom referrer including keyword + $t->setPerformanceTimings(22, 157, 266, 2000, 1002, 666); + self::checkResponse($t->doTrackPageView('Checkout/Purchasing...')); + // - + // End of second visit + } + + private function setUpConfig() + { + $testEnvironment = $this->getTestEnvironment(); + $testEnvironment->overrideConfig('General','disable_archiving_segment_for_plugins','Referrers'); + $testEnvironment->save(); + } + + private function removeConfig() + { + $testEnvironment = $this->getTestEnvironment(); + $testEnvironment->overrideConfig('General','disable_archiving_segment_for_plugins',''); + $testEnvironment->save(); + } +}
\ No newline at end of file diff --git a/tests/PHPUnit/Integration/ArchiveProcessor/LoaderTest.php b/tests/PHPUnit/Integration/ArchiveProcessor/LoaderTest.php index 7465261d28..95ea94833e 100644 --- a/tests/PHPUnit/Integration/ArchiveProcessor/LoaderTest.php +++ b/tests/PHPUnit/Integration/ArchiveProcessor/LoaderTest.php @@ -1463,6 +1463,56 @@ class LoaderTest extends IntegrationTestCase $this->assertTrue($loader->canSkipArchiveForSegment()); } + public function test_canSkipArchiveForSegment_returnTrueIfPluginIsDisabled() + { + Rules::setBrowserTriggerArchiving(false); + $config = Config::getInstance(); + $config->General['disable_archiving_segment_for_plugins'] = 'testPlugin'; + $date = '2010-04-23'; + $definition = 'browserCode==ch'; + $segment = new Segment($definition, [1]); + $doneFlag = Rules::getDoneStringFlagFor([1], $segment, 'day', null); + + $this->insertInvalidations([ + ['date1' => $date, 'date2' => $date, 'period' => 1, 'name' => $doneFlag, 'report' => 'myReport'], + ]); + + SegmentApi::getInstance()->add('segment', $definition, 1, true, true); + $params = new Parameters(new Site(1), Factory::build('day', $date), $segment); + $params->setRequestedPlugin('testPlugin'); + $params->setArchiveOnlyReport('myReport'); + $loader = new Loader($params); + $this->assertTrue($loader->canSkipArchiveForSegment()); + } + + public function test_canSkipArchiveForSegment_returnTrueIfPluginIsDisabledBySiteId() + { + Rules::setBrowserTriggerArchiving(false); + Config::setSetting('General_1','disable_archiving_segment_for_plugins','testPlugin'); + $date = '2010-04-23'; + $definition = 'browserCode==ch'; + $segment = new Segment($definition, [1]); + $doneFlag = Rules::getDoneStringFlagFor([1], $segment, 'day', null); + + $this->insertInvalidations([ + ['date1' => $date, 'date2' => $date, 'period' => 1, 'name' => $doneFlag, 'report' => 'myReport'], + ]); + + SegmentApi::getInstance()->add('segment', $definition, 1, true, true); + $params = new Parameters(new Site(1), Factory::build('day', $date), $segment); + $params->setRequestedPlugin('testPlugin'); + $params->setArchiveOnlyReport('myReport'); + $loader = new Loader($params); + $this->assertTrue($loader->canSkipArchiveForSegment()); + + $params = new Parameters(new Site(2), Factory::build('day', $date), $segment); + $params->setRequestedPlugin('testPlugin'); + $params->setArchiveOnlyReport('myReport'); + $loader = new Loader($params); + $this->assertFalse($loader->canSkipArchiveForSegment()); + } + + public function test_forcePluginArchiving_createsPluginSpecificArchive() { $_GET['trigger'] = 'archivephp'; diff --git a/tests/PHPUnit/System/ArchiveInvalidationTest.php b/tests/PHPUnit/System/ArchiveInvalidationTest.php index 4e537f9562..63c23b47a5 100644 --- a/tests/PHPUnit/System/ArchiveInvalidationTest.php +++ b/tests/PHPUnit/System/ArchiveInvalidationTest.php @@ -71,30 +71,42 @@ class ArchiveInvalidationTest extends SystemTestCase // Build tests for the 2 websites return array( - array($apiToCall, array('idSite' => self::$fixture->idSite2, - 'testSuffix' => 'Website' . self::$fixture->idSite2 . $this->suffix, - 'date' => self::$fixture->dateTimeFirstDateWebsite2, - 'periods' => 'day', - 'segment' => self::TEST_SEGMENT, - 'setDateLastN' => 4, // 4months ahead - 'otherRequestParameters' => array('expanded' => 1)) - ), - array($apiToCall, array('idSite' => self::$fixture->idSite1, - 'testSuffix' => 'Website' . self::$fixture->idSite1 . $this->suffix, - 'date' => self::$fixture->dateTimeFirstDateWebsite1, - 'periods' => 'month', - 'setDateLastN' => 4, // 4months ahead - 'otherRequestParameters' => array('expanded' => 1)) - ), - - array($apiToCall, array('idSite' => self::$fixture->idSite2, - 'testSuffix' => 'Website' . self::$fixture->idSite2 . $this->suffix, - 'date' => self::$fixture->dateTimeFirstDateWebsite2, - 'periods' => 'month', - 'segment' => self::TEST_SEGMENT, - 'setDateLastN' => 4, // 4months ahead - 'otherRequestParameters' => array('expanded' => 1)) + array( + $apiToCall, + array( + 'idSite' => self::$fixture->idSite2, + 'testSuffix' => 'Website' . self::$fixture->idSite2 . $this->suffix, + 'date' => self::$fixture->dateTimeFirstDateWebsite2, + 'periods' => 'day', + 'segment' => self::TEST_SEGMENT, + 'setDateLastN' => 4, // 4months ahead + 'otherRequestParameters' => array('expanded' => 1) ) + ), + array( + $apiToCall, + array( + 'idSite' => self::$fixture->idSite1, + 'testSuffix' => 'Website' . self::$fixture->idSite1 . $this->suffix, + 'date' => self::$fixture->dateTimeFirstDateWebsite1, + 'periods' => 'month', + 'setDateLastN' => 4, // 4months ahead + 'otherRequestParameters' => array('expanded' => 1) + ) + ), + + array( + $apiToCall, + array( + 'idSite' => self::$fixture->idSite2, + 'testSuffix' => 'Website' . self::$fixture->idSite2 . $this->suffix, + 'date' => self::$fixture->dateTimeFirstDateWebsite2, + 'periods' => 'month', + 'segment' => self::TEST_SEGMENT, + 'setDateLastN' => 4, // 4months ahead + 'otherRequestParameters' => array('expanded' => 1) + ) + ) ); } @@ -128,6 +140,72 @@ class ArchiveInvalidationTest extends SystemTestCase } } + public function testDisablePluginArchive() + { + $config = Config::getInstance(); + $config->General['disable_archiving_segment_for_plugins'] = 'testPlugin'; + $this->assertTrue(Rules::isSegmentPluginArchivingDisabled('testPlugin')); + + $config->General['disable_archiving_segment_for_plugins'] = ['testPlugin', 'testPlugin2']; + $this->assertTrue(Rules::isSegmentPluginArchivingDisabled('testPlugin')); + + $config->General['disable_archiving_segment_for_plugins'] = 'testPlugin,testPlugin2'; + $this->assertTrue(Rules::isSegmentPluginArchivingDisabled('testPlugin2')); + + $config->General['disable_archiving_segment_for_plugins'] = ''; + $this->assertFalse(Rules::isSegmentPluginArchivingDisabled('testPlugin')); + + } + + public function testDisablePluginArchiveCaseInsensitive() + { + $config = Config::getInstance(); + $config->General['disable_archiving_segment_for_plugins'] = 'testplugin,testplugin2'; + $this->assertTrue(Rules::isSegmentPluginArchivingDisabled('testPlugin')); + } + + public function testDisablePluginArchiveSpecialCharacters() + { + //special characters will not work + $config = Config::getInstance(); + $config->General['disable_archiving_segment_for_plugins'] = '!@##$%^^&&**(()_+'; + $this->assertFalse(Rules::isSegmentPluginArchivingDisabled('!@##$%^^&&**(()_+')); + } + + public function testDisablePluginArchiveBySiteId() + { + //test siteId 1 by string + Config::setSetting('General_1', 'disable_archiving_segment_for_plugins', 'testPlugin'); + $this->assertTrue(Rules::isSegmentPluginArchivingDisabled('testPlugin',1)); + + //test siteId 1 by array + Config::setSetting('General_1', 'disable_archiving_segment_for_plugins',['testPlugin', 'testPlugin2'] ); + $this->assertTrue(Rules::isSegmentPluginArchivingDisabled('testPlugin',1)); + + //test siteId 1 by string with comma + Config::setSetting('General_1', 'disable_archiving_segment_for_plugins','testPlugin,testPlugin2' ); + $this->assertTrue(Rules::isSegmentPluginArchivingDisabled('testPlugin',1)); + + //test empty + Config::setSetting('General_1', 'disable_archiving_segment_for_plugins','' ); + $this->assertFalse(Rules::isSegmentPluginArchivingDisabled('testPlugin',1)); + + //test siteId 2 not affect siteId1 + Config::setSetting('General_2', 'disable_archiving_segment_for_plugins','testPlugin' ); + $this->assertFalse(Rules::isSegmentPluginArchivingDisabled('testPlugin',1)); + + + //test general setting not affect siteId1 + Config::setSetting('General', 'disable_archiving_segment_for_plugins','myPlugin' ); + Config::setSetting('General_1', 'disable_archiving_segment_for_plugins','testPlugin' ); + $this->assertFalse(Rules::isSegmentPluginArchivingDisabled('myPlugin',1)); + + Config::setSetting('General_1', 'disable_archiving_segment_for_plugins', 'testPlugin2'); + $this->assertFalse(Rules::isSegmentPluginArchivingDisabled('testPlugin', 1)); + } + + + /** * This is called after getApiToTest() * We invalidate old reports and check that data is now returned for old dates @@ -164,4 +242,4 @@ class ArchiveInvalidationTest extends SystemTestCase } } -ArchiveInvalidationTest::$fixture = new VisitsTwoWebsitesWithAdditionalVisits();
\ No newline at end of file +ArchiveInvalidationTest::$fixture = new VisitsTwoWebsitesWithAdditionalVisits(); diff --git a/tests/PHPUnit/Unit/ConfigTest.php b/tests/PHPUnit/Unit/ConfigTest.php index 9a4dac2ffe..1627fcc9df 100644 --- a/tests/PHPUnit/Unit/ConfigTest.php +++ b/tests/PHPUnit/Unit/ConfigTest.php @@ -30,12 +30,12 @@ class MockIniSettingsProvider extends GlobalSettingsProvider parent::__construct(); $this->iniFileChain = new DumpConfigTestMockIniFileChain( - array( - $this->pathGlobal => $configGlobal, - $this->pathCommon => $configCommon, - $this->pathLocal => $configLocal, - ), - $configCache + array( + $this->pathGlobal => $configGlobal, + $this->pathCommon => $configCommon, + $this->pathLocal => $configLocal, + ), + $configCache ); } } @@ -112,8 +112,8 @@ class ConfigTest extends TestCase $this->assertEquals($stringWritten, $config->Category['test']); $config->Category = array( - 'test' => $config->Category['test'], - 'test2' => $stringWritten, + 'test' => $config->Category['test'], + 'test2' => $stringWritten, ); $this->assertEquals($stringWritten, $config->Category['test']); $this->assertEquals($stringWritten, $config->Category['test2']); @@ -147,7 +147,7 @@ class ConfigTest extends TestCase public function getDumpConfigData() { $header = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n" . - "; file automatically generated or modified by Matomo; you can manually override the default values in global.ini.php by redefining them in this file.\n"; + "; file automatically generated or modified by Matomo; you can manually override the default values in global.ini.php by redefining them in this file.\n"; return array( // Test name, array( @@ -156,194 +156,308 @@ class ConfigTest extends TestCase // COMMON // CACHE // --> EXPECTED <-- - array('global only, not cached', array( + array( + 'global only, not cached', + array( array(), // local array('General' => array('debug' => 1)), // global array(), // common array(), false, - )), + ) + ), - array('global only, cached get', array( + array( + 'global only, cached get', + array( array(), // local array('General' => array('debug' => 1)), // global array(), // common array('General' => array('debug' => 1)), false, - )), + ) + ), - array('global only, cached set', array( + array( + 'global only, cached set', + array( array(), // local array('General' => array('debug' => 1)), // global array(), // common array('General' => array('debug' => 2)), $header . "[General]\ndebug = 2\n\n", - )), + ) + ), - array('local copy (same), not cached', array( + array( + 'local copy (same), not cached', + array( array('General' => array('debug' => 1)), // local array('General' => array('debug' => 1)), // global array(), // common array(), false, - )), + ) + ), - array('local copy (same), cached get', array( + array( + 'local copy (same), cached get', + array( array('General' => array('debug' => 1)), // local array('General' => array('debug' => 1)), // global array(), // common array('General' => array('debug' => 1)), false, - )), + ) + ), - array('local copy (same), cached set', array( + array( + 'local copy (same), cached set', + array( array('General' => array('debug' => 1)), // local array('General' => array('debug' => 1)), // global array(), // common array('General' => array('debug' => 2)), $header . "[General]\ndebug = 2\n\n", - )), + ) + ), - array('local copy (different), not cached', array( + array( + 'local copy (different), not cached', + array( array('General' => array('debug' => 2)), // local array('General' => array('debug' => 1)), // global array(), // common array(), false, - )), + ) + ), - array('local copy (different), cached get', array( + array( + 'local copy (different), cached get', + array( array('General' => array('debug' => 2)), // local array('General' => array('debug' => 1)), // global array(), // common array('General' => array('debug' => 2)), false, - )), + ) + ), - array('local copy (different), cached set', array( + array( + 'local copy (different), cached set', + array( array('General' => array('debug' => 2)), // local array('General' => array('debug' => 1)), // global array(), // common array('General' => array('debug' => 3)), $header . "[General]\ndebug = 3\n\n", - )), + ) + ), - array('local copy, not cached, new section', array( + array( + 'local copy, not cached, new section', + array( array('Tracker' => array('anonymize' => 1)), // local array('General' => array('debug' => 1)), // global array(), // common array(), false, - )), + ) + ), - array('local copy, cached get, new section', array( + array( + 'local copy, cached get, new section', + array( array('Tracker' => array('anonymize' => 1)), // local array('General' => array('debug' => 1)), // global array(), // common array('Tracker' => array('anonymize' => 1)), false, - )), + ) + ), - array('local copy, cached set local, new section', array( + array( + 'local copy, cached set local, new section', + array( array('Tracker' => array('anonymize' => 1)), // local array('General' => array('debug' => 1)), // global array(), // common array('Tracker' => array('anonymize' => 2)), $header . "[Tracker]\nanonymize = 2\n\n", - )), + ) + ), - array('local copy, cached set global, new section', array( + array( + 'local copy, cached set global, new section', + array( array('Tracker' => array('anonymize' => 1)), // local array('General' => array('debug' => 1)), // global array(), // common array('General' => array('debug' => 2), 'Tracker' => array('anonymize' => 1)), $header . "[General]\ndebug = 2\n\n[Tracker]\nanonymize = 1\n\n", - )), + ) + ), - array('sort, common sections', array( - array('Tracker' => array('anonymize' => 1), // local - 'General' => array('debug' => 1)), - array('General' => array('debug' => 0), // global - 'Tracker' => array('anonymize' => 0)), + array( + 'sort, common sections', + array( + array( + 'Tracker' => array('anonymize' => 1), // local + 'General' => array('debug' => 1) + ), + array( + 'General' => array('debug' => 0), // global + 'Tracker' => array('anonymize' => 0) + ), array(), // common - array('Tracker' => array('anonymize' => 2), - 'General' => array('debug' => 1)), + array( + 'Tracker' => array('anonymize' => 2), + 'General' => array('debug' => 1) + ), $header . "[General]\ndebug = 1\n\n[Tracker]\nanonymize = 2\n\n", - )), + ) + ), - array('sort, common sections before new section', array( - array('Tracker' => array('anonymize' => 1), // local - 'General' => array('debug' => 1)), - array('General' => array('debug' => 0), // global - 'Tracker' => array('anonymize' => 0)), + array( + 'sort, common sections before new section', + array( + array( + 'Tracker' => array('anonymize' => 1), // local + 'General' => array('debug' => 1) + ), + array( + 'General' => array('debug' => 0), // global + 'Tracker' => array('anonymize' => 0) + ), array(), // common - array('Segment' => array('dimension' => 'foo'), - 'Tracker' => array('anonymize' => 1), // local - 'General' => array('debug' => 1)), + array( + 'Segment' => array('dimension' => 'foo'), + 'Tracker' => array('anonymize' => 1), // local + 'General' => array('debug' => 1) + ), $header . "[General]\ndebug = 1\n\n[Tracker]\nanonymize = 1\n\n[Segment]\ndimension = \"foo\"\n\n", - )), + ) + ), - array('change back to default', array( + array( + 'change back to default', + array( array('Tracker' => array('anonymize' => 1)), // local - array('Tracker' => array('anonymize' => 0), // global - 'General' => array('debug' => 1)), + array( + 'Tracker' => array('anonymize' => 0), // global + 'General' => array('debug' => 1) + ), array(), // common array('Tracker' => array('anonymize' => 0)), $header - )), + ) + ), - array('[General] trusted_hosts has been updated and only this one is written', array( + array( + '[General] trusted_hosts has been updated and only this one is written', + array( array('General' => array('trusted_hosts' => 'someRandomHostToOverwrite')), // local - array('General' => array('settingGlobal' => 'global', // global - 'settingCommon' => 'global', - 'trusted_hosts' => 'none')), - array('General' => array('settingCommon' => 'common', // common - 'settingCommon2' => 'common')), + array( + 'General' => array( + 'settingGlobal' => 'global', // global + 'settingCommon' => 'global', + 'trusted_hosts' => 'none' + ) + ), + array( + 'General' => array( + 'settingCommon' => 'common', // common + 'settingCommon2' => 'common' + ) + ), array('General' => array('trusted_hosts' => 'works')), $header . "[General]\ntrusted_hosts = \"works\"\n\n", - )), + ) + ), // Same as above but without trusted_hosts default value in global.ini.php // Also, settingCommon3 is the same in the local file as in common, so it is not written out - array('trusted_hosts and settingCommon3 changed ', array( + array( + 'trusted_hosts and settingCommon3 changed ', + array( array('General' => array('trusted_hosts' => 'someRandomHostToOverwrite')), // local - array('General' => array('settingGlobal' => 'global', // global - 'settingCommon' => 'global')), - array('General' => array('settingCommon' => 'common', // common - 'settingCommon2' => 'common', - 'settingCommon3' => 'common3')), - array('General' => array('trusted_hosts' => 'works', // common - 'settingCommon2' => 'common', // will be cleared since it's same as in common - 'settingCommon3' => 'commonOverridenByLocal')), + array( + 'General' => array( + 'settingGlobal' => 'global', // global + 'settingCommon' => 'global' + ) + ), + array( + 'General' => array( + 'settingCommon' => 'common', // common + 'settingCommon2' => 'common', + 'settingCommon3' => 'common3' + ) + ), + array( + 'General' => array( + 'trusted_hosts' => 'works', // common + 'settingCommon2' => 'common', // will be cleared since it's same as in common + 'settingCommon3' => 'commonOverridenByLocal' + ) + ), $header . "[General]\ntrusted_hosts = \"works\"\nsettingCommon3 = \"commonOverridenByLocal\"\n\n", - )), + ) + ), // the value in [General]->key has changed // the value in [CommonCategory]->newSetting has changed, // but [CommonCategory]->settingCommon2 hasn't so it is not written - array('Common tests file', array( + array( + 'Common tests file', + array( array('General' => array('key' => 'value')), // local - array('General' => array('key' => 'global'), // global - 'CommonCategory' => array('settingGlobal' => 'valueGlobal')), - array('CommonCategory' => array('settingCommon' => 'common', // common - 'settingCommon2' => 'common2')), - array('CommonCategory' => array('settingCommon2' => 'common2', - 'newSetting' => 'newValue'), - 'General' => array('key' => 'value')), + array( + 'General' => array('key' => 'global'), // global + 'CommonCategory' => array('settingGlobal' => 'valueGlobal') + ), + array( + 'CommonCategory' => array( + 'settingCommon' => 'common', // common + 'settingCommon2' => 'common2' + ) + ), + array( + 'CommonCategory' => array( + 'settingCommon2' => 'common2', + 'newSetting' => 'newValue' + ), + 'General' => array('key' => 'value') + ), $header . "[General]\nkey = \"value\"\n\n[CommonCategory]\nnewSetting = \"newValue\"\n\n", - )), + ) + ), - array('Converts Dollar Sign To Dollar Entity', array( + array( + 'Converts Dollar Sign To Dollar Entity', + array( array('General' => array('key' => '$value', 'key2' => '${value}')), // local - array('General' => array('key' => '$global'), // global - 'CommonCategory' => array('settingGlobal' => 'valueGlobal')), - array('CommonCategory' => array('settingCommon' => 'common', // common - 'settingCommon2' => 'common2')), - array('CommonCategory' => array('settingCommon2' => 'common2', - 'newSetting' => 'newValue'), - 'General' => array('key' => '$value', 'key2' => '${value}')), + array( + 'General' => array('key' => '$global'), // global + 'CommonCategory' => array('settingGlobal' => 'valueGlobal') + ), + array( + 'CommonCategory' => array( + 'settingCommon' => 'common', // common + 'settingCommon2' => 'common2' + ) + ), + array( + 'CommonCategory' => array( + 'settingCommon2' => 'common2', + 'newSetting' => 'newValue' + ), + 'General' => array('key' => '$value', 'key2' => '${value}') + ), $header . "[General]\nkey = \"$value\"\nkey2 = \"${value}\"\n\n[CommonCategory]\nnewSetting = \"newValue\"\n\n", - )), + ) + ), ); } @@ -377,7 +491,7 @@ class ConfigTest extends TestCase $sourceConfigFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/config.ini.php'; $configFile = PIWIK_INCLUDE_PATH . '/tmp/tmp.config.ini.php'; - if(file_exists($configFile)){ + if (file_exists($configFile)) { @unlink($configFile); } copy($sourceConfigFile, $configFile); @@ -387,7 +501,7 @@ class ConfigTest extends TestCase $this->assertEquals(file_get_contents($sourceConfigFile), file_get_contents($configFile)); - if(file_exists($configFile)){ + if (file_exists($configFile)) { @unlink($configFile); } } @@ -397,7 +511,7 @@ class ConfigTest extends TestCase $userFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/config.ini.php'; $globalFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/global.ini.php'; $commonFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/common.config.ini.php'; - + $config = new Config(new GlobalSettingsProvider($globalFile, $userFile, $commonFile)); $configCategory = $config->getFromGlobalConfig('Category'); @@ -405,25 +519,25 @@ class ConfigTest extends TestCase $this->assertEquals('value2', $configCategory['key2']); $this->assertEquals(array('key1' => 'value1', 'key2' => 'value2'), $configCategory); } - + public function testFromCommonConfig() { $userFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/config.ini.php'; $globalFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/global.ini.php'; $commonFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/common.config.ini.php'; - + $config = new Config(new GlobalSettingsProvider($globalFile, $userFile, $commonFile)); $configCategory = $config->getFromCommonConfig('Category'); $this->assertEquals(array('key2' => 'valueCommon', 'key3' => '${@piwik(crash))}'), $configCategory); } - + public function testFromLocalConfig() { $userFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/config.ini.php'; $globalFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/global.ini.php'; $commonFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/common.config.ini.php'; - + $config = new Config(new GlobalSettingsProvider($globalFile, $userFile, $commonFile)); $configCategory = $config->getFromLocalConfig('Category'); diff --git a/tests/UI/expected-screenshots/DisablePluginArchive_referrer_disabled.png b/tests/UI/expected-screenshots/DisablePluginArchive_referrer_disabled.png new file mode 100644 index 0000000000..cf3a6c5289 --- /dev/null +++ b/tests/UI/expected-screenshots/DisablePluginArchive_referrer_disabled.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d4e189d51d7afadc836f686214ce2c2575cec70abc6cd50c10080e7c4e54132 +size 34320 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png index 0047cf1938..a1cff9db36 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:068f11e129bdda8049dbac2ff4c565d521743210707f3be7f7dd3f150db47718 -size 5284899 +oid sha256:137be8e7a24b7075052f0839e2e5c10816d28d418ed9afb0f348e53c8b906b14 +size 5308352 diff --git a/tests/UI/specs/DisablePluginArchive_spec.js b/tests/UI/specs/DisablePluginArchive_spec.js new file mode 100644 index 0000000000..b760add62b --- /dev/null +++ b/tests/UI/specs/DisablePluginArchive_spec.js @@ -0,0 +1,27 @@ +/*! + * Matomo - free/libre analytics platform + * + * Tests that theming works. + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +describe("DisablePluginArchive", function () { + + this.fixture = 'Piwik\\Tests\\Fixtures\\DisablePluginArchive'; + + before(function () { + const firefoxUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 11.2; rv:85.0) Gecko/20100101 Firefox/85.0"; + page.setUserAgent(firefoxUserAgent); + }); + + var url = "?module=Widgetize&action=iframe&moduleToWidgetize=Referrers&idSite=1&period=year&date=2012-08-09&" + + "actionToWidgetize=getKeywords&viewDataTable=table&filter_limit=5&isFooterExpandedInDashboard=1&segment=actions%3D%3D1"; + + + it("should show plugin disable text", async function () { + await page.goto(url); + expect(await page.screenshot({ fullPage: true })).to.matchImage('referrer_disabled'); + }); +}); |