webhooks-8.x-1.x-dev/tests/src/Functional/WebhooksTest.php
tests/src/Functional/WebhooksTest.php
<?php
namespace Drupal\Tests\webhooks\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use Drupal\webhooks\Entity\WebhookConfig;
use Drupal\webhooks\Webhook;
/**
* Test description.
*
* @group webhooks
*/
class WebhooksTest extends BrowserTestBase {
const WEBHOOK_ID_INCOMING = 'webhook_id_incoming';
const WEBHOOK_ID_OUTGOING = 'webhook_id_outgoing';
const WEBHOOK_ID_INCOMING_VERIFIED = 'webhook_id_incoming_verified';
const WEBHOOK_ID_OUTGOING_VERIFIED = 'webhook_id_outgoing_verified';
// cspell:disable-next-line
const WEBHOOK_SECRET = 'iepooleiDahF3eimeikooC2iep1ahqua';
const WEBHOOK_ID_OUTGOING_XML = 'webhook_id_outgoing_xml';
const WEBHOOK_ID_INCOMING_XML = 'webhook_id_incoming_xml';
const WEBHOOK_ID_OUTGOING_YAML = 'webhook_id_outgoing_yaml';
const WEBHOOK_ID_INCOMING_YAML = 'webhook_id_incoming_yaml';
const WEBHOOK_ID_OUTGOING_WWW_FORM_URLENCODED = 'webhook_id_outgoing_www_form_urlencoded';
const WEBHOOK_ID_INCOMING_WWW_FORM_URLENCODED = 'webhook_id_incoming_www_form_urlencoded';
const WEBHOOK_ID_OUTGOING_BUNDLES_0 = 'webhook_id_outgoing_all_0';
const WEBHOOK_ID_OUTGOING_BUNDLES_1 = 'webhook_id_outgoing_all_1';
const WEBHOOK_ID_OUTGOING_BUNDLES_2 = 'webhook_id_outgoing_all_2';
const WEBHOOK_ID_OUTGOING_BUNDLES_3 = 'webhook_id_outgoing_all_3';
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = ['webhooks', 'webhooks_test'];
/**
* {@inheritdoc}
*/
protected $profile = 'minimal';
/**
* The webhook service.
*
* @var \Drupal\webhooks\WebhooksService
*/
protected $webhookService;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The uuid.
*
* @var \Drupal\Component\Uuid\UuidInterface
*/
protected $uuid;
/**
* The payload.
*
* @var string[]
*/
protected $payload = ['payload' => 'attribute'];
/**
* The headers.
*
* @var string[]
*/
protected $headers = ['header-type' => 'header-value'];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->state = $this->container->get('state');
$this->uuid = $this->container->get('uuid');
$this->webhookService = $this->container->get('webhooks.service');
// Create an incoming webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_INCOMING,
'label' => 'Webhook Incoming',
'uuid' => $this->uuid->generate(),
'payload_url' => '',
'type' => 'incoming',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING,
'label' => 'Webhook Outgoing',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => '',
'status' => 1,
])->save();
// Create an incoming webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_INCOMING_VERIFIED,
'label' => 'Webhook Incoming Verified',
'uuid' => $this->uuid->generate(),
'payload_url' => '',
'type' => 'incoming',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => self::WEBHOOK_SECRET,
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_VERIFIED,
'label' => 'Webhook Outgoing Verified',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_VERIFIED])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => self::WEBHOOK_SECRET,
'status' => 1,
])->save();
// Create an incoming webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_INCOMING_XML,
'label' => 'Webhook Incoming XML',
'uuid' => $this->uuid->generate(),
'payload_url' => '',
'type' => 'incoming',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_XML,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_XML,
'label' => 'Webhook Outgoing XML',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_XML])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_XML,
'secret' => '',
'status' => 1,
])->save();
// Create an incoming webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_INCOMING_WWW_FORM_URLENCODED,
'label' => 'Webhook Incoming WWW-FORM-URLENCODED',
'uuid' => $this->uuid->generate(),
'payload_url' => '',
'type' => 'incoming',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_WWW_FORM_URLENCODED,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_WWW_FORM_URLENCODED,
'label' => 'Webhook Outgoing WWW-FORM-URLENCODED',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_XML])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_WWW_FORM_URLENCODED,
'secret' => '',
'status' => 1,
])->save();
// Create an incoming webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_INCOMING_YAML,
'label' => 'Webhook Incoming YAML',
'uuid' => $this->uuid->generate(),
'payload_url' => '',
'type' => 'incoming',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_YAML,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_YAML,
'label' => 'Webhook Outgoing YAML',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_YAML])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => [],
'content_type' => WebhookConfig::CONTENT_TYPE_YAML,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_BUNDLES_0,
'label' => 'Webhook Outgoing Bundles 0',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_XML])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => ['entity:user:create'],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_BUNDLES_1,
'label' => 'Webhook Outgoing Bundles 1',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_XML])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => ['entity:user:create', 'entity:user:user:create'],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_BUNDLES_2,
'label' => 'Webhook Outgoing Bundles 2',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_XML])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => ['entity:user:create', 'entity:user:user:create'],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => '',
'status' => 1,
])->save();
// Create an outgoing webhook.
WebhookConfig::create([
'id' => self::WEBHOOK_ID_OUTGOING_BUNDLES_3,
'label' => 'Webhook Outgoing Bundles 3',
'uuid' => $this->uuid->generate(),
'payload_url' => Url::fromRoute('webhooks.webhook_receive', ['incoming_webhook_name' => self::WEBHOOK_ID_INCOMING_XML])->setAbsolute(TRUE)->toString(),
'type' => 'outgoing',
'events' => ['entity:user:create', 'entity:user:user:create', 'entity:user:mock:create'],
'content_type' => WebhookConfig::CONTENT_TYPE_JSON,
'secret' => '',
'status' => 1,
])->save();
}
/**
* Test creation of incoming webhook.
*/
public function testIncomingCreated() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_INCOMING);
$this->assertInstanceOf(WebhookConfig::class, $webhook_config);
}
/**
* Test creation of outgoing webhook.
*/
public function testOutgoingCreated() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING);
$this->assertInstanceOf(WebhookConfig::class, $webhook_config);
}
/**
* Test outgoing webhook.
*/
public function testEventSend() {
/** @var \Drupal\webhooks\Entity\WebhookConfig $webhook_config */
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING);
$webhook = new Webhook($this->payload);
$this->webhookService->send($webhook_config, $webhook);
$this->assertEquals($this->state->get('onWebhookSend'), TRUE);
}
/**
* Test incoming webhook.
*
* @group dev
*/
public function testEventReceive() {
/** @var \Drupal\webhooks\Entity\WebhookConfig $webhook_config */
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING);
$webhook = new Webhook($this->payload);
$this->webhookService->send($webhook_config, $webhook);
$webhook_received = $this->state->get('onWebhookReceive');
$this->assertEquals($webhook_received, TRUE);
}
/**
* Test webhook payload.
*/
public function testPayload() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING);
$webhook = new Webhook($this->payload);
$this->webhookService->send($webhook_config, $webhook);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
$this->assertEquals($webhook_received->getPayload(), $this->payload);
}
/**
* Test webhook headers.
*/
public function testHeaders() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING);
$webhook = new Webhook($this->payload, $this->headers);
$this->webhookService->send($webhook_config, $webhook);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
$headers_received = $webhook_received->getHeaders();
// Additional custom headers.
$intersection = array_intersect($headers_received, $this->headers);
$this->assertEquals($intersection, $this->headers);
// Check for X-Drupal-Delivery header.
$this->assertEquals($headers_received['x-drupal-delivery'], $webhook->getUuid());
// Check for X-Drupal-Event header.
$this->assertEquals($headers_received['x-drupal-event'], $webhook->getEvent());
}
/**
* Test webhook signature.
*/
public function testSignature() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING_VERIFIED);
$webhook = new Webhook($this->payload);
$this->webhookService->send($webhook_config, $webhook);
// Make sure the secret has been set.
$this->assertEquals($webhook_config->getSecret(), self::WEBHOOK_SECRET);
$webhook_receive = $this->state->get('onWebhookReceive');
// This succeeds if the webhook has been verified and accepted.
$this->assertEquals($webhook_receive, TRUE);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
// Verify signature.
$this->assertEquals($webhook_received->getSignature(), $webhook->getSignature());
}
/**
* Test webhook content type JSON.
*/
public function testContentTypeJson() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING);
$webhook = new Webhook($this->payload);
$webhook->setContentType(WebhookConfig::CONTENT_TYPE_JSON);
$this->webhookService->send($webhook_config, $webhook);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
$this->assertEquals($webhook_received->getContentType(), WebhookConfig::CONTENT_TYPE_JSON);
}
/**
* Test webhook content type WWW-FORM-URLENCODED.
*
* @group specification
*/
public function testContentTypeWwwFormUrlencoded() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING_WWW_FORM_URLENCODED);
$webhook = new Webhook($this->payload);
$webhook->setContentType(WebhookConfig::CONTENT_TYPE_WWW_FORM_URLENCODED);
$this->webhookService->send($webhook_config, $webhook);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
$this->assertEquals(WebhookConfig::CONTENT_TYPE_WWW_FORM_URLENCODED, $webhook_received->getContentType());
$this->assertEquals($this->payload, $webhook_received->getPayload());
}
/**
* Test webhook content type XML.
*/
public function testContentTypeXml() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING_XML);
$webhook = new Webhook($this->payload);
$webhook->setContentType(WebhookConfig::CONTENT_TYPE_XML);
$this->webhookService->send($webhook_config, $webhook);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
$this->assertEquals($webhook_received->getContentType(), WebhookConfig::CONTENT_TYPE_XML);
}
/**
* Test webhook content type YAML.
*/
public function testContentTypeYaml() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING_YAML);
$webhook = new Webhook($this->payload);
$webhook->setContentType(WebhookConfig::CONTENT_TYPE_YAML);
$this->webhookService->send($webhook_config, $webhook);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
$this->assertEquals($webhook_received->getContentType(), WebhookConfig::CONTENT_TYPE_YAML);
}
/**
* Test webhook delivery id matches uuid.
*/
public function testDeliveryIdUuid() {
$webhook_config = WebhookConfig::load(self::WEBHOOK_ID_OUTGOING);
$webhook = new Webhook($this->payload);
$this->webhookService->send($webhook_config, $webhook);
/** @var \Drupal\webhooks\Webhook $webhook_received */
$webhook_received = $this->state->get('onWebhookReceive_webhook');
$this->assertEquals($webhook_received->getUuid(), $webhook->getUuid());
}
/**
* Test webhook content type serialization.
*
* @group serialization
*/
public function testContentTypeSerialization() {
$serializer = \Drupal::service('serializer');
$encoded = $serializer->encode($this->payload, 'json');
$this->assertEquals('{"payload":"attribute"}', $encoded);
$decoded = $serializer->decode($encoded, 'json');
$this->assertEquals($this->payload, $decoded);
$encoded = $serializer->encode($this->payload, 'xml');
$this->assertEquals("<?xml version=\"1.0\"?>\n<response><payload>attribute</payload></response>\n", $encoded);
$decoded = $serializer->decode($encoded, 'xml');
$this->assertEquals($this->payload, $decoded);
$encoded = $serializer->encode($this->payload, 'form');
$this->assertEquals('payload=%7B%22payload%22%3A%22attribute%22%7D', $encoded);
$decoded = $serializer->decode($encoded, 'form');
$this->assertEquals($this->payload, $decoded);
$encoded = $serializer->encode($this->payload, 'yaml');
$this->assertEquals('{ payload: attribute }', $encoded);
$decoded = $serializer->decode($encoded, 'yaml');
$this->assertEquals($this->payload, $decoded);
}
/**
* Test webhook outgoing entity type bundle.
*/
public function testOutgoingEntityTypeBundle() {
$webhook = new Webhook($this->payload);
// Should contain no configuration item.
$webhook_configs = $this->webhookService->loadMultipleByEvent('entity:mock:create');
$this->assertEquals(0, count($webhook_configs));
// Should contain no configuration item.
$webhook_configs = $this->webhookService->loadMultipleByEvent('entity:mock:mock:create');
$this->assertEquals(0, count($webhook_configs));
// Should contain four configuration item.
$webhook_configs = $this->webhookService->loadMultipleByEvent('entity:user:create');
$this->assertEquals(4, count($webhook_configs));
// Should contain one configuration item.
$webhook_configs = $this->webhookService->loadMultipleByEvent('entity:user:user:create');
$this->assertEquals(3, count($webhook_configs));
// Should contain one configuration item.
$webhook_configs = $this->webhookService->loadMultipleByEvent('entity:user:mock:create');
$this->assertEquals(1, count($webhook_configs));
}
}
