first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
{
"version": "https://jsonfeed.org/version/1.1",
"title": "Drupal Announcements Feed",
"home_page_url": "https://www.drupal.org",
"feed_url": "https://www.drupal.org/announcements.json",
"favicon": "https://www.drupal.org/favicon.ico",
"items": [
{
"id": "201",
"title": "new 9 - 10 Drupal 9.1.3 is available",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": false,
"version": "^9 | ^10"
}
},
{
"id": "2021",
"title": "updated 10 - DrupalCon is here",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": true,
"version": "^10"
}
},
{
"id": "2031",
"title": "new 9 only - Download latest drupal here",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": false,
"version": "^9"
}
},
{
"id": "2043",
"title": "Only 10 - Drupal 106 is available",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:39+00:00",
"date_published": "2021-01-18T07:29:39+00:00",
"_drupalorg": {
"featured": false,
"version": "^10"
}
}
]
}

View File

@@ -0,0 +1,8 @@
{
"version": "https://jsonfeed.org/version/1.1",
"title": "Drupal Announcements Feed",
"home_page_url": "https://www.drupal.org",
"feed_url": "https://www.drupal.org/announcements.json",
"favicon": "https://www.drupal.org/favicon.ico",
"items": []
}

View File

@@ -0,0 +1,45 @@
{
"version": "https://jsonfeed.org/version/1.1",
"title": "Drupal Announcements Feed",
"home_page_url": "https://www.drupal.org",
"feed_url": "https://www.drupal.org/announcements.json",
"favicon": "https://www.drupal.org/favicon.ico",
"items": [
{
"id": "201",
"title": "new 9 - 10 Drupal 9.1.3 is available",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": true,
"version": "^9 | ^10"
}
},
{
"id": "2021",
"title": "updated 10 - DrupalCon is here",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": false,
"version": "^10"
}
},
{
"id": "2031",
"title": "new 9 only - Download latest drupal here",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": false,
"version": "^9"
}
}
]
}

View File

@@ -0,0 +1,69 @@
{
"version": "https://jsonfeed.org/version/1.1",
"title": "Drupal Announcements Feed",
"home_page_url": "https://www.drupal.org",
"feed_url": "https://www.drupal.org/announcements.json",
"favicon": "https://www.drupal.org/favicon.ico",
"items": [
{
"id": "201",
"title": "new 9 - 10 Drupal 9.1.3 is available",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg":{
"featured": true,
"version": "^9 | ^10"
}
},
{
"id": "2021",
"title": "updated 10 - DrupalCon is here",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": false,
"version": "^10"
}
},
{
"id": "2031",
"title": "new 9 only - Download latest drupal here",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:38+00:00",
"date_published": "2021-01-18T07:29:38+00:00",
"_drupalorg": {
"featured": false,
"version": "^9"
}
},
{
"id": "2043",
"title": "announce title updated",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce",
"date_modified": "2021-01-19T07:29:39+00:00",
"date_published": "2021-01-18T07:29:39+00:00",
"_drupalorg": {
"featured": false,
"version": "^10"
}
},
{
"id": "2044",
"title": "Only 10 - Drupal 106 is available and this feed is Updated",
"content_html": "This release will have a community alert prototype to notify site admins about drupal updates and required information",
"url": "https://www.drupal.org/project/announce-updated",
"date_modified": "2021-01-19T07:29:39+00:00",
"date_published": "2021-01-18T07:29:39+00:00",
"_drupalorg": {
"featured": false,
"version": "^10"
}
}
]
}

View File

@@ -0,0 +1,9 @@
name: 'Announce feed test'
type: module
description: 'Support module for announce feed testing.'
package: Testing
# Information added by Drupal.org packaging script on 2024-07-04
version: '10.3.1'
project: 'drupal'
datestamp: 1720094222

View File

@@ -0,0 +1,7 @@
announce_feed_test.json_test:
path: '/announce-feed-json/{json_name}'
defaults:
_title: 'Announce Feed test'
_controller: '\Drupal\announce_feed_test\Controller\AnnounceTestController::setFeedConfig'
requirements:
_access: 'TRUE'

