Completed
Pull Request — master (#39)
by Eugene
02:02
created

MailgunEventControllerTest::getRouter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Azine\MailgunWebhooksBundle\Tests\Controller;
4
5
use Azine\MailgunWebhooksBundle\DependencyInjection\AzineMailgunWebhooksExtension;
6
use Azine\MailgunWebhooksBundle\Entity\MailgunEvent;
7
use Azine\MailgunWebhooksBundle\Tests\TestHelper;
8
use Doctrine\ORM\EntityManager;
9
use Symfony\Bundle\FrameworkBundle\Client;
10
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
11
use Symfony\Component\DependencyInjection\ContainerInterface;
12
use Symfony\Component\DomCrawler\Crawler;
13
use Symfony\Component\EventDispatcher\EventDispatcher;
14
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15
use Symfony\Component\HttpFoundation\File\UploadedFile;
16
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
17
18
class MailgunEventControllerTest extends WebTestCase
19
{
20
    public function testWebHookCreateAndEventDispatching()
21
    {
22
        $this->checkApplication();
23
24
        $client = static::createClient();
25
        $client->request('GET', '/');
26
27
        // create a subscriber to listen to create_events.
28
        $subscriberMock = $this->getMockBuilder("Azine\MailgunWebhooksBundle\Tests\EventSubscriberMock")->setMethods(array('handleCreate'))->getMock();
29
        $this->assertTrue($subscriberMock  instanceof EventSubscriberInterface);
30
        $this->getEventDispatcher()->addSubscriber($subscriberMock);
0 ignored issues
show
Documentation introduced by
$subscriberMock is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Symfony\Component...entSubscriberInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
31
        $this->assertTrue($this->getEventDispatcher()->hasListeners(MailgunEvent::CREATE_EVENT));
32
33
        //		dominik I would expect the method handleCreate to be called once, but for some reason it is not.
34
        //		$subscriberMock->expects($this->once())->method("handleCreate");
35
36
        // get webhook url
37
        $url = $this->getRouter()->generate('mailgunevent_webhook', array('_locale', 'en'), UrlGeneratorInterface::ABSOLUTE_URL);
38
39
        $manager = $this->getEntityManager();
40
        $eventReop = $manager->getRepository("Azine\MailgunWebhooksBundle\Entity\MailgunEvent");
41
        $count = sizeof($eventReop->findAll());
42
43
        // post invalid data to the webhook-url and check the response & database
44
        $invalidPostData = $this->getInvalidPostData();
45
        $webhookdata = json_encode($invalidPostData);
46
        $attachments = array(
47
            'attachment-1' => new UploadedFile(realpath(__DIR__.'/../testAttachment.small.png'), 'some.real.file.name1.png'),
48
            'attachment-2' => new UploadedFile(realpath(__DIR__.'/../testAttachment.small.png'), 'some.real.file.name2.png'),
49
            'attachment-3' => new UploadedFile(realpath(__DIR__.'/../testAttachment.small.png'), 'some.real.file.name3.png'),
50
        );
51
        $crawler = $client->request('POST', $url, $invalidPostData, $attachments);
52
53
        $this->assertSame(401, $client->getResponse()->getStatusCode(), "Response-Code 401 expected for post-data with invalid signature: \n\n$webhookdata\n\n\n");
54
        $this->assertContains('Signature verification failed.', $crawler->text(), 'Response expected.');
55
        $this->assertSame($count, sizeof($eventReop->findAll()), 'No new db entry for the webhook expected!');
56
57
        // post valid data to the webhook-url and check the response
58
        $validPostData = $this->getValidPostData();
59
        $webhookdata = json_encode($validPostData);
60
        $crawler = $client->request('POST', $url, $validPostData, $attachments);
61
        $this->assertSame(200, $client->getResponse()->getStatusCode(), "Response-Code 200 expected for '$url'.\n\n$webhookdata\n\n\n".$client->getResponse()->getContent());
62
        $this->assertContains('Thanx, for the info.', $crawler->text(), 'Response expected.');
63
        $this->assertSame($count + 1, sizeof($eventReop->findAll()), 'One new db entry for the webhook expected!');
64
    }
65
66
    private function getValidPostData()
67
    {
68
        $postData = TestHelper::getPostDataWithoutSignature();
69
        $postData['signature'] = $this->getValidSignature($postData['token'], $postData['timestamp']);
70
71
        return $postData;
72
    }
73
74
    private function getInvalidPostData()
75
    {
76
        $postData = TestHelper::getPostDataWithoutSignature();
77
        $postData['signature'] = 'invalid-signature';
78
79
        return $postData;
80
    }
81
82
    /**
83
     * @param string $token
84
     * @param int    $timestamp
85
     */
86
    private function getValidSignature($token, $timestamp)
87
    {
88
        $key = $this->getContainer()->getParameter(AzineMailgunWebhooksExtension::PREFIX.'_'.AzineMailgunWebhooksExtension::API_KEY);
89
        $signature = hash_hmac('SHA256', $timestamp.$token, $key);
90
91
        return $signature;
92
    }
93
94
    public function testShowLog()
95
    {
96
        $this->checkApplication();
97
98
        // Create a new client to browse the application
99
        $client = static::createClient();
100
        $client->followRedirects();
101
102
        $manager = $this->getEntityManager();
103
        $eventReop = $manager->getRepository("Azine\MailgunWebhooksBundle\Entity\MailgunEvent");
104
105
        $apiKey = $this->getContainer()->getParameter(AzineMailgunWebhooksExtension::PREFIX.'_'.AzineMailgunWebhooksExtension::API_KEY);
106
107
        // make sure there is some data in the application
108
        if (sizeof($eventReop->findAll()) < 102) {
109
            TestHelper::addMailgunEvents($manager, 102, $apiKey);
110
        }
111
        $count = sizeof($eventReop->findAll());
112
113
        // view the list of events
114
        $pageSize = 25;
115
        $listUrl = substr($this->getRouter()->generate('mailgunevent_list', array('_locale' => 'en', 'page' => 1, 'pageSize' => $pageSize, 'clear' => true)), 13);
116
        $crawler = $this->loginUserIfRequired($client, $listUrl);
117
        $this->assertSame($pageSize + 1, $crawler->filter('.eventsTable tr')->count(), "$pageSize Mailgun events (+1 header row) expected on this page ($listUrl)!");
118
119
        // view a single event
120
        $link = $crawler->filter('.eventsTable tr a:first-child')->first()->link();
121
        $posLastSlash = strrpos($link->getUri(), '/');
122
        $posOfIdStart = strrpos($link->getUri(), '/', -6) + 1;
123
        $eventId = substr($link->getUri(), $posOfIdStart, $posLastSlash - $posOfIdStart);
124
        $crawler = $client->click($link);
125
        $this->assertSame(200, $client->getResponse()->getStatusCode(), 'Status 200 expected.');
126
        $this->assertSame($eventId, $crawler->filter('td')->first()->text(), "Content of first td should be the eventId ($eventId)");
127
128
        // delete the event from show-page
129
        $link = $crawler->selectLink('delete')->link();
130
        $crawler = $client->click($link);
131
132
        // check that it is gone from the list
133
        $this->assertSame(0, $crawler->filter("#event$eventId")->count(), 'The deleted event should not be in the list anymore.');
134
135
        // delete the event from list-page
136
        $crawler = $client->followRedirect();
137
        $link = $crawler->filter('.eventsTable tr .deleteLink')->first()->link();
138
        $delUri = $link->getUri();
139
        $eventId = substr($delUri, strrpos($delUri, '/') + 1);
140
        $crawler = $client->click($link);
141
142
        // check that it is gone from the list
143
        $this->assertSame(0, $crawler->filter("#event$eventId")->count(), 'The deleted event should not be in the list anymore.');
144
145
        // filter the list for something
146
        $crawler = $client->followRedirect();
147
        $form = $crawler->selectButton('Filter')->form();
148
        $form['filter[eventType]']->select('delivered');
149
        $crawler = $client->submit($form);
150
        $this->assertSame($crawler->filter('.eventsTable tr')->count() - 1, $crawler->filter(".eventsTable a:contains('delivered')")->count(), "There should only be 'delivered' events in the list");
151
152
        // delete entry with xmlHttpRequest
153
        $eventToDelete = $eventReop->findOneBy(array());
154
        $ajaxUrl = $this->getRouter()->generate('mailgunevent_delete_ajax', array('_locale' => 'en'));
155
        $client->request('POST', $ajaxUrl, array('eventId' => $eventToDelete->getId()), array(), array('HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'));
156
        $this->assertSame('{"success":true}', $client->getResponse()->getContent(), "JSON response expcted from $ajaxUrl. for event with id:".$eventToDelete->getId());
157
158
        // show/delete inexistent log entry
159
        $inexistentEventId = md5('123invalid');
160
        $url = substr($this->getRouter()->generate('mailgunevent_delete', array('_locale' => 'en', 'eventId' => $inexistentEventId)), 13);
161
        $client->request('GET', $url);
162
        $this->assertSame(404, $client->getResponse()->getStatusCode(), "404 expected for invalid eventId ($inexistentEventId).");
163
164
        $url = substr($this->getRouter()->generate('mailgunevent_show', array('_locale' => 'en', 'id' => $inexistentEventId)), 13);
165
        $client->request('GET', $url);
166
        $this->assertSame(404, $client->getResponse()->getStatusCode(), '404 expected.');
167
168
        // show inexistent page
169
        $maxPage = floor($count / $pageSize);
170
        $beyondListUrl = $this->getRouter()->generate('mailgunevent_list', array('_locale' => 'en', 'page' => $maxPage + 1, 'pageSize' => $pageSize, 'clear' => true));
171
        $client->request('GET', $beyondListUrl);
172
        $crawler = $client->followRedirect();
173
        $this->assertSame(2, $crawler->filter(".pagination .disabled:contains('Next')")->count(), 'Expected to be on the last page => the next button should be disabled.');
174
    }
175
176
    public function testWebViewLinks()
177
    {
178
        $this->checkApplication();
179
180
        // Create a new client to browse the application
181
        $client = static::createClient();
182
        $client->followRedirects();
183
184
        $manager = $this->getEntityManager();
185
        $eventReop = $manager->getRepository("Azine\MailgunWebhooksBundle\Entity\MailgunEvent");
186
187
        $apiKey = $this->getContainer()->getParameter(AzineMailgunWebhooksExtension::PREFIX.'_'.AzineMailgunWebhooksExtension::API_KEY);
188
189
        // make sure there is some data in the application
190
        if (sizeof($eventReop->findAll()) < 102) {
191
            TestHelper::addMailgunEvents($manager, 102, $apiKey);
192
        }
193
194
        $events = $eventReop->findAll();
195
196
        $testTokenValue = 'testValue';
197
        $messageHeader = array(AzineMailgunWebhooksExtension::WEB_VIEW_TOKEN => $testTokenValue);
198
        $events[0]->setMessageHeaders(json_encode($messageHeader));
199
        $manager->persist($events[0]);
200
        $manager->flush();
201
202
        $events = $eventReop->findAll();
203
        $pageSize = count($events);
204
205
        $listUrl = substr($this->getRouter()->generate('mailgunevent_list', array('_locale' => 'en', 'page' => 1, 'pageSize' => $pageSize, 'clear' => true)), 13);
206
        $crawler = $this->loginUserIfRequired($client, $listUrl);
207
208
        $this->assertSame(1, $crawler->filter("ul:contains('".AzineMailgunWebhooksExtension::WEB_VIEW_TOKEN."')")->count(), 'There should be events with the webView headers in the list');
209
        $this->assertSame(1, $crawler->filter("ul a:contains('".$testTokenValue."')")->count(), 'There should be events with the webView links in the list');
210
    }
211
212
    /**
213
     * Load the url and login if required.
214
     *
215
     * @param string $url
216
     * @param string $username
217
     * @param Client $client
218
     *
219
     * @return Crawler $crawler of the page of the url or the page after the login
220
     */
221 View Code Duplication
    private function loginUserIfRequired(Client $client, $url, $username = 'dominik', $password = 'lkjlkjlkjlkj')
222
    {
223
        // try to get the url
224
        $client->followRedirects();
225
        $crawler = $client->request('GET', $url);
226
227
        $this->assertSame(200, $client->getResponse()->getStatusCode(), 'Status-Code 200 expected.');
228
229
        // if redirected to a login-page, login as admin-user
230
        if (5 == $crawler->filter('input')->count() && 1 == $crawler->filter('#username')->count() && 1 == $crawler->filter('#password')->count()) {
231
            // set the password of the admin
232
            $userProvider = $this->getContainer()->get('fos_user.user_provider.username_email');
233
            $user = $userProvider->loadUserByUsername($username);
234
            $user->setPlainPassword($password);
235
            $user->addRole('ROLE_ADMIN');
236
237
            $userManager = $this->getContainer()->get('fos_user.user_manager');
238
            $userManager->updateUser($user);
239
240
            $crawler = $crawler->filter("input[type='submit']");
241
            $form = $crawler->form();
242
            $form->get('_username')->setValue($username);
243
            $form->get('_password')->setValue($password);
244
            $crawler = $client->submit($form);
245
        }
246
247
        $this->assertSame(200, $client->getResponse()->getStatusCode(), 'Login failed.');
248
        $client->followRedirects(false);
249
250
        $this->assertStringEndsWith($url, $client->getRequest()->getUri(), "Login failed or not redirected to requested url: $url vs. ".$client->getRequest()->getUri());
251
252
        return $crawler;
253
    }
254
255
    /**
256
     * @var ContainerInterface
257
     */
258
    private $appContainer;
259
260
    /**
261
     * Get the current container.
262
     *
263
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
264
     */
265
    private function getContainer()
266
    {
267
        if (null == $this->appContainer) {
268
            $this->appContainer = static::$kernel->getContainer();
269
        }
270
271
        return $this->appContainer;
272
    }
273
274
    /**
275
     * @return UrlGeneratorInterface
276
     */
277
    private function getRouter()
278
    {
279
        return $this->getContainer()->get('router');
280
    }
281
282
    /**
283
     * @return EntityManager
284
     */
285
    private function getEntityManager()
286
    {
287
        return $this->getContainer()->get('doctrine.orm.entity_manager');
288
    }
289
290
    /**
291
     * @return EventDispatcher
292
     */
293
    private function getEventDispatcher()
294
    {
295
        return $this->getContainer()->get('event_dispatcher');
296
    }
297
298
    /**
299
     * Check if the current setup is a full application.
300
     * If not, mark the test as skipped else continue.
301
     */
302
    private function checkApplication()
303
    {
304
        try {
305
            static::$kernel = static::createKernel(array());
306
        } catch (\RuntimeException $ex) {
307
            $this->markTestSkipped('There does not seem to be a full application available (e.g. running tests on travis.org). So this test is skipped.');
308
309
            return;
310
        }
311
    }
312
}
313