Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
SitemapTest.php
Go to the documentation of this file.
1 <?php
7 
17 use Magento\Sitemap\Model\ResourceModel\Catalog\CategoryFactory;
19 use Magento\Sitemap\Model\ResourceModel\Catalog\ProductFactory;
21 use Magento\Sitemap\Model\ResourceModel\Cms\PageFactory;
28 
32 class SitemapTest extends \PHPUnit\Framework\TestCase
33 {
37  private $helperMockSitemap;
38 
42  private $resourceMock;
43 
47  private $sitemapCategoryMock;
48 
52  private $sitemapProductMock;
53 
57  private $sitemapCmsPageMock;
58 
62  private $filesystemMock;
63 
67  private $directoryMock;
68 
72  private $fileMock;
73 
77  private $storeManagerMock;
78 
82  private $itemProviderMock;
83 
87  private $configReaderMock;
88 
92  protected function setUp()
93  {
94  $this->sitemapCategoryMock = $this->getMockBuilder(Category::class)
95  ->disableOriginalConstructor()
96  ->getMock();
97  $this->sitemapProductMock = $this->getMockBuilder(Product::class)
98  ->disableOriginalConstructor()
99  ->getMock();
100  $this->sitemapCmsPageMock = $this->getMockBuilder(Page::class)
101  ->disableOriginalConstructor()
102  ->getMock();
103 
104  $this->helperMockSitemap = $this->getMockBuilder(Data::class)
105  ->disableOriginalConstructor()
106  ->getMock();
107 
108  $resourceMethods = [
109  '_construct',
110  'beginTransaction',
111  'rollBack',
112  'save',
113  'addCommitCallback',
114  'commit',
115  '__wakeup',
116  ];
117 
118  $this->resourceMock = $this->getMockBuilder(SitemapResource::class)
119  ->setMethods($resourceMethods)
120  ->disableOriginalConstructor()
121  ->getMock();
122 
123  $this->resourceMock->expects($this->any())
124  ->method('addCommitCallback')
125  ->willReturnSelf();
126 
127  $this->fileMock = $this->createMock(Write::class);
128 
129  $this->directoryMock = $this->createMock(DirectoryWrite::class);
130 
131  $this->directoryMock->expects($this->any())
132  ->method('openFile')
133  ->willReturn($this->fileMock);
134 
135  $this->filesystemMock = $this->getMockBuilder(Filesystem::class)
136  ->setMethods(['getDirectoryWrite'])
137  ->disableOriginalConstructor()
138  ->getMock();
139 
140  $this->filesystemMock->expects($this->any())
141  ->method('getDirectoryWrite')
142  ->willReturn($this->directoryMock);
143 
144  $this->configReaderMock = $this->getMockForAbstractClass(SitemapConfigReaderInterface::class);
145  $this->itemProviderMock = $this->getMockForAbstractClass(ItemProviderInterface::class);
146  }
147 
154  public function testNotAllowedPath()
155  {
156  $model = $this->getModelMock();
157  $model->setSitemapPath('../');
158  $model->beforeSave();
159  }
160 
167  public function testPathNotExists()
168  {
169  $this->directoryMock->expects($this->once())
170  ->method('isExist')
171  ->willReturn(false);
172 
173  $model = $this->getModelMock();
174  $model->beforeSave();
175  }
176 
183  public function testPathNotWritable()
184  {
185  $this->directoryMock->expects($this->once())
186  ->method('isExist')
187  ->willReturn(true);
188 
189  $this->directoryMock->expects($this->once())
190  ->method('isWritable')
191  ->willReturn(false);
192 
193  $model = $this->getModelMock();
194  $model->beforeSave();
195  }
196 
197  //@codingStandardsIgnoreStart
205  //@codingStandardsIgnoreEnd
206  public function testFilenameInvalidChars()
207  {
208  $this->directoryMock->expects($this->once())
209  ->method('isExist')
210  ->willReturn(true);
211 
212  $this->directoryMock->expects($this->once())
213  ->method('isWritable')
214  ->willReturn(true);
215 
216  $model = $this->getModelMock();
217  $model->setSitemapFilename('*sitemap?.xml');
218  $model->beforeSave();
219  }
220 
231  public static function sitemapDataProvider()
232  {
233  $expectedSingleFile = ['/sitemap-1-1.xml' => __DIR__ . '/_files/sitemap-single.xml'];
234 
235  $expectedMultiFile = [
236  '/sitemap-1-1.xml' => __DIR__ . '/_files/sitemap-1-1.xml',
237  '/sitemap-1-2.xml' => __DIR__ . '/_files/sitemap-1-2.xml',
238  '/sitemap-1-3.xml' => __DIR__ . '/_files/sitemap-1-3.xml',
239  '/sitemap-1-4.xml' => __DIR__ . '/_files/sitemap-1-4.xml',
240  '/sitemap.xml' => __DIR__ . '/_files/sitemap-index.xml',
241  ];
242 
243  return [
244  [50000, 10485760, $expectedSingleFile, 6],
245  [1, 10485760, $expectedMultiFile, 18],
246  [50000, 264, $expectedMultiFile, 18],
247  ];
248  }
249 
259  public function testGenerateXml($maxLines, $maxFileSize, $expectedFile, $expectedWrites)
260  {
261  $actualData = [];
263  $actualData,
264  $maxLines,
265  $maxFileSize,
266  $expectedFile,
267  $expectedWrites,
268  null
269  );
270  $model->generateXml();
271 
272  $this->assertCount(count($expectedFile), $actualData, 'Number of generated files is incorrect');
273  foreach ($expectedFile as $expectedFileName => $expectedFilePath) {
274  $this->assertArrayHasKey(
275  $expectedFileName,
276  $actualData,
277  sprintf('File %s was not generated', $expectedFileName)
278  );
279  $this->assertXmlStringEqualsXmlFile($expectedFilePath, $actualData[$expectedFileName]);
280  }
281  }
282 
289  public static function robotsDataProvider()
290  {
291  $expectedSingleFile = ['/sitemap-1-1.xml' => __DIR__ . '/_files/sitemap-single.xml'];
292 
293  $expectedMultiFile = [
294  '/sitemap-1-1.xml' => __DIR__ . '/_files/sitemap-1-1.xml',
295  '/sitemap-1-2.xml' => __DIR__ . '/_files/sitemap-1-2.xml',
296  '/sitemap-1-3.xml' => __DIR__ . '/_files/sitemap-1-3.xml',
297  '/sitemap-1-4.xml' => __DIR__ . '/_files/sitemap-1-4.xml',
298  '/sitemap.xml' => __DIR__ . '/_files/sitemap-index.xml',
299  ];
300 
301  return [
302  [
303  50000,
304  10485760,
305  $expectedSingleFile,
306  6,
307  [
308  'robotsStart' => '',
309  'robotsFinish' => 'Sitemap: http://store.com/sitemap.xml',
310  'pushToRobots' => 1
311  ],
312  ], // empty robots file
313  [
314  50000,
315  10485760,
316  $expectedSingleFile,
317  6,
318  [
319  'robotsStart' => "User-agent: *",
320  'robotsFinish' => "User-agent: *" . PHP_EOL . 'Sitemap: http://store.com/sitemap.xml',
321  'pushToRobots' => 1
322  ]
323  ], // not empty robots file EOL
324  [
325  1,
326  10485760,
327  $expectedMultiFile,
328  18,
329  [
330  'robotsStart' => "User-agent: *\r\n",
331  'robotsFinish' => "User-agent: *\r\n\r\nSitemap: http://store.com/sitemap.xml",
332  'pushToRobots' => 1
333  ]
334  ], // not empty robots file WIN
335  [
336  50000,
337  264,
338  $expectedMultiFile,
339  18,
340  [
341  'robotsStart' => "User-agent: *\n",
342  'robotsFinish' => "User-agent: *\n\nSitemap: http://store.com/sitemap.xml",
343  'pushToRobots' => 1
344  ]
345  ], // not empty robots file UNIX
346  [
347  50000,
348  10485760,
349  $expectedSingleFile,
350  6,
351  ['robotsStart' => '', 'robotsFinish' => '', 'pushToRobots' => 0]
352  ] // empty robots file
353  ];
354  }
355 
366  public function testAddSitemapToRobotsTxt($maxLines, $maxFileSize, $expectedFile, $expectedWrites, $robotsInfo)
367  {
368  $actualData = [];
370  $actualData,
371  $maxLines,
372  $maxFileSize,
373  $expectedFile,
374  $expectedWrites,
375  $robotsInfo
376  );
377  $model->generateXml();
378  }
379 
392  protected function prepareSitemapModelMock(
393  &$actualData,
394  $maxLines,
395  $maxFileSize,
396  $expectedFile,
397  $expectedWrites,
398  $robotsInfo
399  ) {
400  // Check that all $expectedWrites lines were written
401  $actualData = [];
402  $currentFile = '';
403  $streamWriteCallback = function ($str) use (&$actualData, &$currentFile) {
404  if (!array_key_exists($currentFile, $actualData)) {
405  $actualData[$currentFile] = '';
406  }
407  $actualData[$currentFile] .= $str;
408  };
409 
410  // Check that all expected lines were written
411  $this->fileMock->expects(
412  $this->exactly($expectedWrites)
413  )->method(
414  'write'
415  )->will(
416  $this->returnCallback($streamWriteCallback)
417  );
418 
419  $checkFileCallback = function ($file) use (&$currentFile) {
420  $currentFile = $file;
421  };// Check that all expected file descriptors were created
422  $this->directoryMock->expects($this->exactly(count($expectedFile)))->method('openFile')
423  ->willReturnCallback($checkFileCallback);
424 
425  // Check that all file descriptors were closed
426  $this->fileMock->expects($this->exactly(count($expectedFile)))
427  ->method('close');
428 
429  if (count($expectedFile) == 1) {
430  $this->directoryMock->expects($this->once())
431  ->method('renameFile')
432  ->willReturnCallback(function ($from, $to) {
433  \PHPUnit\Framework\Assert::assertEquals('/sitemap-1-1.xml', $from);
434  \PHPUnit\Framework\Assert::assertEquals('/sitemap.xml', $to);
435  });
436  }
437 
438  // Check robots txt
439  $robotsStart = '';
440  if (isset($robotsInfo['robotsStart'])) {
441  $robotsStart = $robotsInfo['robotsStart'];
442  }
443  $robotsFinish = 'Sitemap: http://store.com/sitemap.xml';
444  if (isset($robotsInfo['robotsFinish'])) {
445  $robotsFinish = $robotsInfo['robotsFinish'];
446  }
447  $this->directoryMock->expects($this->any())
448  ->method('readFile')
449  ->willReturn($robotsStart);
450 
451  $this->directoryMock->expects($this->any())
452  ->method('writeFile')
453  ->with(
454  $this->equalTo('robots.txt'),
455  $this->equalTo($robotsFinish)
456  );
457 
458  // Mock helper methods
459  $pushToRobots = 0;
460  if (isset($robotsInfo['pushToRobots'])) {
461  $pushToRobots = (int)$robotsInfo['pushToRobots'];
462  }
463  $this->configReaderMock->expects($this->any())
464  ->method('getMaximumLinesNumber')
465  ->willReturn($maxLines);
466 
467  $this->configReaderMock->expects($this->any())
468  ->method('getMaximumFileSize')
469  ->willReturn($maxFileSize);
470 
471  $this->configReaderMock->expects($this->any())
472  ->method('getEnableSubmissionRobots')
473  ->willReturn($pushToRobots);
474 
475  $model = $this->getModelMock(true);
476 
477  $storeMock = $this->getMockBuilder(Store::class)
478  ->setMethods(['isFrontUrlSecure', 'getBaseUrl'])
479  ->disableOriginalConstructor()
480  ->getMock();
481 
482  $storeMock->expects($this->atLeastOnce())
483  ->method('isFrontUrlSecure')
484  ->willReturn(false);
485 
486  $storeMock->expects($this->atLeastOnce())
487  ->method('getBaseUrl')
488  ->with($this->isType('string'), false)
489  ->willReturn('http://store.com/');
490 
491  $this->storeManagerMock->expects($this->atLeastOnce())
492  ->method('getStore')
493  ->with(1)
494  ->willReturn($storeMock);
495 
496  return $model;
497  }
498 
505  protected function getModelMock($mockBeforeSave = false)
506  {
507  $methods = [
508  '_construct',
509  '_getResource',
510  '_getBaseDir',
511  '_getFileObject',
512  '_afterSave',
513  '_getCurrentDateTime',
514  '_getCategoryItemsCollection',
515  '_getProductItemsCollection',
516  '_getPageItemsCollection',
517  '_getDocumentRoot',
518  ];
519  if ($mockBeforeSave) {
520  $methods[] = 'beforeSave';
521  }
522 
523  $storeBaseMediaUrl = 'http://store.com/pub/media/catalog/product/cache/c9e0b0ef589f3508e5ba515cde53c5ff/';
524 
525  $this->itemProviderMock->expects($this->any())
526  ->method('getItems')
527  ->willReturn([
528  new SitemapItem('category.html', '1.0', 'daily', '2012-12-21 00:00:00'),
529  new SitemapItem('/category/sub-category.html', '1.0', 'daily', '2012-12-21 00:00:00'),
530  new SitemapItem('product.html', '0.5', 'monthly', '0000-00-00 00:00:00'),
531  new SitemapItem(
532  'product2.html',
533  '0.5',
534  'monthly',
535  '2012-12-21 00:00:00',
536  new DataObject([
537  'collection' => [
538  new DataObject(
539  [
540  'url' => $storeBaseMediaUrl . 'i/m/image1.png',
541  'caption' => 'caption & > title < "'
542  ]
543  ),
544  new DataObject(
545  ['url' => $storeBaseMediaUrl . 'i/m/image_no_caption.png', 'caption' => null]
546  ),
547  ],
548  'thumbnail' => $storeBaseMediaUrl . 't/h/thumbnail.jpg',
549  'title' => 'Product & > title < "',
550  ])
551  )
552  ]);
553 
555  $model = $this->getMockBuilder(Sitemap::class)
556  ->setMethods($methods)
557  ->setConstructorArgs($this->getModelConstructorArgs())
558  ->getMock();
559 
560  $model->expects($this->any())
561  ->method('_getResource')
562  ->willReturn($this->resourceMock);
563 
564  $model->expects($this->any())
565  ->method('_getCurrentDateTime')
566  ->willReturn('2012-12-21T00:00:00-08:00');
567 
568  $model->expects($this->any())
569  ->method('_getDocumentRoot')
570  ->willReturn('/project');
571 
572  $model->setSitemapFilename('sitemap.xml');
573  $model->setStoreId(1);
574  $model->setSitemapPath('/');
575 
576  return $model;
577  }
578 
582  private function getModelConstructorArgs()
583  {
584  $categoryFactory = $this->getMockBuilder(CategoryFactory::class)
585  ->disableOriginalConstructor()
586  ->getMock();
587 
588  $productFactory = $this->getMockBuilder(ProductFactory::class)
589  ->disableOriginalConstructor()
590  ->getMock();
591 
592  $cmsFactory = $this->getMockBuilder(PageFactory::class)
593  ->disableOriginalConstructor()
594  ->getMock();
595 
596  $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
597  ->setMethods(['getStore'])
598  ->getMockForAbstractClass();
599 
600  $objectManager = new ObjectManager($this);
601  $constructArguments = $objectManager->getConstructArguments(
602  Sitemap::class,
603  [
604  'categoryFactory' => $categoryFactory,
605  'productFactory' => $productFactory,
606  'cmsFactory' => $cmsFactory,
607  'storeManager' => $this->storeManagerMock,
608  'sitemapData' => $this->helperMockSitemap,
609  'filesystem' => $this->filesystemMock,
610  'itemProvider' => $this->itemProviderMock,
611  'configReader' => $this->configReaderMock,
612  ]
613  );
614  $constructArguments['resource'] = null;
615  return $constructArguments;
616  }
617 
629  public function testGetSitemapUrl($storeBaseUrl, $documentRoot, $baseDir, $sitemapPath, $sitemapFileName, $result)
630  {
632  $model = $this->getMockBuilder(Sitemap::class)
633  ->setMethods(
634  [
635  '_getStoreBaseUrl',
636  '_getDocumentRoot',
637  '_getBaseDir',
638  '_construct',
639  ]
640  )
641  ->setConstructorArgs($this->getModelConstructorArgs())
642  ->getMock();
643 
644  $model->expects($this->any())
645  ->method('_getStoreBaseUrl')
646  ->willReturn($storeBaseUrl);
647 
648  $model->expects($this->any())
649  ->method('_getDocumentRoot')
650  ->willReturn($documentRoot);
651 
652  $model->expects($this->any())
653  ->method('_getBaseDir')
654  ->willReturn($baseDir);
655 
656  $this->assertEquals($result, $model->getSitemapUrl($sitemapPath, $sitemapFileName));
657  }
658 
665  public static function siteUrlDataProvider()
666  {
667  return [
668  [
669  'http://store.com',
670  'c:\\http\\mage2\\',
671  'c:\\http\\mage2\\',
672  '/',
673  'sitemap.xml',
674  'http://store.com/sitemap.xml',
675  ],
676  [
677  'http://store.com/store2',
678  'c:\\http\\mage2\\',
679  'c:\\http\\mage2\\',
680  '/sitemaps/store2',
681  'sitemap.xml',
682  'http://store.com/sitemaps/store2/sitemap.xml'
683  ],
684  [
685  'http://store.com/builds/regression/ee/',
686  '/var/www/html',
687  '/opt/builds/regression/ee',
688  '/',
689  'sitemap.xml',
690  'http://store.com/builds/regression/ee/sitemap.xml'
691  ],
692  [
693  'http://store.com/store2',
694  'c:\\http\\mage2\\',
695  'c:\\http\\mage2\\store2',
696  '/sitemaps/store2',
697  'sitemap.xml',
698  'http://store.com/store2/sitemaps/store2/sitemap.xml'
699  ],
700  [
701  'http://store2.store.com',
702  'c:\\http\\mage2\\',
703  'c:\\http\\mage2\\',
704  '/sitemaps/store2',
705  'sitemap.xml',
706  'http://store2.store.com/sitemaps/store2/sitemap.xml'
707  ],
708  [
709  'http://store.com',
710  '/var/www/store/',
711  '/var/www/store/',
712  '/',
713  'sitemap.xml',
714  'http://store.com/sitemap.xml'
715  ],
716  [
717  'http://store.com/store2',
718  '/var/www/store/',
719  '/var/www/store/store2/',
720  '/sitemaps/store2',
721  'sitemap.xml',
722  'http://store.com/store2/sitemaps/store2/sitemap.xml'
723  ]
724  ];
725  }
726 }
prepareSitemapModelMock(&$actualData, $maxLines, $maxFileSize, $expectedFile, $expectedWrites, $robotsInfo)
testGenerateXml($maxLines, $maxFileSize, $expectedFile, $expectedWrites)
$objectManager
Definition: bootstrap.php:17
$baseDir
Definition: autoload.php:9
defined('TESTS_BP')||define('TESTS_BP' __DIR__
Definition: _bootstrap.php:60
testAddSitemapToRobotsTxt($maxLines, $maxFileSize, $expectedFile, $expectedWrites, $robotsInfo)
$methods
Definition: billing.phtml:71