View File

@@ -0,0 +1,5 @@
services:
announce_feed_test.announce_client_middleware:
class: Drupal\announce_feed_test\AnnounceTestHttpClientMiddleware
tags:
- { name: http_client_middleware }

View File

@@ -0,0 +1,48 @@
<?php
namespace Drupal\announce_feed_test;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Url;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\Uri;
use Psr\Http\Message\RequestInterface;
/**
* Overrides the requested endpoint when running tests.
*/
class AnnounceTestHttpClientMiddleware {
/**
* HTTP middleware that replaces request endpoint for a test one.
*/
public function __invoke(): \Closure {
return function ($handler) {
return function (RequestInterface $request, array $options) use ($handler): PromiseInterface {
$test_end_point = \Drupal::state()->get('announce_test_endpoint');
if ($test_end_point && str_contains($request->getUri(), '://www.drupal.org/announcements.json')) {
// Only override $uri if it matches the advisories JSON feed to avoid
// changing any other uses of the 'http_client' service during tests with
// this module installed.
$request = $request->withUri(new Uri($test_end_point));
}
return $handler($request, $options);
};
};
}
/**
* Sets the test endpoint for the advisories JSON feed.
*
* @param string $test_endpoint
* The test endpoint.
*/
public static function setAnnounceTestEndpoint(string $test_endpoint): void {
// Convert the endpoint to an absolute URL.
$test_endpoint = Url::fromUri('base:/' . $test_endpoint)->setAbsolute()->toString();
\Drupal::state()->set('announce_test_endpoint', $test_endpoint);
\Drupal::service('keyvalue.expirable')->get('announcements_feed')->delete('announcements');
Cache::invalidateTags(['announcements_feed:feed']);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Drupal\announce_feed_test\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
/**
* Defines a controller to return JSON for security advisory tests.
*/
class AnnounceTestController {
/**
* Reads a JSON file and returns the contents as a Response.
*
* This method will replace the string '[CORE_VERSION]' with the current core
* version to allow testing core version matches.
*
* @param string $json_name
* The name of the JSON file without the file extension.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
* If a fixture file with the name $json_name + '.json' is found a
* JsonResponse will be returned using the contents of the file, otherwise a
* Response will be returned with a 404 status code.
*/
public function setFeedConfig(string $json_name): JsonResponse|Response {
$file = __DIR__ . "/../../../../announce_feed/$json_name.json";
$headers = ['Content-Type' => 'application/json; charset=utf-8'];
if (!is_file($file)) {
// Return an empty response.
return new Response('', 404, $headers);
}
return new JsonResponse(file_get_contents($file), 200, $headers, TRUE);
}
}

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
/**
* Defines a class for testing pages are still cacheable with dynamic page cache.
*
* @group announcements_feed
*/
final class AnnouncementsCacheTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'announcements_feed',
'dynamic_page_cache',
'toolbar',
];
/**
* Tests dynamic page cache.
*/
public function testDynamicPageCache(): void {
$this->drupalLogin($this->drupalCreateUser([
'access toolbar',
'access announcements',
]));
// Front-page is visited right after login.
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'MISS');
// Reload the page, it should be cached now.
$this->drupalGet(Url::fromRoute('<front>'));
$this->assertSession()->elementExists('css', '[data-drupal-announce-trigger]');
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'HIT');
}
}

View File

