View source
<?php
namespace Drupal\Tests\apigee_edge\Functional;
use Apigee\Edge\Api\Management\Controller\DeveloperController;
use Drupal\apigee_edge\Entity\Developer;
use Drupal\apigee_edge\Entity\DeveloperApp;
use Drupal\Core\Url;
use Drupal\Tests\apigee_edge\Traits\EntityUtilsTrait;
class DeveloperAppUITest extends ApigeeEdgeFunctionalTestBase {
use DeveloperAppUITestTrait;
use EntityUtilsTrait;
protected const DUPLICATE_MACHINE_NAME = 'The machine-readable name is already in use. It must be unique.';
protected static $modules = [
'field_ui',
];
protected function setUp() {
parent::setUp();
$this
->installExtraModules([
'block',
]);
$this
->drupalPlaceBlock('local_tasks_block');
$this
->drupalPlaceBlock('system_breadcrumb_block');
$this
->drupalPlaceBlock('system_menu_block:account');
$config = $this
->config('apigee_edge.dangerzone');
$config
->set('skip_developer_app_settings_validation', TRUE);
$config
->save();
$this->products[] = $this
->createProduct();
$this->account = $this
->createAccount(static::$permissions);
$this
->drupalLogin($this->account);
}
protected function tearDown() {
try {
if ($this->account !== NULL) {
$this->account
->delete();
}
} catch (\Exception $exception) {
$this
->logException($exception);
}
foreach ($this->products as $product) {
try {
if ($product !== NULL) {
$product
->delete();
}
} catch (\Exception $exception) {
$this
->logException($exception);
}
}
parent::tearDown();
}
public function testDeveloperAppLabel() {
$this
->changeEntityAliasesAndValidate('developer_app', 'apigee_edge.settings.developer_app');
$type = \Drupal::entityTypeManager()
->getDefinition('developer_app');
$this
->drupalGet(Url::fromRoute('entity.developer_app.collection_by_developer', [
'user' => $this->account
->id(),
]));
$this
->assertSession()
->elementContains('css', 'title', $type
->getPluralLabel());
$this
->assertLink($type
->getPluralLabel());
}
public function testAssociateApps() {
$this
->submitAdminForm([
'user_select' => FALSE,
"default_api_product_multiple[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$this
->gotoCreateAppForm();
$this
->assertSession()
->pageTextNotContains('APIs');
$this
->submitAdminForm();
$this
->gotoCreateAppForm();
$this
->assertSession()
->pageTextContains('APIs');
}
public function testCreateAndListApp() {
$name = strtolower($this
->randomMachineName());
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
"api_products[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$this
->assertSession()
->pageTextContains($name);
}
public function testCreateAndDeleteApp() {
$name = strtolower($this
->randomMachineName());
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
"api_products[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$this
->assertSession()
->pageTextContains($name);
$this
->clickLink($name);
$this
->assertSession()
->pageTextContains($name);
$this
->assertSession()
->pageTextContains($this->products[0]
->label());
$this
->clickLink('Delete');
$this
->submitForm([], 'Delete');
$this
->assertSession()
->pageTextContains('The name does not match the app you are attempting to delete.');
$this
->submitForm([
'verification_code' => $name,
], 'Delete');
$this
->assertSession()
->pageTextContains("The {$name} app has been deleted.");
$apps = array_filter($this
->getApps(), function (DeveloperApp $app) use ($name) : bool {
return $app
->getName() === $name;
});
$this
->assertEquals([], $apps, 'App is deleted');
$this
->drupalGet("user/{$this->account->id()}/apps");
$this
->assertSession()
->pageTextNotContains($name);
}
public function testCreateDuplicateApps() {
$name = strtolower($this
->randomMachineName());
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
"api_products[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$this
->assertDeveloperAppExists($name);
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
]);
$this
->assertSession()
->pageTextContains(static::DUPLICATE_MACHINE_NAME);
}
public function testFieldValidationConstraints() {
$name = strtolower($this
->randomMachineName(31));
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
"api_products[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$this
->assertSession()
->pageTextContains('This value is too long. It should have 30 characters or less.');
}
public function testSameAppNameDifferentUser() {
$name = strtolower($this
->randomMachineName());
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
"api_products[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$second_user = $this
->createAccount(static::$permissions);
$this
->drupalLogin($second_user);
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
], $second_user);
$this
->assertSession()
->pageTextNotContains(static::DUPLICATE_MACHINE_NAME);
$this
->drupalLogin($this->account);
$second_user
->delete();
}
public function testCreateAppWithProducts() {
$this->products[] = $this
->createProduct();
$this
->assertAppCreationWithProduct([
$this->products[0],
], FALSE, TRUE);
$this
->assertAppCreationWithProduct([
$this->products[0],
$this->products[1],
]);
}
public function testCreateAppWithModifiedCredentialLifetime() {
$url = Url::fromRoute('apigee_edge.settings.developer_app.credentials');
$this
->drupalPostForm($url, [
'credential_lifetime' => 10,
], 'Save configuration');
$this
->assertSession()
->pageTextContains('The configuration options have been saved.');
$name = strtolower($this
->randomMachineName());
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
"api_products[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$this
->assertSession()
->pageTextContains($name);
$this
->clickLink($name);
$this
->assertSession()
->pageTextMatches('/1 week (2|3) days hence/');
$this
->drupalPostForm($url, [
'credential_lifetime' => 0,
], 'Save configuration');
$this
->assertSession()
->pageTextContains('The configuration options have been saved.');
$name = strtolower($this
->randomMachineName());
$this
->postCreateAppForm([
'name' => $name,
'displayName[0][value]' => $name,
"api_products[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$this
->assertSession()
->pageTextContains($name);
$this
->clickLink($name);
$this
->assertSession()
->pageTextContains('Never');
}
public function testAppDefaultProduct() {
$this
->submitAdminForm([
'multiple_products' => FALSE,
'user_select' => FALSE,
"default_api_product_multiple[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
]);
$asserts = function () {
$this
->assertSession()
->pageTextContains($this->products[0]
->label());
};
$this
->assertAppCrud(NULL, $asserts, NULL, $asserts);
}
public function testAppDefaultProducts() {
$this->products[] = $this
->createProduct();
$this->products[] = $this
->createProduct();
$this
->submitAdminForm([
'multiple_products' => TRUE,
'user_select' => FALSE,
"default_api_product_multiple[{$this->products[0]->getName()}]" => $this->products[0]
->getName(),
"default_api_product_multiple[{$this->products[1]->getName()}]" => $this->products[1]
->getName(),
]);
$asserts = function () {
$this
->assertSession()
->pageTextContains($this->products[0]
->label());
$this
->assertSession()
->pageTextContains($this->products[1]
->label());
$this
->assertSession()
->pageTextNotContains($this->products[2]
->label());
};
$this
->assertAppCrud(NULL, $asserts, NULL, $asserts);
}
public function testAppCrudSingleProductChange() {
$this
->submitAdminForm([
'display_as_select' => TRUE,
'multiple_products' => FALSE,
]);
$this->products[] = $this
->createProduct();
$this
->assertAppCrud(function (array $data) : array {
$data['api_products'] = $this->products[0]
->getName();
return $data;
}, function () {
$this
->assertSession()
->pageTextContains($this->products[0]
->label());
}, function (array $data, string $credential_id) : array {
$data["credential[{$credential_id}][api_products]"] = $this->products[1]
->getName();
return $data;
}, function () {
$this
->assertSession()
->pageTextNotContains($this->products[0]
->label());
$this
->assertSession()
->pageTextContains($this->products[1]
->label());
});
}
public function testAppCrudSingleProductAdd() {
$this
->submitAdminForm([
'multiple_products' => FALSE,
]);
$this->products[] = $this
->createProduct();
$this
->assertAppCrud(function (array $data) : array {
$data['api_products'] = $this->products[1]
->getName();
return $data;
}, function () {
$this
->assertSession()
->pageTextContains($this->products[1]
->label());
}, function (array $data, string $credential_id) : array {
$data["credential[{$credential_id}][api_products]"] = $this->products[0]
->getName();
return $data;
}, function () {
$this
->assertSession()
->pageTextContains($this->products[0]
->label());
});
}
public function testAppCrudMultiplePruductsRemove() {
$this
->submitAdminForm([
'display_as_select' => TRUE,
]);
$this->products[] = $this
->createProduct();
$this->products[] = $this
->createProduct();
$this
->assertAppCrud(function (array $data) : array {
$data['api_products[]'] = [
$this->products[0]
->getName(),
$this->products[1]
->getName(),
];
return $data;
}, function () {
$this
->assertSession()
->pageTextContains($this->products[0]
->label());
$this
->assertSession()
->pageTextContains($this->products[1]
->label());
$this
->assertSession()
->pageTextNotContains($this->products[2]
->label());
}, function (array $data, string $credential_id) : array {
$data["credential[{$credential_id}][api_products][]"] = [
$this->products[2]
->getName(),
];
return $data;
}, function () {
$this
->assertSession()
->pageTextNotContains($this->products[0]
->label());
$this
->assertSession()
->pageTextNotContains($this->products[1]
->label());
$this
->assertSession()
->pageTextContains($this->products[2]
->label());
});
}
public function testAppCrudMultipleProductsAdd() {
$this
->submitAdminForm([]);
$this->products[] = $this
->createProduct();
$this->products[] = $this
->createProduct();
$this
->assertAppCrud(function (array $data) : array {
$data["api_products[{$this->products[2]->getName()}]"] = $this->products[2]
->getName();
return $data;
}, function () {
$this
->assertSession()
->pageTextNotContains($this->products[0]
->label());
$this
->assertSession()
->pageTextNotContains($this->products[1]
->label());
$this
->assertSession()
->pageTextContains($this->products[2]
->label());
}, function (array $data, string $credential_id) : array {
$data["credential[{$credential_id}][api_products][{$this->products[0]->getName()}]"] = $this->products[0]
->getName();
$data["credential[{$credential_id}][api_products][{$this->products[1]->getName()}]"] = $this->products[1]
->getName();
$data["credential[{$credential_id}][api_products][{$this->products[2]->getName()}]"] = "";
return $data;
}, function () {
$this
->assertSession()
->pageTextContains($this->products[0]
->label());
$this
->assertSession()
->pageTextContains($this->products[1]
->label());
$this
->assertSession()
->pageTextNotContains($this->products[2]
->label());
});
}
public function testNotificationsWhenAccountIsInactiveOnEdge() {
$connector = $this->container
->get('apigee_edge.sdk_connector');
$controller = new DeveloperController($connector
->getOrganization(), $connector
->getClient());
$controller
->setStatus($this->account
->getEmail(), Developer::STATUS_INACTIVE);
$this
->drupalGet("/user/{$this->account->id()}/apps");
$this
->assertSession()
->pageTextContains('Your developer account has inactive status so you will not be able to use your credentials until your account gets activated. Please contact support for further assistance.');
$this
->drupalLogin($this->rootUser);
$this
->drupalGet("/user/{$this->account->id()}/apps");
$this
->assertSession()
->pageTextContains("The developer account of {$this->account->getDisplayName()} has inactive status so this user has invalid credentials until the account gets activated.");
}
public function testWarningMessagesIfMultipleProductsDisabled() {
$admin_warning_message = 'Access to multiple API products will be retained until an app is edited and the developer is prompted to confirm a single API Product selection.';
$end_user_warning_message = 'Foos now require selection of a single Bar; multiple Bar selection is no longer supported. Confirm your Bar selection below.';
$app_settings_url = Url::fromRoute('apigee_edge.settings.general_app');
$this
->config('apigee_edge.common_app_settings')
->set('multiple_products', TRUE)
->save();
$this
->config('apigee_edge.developer_app_settings')
->set('entity_label_singular', 'Foo')
->set('entity_label_plural', 'Foos')
->save();
$this
->config('apigee_edge.api_product_settings')
->set('entity_label_singular', 'Bar')
->set('entity_label_plural', 'Bars')
->save();
\Drupal::entityTypeManager()
->clearCachedDefinitions();
$product1 = $this
->createProduct();
$product2 = $this
->createProduct();
$this->products[] = $product1;
$this->products[] = $product2;
$app = $this
->createDeveloperApp([
'name' => $this
->randomMachineName(),
'displayName' => $this
->randomString(),
], $this->account, [
$product1
->id(),
$product2
->id(),
]);
$app_edit_url = $app
->toUrl('edit-form-for-developer');
$this
->drupalGet($app_settings_url);
$this
->assertSession()
->pageTextNotContains($admin_warning_message);
$this
->drupalGet($app_edit_url);
$this
->assertSession()
->pageTextNotContains($end_user_warning_message);
$this
->config('apigee_edge.common_app_settings')
->set('multiple_products', FALSE)
->save();
$this
->drupalGet($app_settings_url);
$this
->assertSession()
->pageTextContains($admin_warning_message);
$this
->drupalGet($app_edit_url);
$this
->assertSession()
->pageTextContains($end_user_warning_message);
}
public function testCallbackUrlValidationServerSide() {
$description = 'This is a Callback URL field.';
$this
->config('apigee_edge.common_app_settings')
->set('callback_url_pattern', '^https:\\/\\/example.com')
->set('callback_url_description', $description)
->save();
$callback_url = $this
->randomMachineName();
$product = $this
->createProduct();
$this->products[] = $product;
$app = $this
->createDeveloperApp([
'name' => $callback_url,
'displayName' => $this
->randomString(),
'callbackUrl' => $callback_url,
], $this->account, [
$product
->id(),
]);
$app_edit_url = $app
->toUrl('edit-form-for-developer');
$this
->drupalGet($app_edit_url);
$this
->assertSession()
->pageTextContains($description);
$this
->drupalPostForm($app_edit_url, [], 'Save');
$this
->assertSession()
->pageTextContains("The URL {$callback_url} is not valid.");
$this
->drupalPostForm($app_edit_url, [
'callbackUrl[0][value]' => 'http://example.com',
], 'Save');
$this
->assertSession()
->pageTextContains("Callback URL field is not in the right format.");
$this
->drupalPostForm($app_edit_url, [
'callbackUrl[0][value]' => 'https://example.com',
], 'Save');
$this
->assertSession()
->pageTextContains('App has been successfully updated.');
$this
->assertSession()
->pageTextContains('https://example.com');
}
public function testInvalidEdgeSideCallbackUrl() {
$this
->drupalLogin($this->rootUser);
$this->products[] = $this
->createProduct();
$callback_url = $this->randomGenerator
->word(8);
$callback_url_warning_msg = "The Callback URL value should be fixed. The URI '{$callback_url}' is invalid. You must use a valid URI scheme.";
$app = $this
->createDeveloperApp([
'name' => $this
->randomMachineName(),
'displayName' => $this
->randomString(),
'callbackUrl' => $callback_url,
], $this->account, [
$this->products[0]
->id(),
]);
$app_view_url = $app
->toUrl('canonical');
$app_view_by_developer_url = $app
->toUrl('canonical-by-developer');
$app_edit_form_url = $app
->toUrl('edit-form');
$app_edit_form_for_developer_url = $app
->toUrl('edit-form-for-developer');
$this
->drupalGet($app_view_url);
$this
->assertSession()
->pageTextContains($callback_url_warning_msg);
$this
->assertSession()
->pageTextNotContains('Callback URL:');
$this
->drupalGet($app_view_by_developer_url);
$this
->assertSession()
->pageTextContains($callback_url_warning_msg);
$this
->assertSession()
->pageTextNotContains('Callback URL:');
$this
->drupalGet($app_edit_form_url);
$this
->assertSession()
->fieldValueEquals('callbackUrl[0][value]', $callback_url);
$this
->drupalGet($app_edit_form_for_developer_url);
$this
->assertSession()
->fieldValueEquals('callbackUrl[0][value]', $callback_url);
$this
->drupalPostForm(Url::fromRoute('entity.entity_view_display.developer_app.default'), [
'fields[callbackUrl][region]' => 'hidden',
], 'Save');
$this
->drupalPostForm(Url::fromRoute('entity.entity_form_display.developer_app.default'), [
'fields[callbackUrl][region]' => 'hidden',
], 'Save');
$this
->drupalGet($app_view_url);
$this
->assertSession()
->pageTextNotContains($callback_url_warning_msg);
$this
->assertSession()
->pageTextNotContains('Callback URL:');
$this
->drupalGet($app_view_by_developer_url);
$this
->assertSession()
->pageTextNotContains($callback_url_warning_msg);
$this
->assertSession()
->pageTextNotContains('Callback URL:');
}
public function testBreadcrumbOnDeveloperAppPages() {
$this
->drupalLogin($this->rootUser);
$user = $this
->createAccount();
$this
->drupalGet(Url::fromRoute('entity.developer_app.collection_by_developer', [
'user' => $this->account
->id(),
]));
$breadcrumb_links = $this
->getBreadcrumbLinks();
$this
->assertEquals('/', $breadcrumb_links[0]
->getAttribute('href'));
$this
->assertEquals(Url::fromRoute('entity.user.canonical', [
'user' => $this->account
->id(),
])
->toString(), $breadcrumb_links[1]
->getAttribute('href'));
$this
->drupalGet(Url::fromRoute('entity.developer_app.add_form_for_developer', [
'user' => $this->account
->id(),
]));
$breadcrumb_links = $this
->getBreadcrumbLinks();
$this
->assertEquals('/', $breadcrumb_links[0]
->getAttribute('href'));
$this
->assertEquals(Url::fromRoute('entity.user.canonical', [
'user' => $this->account
->id(),
])
->toString(), $breadcrumb_links[1]
->getAttribute('href'));
$this
->assertEquals(Url::fromRoute('entity.developer_app.collection_by_developer', [
'user' => $this->account
->id(),
])
->toString(), $breadcrumb_links[2]
->getAttribute('href'));
$this
->drupalGet(Url::fromRoute('entity.developer_app.collection_by_developer', [
'user' => $user
->id(),
]));
$breadcrumb_links = $this
->getBreadcrumbLinks();
$this
->assertEquals('/', $breadcrumb_links[0]
->getAttribute('href'));
$this
->assertEquals(Url::fromRoute('entity.user.canonical', [
'user' => $user
->id(),
])
->toString(), $breadcrumb_links[1]
->getAttribute('href'));
$this
->drupalGet(Url::fromRoute('entity.developer_app.add_form_for_developer', [
'user' => $user
->id(),
]));
$expected_breadcrumb[] = Url::fromRoute('entity.developer_app.collection_by_developer', [
'user' => $user
->id(),
])
->toString();
$breadcrumb_links = $this
->getBreadcrumbLinks();
$this
->assertEquals('/', $breadcrumb_links[0]
->getAttribute('href'));
$this
->assertEquals(Url::fromRoute('entity.user.canonical', [
'user' => $user
->id(),
])
->toString(), $breadcrumb_links[1]
->getAttribute('href'));
$this
->assertEquals(Url::fromRoute('entity.developer_app.collection_by_developer', [
'user' => $user
->id(),
])
->toString(), $breadcrumb_links[2]
->getAttribute('href'));
}
}