Issues (114)

Command/ClearAndLogFailedMailsCommandTest.php (9 issues)

1
<?php
2
3
namespace Azine\EmailBundle\Tests\Command;
4
5
use Azine\EmailBundle\Command\ClearAndLogFailedMailsCommand;
6
use Symfony\Component\Console\Application;
7
use Symfony\Component\Console\Tester\CommandTester;
8
use Symfony\Component\DependencyInjection\ContainerInterface;
9
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
10
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
11
use Symfony\Component\Finder\Finder;
12
13
/**
14
 * @author dominik
15
 */
16
class ClearAndLogFailedMailsCommandTest extends \PHPUnit\Framework\TestCase
17
{
18
    public function testHelpInfo()
19
    {
20
        $command = $this->getCommand();
21
22
        $display = $command->getHelp();
23
        $this->assertContains('Any email-address that still failed, is logged.', $display);
24
    }
25
26
    public function testSendingFailedMails()
27
    {
28
        $command = $this->getCommand();
29
        $failedRecipients = array('[email protected]');
30
        $count = 2;
31
32
        $this->createFakeFailedMessageFiles($count);
33
        $command->setContainer($this->getMockSetup($failedRecipients, false, false, $this->exactly($count)));
34
35
        $display = $this->executeCommandAndGetDisplay($command, array(''));
36
        $this->assertContains("Retrying to send 'subject blabbla' to '[email protected]'", $display);
37
        $this->assertContains('Sent!', $display);
38
    }
39
40
    public function testSendingFailedMailsWithDate()
41
    {
42
        $command = $this->getCommand();
43
        $failedRecipients = array('[email protected]');
44
        $count = 4;
45
        $this->createFakeFailedMessageFiles($count);
46
47
        $command->setContainer($this->getMockSetup($failedRecipients, false, false, $this->exactly($count)));
48
49
        $display = $this->executeCommandAndGetDisplay($command, array('date' => ' > now -1 minute'));
50
        $this->assertContains("Retrying to send 'subject blabbla' to '[email protected]'", $display);
51
        $this->assertContains('Sent!', $display);
52
    }
53
54
    public function testSendingFailedMailsNoMailsFound()
55
    {
56
        $command = $this->getCommand();
57
        $failedRecipients = array();
58
        $command->setContainer($this->getMockSetup($failedRecipients, false, false, $this->never()));
59
60
        $display = $this->executeCommandAndGetDisplay($command, array(''));
61
62
        $this->assertContains('No failed-message-files found', $display);
63
    }
64
65
    public function testSendingFailedMailsWithoutTransport()
66
    {
67
        $command = $this->getCommand();
68
        $failedRecipients = array('[email protected]');
69
        $command->setContainer($this->getMockSetup($failedRecipients, false, true));
70
71
        $display = $this->executeCommandAndGetDisplay($command, array(''));
72
73
        $this->assertContains('Could not load transport. Is file-spooling configured in your config.yml for this environment?', $display);
74
    }
75
76
    public function testSendingFailedMailsWithoutSpooling()
77
    {
78
        $command = $this->getCommand();
79
        $failedRecipients = array('[email protected]');
80
        $command->setContainer($this->getMockSetup($failedRecipients, true));
81
82
        $display = $this->executeCommandAndGetDisplay($command, array(''));
83
84
        $this->assertContains('Could not find file spool path. Is file-spooling configured in your config.yml for this environment?', $display);
85
    }
86
87
    /**
88
     * @param string[] $failedRecipients
89
     * @param bool     $noSpoolPath
90
     * @param bool     $noTransport
91
     * @param null     $msgCount
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $msgCount is correct as it would always require null to be passed?
Loading history...
92
     *
93
     * @internal param string $message
94
     *
95
     * @return ContainerInterface
96
     */
97
    private function getMockSetup($failedRecipients, $noSpoolPath = false, $noTransport = false, $msgCount = null)
98
    {
99
        if (null == $msgCount) {
0 ignored issues
show
The condition null == $msgCount is always true.
Loading history...
100
            $msgCount = $this->once();
101
        }
102
103
        $containerMock = $this->getMockBuilder("Symfony\Component\DependencyInjection\ContainerInterface")->disableOriginalConstructor()->getMock();
104
105
        if ($noTransport) {
106
            $containerMock->expects($this->once())->method('get')->will($this->throwException(new ServiceNotFoundException('swiftmailer.transport.real')));
107
108
            return $containerMock;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $containerMock returns the type PHPUnit\Framework\MockObject\MockObject which is incompatible with the documented return type Symfony\Component\Depend...tion\ContainerInterface.
Loading history...
109
        }
110
111
        $transportMock = $this->getMockBuilder("\Swift_SmtpTransport")->getMock();
112
113
        if ($noSpoolPath) {
114
            $containerMock->expects($this->once())->method('get')->will($this->returnValue($transportMock));
115
            $containerMock->expects($this->once())->method('getParameter')->will($this->throwException(new InvalidArgumentException()));
116
117
            return $containerMock;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $containerMock returns the type PHPUnit\Framework\MockObject\MockObject which is incompatible with the documented return type Symfony\Component\Depend...tion\ContainerInterface.
Loading history...
118
        }
119
120
        $loggerMock = $this->getMockBuilder("Psr\Log\LoggerInterface")->disableOriginalConstructor()->getMock();
121
        if (sizeof($failedRecipients) > 0) {
122
            $loggerMock->expects($this->once())->method('warning')->with('<error>Failed to send an email to : '.implode(', ', $failedRecipients).'</error>');
123
            $getServiceCallCount = $this->exactly(2);
124
        } else {
125
            $loggerMock->expects($this->never())->method('warning');
126
            $getServiceCallCount = $this->once();
127
        }
128
129
        $transportMock->expects($this->once())->method('isStarted')->will($this->returnValue(false));
130
        $transportMock->expects($this->once())->method('start');
131
        $this->failedRecipients = $failedRecipients;
132
        $transportMock->expects($msgCount)->method('send')->will($this->returnCallback(array($this, 'send_failures_callback')));
133
134
        $containerMock->expects($getServiceCallCount)->method('get')->will($this->returnValueMap(array(
135
                                                                                                    array('swiftmailer.transport.real', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $transportMock),
136
                                                                                                    array('logger', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $loggerMock),
137
                                                                                            )));
138
        $containerMock->expects($this->exactly(2))->method('getParameter')->will($this->returnValueMap(array(
139
                                                                                                    array('swiftmailer.mailers', array('default_mailer' => 'a dummy value for a mailer')),
140
                                                                                                    array('swiftmailer.spool.default_mailer.file.path', __DIR__.'/mock.spool.path'),
141
                                                                                            )));
142
143
        return $containerMock;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $containerMock returns the type PHPUnit\Framework\MockObject\MockObject which is incompatible with the documented return type Symfony\Component\Depend...tion\ContainerInterface.
Loading history...
144
    }
145
146
    private $failedRecipients = array();
147
148
    public function send_failures_callback($message, &$failedRecipients = null)
149
    {
150
        if (sizeof($this->failedRecipients) > 0) {
151
            $failedRecipients[] = array_pop($this->failedRecipients);
152
        }
153
    }
154
155
    private function createFakeFailedMessageFiles($count = 1)
156
    {
157
        $targetDir = __DIR__.'/mock.spool.path/';
158
159
        $i = 0;
160
        while ($i < $count) {
161
            $random = md5(date('now')).$count.rand(0, 10000000);
162
            $filename = $targetDir."$random.sending";
163
            $msg = new \Swift_Message();
164
            $msg->setTo('[email protected]');
165
            $msg->setBody("random file $random bla bla.");
166
            $msg->setSubject('subject blabbla');
167
            $msg->setSender('[email protected]');
168
            $ser = serialize($msg);
169
            $filehandle = fopen($filename, 'w');
170
            fwrite($filehandle, $ser);
0 ignored issues
show
It seems like $filehandle can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
            fwrite(/** @scrutinizer ignore-type */ $filehandle, $ser);
Loading history...
171
            fclose($filehandle);
0 ignored issues
show
It seems like $filehandle can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

171
            fclose(/** @scrutinizer ignore-type */ $filehandle);
Loading history...
172
            ++$i;
173
        }
174
175
        // make sure the right number of files has been created.
176
        $fileCount = 0;
177
        $targetDirHandle = opendir($targetDir);
178
        while (false !== ($file = readdir($targetDirHandle))) {
0 ignored issues
show
It seems like $targetDirHandle can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

178
        while (false !== ($file = readdir(/** @scrutinizer ignore-type */ $targetDirHandle))) {
Loading history...
The assignment to $file is dead and can be removed.
Loading history...
179
            ++$fileCount;
180
        }
181
        $this->assertSame($count + 3, $fileCount, "Exactly $count + 2 files (*.sending, '.', '..' and '.keepMe') expected in this directory( $targetDir ).");
182
    }
183
184
    /**
185
     * @return ClearAndLogFailedMailsCommand
186
     */
187
    private function getCommand()
188
    {
189
        $application = new Application();
190
        $application->add(new ClearAndLogFailedMailsCommand());
191
192
        return $application->find('emails:clear-and-log-failures');
193
    }
194
195
    /**
196
     * @param ClearAndLogFailedMailsCommand $command
197
     * @param array                         $input
198
     *
199
     * @return string
200
     */
201
    private function executeCommandAndGetDisplay($command, $input)
202
    {
203
        $tester = new CommandTester($command);
204
        $tester->execute($input);
205
        $display = $tester->getDisplay();
206
207
        return $display;
208
    }
209
210
    public function tearDown()
211
    {
212
        parent::tearDown();
213
        $finder = Finder::create()->in(__DIR__.'/mock.spool.path/')->name('*');
214
        foreach ($finder as $next) {
215
            unlink($next);
216
        }
217
    }
218
}
219