@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\Functional;
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
/**
* Generic module test for announcements_feed.
*
* @group announcements_feed
*/
class GenericTest extends GenericModuleTestBase {}

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\FunctionalJavascript;
use Drupal\Tests\system\FunctionalJavascript\OffCanvasTestBase;
use Drupal\announce_feed_test\AnnounceTestHttpClientMiddleware;
/**
* Test the access announcement permissions to get access announcement icon.
*
* @group announcements_feed
*/
class AccessAnnouncementTest extends OffCanvasTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'user',
'toolbar',
'announcements_feed',
'announce_feed_test',
];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
public function setUp():void {
parent::setUp();
AnnounceTestHttpClientMiddleware::setAnnounceTestEndpoint('/announce-feed-json/community-feeds');
}
/**
* Test of viewing announcements by a user with appropriate permission.
*/
public function testAnnounceFirstLogin(): void {
$this->drupalLogin(
$this->drupalCreateUser(
[
'access toolbar',
'access announcements',
]
)
);
$this->drupalGet('<front>');
// Check that the user can see the toolbar.
$this->assertSession()->elementExists('css', '#toolbar-bar');
// And the announcements.
$this->assertSession()->elementExists('css', '.toolbar-icon-announce');
}
/**
* Testing announce icon without announce permission.
*/
public function testAnnounceWithoutPermission(): void {
// User without "access announcements" permission.
$account = $this->drupalCreateUser(
[
'access toolbar',
]
);
$this->drupalLogin($account);
$this->drupalGet('<front>');
// Check that the user can see the toolbar.
$this->assertSession()->elementExists('css', '#toolbar-bar');
// But not the announcements.
$this->assertSession()->elementNotExists('css', '.toolbar-icon-announce');
$this->drupalGet('admin/announcements_feed');
$this->assertSession()->responseContains('You are not authorized to access this page.');
}
}

View File

@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\FunctionalJavascript;
use Drupal\Tests\system\FunctionalJavascript\OffCanvasTestBase;
use Drupal\announce_feed_test\AnnounceTestHttpClientMiddleware;
use Drupal\user\UserInterface;
/**
* Test the access announcement according to json feed changes.
*
* @group announcements_feed
*/
class AlertsJsonFeedTest extends OffCanvasTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'user',
'toolbar',
'announcements_feed',
'announce_feed_test',
];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* A user with permission to access toolbar and access announcements.
*
* @var \Drupal\user\UserInterface
*/
protected UserInterface $user;
/**
* {@inheritdoc}
*/
public function setUp():void {
parent::setUp();
$this->user = $this->drupalCreateUser(
[
'access toolbar',
'access announcements',
]
);
AnnounceTestHttpClientMiddleware::setAnnounceTestEndpoint('/announce-feed-json/community-feeds');
}
/**
* Check the status of the announcements when the feed is updated and removed.
*/
public function testAnnounceFeedUpdatedAndRemoved(): void {
$this->markTestSkipped('Skipped due to major version-specific logic. See https://www.drupal.org/project/drupal/issues/3359322');
$this->drupalLogin($this->user);
$this->drupalGet('<front>');
$this->clickLink('Announcements');
$this->waitForOffCanvasToOpen();
$page_html = $this->getSession()->getPage()->getHtml();
$this->assertStringNotContainsString('Only 10 - Drupal 106 is available and this feed is Updated', $page_html);
// Change the feed url and reset temp storage.
AnnounceTestHttpClientMiddleware::setAnnounceTestEndpoint('/announce-feed-json/updated');
$this->drupalGet('<front>');
$this->clickLink('Announcements');
$this->waitForOffCanvasToOpen();
$page_html = $this->getSession()->getPage()->getHtml();
$this->assertStringContainsString('Only 10 - Drupal 106 is available and this feed is Updated', $page_html);
$this->drupalLogout();
// Change the feed url and reset temp storage.
AnnounceTestHttpClientMiddleware::setAnnounceTestEndpoint('/announce-feed-json/removed');
$this->drupalLogin($this->user);
$this->drupalGet('<front>');
$this->clickLink('Announcements');
$this->waitForOffCanvasToOpen();
$page_html = $this->getSession()->getPage()->getHtml();
$this->assertStringNotContainsString('Only 10 - Drupal 106 is available and this feed is Updated', $page_html);
}
/**
* Check with an empty JSON feed.
*/
public function testAnnounceFeedEmpty(): void {
// Change the feed url and reset temp storage.
AnnounceTestHttpClientMiddleware::setAnnounceTestEndpoint('/announce-feed-json/empty');
$this->drupalLogin($this->user);
$this->drupalGet('<front>');
// Removed items should not display in the announcement model.
$this->clickLink('Announcements');
$this->waitForOffCanvasToOpen();
$this->assertStringContainsString('No announcements available', $this->getSession()->getPage()->getHtml());
}
}

