mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-12-06 11:09:29 +00:00
Add tests and fix static errors
This commit is contained in:
parent
fa7f3a1da1
commit
2bc39e7791
8 changed files with 576 additions and 25 deletions
|
|
@ -28,7 +28,6 @@ use App\Entity\Parts\Part;
|
||||||
use App\Entity\Parts\Supplier;
|
use App\Entity\Parts\Supplier;
|
||||||
use App\Form\InfoProviderSystem\GlobalFieldMappingType;
|
use App\Form\InfoProviderSystem\GlobalFieldMappingType;
|
||||||
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
||||||
use App\Services\InfoProviderSystem\ProviderRegistry;
|
|
||||||
use App\Services\InfoProviderSystem\ExistingPartFinder;
|
use App\Services\InfoProviderSystem\ExistingPartFinder;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
@ -37,12 +36,12 @@ use Symfony\Component\HttpClient\Exception\ClientException;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use App\Entity\UserSystem\User;
|
||||||
|
|
||||||
#[Route('/tools/bulk-info-provider-import')]
|
#[Route('/tools/bulk-info-provider-import')]
|
||||||
class BulkInfoProviderImportController extends AbstractController
|
class BulkInfoProviderImportController extends AbstractController
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly ProviderRegistry $providerRegistry,
|
|
||||||
private readonly PartInfoRetriever $infoRetriever,
|
private readonly PartInfoRetriever $infoRetriever,
|
||||||
private readonly ExistingPartFinder $existingPartFinder,
|
private readonly ExistingPartFinder $existingPartFinder,
|
||||||
private readonly EntityManagerInterface $entityManager
|
private readonly EntityManagerInterface $entityManager
|
||||||
|
|
@ -108,7 +107,11 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
$job->setPartIds(array_map(fn($part) => $part->getId(), $parts));
|
$job->setPartIds(array_map(fn($part) => $part->getId(), $parts));
|
||||||
$job->setFieldMappings($fieldMappings);
|
$job->setFieldMappings($fieldMappings);
|
||||||
$job->setPrefetchDetails($prefetchDetails);
|
$job->setPrefetchDetails($prefetchDetails);
|
||||||
$job->setCreatedBy($this->getUser());
|
$user = $this->getUser();
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new \RuntimeException('User must be authenticated and of type User');
|
||||||
|
}
|
||||||
|
$job->setCreatedBy($user);
|
||||||
|
|
||||||
$this->entityManager->persist($job);
|
$this->entityManager->persist($job);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
@ -124,6 +127,7 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
|
|
||||||
// Collect all DTOs from all applicable field mappings
|
// Collect all DTOs from all applicable field mappings
|
||||||
$allDtos = [];
|
$allDtos = [];
|
||||||
|
$dtoMetadata = []; // Store source field info separately
|
||||||
|
|
||||||
foreach ($fieldMappings as $mapping) {
|
foreach ($fieldMappings as $mapping) {
|
||||||
$field = $mapping['field'];
|
$field = $mapping['field'];
|
||||||
|
|
@ -142,10 +146,13 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
providers: $providers
|
providers: $providers
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add field info to each DTO for tracking
|
// Store field info for each DTO separately
|
||||||
foreach ($dtos as $dto) {
|
foreach ($dtos as $dto) {
|
||||||
$dto->_source_field = $field;
|
$dtoKey = $dto->provider_key . '|' . $dto->provider_id;
|
||||||
$dto->_source_keyword = $keyword;
|
$dtoMetadata[$dtoKey] = [
|
||||||
|
'source_field' => $field,
|
||||||
|
'source_keyword' => $keyword
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$allDtos = array_merge($allDtos, $dtos);
|
$allDtos = array_merge($allDtos, $dtos);
|
||||||
|
|
@ -160,16 +167,28 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
$uniqueDtos = [];
|
$uniqueDtos = [];
|
||||||
$seenKeys = [];
|
$seenKeys = [];
|
||||||
foreach ($allDtos as $dto) {
|
foreach ($allDtos as $dto) {
|
||||||
$key = $dto->provider_key . '|' . $dto->provider_id;
|
if ($dto === null || !isset($dto->provider_key, $dto->provider_id)) {
|
||||||
if (!in_array($key, $seenKeys)) {
|
continue;
|
||||||
|
}
|
||||||
|
$key = "{$dto->provider_key}|{$dto->provider_id}";
|
||||||
|
if (!in_array($key, $seenKeys, true)) {
|
||||||
$seenKeys[] = $key;
|
$seenKeys[] = $key;
|
||||||
$uniqueDtos[] = $dto;
|
$uniqueDtos[] = $dto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert DTOs to result format
|
// Convert DTOs to result format with metadata
|
||||||
$partResult['search_results'] = array_map(
|
$partResult['search_results'] = array_map(
|
||||||
fn($dto) => ['dto' => $dto, 'localPart' => $this->existingPartFinder->findFirstExisting($dto)],
|
function($dto) use ($dtoMetadata) {
|
||||||
|
$dtoKey = $dto->provider_key . '|' . $dto->provider_id;
|
||||||
|
$metadata = $dtoMetadata[$dtoKey] ?? [];
|
||||||
|
return [
|
||||||
|
'dto' => $dto,
|
||||||
|
'localPart' => $this->existingPartFinder->findFirstExisting($dto),
|
||||||
|
'source_field' => $metadata['source_field'] ?? null,
|
||||||
|
'source_keyword' => $metadata['source_keyword'] ?? null
|
||||||
|
];
|
||||||
|
},
|
||||||
$uniqueDtos
|
$uniqueDtos
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -182,7 +201,7 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
// Prefetch details if requested
|
// Prefetch details if requested
|
||||||
if ($prefetchDetails && !empty($searchResults)) {
|
if ($prefetchDetails) {
|
||||||
$this->prefetchDetailsForResults($searchResults, $exceptionLogger);
|
$this->prefetchDetailsForResults($searchResults, $exceptionLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,8 +406,8 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
'mpn' => $dto->mpn,
|
'mpn' => $dto->mpn,
|
||||||
'provider_url' => $dto->provider_url,
|
'provider_url' => $dto->provider_url,
|
||||||
'preview_image_url' => $dto->preview_image_url,
|
'preview_image_url' => $dto->preview_image_url,
|
||||||
'_source_field' => $dto->_source_field ?? null,
|
'_source_field' => $result['source_field'] ?? null,
|
||||||
'_source_keyword' => $dto->_source_keyword ?? null,
|
'_source_keyword' => $result['source_keyword'] ?? null,
|
||||||
],
|
],
|
||||||
'localPart' => $result['localPart'] ? $result['localPart']->getId() : null
|
'localPart' => $result['localPart'] ? $result['localPart']->getId() : null
|
||||||
];
|
];
|
||||||
|
|
@ -435,10 +454,6 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
preview_image_url: $dtoData['preview_image_url']
|
preview_image_url: $dtoData['preview_image_url']
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add the source field info
|
|
||||||
$dto->_source_field = $dtoData['_source_field'];
|
|
||||||
$dto->_source_keyword = $dtoData['_source_keyword'];
|
|
||||||
|
|
||||||
$localPart = null;
|
$localPart = null;
|
||||||
if ($resultData['localPart']) {
|
if ($resultData['localPart']) {
|
||||||
$localPart = $this->entityManager->getRepository(Part::class)->find($resultData['localPart']);
|
$localPart = $this->entityManager->getRepository(Part::class)->find($resultData['localPart']);
|
||||||
|
|
@ -446,7 +461,9 @@ class BulkInfoProviderImportController extends AbstractController
|
||||||
|
|
||||||
$partResult['search_results'][] = [
|
$partResult['search_results'][] = [
|
||||||
'dto' => $dto,
|
'dto' => $dto,
|
||||||
'localPart' => $localPart
|
'localPart' => $localPart,
|
||||||
|
'source_field' => $dtoData['_source_field'] ?? null,
|
||||||
|
'source_keyword' => $dtoData['_source_keyword'] ?? null
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ class BulkInfoProviderImportJob extends AbstractDBElement
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: User::class)]
|
#[ORM\ManyToOne(targetEntity: User::class)]
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
#[ORM\JoinColumn(nullable: false)]
|
||||||
private User $createdBy;
|
private ?User $createdBy = null;
|
||||||
|
|
||||||
#[ORM\Column(type: Types::JSON)]
|
#[ORM\Column(type: Types::JSON)]
|
||||||
private array $progress = [];
|
private array $progress = [];
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,4 @@ class BulkProviderSearchType extends AbstractType
|
||||||
]);
|
]);
|
||||||
$resolver->setRequired('parts');
|
$resolver->setRequired('parts');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDefaultSearchField(Part $part): string
|
|
||||||
{
|
|
||||||
// Default to MPN if available, otherwise name
|
|
||||||
return $part->getManufacturerProductNumber() ? 'mpn' : 'name';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
126
tests/Controller/BulkInfoProviderImportControllerTest.php
Normal file
126
tests/Controller/BulkInfoProviderImportControllerTest.php
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Controller;
|
||||||
|
|
||||||
|
use App\Entity\UserSystem\User;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group slow
|
||||||
|
* @group DB
|
||||||
|
*/
|
||||||
|
class BulkInfoProviderImportControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
public function testStep1WithoutIds(): void
|
||||||
|
{
|
||||||
|
$client = static::createClient();
|
||||||
|
$this->loginAsUser($client, 'admin');
|
||||||
|
|
||||||
|
$client->request('GET', '/tools/bulk-info-provider-import/step1');
|
||||||
|
|
||||||
|
$this->assertResponseRedirects();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStep1WithInvalidIds(): void
|
||||||
|
{
|
||||||
|
$client = static::createClient();
|
||||||
|
$this->loginAsUser($client, 'admin');
|
||||||
|
|
||||||
|
$client->request('GET', '/tools/bulk-info-provider-import/step1?ids=999999,888888');
|
||||||
|
|
||||||
|
$this->assertResponseRedirects();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManagePage(): void
|
||||||
|
{
|
||||||
|
$client = static::createClient();
|
||||||
|
$this->loginAsUser($client, 'admin');
|
||||||
|
|
||||||
|
$client->request('GET', '/tools/bulk-info-provider-import/manage');
|
||||||
|
|
||||||
|
// Follow any redirects (like locale redirects)
|
||||||
|
if ($client->getResponse()->isRedirect()) {
|
||||||
|
$client->followRedirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAccessControlForStep1(): void
|
||||||
|
{
|
||||||
|
$client = static::createClient();
|
||||||
|
|
||||||
|
$client->request('GET', '/tools/bulk-info-provider-import/step1?ids=1');
|
||||||
|
$this->assertResponseRedirects();
|
||||||
|
|
||||||
|
$this->loginAsUser($client, 'noread');
|
||||||
|
$client->request('GET', '/tools/bulk-info-provider-import/step1?ids=1');
|
||||||
|
|
||||||
|
// Follow redirects if any, then check for 403 or final response
|
||||||
|
if ($client->getResponse()->isRedirect()) {
|
||||||
|
$client->followRedirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user might get redirected to an error page instead of direct 403
|
||||||
|
$this->assertTrue(
|
||||||
|
$client->getResponse()->getStatusCode() === Response::HTTP_FORBIDDEN ||
|
||||||
|
$client->getResponse()->getStatusCode() === Response::HTTP_OK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAccessControlForManage(): void
|
||||||
|
{
|
||||||
|
$client = static::createClient();
|
||||||
|
|
||||||
|
$client->request('GET', '/tools/bulk-info-provider-import/manage');
|
||||||
|
$this->assertResponseRedirects();
|
||||||
|
|
||||||
|
$this->loginAsUser($client, 'noread');
|
||||||
|
$client->request('GET', '/tools/bulk-info-provider-import/manage');
|
||||||
|
|
||||||
|
// Follow redirects if any, then check for 403 or final response
|
||||||
|
if ($client->getResponse()->isRedirect()) {
|
||||||
|
$client->followRedirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user might get redirected to an error page instead of direct 403
|
||||||
|
$this->assertTrue(
|
||||||
|
$client->getResponse()->getStatusCode() === Response::HTTP_FORBIDDEN ||
|
||||||
|
$client->getResponse()->getStatusCode() === Response::HTTP_OK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loginAsUser($client, string $username): void
|
||||||
|
{
|
||||||
|
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||||
|
$userRepository = $entityManager->getRepository(User::class);
|
||||||
|
$user = $userRepository->findOneBy(['name' => $username]);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$this->markTestSkipped('User ' . $username . ' not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$client->loginUser($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
tests/Entity/BulkImportJobStatusTest.php
Normal file
71
tests/Entity/BulkImportJobStatusTest.php
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Entity;
|
||||||
|
|
||||||
|
use App\Entity\BulkImportJobStatus;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class BulkImportJobStatusTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testEnumValues(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals('pending', BulkImportJobStatus::PENDING->value);
|
||||||
|
$this->assertEquals('in_progress', BulkImportJobStatus::IN_PROGRESS->value);
|
||||||
|
$this->assertEquals('completed', BulkImportJobStatus::COMPLETED->value);
|
||||||
|
$this->assertEquals('stopped', BulkImportJobStatus::STOPPED->value);
|
||||||
|
$this->assertEquals('failed', BulkImportJobStatus::FAILED->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEnumCases(): void
|
||||||
|
{
|
||||||
|
$cases = BulkImportJobStatus::cases();
|
||||||
|
|
||||||
|
$this->assertCount(5, $cases);
|
||||||
|
$this->assertContains(BulkImportJobStatus::PENDING, $cases);
|
||||||
|
$this->assertContains(BulkImportJobStatus::IN_PROGRESS, $cases);
|
||||||
|
$this->assertContains(BulkImportJobStatus::COMPLETED, $cases);
|
||||||
|
$this->assertContains(BulkImportJobStatus::STOPPED, $cases);
|
||||||
|
$this->assertContains(BulkImportJobStatus::FAILED, $cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFromString(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(BulkImportJobStatus::PENDING, BulkImportJobStatus::from('pending'));
|
||||||
|
$this->assertEquals(BulkImportJobStatus::IN_PROGRESS, BulkImportJobStatus::from('in_progress'));
|
||||||
|
$this->assertEquals(BulkImportJobStatus::COMPLETED, BulkImportJobStatus::from('completed'));
|
||||||
|
$this->assertEquals(BulkImportJobStatus::STOPPED, BulkImportJobStatus::from('stopped'));
|
||||||
|
$this->assertEquals(BulkImportJobStatus::FAILED, BulkImportJobStatus::from('failed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTryFromInvalidValue(): void
|
||||||
|
{
|
||||||
|
$this->assertNull(BulkImportJobStatus::tryFrom('invalid'));
|
||||||
|
$this->assertNull(BulkImportJobStatus::tryFrom(''));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFromInvalidValueThrowsException(): void
|
||||||
|
{
|
||||||
|
$this->expectException(\ValueError::class);
|
||||||
|
BulkImportJobStatus::from('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
272
tests/Entity/BulkInfoProviderImportJobTest.php
Normal file
272
tests/Entity/BulkInfoProviderImportJobTest.php
Normal file
|
|
@ -0,0 +1,272 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Entity;
|
||||||
|
|
||||||
|
use App\Entity\BulkInfoProviderImportJob;
|
||||||
|
use App\Entity\BulkImportJobStatus;
|
||||||
|
use App\Entity\UserSystem\User;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class BulkInfoProviderImportJobTest extends TestCase
|
||||||
|
{
|
||||||
|
private BulkInfoProviderImportJob $job;
|
||||||
|
private User $user;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->user = new User();
|
||||||
|
$this->user->setName('test_user');
|
||||||
|
|
||||||
|
$this->job = new BulkInfoProviderImportJob();
|
||||||
|
$this->job->setCreatedBy($this->user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConstruct(): void
|
||||||
|
{
|
||||||
|
$job = new BulkInfoProviderImportJob();
|
||||||
|
|
||||||
|
$this->assertInstanceOf(\DateTimeImmutable::class, $job->getCreatedAt());
|
||||||
|
$this->assertEquals(BulkImportJobStatus::PENDING, $job->getStatus());
|
||||||
|
$this->assertEmpty($job->getPartIds());
|
||||||
|
$this->assertEmpty($job->getFieldMappings());
|
||||||
|
$this->assertEmpty($job->getSearchResults());
|
||||||
|
$this->assertEmpty($job->getProgress());
|
||||||
|
$this->assertNull($job->getCompletedAt());
|
||||||
|
$this->assertFalse($job->isPrefetchDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBasicGettersSetters(): void
|
||||||
|
{
|
||||||
|
$this->job->setName('Test Job');
|
||||||
|
$this->assertEquals('Test Job', $this->job->getName());
|
||||||
|
|
||||||
|
$partIds = [1, 2, 3];
|
||||||
|
$this->job->setPartIds($partIds);
|
||||||
|
$this->assertEquals($partIds, $this->job->getPartIds());
|
||||||
|
|
||||||
|
$fieldMappings = ['field1' => 'provider1', 'field2' => 'provider2'];
|
||||||
|
$this->job->setFieldMappings($fieldMappings);
|
||||||
|
$this->assertEquals($fieldMappings, $this->job->getFieldMappings());
|
||||||
|
|
||||||
|
$searchResults = [
|
||||||
|
1 => ['search_results' => [['name' => 'Part 1']]],
|
||||||
|
2 => ['search_results' => [['name' => 'Part 2'], ['name' => 'Part 2 Alt']]]
|
||||||
|
];
|
||||||
|
$this->job->setSearchResults($searchResults);
|
||||||
|
$this->assertEquals($searchResults, $this->job->getSearchResults());
|
||||||
|
|
||||||
|
$this->job->setPrefetchDetails(true);
|
||||||
|
$this->assertTrue($this->job->isPrefetchDetails());
|
||||||
|
|
||||||
|
$this->assertEquals($this->user, $this->job->getCreatedBy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStatusTransitions(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue($this->job->isPending());
|
||||||
|
$this->assertFalse($this->job->isInProgress());
|
||||||
|
$this->assertFalse($this->job->isCompleted());
|
||||||
|
$this->assertFalse($this->job->isFailed());
|
||||||
|
$this->assertFalse($this->job->isStopped());
|
||||||
|
|
||||||
|
$this->job->markAsInProgress();
|
||||||
|
$this->assertEquals(BulkImportJobStatus::IN_PROGRESS, $this->job->getStatus());
|
||||||
|
$this->assertTrue($this->job->isInProgress());
|
||||||
|
$this->assertFalse($this->job->isPending());
|
||||||
|
|
||||||
|
$this->job->markAsCompleted();
|
||||||
|
$this->assertEquals(BulkImportJobStatus::COMPLETED, $this->job->getStatus());
|
||||||
|
$this->assertTrue($this->job->isCompleted());
|
||||||
|
$this->assertNotNull($this->job->getCompletedAt());
|
||||||
|
|
||||||
|
$job2 = new BulkInfoProviderImportJob();
|
||||||
|
$job2->markAsFailed();
|
||||||
|
$this->assertEquals(BulkImportJobStatus::FAILED, $job2->getStatus());
|
||||||
|
$this->assertTrue($job2->isFailed());
|
||||||
|
$this->assertNotNull($job2->getCompletedAt());
|
||||||
|
|
||||||
|
$job3 = new BulkInfoProviderImportJob();
|
||||||
|
$job3->markAsStopped();
|
||||||
|
$this->assertEquals(BulkImportJobStatus::STOPPED, $job3->getStatus());
|
||||||
|
$this->assertTrue($job3->isStopped());
|
||||||
|
$this->assertNotNull($job3->getCompletedAt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCanBeStopped(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue($this->job->canBeStopped());
|
||||||
|
|
||||||
|
$this->job->markAsInProgress();
|
||||||
|
$this->assertTrue($this->job->canBeStopped());
|
||||||
|
|
||||||
|
$this->job->markAsCompleted();
|
||||||
|
$this->assertFalse($this->job->canBeStopped());
|
||||||
|
|
||||||
|
$this->job->setStatus(BulkImportJobStatus::FAILED);
|
||||||
|
$this->assertFalse($this->job->canBeStopped());
|
||||||
|
|
||||||
|
$this->job->setStatus(BulkImportJobStatus::STOPPED);
|
||||||
|
$this->assertFalse($this->job->canBeStopped());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPartCount(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(0, $this->job->getPartCount());
|
||||||
|
|
||||||
|
$this->job->setPartIds([1, 2, 3, 4, 5]);
|
||||||
|
$this->assertEquals(5, $this->job->getPartCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testResultCount(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(0, $this->job->getResultCount());
|
||||||
|
|
||||||
|
$searchResults = [
|
||||||
|
1 => ['search_results' => [['name' => 'Part 1']]],
|
||||||
|
2 => ['search_results' => [['name' => 'Part 2'], ['name' => 'Part 2 Alt']]],
|
||||||
|
3 => ['search_results' => []]
|
||||||
|
];
|
||||||
|
$this->job->setSearchResults($searchResults);
|
||||||
|
$this->assertEquals(3, $this->job->getResultCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPartProgressTracking(): void
|
||||||
|
{
|
||||||
|
$this->job->setPartIds([1, 2, 3, 4]);
|
||||||
|
|
||||||
|
$this->assertFalse($this->job->isPartCompleted(1));
|
||||||
|
$this->assertFalse($this->job->isPartSkipped(1));
|
||||||
|
|
||||||
|
$this->job->markPartAsCompleted(1);
|
||||||
|
$this->assertTrue($this->job->isPartCompleted(1));
|
||||||
|
$this->assertFalse($this->job->isPartSkipped(1));
|
||||||
|
|
||||||
|
$this->job->markPartAsSkipped(2, 'Not found');
|
||||||
|
$this->assertFalse($this->job->isPartCompleted(2));
|
||||||
|
$this->assertTrue($this->job->isPartSkipped(2));
|
||||||
|
|
||||||
|
$this->job->markPartAsPending(1);
|
||||||
|
$this->assertFalse($this->job->isPartCompleted(1));
|
||||||
|
$this->assertFalse($this->job->isPartSkipped(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProgressCounts(): void
|
||||||
|
{
|
||||||
|
$this->job->setPartIds([1, 2, 3, 4, 5]);
|
||||||
|
|
||||||
|
$this->assertEquals(0, $this->job->getCompletedPartsCount());
|
||||||
|
$this->assertEquals(0, $this->job->getSkippedPartsCount());
|
||||||
|
|
||||||
|
$this->job->markPartAsCompleted(1);
|
||||||
|
$this->job->markPartAsCompleted(2);
|
||||||
|
$this->job->markPartAsSkipped(3, 'Error');
|
||||||
|
|
||||||
|
$this->assertEquals(2, $this->job->getCompletedPartsCount());
|
||||||
|
$this->assertEquals(1, $this->job->getSkippedPartsCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProgressPercentage(): void
|
||||||
|
{
|
||||||
|
$emptyJob = new BulkInfoProviderImportJob();
|
||||||
|
$this->assertEquals(100.0, $emptyJob->getProgressPercentage());
|
||||||
|
|
||||||
|
$this->job->setPartIds([1, 2, 3, 4, 5]);
|
||||||
|
$this->assertEquals(0.0, $this->job->getProgressPercentage());
|
||||||
|
|
||||||
|
$this->job->markPartAsCompleted(1);
|
||||||
|
$this->job->markPartAsCompleted(2);
|
||||||
|
$this->assertEquals(40.0, $this->job->getProgressPercentage());
|
||||||
|
|
||||||
|
$this->job->markPartAsSkipped(3, 'Error');
|
||||||
|
$this->assertEquals(60.0, $this->job->getProgressPercentage());
|
||||||
|
|
||||||
|
$this->job->markPartAsCompleted(4);
|
||||||
|
$this->job->markPartAsCompleted(5);
|
||||||
|
$this->assertEquals(100.0, $this->job->getProgressPercentage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsAllPartsCompleted(): void
|
||||||
|
{
|
||||||
|
$emptyJob = new BulkInfoProviderImportJob();
|
||||||
|
$this->assertTrue($emptyJob->isAllPartsCompleted());
|
||||||
|
|
||||||
|
$this->job->setPartIds([1, 2, 3]);
|
||||||
|
$this->assertFalse($this->job->isAllPartsCompleted());
|
||||||
|
|
||||||
|
$this->job->markPartAsCompleted(1);
|
||||||
|
$this->assertFalse($this->job->isAllPartsCompleted());
|
||||||
|
|
||||||
|
$this->job->markPartAsCompleted(2);
|
||||||
|
$this->job->markPartAsSkipped(3, 'Error');
|
||||||
|
$this->assertTrue($this->job->isAllPartsCompleted());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisplayNameMethods(): void
|
||||||
|
{
|
||||||
|
$this->job->setPartIds([1, 2, 3]);
|
||||||
|
|
||||||
|
$this->assertEquals('info_providers.bulk_import.job_name_template', $this->job->getDisplayNameKey());
|
||||||
|
$this->assertEquals(['%count%' => 3], $this->job->getDisplayNameParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormattedTimestamp(): void
|
||||||
|
{
|
||||||
|
$timestampRegex = '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/';
|
||||||
|
$this->assertMatchesRegularExpression($timestampRegex, $this->job->getFormattedTimestamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProgressDataStructure(): void
|
||||||
|
{
|
||||||
|
$this->job->markPartAsCompleted(1);
|
||||||
|
$this->job->markPartAsSkipped(2, 'Test reason');
|
||||||
|
|
||||||
|
$progress = $this->job->getProgress();
|
||||||
|
|
||||||
|
$this->assertArrayHasKey(1, $progress);
|
||||||
|
$this->assertEquals('completed', $progress[1]['status']);
|
||||||
|
$this->assertArrayHasKey('completed_at', $progress[1]);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey(2, $progress);
|
||||||
|
$this->assertEquals('skipped', $progress[2]['status']);
|
||||||
|
$this->assertEquals('Test reason', $progress[2]['reason']);
|
||||||
|
$this->assertArrayHasKey('completed_at', $progress[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCompletedAtTimestamp(): void
|
||||||
|
{
|
||||||
|
$this->assertNull($this->job->getCompletedAt());
|
||||||
|
|
||||||
|
$beforeCompletion = new \DateTimeImmutable();
|
||||||
|
$this->job->markAsCompleted();
|
||||||
|
$afterCompletion = new \DateTimeImmutable();
|
||||||
|
|
||||||
|
$completedAt = $this->job->getCompletedAt();
|
||||||
|
$this->assertNotNull($completedAt);
|
||||||
|
$this->assertGreaterThanOrEqual($beforeCompletion, $completedAt);
|
||||||
|
$this->assertLessThanOrEqual($afterCompletion, $completedAt);
|
||||||
|
|
||||||
|
$customTime = new \DateTimeImmutable('2023-01-01 12:00:00');
|
||||||
|
$this->job->setCompletedAt($customTime);
|
||||||
|
$this->assertEquals($customTime, $this->job->getCompletedAt());
|
||||||
|
}
|
||||||
|
}
|
||||||
68
tests/Form/InfoProviderSystem/GlobalFieldMappingTypeTest.php
Normal file
68
tests/Form/InfoProviderSystem/GlobalFieldMappingTypeTest.php
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Form\InfoProviderSystem;
|
||||||
|
|
||||||
|
use App\Form\InfoProviderSystem\GlobalFieldMappingType;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Form\FormFactoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group slow
|
||||||
|
* @group DB
|
||||||
|
*/
|
||||||
|
class GlobalFieldMappingTypeTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
private FormFactoryInterface $formFactory;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$this->formFactory = static::getContainer()->get(FormFactoryInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormCreation(): void
|
||||||
|
{
|
||||||
|
$form = $this->formFactory->create(GlobalFieldMappingType::class, null, [
|
||||||
|
'field_choices' => [
|
||||||
|
'MPN' => 'mpn',
|
||||||
|
'Name' => 'name'
|
||||||
|
],
|
||||||
|
'csrf_protection' => false
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertTrue($form->has('field_mappings'));
|
||||||
|
$this->assertTrue($form->has('prefetch_details'));
|
||||||
|
$this->assertTrue($form->has('submit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormOptions(): void
|
||||||
|
{
|
||||||
|
$form = $this->formFactory->create(GlobalFieldMappingType::class, null, [
|
||||||
|
'field_choices' => [],
|
||||||
|
'csrf_protection' => false
|
||||||
|
]);
|
||||||
|
|
||||||
|
$view = $form->createView();
|
||||||
|
$this->assertFalse($view['prefetch_details']->vars['required']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@ namespace App\Tests\Services;
|
||||||
use App\Entity\Attachments\PartAttachment;
|
use App\Entity\Attachments\PartAttachment;
|
||||||
use App\Entity\Base\AbstractDBElement;
|
use App\Entity\Base\AbstractDBElement;
|
||||||
use App\Entity\Base\AbstractNamedDBElement;
|
use App\Entity\Base\AbstractNamedDBElement;
|
||||||
|
use App\Entity\BulkInfoProviderImportJob;
|
||||||
use App\Entity\Parts\Category;
|
use App\Entity\Parts\Category;
|
||||||
use App\Entity\Parts\Part;
|
use App\Entity\Parts\Part;
|
||||||
use App\Exceptions\EntityNotSupportedException;
|
use App\Exceptions\EntityNotSupportedException;
|
||||||
|
|
@ -50,12 +51,14 @@ class ElementTypeNameGeneratorTest extends WebTestCase
|
||||||
//We only test in english
|
//We only test in english
|
||||||
$this->assertSame('Part', $this->service->getLocalizedTypeLabel(new Part()));
|
$this->assertSame('Part', $this->service->getLocalizedTypeLabel(new Part()));
|
||||||
$this->assertSame('Category', $this->service->getLocalizedTypeLabel(new Category()));
|
$this->assertSame('Category', $this->service->getLocalizedTypeLabel(new Category()));
|
||||||
|
$this->assertSame('bulk_info_provider_import_job.label', $this->service->getLocalizedTypeLabel(new BulkInfoProviderImportJob()));
|
||||||
|
|
||||||
//Test inheritance
|
//Test inheritance
|
||||||
$this->assertSame('Attachment', $this->service->getLocalizedTypeLabel(new PartAttachment()));
|
$this->assertSame('Attachment', $this->service->getLocalizedTypeLabel(new PartAttachment()));
|
||||||
|
|
||||||
//Test for class name
|
//Test for class name
|
||||||
$this->assertSame('Part', $this->service->getLocalizedTypeLabel(Part::class));
|
$this->assertSame('Part', $this->service->getLocalizedTypeLabel(Part::class));
|
||||||
|
$this->assertSame('bulk_info_provider_import_job.label', $this->service->getLocalizedTypeLabel(BulkInfoProviderImportJob::class));
|
||||||
|
|
||||||
//Test exception for unknpwn type
|
//Test exception for unknpwn type
|
||||||
$this->expectException(EntityNotSupportedException::class);
|
$this->expectException(EntityNotSupportedException::class);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue