Completed
Push — master ( 6340d4...68ed89 )
by Dominik
03:05
created

MailgunEventControllerTest   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 260
Duplicated Lines 13.08 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 10
dl 34
loc 260
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
B testWebHookCreateAndEventDispatching() 0 46 1
A getValidPostData() 0 7 1
A getInvalidPostData() 0 7 1
A getValidSignature() 0 7 1
B testShowLog() 0 82 2
B loginUserIfRequired() 34 34 4
A getContainer() 0 8 2
A getRouter() 0 4 1
A getEntityManager() 0 4 1
A getEventDispatcher() 0 4 1
A checkApplication() 0 10 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
namespace Azine\MailgunWebhooksBundle\Tests\Controller;
3
4
use Azine\MailgunWebhooksBundle\Tests\TestHelper;
5
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6
use Symfony\Component\DomCrawler\Crawler;
7
use Symfony\Bundle\FrameworkBundle\Client;
8
use Symfony\Component\DependencyInjection\ContainerInterface;
9
use Azine\MailgunWebhooksBundle\Entity\MailgunEvent;
10
use Symfony\Component\EventDispatcher\EventDispatcher;
11
use Azine\MailgunWebhooksBundle\DependencyInjection\AzineMailgunWebhooksExtension;
12
use Doctrine\ORM\EntityManager;
13
use Symfony\Component\HttpFoundation\File\UploadedFile;
14
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
16
17
class MailgunEventControllerTest extends WebTestCase
18
{
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);
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 = substr($this->getRouter()->generate("mailgunevent_webhook", array()),13);
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->assertEquals(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->assertEquals($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->assertEquals(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->assertEquals($count + 1, sizeof($eventReop->findAll()), "One new db entry for the webhook expected!");
64
65
    }
66
67
    private function getValidPostData()
68
    {
69
        $postData = TestHelper::getPostDataWithoutSignature();
70
        $postData['signature'] = $this->getValidSignature($postData['token'], $postData['timestamp']);
71
72
        return $postData;
73
    }
74
75
    private function getInvalidPostData()
76
    {
77
        $postData = TestHelper::getPostDataWithoutSignature();
78
        $postData['signature'] = "invalid-signature";
79
80
        return $postData;
81
    }
82
83
    /**
84
     * @param string  $token
85
     * @param integer $timestamp
86
     */
87
    private function getValidSignature($token, $timestamp)
88
    {
89
        $key = $this->getContainer()->getParameter(AzineMailgunWebhooksExtension::PREFIX."_".AzineMailgunWebhooksExtension::API_KEY);
90
        $signature = hash_hmac("SHA256", $timestamp.$token, $key);
91
92
        return $signature;
93
    }
94
95
    public function testShowLog()
96
    {
97
        $this->checkApplication();
98
99
        // Create a new client to browse the application
100
        $client = static::createClient();
101
        $client->followRedirects();
102
103
        $manager = $this->getEntityManager();
104
        $eventReop = $manager->getRepository("Azine\MailgunWebhooksBundle\Entity\MailgunEvent");
105
106
        $apiKey = $this->getContainer()->getParameter(AzineMailgunWebhooksExtension::PREFIX."_".AzineMailgunWebhooksExtension::API_KEY);
107
108
        // make sure there is some data in the application
109
        if (sizeof($eventReop->findAll()) < 102) {
110
            TestHelper::addMailgunEvents($manager, 102, $apiKey);
111
        }
112
        $count = sizeof($eventReop->findAll());
113
114
        // view the list of events
115
        $pageSize = 25;
116
        $listUrl = substr($this->getRouter()->generate("mailgunevent_list", array('_locale' => "en", 'page' => 1, 'pageSize' => $pageSize, 'clear' => true)), 13);
117
        $crawler = $this->loginUserIfRequired($client, $listUrl);
118
        $this->assertEquals($pageSize+1, $crawler->filter(".eventsTable tr")->count(), "$pageSize Mailgun events (+1 header row) expected on this page ($listUrl)!");
119
120
        // view a single event
121
        $link = $crawler->filter(".eventsTable tr a:first-child")->first()->link();
122
        $posLastSlash = strrpos($link->getUri(), "/");
123
        $posOfIdStart = strrpos($link->getUri(), "/", -6) +1;
124
        $eventId = substr($link->getUri(), $posOfIdStart, $posLastSlash-$posOfIdStart);
125
        $crawler = $client->click($link);
126
        $this->assertEquals(200, $client->getResponse()->getStatusCode(), "Status 200 expected.");
127
        $this->assertEquals($eventId, $crawler->filter("td")->first()->text(), "Content of first td should be the eventId ($eventId)");
128
129
        // delete the event from show-page
130
        $link = $crawler->selectLink("delete")->link();
131
        $crawler = $client->click($link);
132
133
        // check that it is gone from the list
134
        $this->assertEquals(0, $crawler->filter("#event$eventId")->count(), "The deleted event should not be in the list anymore.");
135
136
        // delete the event from list-page
137
        $crawler = $client->followRedirect();
138
        $link = $crawler->filter(".eventsTable tr .deleteLink")->first()->link();
139
        $delUri = $link->getUri();
140
        $eventId = substr($delUri, strrpos($delUri, "/") + 1);
141
        $crawler = $client->click($link);
142
143
        // check that it is gone from the list
144
        $this->assertEquals(0, $crawler->filter("#event$eventId")->count(), "The deleted event should not be in the list anymore.");
145
146
        // filter the list for something
147
        $crawler = $client->followRedirect();
148
        $form = $crawler->selectButton("Filter")->form();
149
        $form['filter[eventType]']->select("delivered");
150
        $crawler = $client->submit($form);
151
        $this->assertEquals($crawler->filter(".eventsTable tr")->count() -1, $crawler->filter(".eventsTable a:contains('delivered')")->count(), "There should only be 'delivered' events in the list");
152
153
        // delete entry with xmlHttpRequest
154
        $eventToDelete = $eventReop->findOneBy(array());
155
        $ajaxUrl = substr($this->getRouter()->generate("mailgunevent_delete_ajax", array("_locale" => "en")),13);
156
        $client->request("POST", $ajaxUrl, array('eventId' => $eventToDelete->getId()), array(), array('HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'));
157
        $this->assertEquals('{"success":true}', $client->getResponse()->getContent(), "JSON response expcted from $ajaxUrl. for event with id:".$eventToDelete->getId());
158
159
        // show/delete inexistent log entry
160
        $inexistentEventId = md5("123invalid");
161
        $url = substr($this->getRouter()->generate("mailgunevent_delete", array("_locale" => "en", "eventId" => $inexistentEventId)),13);
162
        $client->request("GET", $url);
163
        $this->assertEquals(404, $client->getResponse()->getStatusCode(), "404 expected for invalid eventId ($inexistentEventId).");
164
165
        $url = substr($this->getRouter()->generate("mailgunevent_show", array("_locale" => "en", "id" => $inexistentEventId)),13);
166
        $client->request("GET", $url);
167
        $this->assertEquals(404, $client->getResponse()->getStatusCode(), "404 expected.");
168
169
        // show inexistent page
170
        $maxPage = floor($count/$pageSize);
171
        $beyondListUrl = substr($this->getRouter()->generate("mailgunevent_list", array('_locale' => "en", 'page' => $maxPage + 1, 'pageSize' => $pageSize, 'clear' => true)),13);
172
        $client->request("GET", $beyondListUrl);
173
        $crawler = $client->followRedirect();
174
        $this->assertEquals(2, $crawler->filter(".pagination .disabled:contains('Next')")->count(), "Expected to be on the last page => the next button should be disabled.");
175
176
    }
177
178
    /**
179
     * Load the url and login if required.
180
     * @param  string  $url
181
     * @param  string  $username
182
     * @param  Client  $client
183
     * @return Crawler $crawler of the page of the url or the page after the login
184
     */
185 View Code Duplication
    private function loginUserIfRequired(Client $client, $url, $username = "dominik", $password = "lkjlkjlkjlkj")
186
    {
187
        // try to get the url
188
        $client->followRedirects();
189
        $crawler = $client->request("GET", $url);
190
191
        $this->assertEquals(200, $client->getResponse()->getStatusCode(), "Status-Code 200 expected.");
192
193
        // if redirected to a login-page, login as admin-user
194
        if ($crawler->filter("input")->count() == 5 && $crawler->filter("#username")->count() == 1 && $crawler->filter("#password")->count() == 1 ) {
195
196
            // set the password of the admin
197
               $userProvider = $this->getContainer()->get('fos_user.user_provider.username_email');
198
            $user = $userProvider->loadUserByUsername($username);
199
            $user->setPlainPassword($password);
200
            $user->addRole("ROLE_ADMIN");
201
202
            $userManager = $this->getContainer()->get('fos_user.user_manager');
203
            $userManager->updateUser($user);
204
205
            $crawler = $crawler->filter("input[type='submit']");
206
            $form = $crawler->form();
207
            $form->get('_username')->setValue($username);
208
            $form->get('_password')->setValue($password);
209
            $crawler = $client->submit($form);
210
        }
211
212
        $this->assertEquals(200, $client->getResponse()->getStatusCode(),"Login failed.");
213
        $client->followRedirects(false);
214
215
        $this->assertStringEndsWith($url, $client->getRequest()->getUri(), "Login failed or not redirected to requested url: $url vs. ".$client->getRequest()->getUri());
216
217
        return $crawler;
218
    }
219
220
    /**
221
     * @var ContainerInterface
222
     */
223
    private $container;
224
225
    /**
226
     * Get the current container
227
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
228
     */
229
    private function getContainer()
230
    {
231
        if ($this->container == null) {
232
            $this->container = static::$kernel->getContainer();
233
        }
234
235
        return $this->container;
236
    }
237
238
    /**
239
     * @return UrlGeneratorInterface
240
     */
241
    private function getRouter()
242
    {
243
        return $this->getContainer()->get('router');
244
    }
245
246
    /**
247
     * @return EntityManager
248
     */
249
    private function getEntityManager()
250
    {
251
        return $this->getContainer()->get('doctrine.orm.entity_manager');
252
    }
253
254
    /**
255
     * @return EventDispatcher
256
     */
257
    private function getEventDispatcher()
258
    {
259
        return $this->getContainer()->get("event_dispatcher");
260
    }
261
262
    /**
263
     * Check if the current setup is a full application.
264
     * If not, mark the test as skipped else continue.
265
     */
266
    private function checkApplication()
267
    {
268
        try {
269
            static::$kernel = static::createKernel(array());
270
        } catch (\RuntimeException $ex) {
271
            $this->markTestSkipped("There does not seem to be a full application available (e.g. running tests on travis.org). So this test is skipped.");
272
273
            return;
274
        }
275
    }
276
}
277