View File

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\FunctionalJavascript;
use Drupal\announce_feed_test\AnnounceTestHttpClientMiddleware;
use Drupal\block\BlockInterface;
use Drupal\Core\Access\AccessResultAllowed;
use Drupal\Core\Access\AccessResultNeutral;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
/**
* Test the announcement block test visibility.
*
* @group announcements_feed
*/
class AnnounceBlockTest extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'announcements_feed',
'block',
];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* The announce block instance.
*
* @var \Drupal\block\BlockInterface
*/
protected BlockInterface $announceBlock;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
AnnounceTestHttpClientMiddleware::setAnnounceTestEndpoint('/announce-feed-json/community-feeds');
$this->announceBlock = $this->placeBlock('announce_block', [
'label' => 'Announcements Feed',
]);
}
/**
* Testing announce feed block visibility.
*/
public function testAnnounceWithoutPermission(): void {
// User with "access announcements" permission and anonymous session.
$account = $this->drupalCreateUser([
'access announcements',
]);
$anonymous_account = new AnonymousUserSession();
$this->drupalLogin($account);
$this->drupalGet('<front>');
$assert_session = $this->assertSession();
// Block should be visible for the user.
$assert_session->pageTextContains('Announcements Feed');
// Block is not accessible without permission.
$this->drupalLogout();
$assert_session->pageTextNotContains('Announcements Feed');
// Test access() method return type.
$this->assertTrue($this->announceBlock->getPlugin()->access($account));
$this->assertInstanceOf(AccessResultAllowed::class, $this->announceBlock->getPlugin()->access($account, TRUE));
$this->assertFalse($this->announceBlock->getPlugin()->access($anonymous_account));
$this->assertInstanceOf(AccessResultNeutral::class, $this->announceBlock->getPlugin()->access($anonymous_account, TRUE));
}
}

View File

