Skip to content

Commit

Permalink
[#408] Fix team lists cache errors. (#419)
Browse files Browse the repository at this point in the history
* [#408] Fix team lists cache errors.

* [#408] Fix team lists cache errors - updated cache tags.

* [#408] Fix team lists cache errors - updates and test.

* [#408] Fix team lists cache errors - updates and test.

* [#408] Fix team lists cache errors - fixing phpcs.

* [#408] Fix tests.

* [#408] Fix tests.
  • Loading branch information
arlina-espinoza authored Jun 29, 2020
1 parent 6e17213 commit f62b71f
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ protected function setUp() {
'first_name' => $this->getRandomGenerator()->word(16),
'last_name' => $this->getRandomGenerator()->word(16),
]);
$this->account->save();
$this->queueDeveloperResponse($this->account, Response::HTTP_CREATED);
$this->account->save();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,7 @@ public function testEvent() {
$team = $this->createTeam();

// Add team member.
$this->queueCompanyResponse($team->decorated());
$this->queueDeveloperResponse($this->account);
$this->container->get('apigee_edge_teams.team_membership_manager')->addMembers($team->id(), [
$this->account->getEmail(),
]);
$this->addUserToTeam($team, $this->account);

$this->assertLogsContains("Event apigee_edge_actions_entity_add_member:team was dispatched.");
$this->assertLogsContains("Member {$this->account->first_name->value} was added to team {$team->getDisplayName()}.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,13 @@ public function testEvent() {
// Create a new team.
$team = $this->createTeam();

// Add team member.
$this->queueCompanyResponse($team->decorated());
$this->queueDeveloperResponse($this->account);
$team_membership_manager = $this->container->get('apigee_edge_teams.team_membership_manager');
$team_membership_manager->addMembers($team->id(), [
$this->account->getEmail(),
]);

// Add team member.
$this->addUserToTeam($team, $this->account);

// Remove team member.
$this->stack->queueMockResponse('no_content');
$team_membership_manager->removeMembers($team->id(), [
$this->account->getEmail(),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Drupal\apigee_edge\Element\StatusPropertyElement;
use Drupal\apigee_edge\Entity\ListBuilder\EdgeEntityListBuilder;
use Drupal\apigee_edge_teams\Entity\TeamInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Url;

Expand Down Expand Up @@ -110,4 +111,35 @@ public function buildRow(EntityInterface $entity) {
return $row + parent::buildRow($entity);
}

/**
* {@inheritdoc}
*/
public function render() {
$build = parent::render();
$account = $this->entityTypeManager->getStorage('user')->load(\Drupal::currentUser()->id());

$build = empty($build['table']) ? $build : $build['table'];

$build['#cache']['keys'][] = 'team_list_per_user';

// Team lists vary for each user and their permissions.
// Note: Even though cache contexts will be optimized to only include the
// 'user' cache context, the element should be invalidated correctly when
// permissions change because the 'user.permissions' cache context defined
// cache tags for permission changes, which should have bubbled up for the
// element when it was optimized away.
// @see \Drupal\KernelTests\Core\Cache\CacheContextOptimizationTest
$build['#cache']['contexts'][] = 'user';
$build['#cache']['contexts'][] = 'user.permissions';

$build['#cache']['tags'] = Cache::mergeTags($build['#cache']['tags'], $account->getCacheTags());

// Use cache expiration defined in configuration.
$build['#cache']['max-age'] = $this->configFactory
->get('apigee_edge_teams.team_settings')
->get('cache_expiration');

return $build;
}

}
238 changes: 238 additions & 0 deletions modules/apigee_edge_teams/tests/src/Functional/TeamListBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
<?php

/**
* Copyright 2020 Google Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace Drupal\Tests\apigee_edge_teams\Functional;

use Drupal\apigee_edge\Entity\Developer;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Response;

/**
* Apigee Edge Teams list builder tests.
*
* @group apigee_edge
* @group apigee_edge_teams
*/
class TeamListBuilderTest extends ApigeeEdgeTeamsFunctionalTestBase {

/**
* Indicates this test class is mock API client ready.
*
* @var bool
*/
protected static $mock_api_client_ready = TRUE;

/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'user',
'options',
'key',
'apigee_edge',
'apigee_edge_teams',
'apigee_mock_api_client',
];

/**
* The team entity storage.
*
* @var \Drupal\apigee_edge_teams\Entity\Storage\TeamStorageInterface
*/
protected $teamStorage;

/**
* The user 1 account.
*
* @var \Drupal\user\UserInterface
*/
protected $account;

/**
* Drupal user who is a member team A.
*
* @var \Drupal\user\UserInterface
*/
protected $aMemberAccount;

/**
* Drupal user who is a member team B.
*
* @var \Drupal\user\UserInterface
*/
protected $bMemberAccount;

/**
* Drupal user who is an admin.
*
* @var \Drupal\user\UserInterface
*/
protected $cMemberAccount;

/**
* Team A entity to test.
*
* @var \Drupal\apigee_edge_teams\Entity\TeamInterface
*/
protected $teamA;

/**
* Team B entity to test.
*
* @var \Drupal\apigee_edge_teams\Entity\TeamInterface
*/
protected $teamB;

/**
* A role.
*
* @var \Drupal\user\Entity\Role
*/
protected $customRole;

/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();

$this->addOrganizationMatchedResponse();

$this->teamStorage = $this->entityTypeManager->getStorage('team');

$config_factory = \Drupal::configFactory();
$config = $config_factory->getEditable('apigee_edge_teams.team_settings');
$config->set('cache_expiration', 300);
$config->save(TRUE);

// Create accounts: user 1, for members of two teams, and an extra one.
$this->account = $this->rootUser;
$this->aMemberAccount = $this->createNewAccount();
$this->bMemberAccount = $this->createNewAccount();
$this->cMemberAccount = $this->createNewAccount();

$this->customRole = $this->drupalCreateRole(['view any team']);

// Create teams.
$this->teamA = $this->createTeam();
$this->teamB = $this->createTeam();

// Add accounts to teams.
$this->addUserToTeam($this->teamA, $this->aMemberAccount);
$this->addUserToTeam($this->teamB, $this->bMemberAccount);
}

/**
* {@inheritdoc}
*/
protected function tearDown() {
try {
$this->teamStorage->delete([$this->teamA, $this->teamB]);
$this->account->delete();
$this->aMemberAccount->delete();
$this->bMemberAccount->delete();
$this->cMemberAccount->delete();
}
catch (\Error $error) {
// Do nothing.
}
catch (\Exception $exception) {
// Do nothing.
}
}

/**
* Tests team list cache.
*/
public function testTeamListCache() {
$companies = [
$this->teamA->decorated(),
$this->teamB->decorated(),
];

// aMemberAccount should only see teamA.
$this->drupalLogin($this->aMemberAccount);
$this->queueCompaniesResponse($companies);
$this->queueDeveloperResponse($this->aMemberAccount, 200, ['companies' => [$this->teamA->id()]]);
$this->drupalGet(Url::fromRoute('entity.team.collection'));
$assert = $this->assertSession();
$assert->pageTextContains($this->teamA->label());
$assert->pageTextNotContains($this->teamB->label());
$this->drupalLogout();

// bMemberAccount should only see teamB.
$this->drupalLogin($this->bMemberAccount);
$this->queueCompaniesResponse($companies);
$this->queueDeveloperResponse($this->bMemberAccount, 200, ['companies' => [$this->teamB->id()]]);
$this->drupalGet(Url::fromUserInput('/teams'));
$assert = $this->assertSession();
$assert->pageTextNotContains($this->teamA->label());
$assert->pageTextContains($this->teamB->label());
$this->drupalLogout();

// cMemberAccount should not see any teams.
$this->drupalLogin($this->cMemberAccount);
$this->queueCompaniesResponse($companies);
$this->queueDeveloperResponse($this->cMemberAccount);
$this->queueDeveloperResponse($this->cMemberAccount);
$this->drupalGet(Url::fromUserInput('/teams'));
$assert = $this->assertSession();
$assert->pageTextNotContains($this->teamA->label());
$assert->pageTextNotContains($this->teamB->label());

// Give cMemberAccount permission to view all teams.
$this->cMemberAccount->addRole($this->customRole);
$this->cMemberAccount->save();

// cMemberAccount should see both teams now.
$this->queueCompaniesResponse($companies);
$this->drupalGet(Url::fromUserInput('/teams'));
$assert = $this->assertSession();
$assert->pageTextContains($this->teamA->label());
$assert->pageTextContains($this->teamB->label());
}

/**
* Helper function to create a random user account.
*
* @return \Drupal\Core\Entity\EntityInterface
* The user account.
*/
protected function createNewAccount() {
$this->disableUserPresave();
$account = $this->createAccount();

$fields = [
'email' => $account->getEmail(),
'userName' => $account->getAccountName(),
'firstName' => $this->getRandomGenerator()->word(8),
'lastName' => $this->getRandomGenerator()->word(8),
];

// Stack developer responses for "created" and "set active".
$this->queueDeveloperResponse($account, Response::HTTP_CREATED);
$this->stack->queueMockResponse('no_content');
$developer = Developer::create($fields);
$developer->save();

return $account;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{#
/**
* @file
* Companies
*
* Usage:
* @code {% include 'companies.json.twig' %} @endcode
*
* Variables:
* - companies: an array of company objects.
*/
#}
{
"company" : [
{% for company in companies %}
{% include 'company.json.twig' with {'company': company} %}{{ loop.last ? '' : ',' }}
{% endfor %}
]
}
Loading

0 comments on commit f62b71f

Please sign in to comment.