Passed
Push — master ( 34494b...39d0af )
by Aimeos
04:11
created

StandardTest::access()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 7
rs 10
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2024
6
 */
7
8
9
namespace Aimeos\Controller\Jobs\Product\Import\Csv;
10
11
12
class StandardTest extends \PHPUnit\Framework\TestCase
13
{
14
	private $object;
15
	private $context;
16
	private $aimeos;
17
18
19
	public static function setUpBeforeClass() : void
20
	{
21
		$context = \TestHelper::context();
22
23
		$fs = $context->fs( 'fs-import' );
24
		$fs->has( 'product' ) ?: $fs->mkdir( 'product' );
25
		$fs->writef( 'product/empty.csv', __DIR__ . '/_testfiles/empty.csv' );
26
27
		$fs->has( 'product/valid' ) ?: $fs->mkdir( 'product/valid' );
28
		$fs->writef( 'product/valid/products.csv', __DIR__ . '/_testfiles/valid/products.csv' );
29
30
		$fs->has( 'product/position' ) ?: $fs->mkdir( 'product/position' );
31
		$fs->writef( 'product/position/products.csv', __DIR__ . '/_testfiles/position/products.csv' );
32
33
		$fs = $context->fs( 'fs-media' );
34
		$fs->has( 'path/to' ) ?: $fs->mkdir( 'path/to' );
35
		$fs->write( 'path/to/image2.jpg', 'test' );
36
		$fs->write( 'path/to/image.jpg', 'test' );
37
38
		$fs = $context->fs( 'fs-mimeicon' );
39
		$fs->write( 'unknown.png', 'icon' );
40
	}
41
42
43
	protected function setUp() : void
44
	{
45
		\Aimeos\MShop::cache( true );
46
47
		$this->context = \TestHelper::context();
48
		$this->aimeos = \TestHelper::getAimeos();
49
50
		$config = $this->context->config();
51
		$config->set( 'controller/jobs/product/import/csv/skip-lines', 1 );
52
		$config->set( 'controller/jobs/product/import/csv/location', 'product/valid' );
53
54
		$this->object = new \Aimeos\Controller\Jobs\Product\Import\Csv\Standard( $this->context, $this->aimeos );
55
	}
56
57
58
	protected function tearDown() : void
59
	{
60
		\Aimeos\MShop::cache( false );
61
		unset( $this->object, $this->context, $this->aimeos );
62
	}
63
64
65
	public function testGetName()
66
	{
67
		$this->assertEquals( 'Product import CSV', $this->object->getName() );
68
	}
69
70
71
	public function testGetDescription()
72
	{
73
		$text = 'Imports new and updates existing products from CSV files';
74
		$this->assertEquals( $text, $this->object->getDescription() );
75
	}
76
77
78
	public function testRun()
79
	{
80
		$prodcodes = array( 'job_csv_test', 'job_csv_test2' );
81
		$nondelete = array( 'attribute', 'product', 'catalog' );
82
		$delete = array( 'media', 'price', 'text' );
83
84
		$this->object->run();
85
86
		$result = $this->get( $prodcodes, array_merge( $delete, $nondelete ) );
87
		$properties = $this->getProperties( array_keys( $result ) );
88
		$this->delete( $prodcodes, $delete );
89
90
		$this->assertEquals( 2, count( $result ) );
91
		$this->assertEquals( 2, count( $properties ) );
92
93
		foreach( $result as $product ) {
94
			$this->assertEquals( 6, count( $product->getListItems() ) );
95
		}
96
	}
97
98
99
	public function testRunUpdate()
100
	{
101
		$prodcodes = array( 'job_csv_test', 'job_csv_test2' );
102
		$nondelete = array( 'attribute', 'product', 'catalog' );
103
		$delete = array( 'media', 'price', 'text' );
104
105
		$mapping = array(
106
			'item' => array(
107
				0 => 'product.code',
108
				1 => 'product.label',
109
				2 => 'product.type',
110
				3 => 'product.status',
111
			),
112
			'text' => array(
113
				4 => 'text.type',
114
				5 => 'text.content',
115
				6 => 'text.type',
116
				7 => 'text.content',
117
			),
118
			'media' => array(
119
				8 => 'media.url',
120
			),
121
			'price' => array(
122
				9 => 'price.currencyid',
123
				10 => 'price.quantity',
124
				11 => 'price.value',
125
				12 => 'price.taxrate',
126
			),
127
			'attribute' => array(
128
				13 => 'product.lists.type',
129
				14 => 'attribute.code',
130
				15 => 'attribute.type',
131
			),
132
			'product' => array(
133
				16 => 'product.code',
134
				17 => 'product.lists.type',
135
			),
136
			'property' => array(
137
				18 => 'product.property.value',
138
				19 => 'product.property.type',
139
			),
140
			'catalog' => array(
141
				20 => 'catalog.code',
142
				21 => 'catalog.lists.type',
143
				22 => 'product.lists.config',
144
			),
145
		);
146
		$this->context->config()->set( 'controller/jobs/product/import/csv/mapping', $mapping );
147
148
		$fs = $this->context->fs( 'fs-import' );
149
		$fs->writef( 'product/valid/products.csv', __DIR__ . '/_testfiles/valid/products.csv' );
150
151
		$this->object->run();
152
153
		$fs = $this->context->fs( 'fs-import' );
154
		$fs->writef( 'product/valid/products.csv', __DIR__ . '/_testfiles/valid/products.csv' );
155
156
		$this->object->run();
157
158
		$result = $this->get( $prodcodes, array_merge( $delete, $nondelete ) );
159
		$properties = $this->getProperties( array_keys( $result ) );
160
		$this->delete( $prodcodes, $delete );
161
162
		$this->assertEquals( 2, count( $result ) );
163
		$this->assertEquals( 2, count( $properties ) );
164
165
		foreach( $result as $product ) {
166
			$this->assertEquals( 6, count( $product->getListItems() ) );
167
		}
168
169
		$config = map( $result )->getListItems( 'catalog' )->flat( 1 )->getConfig()->first();
170
		$this->assertEquals( ['num' => 2, 'key' => 'value'], $config );
171
	}
172
173
174
	public function testRunPosition()
175
	{
176
		$prodcodes = array( 'job_csv_test', 'job_csv_test2' );
177
		$nondelete = array( 'attribute', 'product' );
178
		$delete = array( 'media', 'price', 'text' );
179
180
		$config = $this->context->config();
181
		$mapping = $config->get( 'controller/jobs/product/import/csv/mapping', [] );
182
		$mapping['item'] = array( 0 => 'product.label', 1 => 'product.code' );
183
184
		$config->set( 'controller/jobs/product/import/csv/mapping', $mapping );
185
		$config->set( 'controller/jobs/product/import/csv/location', 'product/position' );
186
187
		$this->object->run();
188
189
		$result = $this->get( $prodcodes, array_merge( $delete, $nondelete ) );
190
		$this->delete( $prodcodes, $delete );
191
192
		$this->assertEquals( 2, count( $result ) );
193
	}
194
195
196
	public function testRunProcessorInvalidMapping()
197
	{
198
		$config = $this->context->config();
199
		$config->set( 'controller/jobs/product/import/csv/location', 'product' );
200
201
		$mapping = array(
202
			'media' => array(
203
					8 => 'media.url',
204
			),
205
		);
206
207
		$this->context->config()->set( 'controller/jobs/product/import/csv/mapping', $mapping );
208
209
		$this->expectException( '\\Aimeos\\Controller\\Jobs\\Exception' );
210
		$this->object->run();
211
	}
212
213
214
	public function testRunBackup()
215
	{
216
		$config = $this->context->config();
217
		$config->set( 'controller/jobs/product/import/csv/backup', 'backup-%Y-%m-%d.csv' );
218
		$config->set( 'controller/jobs/product/import/csv/location', 'product' );
219
220
		$this->object->run();
221
222
		$filename = \Aimeos\Base\Str::strtime( 'backup-%Y-%m-%d.csv' );
223
		$this->assertTrue( $this->context->fs( 'fs-import' )->has( $filename ) );
224
225
		$this->context->fs( 'fs-import' )->rm( $filename );
226
	}
227
228
229
	public function testRunCleanup()
230
	{
231
		$stub = $this->getMockBuilder( '\\Aimeos\\MShop\\Product\\Manager\\Standard' )
232
			->setConstructorArgs( [\TestHelper::context()] )
233
			->onlyMethods( ['delete'] )
234
			->getMock();
235
236
		\Aimeos\MShop::inject( '\\Aimeos\\MShop\\Product\\Manager\\Standard', $stub );
237
238
		$result = $this->access( 'cleanup' )->invokeArgs( $this->object, [date( 'Y-m-d H:i:s')] );
239
240
		$this->assertEquals( 15, $result );
241
	}
242
243
244
	protected function access( $name )
245
	{
246
		$class = new \ReflectionClass( \Aimeos\Controller\Jobs\Product\Import\Csv\Standard::class );
247
		$method = $class->getMethod( $name );
248
		$method->setAccessible( true );
249
250
		return $method;
251
	}
252
253
254
	protected function delete( array $prodcodes, array $delete )
255
	{
256
		$productManager = \Aimeos\MShop::create( $this->context, 'product' );
257
258
		foreach( $this->get( $prodcodes, $delete ) as $id => $product )
259
		{
260
			foreach( $delete as $domain )
261
			{
262
				$ids = $product->getListItems( $domain )->getRefId()->all();
263
				\Aimeos\MShop::create( $this->context, $domain )->delete( $ids );
264
			}
265
266
			$productManager->delete( $product->getId() );
267
		}
268
269
270
		$attrManager = \Aimeos\MShop::create( $this->context, 'attribute' );
271
272
		$search = $attrManager->filter();
273
		$search->setConditions( $search->compare( '==', 'attribute.code', 'import-test' ) );
274
275
		$attrManager->delete( $attrManager->search( $search ) );
276
	}
277
278
279
	protected function get( array $prodcodes, array $domains ) : array
280
	{
281
		$productManager = \Aimeos\MShop::create( $this->context, 'product' );
282
283
		$search = $productManager->filter();
284
		$search->setConditions( $search->compare( '==', 'product.code', $prodcodes ) );
285
286
		return $productManager->search( $search, $domains )->all();
287
	}
288
289
290
	protected function getProperties( array $prodids ) : array
291
	{
292
		$manager = \Aimeos\MShop::create( $this->context, 'product/property' );
293
294
		$search = $manager->filter()->order( 'product.property.type' )
295
			->add( ['product.property.parentid' => $prodids] );
296
297
		return $manager->search( $search )->all();
298
	}
299
}
300