@@ -0,0 +1,156 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\Kernel;
use GuzzleHttp\Psr7\Response;
/**
* @coversDefaultClass \Drupal\announcements_feed\AnnounceFetcher
*
* @group announcements_feed
*/
class AnnounceFetcherTest extends AnnounceTestBase {
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installConfig(['announcements_feed']);
}
/**
* Tests announcement that should be displayed.
*
* @param mixed[] $feed_item
* The feed item to test. 'title' and 'url' are omitted from this array
* because they do not need to vary between test cases.
*
* @dataProvider providerShowAnnouncements
*/
public function testShowAnnouncements(array $feed_item): void {
$this->markTestSkipped('Skipped due to major version-specific logic. See https://www.drupal.org/project/drupal/issues/3359322');
$this->setFeedItems([$feed_item]);
$feeds = $this->fetchFeedItems();
$this->assertCount(1, $feeds);
$this->assertSame('https://www.drupal.org/project/announce', $feeds[0]->url);
$this->assertSame('Drupal security update Test', $feeds[0]->title);
$this->assertSame('^10', $feeds[0]->version);
$this->assertCount(1, $this->history);
}
/**
* Tests feed fields.
*/
public function testFeedFields(): void {
$this->markTestSkipped('Skipped due to major version-specific logic. See https://www.drupal.org/project/drupal/issues/3359322');
$feed_item_1 = [
'id' => '1001',
'content_html' => 'Test teaser 1',
'url' => 'https://www.drupal.org/project/announce',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => "2021-09-02T15:09:42+00:00",
'date_published' => "2021-09-01T15:09:42+00:00",
];
$this->setFeedItems([$feed_item_1]);
$feeds = $this->fetchFeedItems();
$this->assertCount(1, $feeds);
$this->assertSame($feed_item_1['id'], $feeds[0]->id);
$this->assertSame($feed_item_1['content_html'], $feeds[0]->content_html);
$this->assertSame($feed_item_1['_drupalorg']['featured'], $feeds[0]->featured);
$this->assertSame($feed_item_1['date_published'], $feeds[0]->date_published);
$this->assertSame($feed_item_1['_drupalorg']['version'], $feeds[0]->version);
}
/**
* Data provider for testShowAnnouncements().
*/
public static function providerShowAnnouncements(): array {
return [
'1' => [
'feed_item' => [
'id' => '1001',
'content_html' => 'Test teaser 1',
'_drupalorg' => [
'featured' => 1,
'version' => '^10',
],
'date_modified' => "2021-09-02T15:09:42+00:00",
'date_published' => "2021-09-01T15:09:42+00:00",
],
],
'2' => [
'feed_item' => [
'id' => '1002',
'content_html' => 'Test teaser 2',
'_drupalorg' => [
'featured' => 1,
'version' => '^10',
],
'date_modified' => "2021-09-02T15:09:42+00:00",
'date_published' => "2021-09-01T15:09:42+00:00",
],
],
'3' => [
'feed_item' => [
'id' => '1003',
'content_html' => 'Test teaser 3',
'_drupalorg' => [
'featured' => 1,
'version' => '^10',
],
'date_modified' => "2021-09-02T15:09:42+00:00",
'date_published' => "2021-09-01T15:09:42+00:00",
],
],
'4' => [
'feed_item' => [
'id' => '1004',
'content_html' => 'Test teaser 4',
'_drupalorg' => [
'featured' => 1,
'version' => '^10',
],
'date_modified' => "2021-09-02T15:09:42+00:00",
'date_published' => "2021-09-01T15:09:42+00:00",
],
],
];
}
/**
* Sets the feed items to be returned for the test.
*
* @param mixed[][] $feed_items
* The feeds items to test. Every time the http_client makes a request the
* next item in this array will be returned. For each feed item 'title' and
* 'url' are omitted because they do not need to vary between test cases.
*/
protected function setFeedItems(array $feed_items): void {
$responses = [];
foreach ($feed_items as $feed_item) {
$feed_item += [
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
];
$responses[] = new Response(200, [], json_encode(['items' => [$feed_item]]));
}
$this->setTestFeedResponses($responses);
}
/**
* Gets the announcements from the 'announce.fetcher' service.
*
* @return \Drupal\announcements_feed\Announcement[]
* The return value of AnnounceFetcher::fetch().
*/
protected function fetchFeedItems(): array {
return $this->container->get('announcements_feed.fetcher')->fetch();
}
}

View File

