Completed
Push — master ( 167ab4...693f6f )
by
unknown
12:29
created

ImportExportTest::stringToArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
dl 0
loc 4
rs 10
c 1
b 0
f 1
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace OroCRM\Bundle\ContactBundle\Tests\Functional;
4
5
use Akeneo\Bundle\BatchBundle\Job\DoctrineJobRepository as BatchJobRepository;
6
7
use Symfony\Component\DomCrawler\Form;
8
9
use Oro\Bundle\ImportExportBundle\Job\JobExecutor;
10
use Oro\Bundle\ImportExportBundle\Processor\ProcessorRegistry;
11
use Oro\Bundle\TestFrameworkBundle\Test\WebTestCase;
12
13
/**
14
 * @outputBuffering enabled
15
 * @dbIsolation
16
 * @dbReindex
17
 */
18
class ImportExportTest extends WebTestCase
19
{
20
    /**
21
     * @var string
22
     */
23
    protected $file;
24
25
    protected function setUp()
26
    {
27
        $this->initClient(array(), $this->generateBasicAuthHeader());
28
    }
29
30
    /**
31
     * Delete data required because there is commit to job repository in import/export controller action
32
     * Please use
33
     *   $this->getContainer()->get('akeneo_batch.job_repository')->getJobManager()->beginTransaction();
34
     *   $this->getContainer()->get('akeneo_batch.job_repository')->getJobManager()->rollback();
35
     *   $this->getContainer()->get('akeneo_batch.job_repository')->getJobManager()->getConnection()->clear();
36
     * if you don't use controller
37
     */
38
    protected function tearDown()
39
    {
40
        // clear DB from separate connection, close to avoid connection limit and memory leak
41
        $batchJobManager = $this->getBatchJobManager();
42
        $batchJobManager->createQuery('DELETE AkeneoBatchBundle:JobInstance')->execute();
43
        $batchJobManager->createQuery('DELETE AkeneoBatchBundle:JobExecution')->execute();
44
        $batchJobManager->createQuery('DELETE AkeneoBatchBundle:StepExecution')->execute();
45
46
        parent::tearDown();
47
    }
48
49
    /**
50
     * @return \Doctrine\ORM\EntityManager
51
     */
52
    protected function getBatchJobManager()
53
    {
54
        /** @var BatchJobRepository $batchJobRepository */
55
        $batchJobRepository = $this->getContainer()->get('akeneo_batch.job_repository');
56
        return $batchJobRepository->getJobManager();
57
    }
58
59
    public function strategyDataProvider()
60
    {
61
        return [
62
            'add'            => ['orocrm_contact.add'],
63
            'add or replace' => ['orocrm_contact.add_or_replace'],
64
        ];
65
    }
66
67
    /**
68
     * @param string $strategy
69
     * @dataProvider strategyDataProvider
70
     */
71
    public function testImportExport($strategy)
72
    {
73
        $this->validateImportFile($strategy);
74
        $this->doImport($strategy);
75
76
        $this->doExport();
77
        $this->validateExportResult();
78
    }
79
80
    /**
81
     * @param string $strategy
82
     */
83
    protected function validateImportFile($strategy)
84
    {
85
        $crawler = $this->client->request(
86
            'GET',
87
            $this->getUrl(
88
                'oro_importexport_import_form',
89
                array(
90
                    'entity'           => 'OroCRM\Bundle\ContactBundle\Entity\Contact',
91
                    '_widgetContainer' => 'dialog'
92
                )
93
            )
94
        );
95
        $result = $this->client->getResponse();
96
        $this->assertHtmlResponseStatusCodeEquals($result, 200);
97
        $this->assertContains($strategy, $result->getContent());
98
99
        $this->file = $this->getImportTemplate();
100
        $this->assertTrue(file_exists($this->file));
101
102
        /** @var Form $form */
103
        $form = $crawler->selectButton('Submit')->form();
104
105
        /** TODO Change after BAP-1813 */
106
        $form->getFormNode()->setAttribute(
107
            'action',
108
            $form->getFormNode()->getAttribute('action') . '&_widgetContainer=dialog'
109
        );
110
111
        $form['oro_importexport_import[file]']->upload($this->file);
112
        $form['oro_importexport_import[processorAlias]'] = $strategy;
113
114
        $this->client->followRedirects(true);
115
        $this->client->submit($form);
116
117
        $result = $this->client->getResponse();
118
119
        $this->assertHtmlResponseStatusCodeEquals($result, 200);
120
121
        $crawler = $this->client->getCrawler();
122
        $this->assertEquals(0, $crawler->filter('.import-errors')->count());
123
    }
124
125
    /**
126
     * @param string $strategy
127
     */
128
    protected function doImport($strategy)
129
    {
130
        // test import
131
        $this->client->followRedirects(false);
132
        $this->client->request(
133
            'GET',
134
            $this->getUrl(
135
                'oro_importexport_import_process',
136
                array(
137
                    'processorAlias' => $strategy,
138
                    '_format'        => 'json'
139
                )
140
            )
141
        );
142
143
        $data = $this->getJsonResponseContent($this->client->getResponse(), 200);
144
145
        $this->assertEquals(
146
            array(
147
                'success'   => true,
148
                'message'   => 'File was successfully imported.',
149
                'errorsUrl' => null
150
            ),
151
            $data
152
        );
153
    }
154
155
    protected function doExport()
156
    {
157
        $this->client->followRedirects(false);
158
        $this->client->request(
159
            'GET',
160
            $this->getUrl(
161
                'oro_importexport_export_instant',
162
                array(
163
                    'processorAlias' => 'orocrm_contact',
164
                    '_format'        => 'json'
165
                )
166
            )
167
        );
168
169
        $data = $this->getJsonResponseContent($this->client->getResponse(), 200);
170
171
        $this->assertTrue($data['success']);
172
        $this->assertEquals(1, $data['readsCount']);
173
        $this->assertEquals(0, $data['errorsCount']);
174
175
        $this->client->request(
176
            'GET',
177
            $data['url']
178
        );
179
180
        $result = $this->client->getResponse();
181
        $this->assertResponseStatusCodeEquals($result, 200);
182
        $this->assertResponseContentTypeEquals($result, 'text/csv');
183
    }
184
185
    protected function validateExportResult()
186
    {
187
        $importTemplate = $this->getFileContents($this->file);
188
        $exportedData = $this->getFileContents($this->getExportFile());
189
190
        $commonFields = array_intersect($importTemplate[0], $exportedData[0]);
191
192
        $importTemplateValues = $this->extractFieldValues($commonFields, $importTemplate);
193
        $exportedDataValues = $this->extractFieldValues($commonFields, $exportedData);
194
195
        $this->assertExportResults($importTemplateValues, $exportedDataValues);
196
    }
197
198
    /**
199
     * @param array $expected
200
     * @param array $actual
201
     */
202
    protected function assertExportResults(array $expected, array $actual)
203
    {
204
        $this->assertCollectionData($expected, $actual, ['Emails 2 Email', 'Emails 3 Email']);
205
        $this->assertCollectionData($expected, $actual, ['Phones 2 Phone', 'Phones 3 Phone']);
206
        $this->assertCollectionData($expected, $actual, ['Addresses 2 Street', 'Addresses 3 Street']);
207
        $this->assertCollectionData($expected, $actual, ['Addresses 2 Zip/postal code', 'Addresses 3 Zip/postal code']);
208
        $this->assertArrayData($expected, $actual, 'Tags');
209
210
        $this->assertEquals($expected, $actual);
211
    }
212
213
    /**
214
     * @param array $expected
215
     * @param array $actual
216
     * @param string $key
217
     */
218
    protected function assertArrayData(array &$expected, array &$actual, $key)
219
    {
220
        $this->assertArrayHasKey($key, $expected);
221
        $this->assertArrayHasKey($key, $actual);
222
223
        $e = $this->stringToArray($expected[$key]);
224
        $a = $this->stringToArray($actual[$key]);
225
        sort($e);
226
        sort($a);
227
228
        $this->assertEquals($e, $a);
229
230
        unset($expected[$key]);
231
        unset($actual[$key]);
232
    }
233
234
    protected function stringToArray($string)
235
    {
236
        return explode(', ', $string);
237
    }
238
239
    /**
240
     * Order of elements in collection is not important, except the first (primary) element
241
     *
242
     * @param array $expected
243
     * @param array $actual
244
     * @param array $keys
245
     */
246
    protected function assertCollectionData(array &$expected, array &$actual, array $keys)
247
    {
248
        $expectedValues = [];
249
        $actualValues = [];
250
251
        foreach ($keys as $key) {
252
            $this->assertArrayHasKey($key, $expected);
253
            $this->assertArrayHasKey($key, $actual);
254
            $expectedValues[] = $expected[$key];
255
            $actualValues[] = $actual[$key];
256
            unset($expected[$key]);
257
            unset($actual[$key]);
258
        }
259
260
        sort($expectedValues);
261
        sort($actualValues);
262
263
        $this->assertEquals($expectedValues, $actualValues);
264
    }
265
266
    /**
267
     * @param array $fields
268
     * @param array $data
269
     * @return array
270
     */
271
    protected function extractFieldValues(array $fields, array $data)
272
    {
273
        // ID is changed
274
        // birthdays have different timestamps
275
        $skippedFields = ['Id', 'Birthday'];
276
277
        $values = [];
278
        foreach ($fields as $field) {
279
            if (!in_array($field, $skippedFields)) {
280
                $key = array_search($field, $data[0]);
281
                if (false !== $key) {
282
                    $values[$field] = $data[1][$key];
283
                }
284
            }
285
        }
286
287
        return $values;
288
    }
289
290
    /**
291
     * @return string
292
     */
293
    protected function getImportTemplate()
294
    {
295
        $result = $this
296
            ->getContainer()
297
            ->get('oro_importexport.handler.export')
298
            ->getExportResult(
299
                JobExecutor::JOB_EXPORT_TEMPLATE_TO_CSV,
300
                'orocrm_contact',
301
                ProcessorRegistry::TYPE_EXPORT_TEMPLATE
302
            );
303
304
        $chains = explode('/', $result['url']);
305
        return $this
306
            ->getContainer()
307
            ->get('oro_importexport.file.file_system_operator')
308
            ->getTemporaryFile(end($chains))
309
            ->getRealPath();
310
    }
311
312
    /**
313
     * @return string
314
     */
315
    protected function getExportFile()
316
    {
317
        $result = $this
318
            ->getContainer()
319
            ->get('oro_importexport.handler.export')
320
            ->handleExport(
321
                JobExecutor::JOB_EXPORT_TO_CSV,
322
                'orocrm_contact',
323
                ProcessorRegistry::TYPE_EXPORT
324
            );
325
326
        $result = json_decode($result->getContent(), true);
327
        $chains = explode('/', $result['url']);
328
        return $this
329
            ->getContainer()
330
            ->get('oro_importexport.file.file_system_operator')
331
            ->getTemporaryFile(end($chains))
332
            ->getRealPath();
333
    }
334
335
    /**
336
     * @param string $fileName
337
     * @return array
338
     */
339
    protected function getFileContents($fileName)
340
    {
341
        $content = file_get_contents($fileName);
342
        $content = explode("\n", $content);
343
        $content = array_filter($content, 'strlen');
344
        return array_map('str_getcsv', $content);
345
    }
346
}
347