@@ -0,0 +1,228 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\Kernel;
use Drupal\Tests\user\Traits\UserCreationTrait;
use GuzzleHttp\Psr7\Response;
/**
* @coversDefaultClass \Drupal\announcements_feed\AnnounceFetcher
*
* @group announcements_feed
*/
class AnnounceFetcherUserTest extends AnnounceTestBase {
use UserCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'toolbar',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installSchema('user', ['users_data']);
// Setting current user.
$permissions = [
'access toolbar',
'access announcements',
];
$this->setUpCurrentUser(['uid' => 1], $permissions);
}
/**
* Tests testAllAnnouncements should get all announcements.
*
* First time accessing the announcements.
*/
public function testAllAnnouncementsFirst(): void {
$this->markTestSkipped('Skipped due to major version-specific logic. See https://www.drupal.org/project/drupal/issues/3359322');
$feed_items = $this->providerShowAnnouncements();
// First time access.
$this->setFeedItems($feed_items);
$all_items = $this->container->get('announcements_feed.fetcher')->fetch();
$this->assertCount(4, $all_items);
$this->assertCount(1, $this->history);
// Second time access.
$this->setFeedItems($feed_items);
$all_items = $this->container->get('announcements_feed.fetcher')->fetch();
$this->assertCount(4, $all_items);
$this->assertCount(2, $this->history);
// Create another user and test again.
$permissions = [
'access toolbar',
'access announcements',
];
$this->setUpCurrentUser(['uid' => 2], $permissions);
$this->setFeedItems($feed_items);
// First time access.
$all_items = $this->container->get('announcements_feed.fetcher')->fetch();
$this->assertCount(4, $all_items);
$this->assertCount(3, $this->history);
// Check after adding new record.
$feed_items = $this->providerShowUpdatedAnnouncements();
$this->setFeedItems($feed_items);
$all_items = $this->container->get('announcements_feed.fetcher')->fetch();
$this->assertCount(5, $all_items);
$this->assertSame('1005', $all_items[0]->id);
$this->assertCount(4, $this->history);
}
/**
* Data provider for testAllAnnouncements().
*/
public function providerShowAnnouncements(): array {
return [
[
'id' => '1001',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 1',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
[
'id' => '1002',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 2',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
[
'id' => '1003',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 3',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
[
'id' => '1004',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 4',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
];
}
/**
* Data provider for testAllAnnouncements().
*/
public function providerShowUpdatedAnnouncements(): array {
return [
[
'id' => '1005',
'title' => 'Drupal security update Test new',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 1',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
[
'id' => '1001',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 1',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
[
'id' => '1002',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 2',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
[
'id' => '1003',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 3',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
[
'id' => '1004',
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
'content_html' => 'Test teaser 4',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10',
],
'date_modified' => date('c', 1611041378),
'date_published' => date('c', 1610958578),
],
];
}
/**
* Sets the feed items to be returned for the test.
*
* @param mixed[][] $feed_items
* The feeds items to test. Every time the http_client makes a request the
* next item in this array will be returned. For each feed item 'title' and
* 'url' are omitted because they do not need to vary between test cases.
*/
protected function setFeedItems(array $feed_items): void {
$responses[] = new Response(200, [], json_encode(['items' => $feed_items]));
$responses[] = new Response(200, [], json_encode(['items' => $feed_items]));
$responses[] = new Response(200, [], json_encode(['items' => $feed_items]));
$this->setTestFeedResponses($responses);
}
}

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\Kernel;
use GuzzleHttp\Psr7\Response;
/**
* @coversDefaultClass \Drupal\announcements_feed\AnnounceRenderer
*
* @group announcements_feed
*/
class AnnounceRendererTest extends AnnounceTestBase {
/**
* Tests rendered valid when something goes wrong.
*/
public function testRendererException(): void {
$this->setTestFeedResponses([
new Response(403),
]);
$render = $this->container->get('announcements_feed.renderer')->render();
$this->assertEquals('status_messages', $render['#theme']);
$this->assertEquals('An error occurred while parsing the announcements feed, check the logs for more information.', $render['#message_list']['error'][0]);
}
/**
* Tests rendered valid content.
*/
public function testRendererContent(): void {
$feed_item_1 = [
'id' => '1001',
'content_html' => 'Test teaser 1',
'url' => 'https://www.drupal.org/project/announce',
'_drupalorg' => [
'featured' => TRUE,
'version' => '^10||^11',
],
'date_modified' => "2021-09-02T15:09:42+00:00",
'date_published' => "2021-09-01T15:09:42+00:00",
];
$feed_item_2 = [
'id' => '1002',
'content_html' => 'Test teaser 1',
'url' => 'https://www.drupal.org/project/announce',
'_drupalorg' => [
'featured' => FALSE,
'version' => '^10||^11',
],
'date_modified' => "2021-09-02T15:09:42+00:00",
'date_published' => "2021-09-01T15:09:42+00:00",
];
$this->setFeedItems([$feed_item_1, $feed_item_2]);
$render = $this->container->get('announcements_feed.renderer')->render();
$this->assertEquals('announcements_feed', $render['#theme']);
$this->assertEquals(1, $render['#count']);
$this->assertEquals(1001, $render['#featured'][0]->id);
$render = $this->container->get('announcements_feed.renderer')->render();
$this->assertEquals('announcements_feed', $render['#theme']);
$this->assertEquals(1, $render['#count']);
$this->assertEquals(1002, $render['#standard'][0]->id);
}
}

View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\Kernel;
use Drupal\KernelTests\KernelTestBase;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Response;
/**
* Base class for Announce Kernel tests.
*/
class AnnounceTestBase extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'user',
'system',
'announcements_feed',
];
/**
* History of requests/responses.
*
* @var array
*/
protected array $history = [];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installConfig('system');
$this->installConfig(['user']);
}
/**
* Sets the feed items to be returned for the test.
*
* @param mixed[][] $feed_items
* The feeds items to test. Every time the http_client makes a request the
* next item in this array will be returned. For each feed item 'title' and
* 'url' are omitted because they do not need to vary between test cases.
*/
protected function setFeedItems(array $feed_items): void {
$responses = [];
foreach ($feed_items as $feed_item) {
$feed_item += [
'title' => 'Drupal security update Test',
'url' => 'https://www.drupal.org/project/announce',
];
$responses[] = new Response(200, [], json_encode(['items' => [$feed_item]]));
}
$this->setTestFeedResponses($responses);
}
/**
* Sets test feed responses.
*
* @param \GuzzleHttp\Psr7\Response[] $responses
* The responses for the http_client service to return.
*/
protected function setTestFeedResponses(array $responses): void {
// Create a mock and queue responses.
$mock = new MockHandler($responses);
$handler_stack = HandlerStack::create($mock);
$history = Middleware::history($this->history);
$handler_stack->push($history);
// Rebuild the container because the 'system.sa_fetcher' service and other
// services may already have an instantiated instance of the 'http_client'
// service without these changes.
$this->container->get('kernel')->rebuildContainer();
$this->container = $this->container->get('kernel')->getContainer();
$this->container->set('http_client', new Client(['handler' => $handler_stack]));
}
}

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\announcements_feed\Unit;
use Drupal\Tests\UnitTestCase;
use Drupal\announcements_feed\AnnounceFetcher;
/**
* Simple test to ensure that asserts pass.
*
* @group announcements_feed
*/
class AnnounceFetcherUnitTest extends UnitTestCase {
/**
* The Fetcher service object.
*
* @var \Drupal\announcements_feed\AnnounceFetcher
*/
protected AnnounceFetcher $fetcher;
/**
* {@inheritdoc}
*/
public function setUp():void {
parent::setUp();
$httpClient = $this->createMock('GuzzleHttp\ClientInterface');
$config = $this->getConfigFactoryStub([
'announcements_feed.settings' => [
'max_age' => 86400,
'cron_interval' => 21600,
'limit' => 10,
],
]);
$tempStore = $this->createMock('Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface');
$tempStore->expects($this->once())
->method('get')
->willReturn($this->createMock('Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface'));
$logger = $this->createMock('Psr\Log\LoggerInterface');
$this->fetcher = new AnnounceFetcher($httpClient, $config, $tempStore, $logger, 'https://www.drupal.org/announcements.json');
}
/**
* Test the ValidateUrl() method.
*
* @covers \Drupal\announcements_feed\AnnounceFetcher::validateUrl
*
* @dataProvider urlProvider
*/
public function testValidateUrl($url, $isValid): void {
$this->assertEquals($isValid, $this->fetcher->validateUrl($url));
}
/**
* Data for the testValidateUrl.
*/
public static function urlProvider(): array {
return [
['https://www.drupal.org', TRUE],
['https://drupal.org', TRUE],
['https://api.drupal.org', TRUE],
['https://a.drupal.org', TRUE],
['https://123.drupal.org', TRUE],
['https://api-new.drupal.org', TRUE],
['https://api_new.drupal.org', TRUE],
['https://api-.drupal.org', TRUE],
['https://www.example.org', FALSE],
['https://example.org', FALSE],
['https://api.example.org/project/announce', FALSE],
['https://-api.drupal.org', FALSE],
['https://a.example.org/project/announce', FALSE],
['https://test.drupaal.com', FALSE],
['https://api.drupal.org.example.com', FALSE],
['https://example.org/drupal.org', FALSE],
];
}
}