606 lines
19 KiB
PHP
606 lines
19 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Feature;
|
||
|
|
|
||
|
|
use App\Models\BomConditionRule;
|
||
|
|
use App\Models\Model;
|
||
|
|
use App\Models\ModelFormula;
|
||
|
|
use App\Models\ModelParameter;
|
||
|
|
use App\Models\User;
|
||
|
|
use Database\Seeders\ParameterBasedBomTestSeeder;
|
||
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
|
use Laravel\Sanctum\Sanctum;
|
||
|
|
use Tests\TestCase;
|
||
|
|
|
||
|
|
class ParameterBasedBomApiTest extends TestCase
|
||
|
|
{
|
||
|
|
use RefreshDatabase;
|
||
|
|
|
||
|
|
private User $user;
|
||
|
|
private Model $kss01Model;
|
||
|
|
|
||
|
|
protected function setUp(): void
|
||
|
|
{
|
||
|
|
parent::setUp();
|
||
|
|
|
||
|
|
// Set up test environment
|
||
|
|
$this->artisan('migrate');
|
||
|
|
$this->seed(ParameterBasedBomTestSeeder::class);
|
||
|
|
|
||
|
|
// Create test user and authenticate
|
||
|
|
$this->user = User::factory()->create(['tenant_id' => 1]);
|
||
|
|
Sanctum::actingAs($this->user);
|
||
|
|
|
||
|
|
// Set required headers
|
||
|
|
$this->withHeaders([
|
||
|
|
'X-API-KEY' => config('app.api_key', 'test-api-key'),
|
||
|
|
'Accept' => 'application/json',
|
||
|
|
'Content-Type' => 'application/json',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->kss01Model = Model::where('code', 'KSS01')->first();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_get_model_parameters()
|
||
|
|
{
|
||
|
|
// Act
|
||
|
|
$response = $this->getJson("/api/v1/design/models/{$this->kss01Model->id}/parameters");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk()
|
||
|
|
->assertJsonStructure([
|
||
|
|
'success',
|
||
|
|
'message',
|
||
|
|
'data' => [
|
||
|
|
'*' => [
|
||
|
|
'id',
|
||
|
|
'name',
|
||
|
|
'label',
|
||
|
|
'type',
|
||
|
|
'default_value',
|
||
|
|
'validation_rules',
|
||
|
|
'options',
|
||
|
|
'sort_order',
|
||
|
|
'is_required',
|
||
|
|
'is_active',
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
$parameters = $response->json('data');
|
||
|
|
$this->assertCount(5, $parameters); // W0, H0, screen_type, install_type, power_source
|
||
|
|
|
||
|
|
// Check parameter order
|
||
|
|
$this->assertEquals('W0', $parameters[0]['name']);
|
||
|
|
$this->assertEquals('H0', $parameters[1]['name']);
|
||
|
|
$this->assertEquals('screen_type', $parameters[2]['name']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_get_model_formulas()
|
||
|
|
{
|
||
|
|
// Act
|
||
|
|
$response = $this->getJson("/api/v1/design/models/{$this->kss01Model->id}/formulas");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk()
|
||
|
|
->assertJsonStructure([
|
||
|
|
'success',
|
||
|
|
'message',
|
||
|
|
'data' => [
|
||
|
|
'*' => [
|
||
|
|
'id',
|
||
|
|
'name',
|
||
|
|
'expression',
|
||
|
|
'description',
|
||
|
|
'return_type',
|
||
|
|
'sort_order',
|
||
|
|
'is_active',
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
$formulas = $response->json('data');
|
||
|
|
$this->assertGreaterThanOrEqual(7, count($formulas)); // W1, H1, area, weight, motor, bracket, guide
|
||
|
|
|
||
|
|
// Check formula order
|
||
|
|
$this->assertEquals('W1', $formulas[0]['name']);
|
||
|
|
$this->assertEquals('H1', $formulas[1]['name']);
|
||
|
|
$this->assertEquals('area', $formulas[2]['name']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_get_model_condition_rules()
|
||
|
|
{
|
||
|
|
// Act
|
||
|
|
$response = $this->getJson("/api/v1/design/models/{$this->kss01Model->id}/rules");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk()
|
||
|
|
->assertJsonStructure([
|
||
|
|
'success',
|
||
|
|
'message',
|
||
|
|
'data' => [
|
||
|
|
'*' => [
|
||
|
|
'id',
|
||
|
|
'name',
|
||
|
|
'description',
|
||
|
|
'condition_expression',
|
||
|
|
'component_code',
|
||
|
|
'quantity_expression',
|
||
|
|
'priority',
|
||
|
|
'is_active',
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
$rules = $response->json('data');
|
||
|
|
$this->assertGreaterThanOrEqual(7, count($rules)); // Various case, bottom, shaft, pipe rules
|
||
|
|
|
||
|
|
// Check rules are ordered by priority
|
||
|
|
$priorities = collect($rules)->pluck('priority');
|
||
|
|
$this->assertEquals($priorities->sort()->values(), $priorities->values());
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_resolve_bom_for_small_screen()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
$inputParams = [
|
||
|
|
'W0' => 1000,
|
||
|
|
'H0' => 800,
|
||
|
|
'screen_type' => 'SCREEN',
|
||
|
|
'install_type' => 'WALL',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/bom/resolve", [
|
||
|
|
'parameters' => $inputParams
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk()
|
||
|
|
->assertJsonStructure([
|
||
|
|
'success',
|
||
|
|
'message',
|
||
|
|
'data' => [
|
||
|
|
'model_id',
|
||
|
|
'input_parameters',
|
||
|
|
'calculated_formulas' => [
|
||
|
|
'W1',
|
||
|
|
'H1',
|
||
|
|
'area',
|
||
|
|
'weight',
|
||
|
|
'motor',
|
||
|
|
'bracket',
|
||
|
|
'guide',
|
||
|
|
],
|
||
|
|
'bom_items' => [
|
||
|
|
'*' => [
|
||
|
|
'component_code',
|
||
|
|
'quantity',
|
||
|
|
'rule_name',
|
||
|
|
'condition_expression',
|
||
|
|
]
|
||
|
|
],
|
||
|
|
'summary' => [
|
||
|
|
'total_components',
|
||
|
|
'total_weight',
|
||
|
|
'component_categories',
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
$data = $response->json('data');
|
||
|
|
|
||
|
|
// Check calculated formulas
|
||
|
|
$formulas = $data['calculated_formulas'];
|
||
|
|
$this->assertEquals(1120, $formulas['W1']); // 1000 + 120
|
||
|
|
$this->assertEquals(900, $formulas['H1']); // 800 + 100
|
||
|
|
$this->assertEquals(1.008, $formulas['area']); // 1120 * 900 / 1000000
|
||
|
|
$this->assertEquals('0.5HP', $formulas['motor']); // area <= 3
|
||
|
|
|
||
|
|
// Check BOM items
|
||
|
|
$bomItems = $data['bom_items'];
|
||
|
|
$this->assertGreaterThan(0, count($bomItems));
|
||
|
|
|
||
|
|
// Check specific components
|
||
|
|
$caseItem = collect($bomItems)->first(fn($item) => str_contains($item['component_code'], 'CASE'));
|
||
|
|
$this->assertEquals('CASE-SMALL', $caseItem['component_code']);
|
||
|
|
|
||
|
|
$screenPipe = collect($bomItems)->first(fn($item) => $item['component_code'] === 'PIPE-SCREEN');
|
||
|
|
$this->assertNotNull($screenPipe);
|
||
|
|
|
||
|
|
$slatPipe = collect($bomItems)->first(fn($item) => $item['component_code'] === 'PIPE-SLAT');
|
||
|
|
$this->assertNull($slatPipe);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_resolve_bom_for_large_screen()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
$inputParams = [
|
||
|
|
'W0' => 2500,
|
||
|
|
'H0' => 1500,
|
||
|
|
'screen_type' => 'SCREEN',
|
||
|
|
'install_type' => 'SIDE',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/bom/resolve", [
|
||
|
|
'parameters' => $inputParams
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk();
|
||
|
|
|
||
|
|
$data = $response->json('data');
|
||
|
|
$formulas = $data['calculated_formulas'];
|
||
|
|
|
||
|
|
// Check large screen calculations
|
||
|
|
$this->assertEquals(2620, $formulas['W1']); // 2500 + 120
|
||
|
|
$this->assertEquals(1600, $formulas['H1']); // 1500 + 100
|
||
|
|
$this->assertEquals(4.192, $formulas['area']); // 2620 * 1600 / 1000000
|
||
|
|
$this->assertEquals('1HP', $formulas['motor']); // 3 < area <= 6
|
||
|
|
|
||
|
|
// Check medium case is selected
|
||
|
|
$bomItems = $data['bom_items'];
|
||
|
|
$caseItem = collect($bomItems)->first(fn($item) => str_contains($item['component_code'], 'CASE'));
|
||
|
|
$this->assertEquals('CASE-MEDIUM', $caseItem['component_code']);
|
||
|
|
|
||
|
|
// Check bracket quantity
|
||
|
|
$bottomItem = collect($bomItems)->first(fn($item) => $item['component_code'] === 'BOTTOM-001');
|
||
|
|
$this->assertEquals(3, $bottomItem['quantity']); // CEIL(2620 / 1000)
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_resolve_bom_for_slat_type()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
$inputParams = [
|
||
|
|
'W0' => 1500,
|
||
|
|
'H0' => 1000,
|
||
|
|
'screen_type' => 'SLAT',
|
||
|
|
'install_type' => 'WALL',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/bom/resolve", [
|
||
|
|
'parameters' => $inputParams
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk();
|
||
|
|
|
||
|
|
$bomItems = $response->json('data.bom_items');
|
||
|
|
|
||
|
|
// Check that SLAT pipe is used
|
||
|
|
$screenPipe = collect($bomItems)->first(fn($item) => $item['component_code'] === 'PIPE-SCREEN');
|
||
|
|
$slatPipe = collect($bomItems)->first(fn($item) => $item['component_code'] === 'PIPE-SLAT');
|
||
|
|
|
||
|
|
$this->assertNull($screenPipe);
|
||
|
|
$this->assertNotNull($slatPipe);
|
||
|
|
$this->assertEquals('PIPE-SLAT', $slatPipe['component_code']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_validates_missing_required_parameters()
|
||
|
|
{
|
||
|
|
// Arrange - Missing H0 parameter
|
||
|
|
$incompleteParams = [
|
||
|
|
'W0' => 1000,
|
||
|
|
'screen_type' => 'SCREEN',
|
||
|
|
'install_type' => 'WALL',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/bom/resolve", [
|
||
|
|
'parameters' => $incompleteParams
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertStatus(422)
|
||
|
|
->assertJsonValidationErrors(['parameters.H0']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_validates_parameter_ranges()
|
||
|
|
{
|
||
|
|
// Arrange - W0 below minimum
|
||
|
|
$invalidParams = [
|
||
|
|
'W0' => 100, // Below minimum (500)
|
||
|
|
'H0' => 800,
|
||
|
|
'screen_type' => 'SCREEN',
|
||
|
|
'install_type' => 'WALL',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/bom/resolve", [
|
||
|
|
'parameters' => $invalidParams
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertStatus(422)
|
||
|
|
->assertJsonValidationErrors(['parameters.W0']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_validates_select_parameter_options()
|
||
|
|
{
|
||
|
|
// Arrange - Invalid screen_type
|
||
|
|
$invalidParams = [
|
||
|
|
'W0' => 1000,
|
||
|
|
'H0' => 800,
|
||
|
|
'screen_type' => 'INVALID_TYPE',
|
||
|
|
'install_type' => 'WALL',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/bom/resolve", [
|
||
|
|
'parameters' => $invalidParams
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertStatus(422)
|
||
|
|
->assertJsonValidationErrors(['parameters.screen_type']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_create_product_from_model()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
$inputParams = [
|
||
|
|
'W0' => 1200,
|
||
|
|
'H0' => 900,
|
||
|
|
'screen_type' => 'SCREEN',
|
||
|
|
'install_type' => 'WALL',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
$productData = [
|
||
|
|
'code' => 'KSS01-TEST-001',
|
||
|
|
'name' => '테스트 스크린 블라인드 1200x900',
|
||
|
|
'description' => 'API 테스트로 생성된 제품',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/products", [
|
||
|
|
'parameters' => $inputParams,
|
||
|
|
'product' => $productData,
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertCreated()
|
||
|
|
->assertJsonStructure([
|
||
|
|
'success',
|
||
|
|
'message',
|
||
|
|
'data' => [
|
||
|
|
'product' => [
|
||
|
|
'id',
|
||
|
|
'code',
|
||
|
|
'name',
|
||
|
|
'description',
|
||
|
|
'product_type',
|
||
|
|
'model_id',
|
||
|
|
'parameter_values',
|
||
|
|
],
|
||
|
|
'bom_items' => [
|
||
|
|
'*' => [
|
||
|
|
'id',
|
||
|
|
'product_id',
|
||
|
|
'component_code',
|
||
|
|
'component_type',
|
||
|
|
'quantity',
|
||
|
|
'unit',
|
||
|
|
]
|
||
|
|
],
|
||
|
|
'summary' => [
|
||
|
|
'total_components',
|
||
|
|
'calculated_formulas',
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
$data = $response->json('data');
|
||
|
|
$product = $data['product'];
|
||
|
|
|
||
|
|
// Check product data
|
||
|
|
$this->assertEquals('KSS01-TEST-001', $product['code']);
|
||
|
|
$this->assertEquals('테스트 스크린 블라인드 1200x900', $product['name']);
|
||
|
|
$this->assertEquals($this->kss01Model->id, $product['model_id']);
|
||
|
|
|
||
|
|
// Check parameter values are stored
|
||
|
|
$parameterValues = json_decode($product['parameter_values'], true);
|
||
|
|
$this->assertEquals(1200, $parameterValues['W0']);
|
||
|
|
$this->assertEquals(900, $parameterValues['H0']);
|
||
|
|
|
||
|
|
// Check BOM items
|
||
|
|
$bomItems = $data['bom_items'];
|
||
|
|
$this->assertGreaterThan(0, count($bomItems));
|
||
|
|
|
||
|
|
foreach ($bomItems as $item) {
|
||
|
|
$this->assertEquals($product['id'], $item['product_id']);
|
||
|
|
$this->assertNotEmpty($item['component_code']);
|
||
|
|
$this->assertGreaterThan(0, $item['quantity']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_can_preview_product_without_creating()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
$inputParams = [
|
||
|
|
'W0' => 1800,
|
||
|
|
'H0' => 1200,
|
||
|
|
'screen_type' => 'SCREEN',
|
||
|
|
'install_type' => 'SIDE',
|
||
|
|
'power_source' => 'DC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/preview", [
|
||
|
|
'parameters' => $inputParams
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk()
|
||
|
|
->assertJsonStructure([
|
||
|
|
'success',
|
||
|
|
'message',
|
||
|
|
'data' => [
|
||
|
|
'suggested_product' => [
|
||
|
|
'code',
|
||
|
|
'name',
|
||
|
|
'description',
|
||
|
|
],
|
||
|
|
'calculated_values' => [
|
||
|
|
'W1',
|
||
|
|
'H1',
|
||
|
|
'area',
|
||
|
|
'weight',
|
||
|
|
'motor',
|
||
|
|
],
|
||
|
|
'bom_preview' => [
|
||
|
|
'total_components',
|
||
|
|
'components' => [
|
||
|
|
'*' => [
|
||
|
|
'component_code',
|
||
|
|
'quantity',
|
||
|
|
'description',
|
||
|
|
]
|
||
|
|
]
|
||
|
|
],
|
||
|
|
'cost_estimate' => [
|
||
|
|
'total_material_cost',
|
||
|
|
'estimated_labor_cost',
|
||
|
|
'total_estimated_cost',
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
$data = $response->json('data');
|
||
|
|
|
||
|
|
// Check suggested product info
|
||
|
|
$suggestedProduct = $data['suggested_product'];
|
||
|
|
$this->assertStringContains('KSS01', $suggestedProduct['code']);
|
||
|
|
$this->assertStringContains('1800x1200', $suggestedProduct['name']);
|
||
|
|
|
||
|
|
// Check calculated values
|
||
|
|
$calculatedValues = $data['calculated_values'];
|
||
|
|
$this->assertEquals(1920, $calculatedValues['W1']); // 1800 + 120
|
||
|
|
$this->assertEquals(1300, $calculatedValues['H1']); // 1200 + 100
|
||
|
|
|
||
|
|
// Check BOM preview
|
||
|
|
$bomPreview = $data['bom_preview'];
|
||
|
|
$this->assertGreaterThan(0, $bomPreview['total_components']);
|
||
|
|
$this->assertNotEmpty($bomPreview['components']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_handles_authentication_properly()
|
||
|
|
{
|
||
|
|
// Arrange - Remove authentication
|
||
|
|
Sanctum::actingAs(null);
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->getJson("/api/v1/design/models/{$this->kss01Model->id}/parameters");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertUnauthorized();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_handles_tenant_isolation()
|
||
|
|
{
|
||
|
|
// Arrange - Create user with different tenant
|
||
|
|
$otherTenantUser = User::factory()->create(['tenant_id' => 2]);
|
||
|
|
Sanctum::actingAs($otherTenantUser);
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$response = $this->getJson("/api/v1/design/models/{$this->kss01Model->id}/parameters");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertNotFound();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_handles_performance_for_large_datasets()
|
||
|
|
{
|
||
|
|
// Arrange - Use performance test model with many parameters/formulas/rules
|
||
|
|
$performanceModel = Model::where('code', 'PERF-TEST')->first();
|
||
|
|
|
||
|
|
if (!$performanceModel) {
|
||
|
|
$this->markTestSkipped('Performance test model not found. Run in testing environment.');
|
||
|
|
}
|
||
|
|
|
||
|
|
$inputParams = array_fill_keys(
|
||
|
|
ModelParameter::where('model_id', $performanceModel->id)->pluck('name')->toArray(),
|
||
|
|
100
|
||
|
|
);
|
||
|
|
|
||
|
|
// Act
|
||
|
|
$startTime = microtime(true);
|
||
|
|
$response = $this->postJson("/api/v1/design/models/{$performanceModel->id}/bom/resolve", [
|
||
|
|
'parameters' => $inputParams
|
||
|
|
]);
|
||
|
|
$executionTime = microtime(true) - $startTime;
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertOk();
|
||
|
|
$this->assertLessThan(2.0, $executionTime, 'BOM resolution should complete within 2 seconds');
|
||
|
|
|
||
|
|
$data = $response->json('data');
|
||
|
|
$this->assertArrayHasKey('calculated_formulas', $data);
|
||
|
|
$this->assertArrayHasKey('bom_items', $data);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_returns_appropriate_error_for_nonexistent_model()
|
||
|
|
{
|
||
|
|
// Act
|
||
|
|
$response = $this->getJson('/api/v1/design/models/999999/parameters');
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
$response->assertNotFound()
|
||
|
|
->assertJson([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'error.model_not_found',
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @test */
|
||
|
|
public function it_handles_concurrent_requests_safely()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
$inputParams = [
|
||
|
|
'W0' => 1000,
|
||
|
|
'H0' => 800,
|
||
|
|
'screen_type' => 'SCREEN',
|
||
|
|
'install_type' => 'WALL',
|
||
|
|
'power_source' => 'AC',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Act - Simulate concurrent requests
|
||
|
|
$promises = [];
|
||
|
|
for ($i = 0; $i < 5; $i++) {
|
||
|
|
$promises[] = $this->postJson("/api/v1/design/models/{$this->kss01Model->id}/bom/resolve", [
|
||
|
|
'parameters' => $inputParams
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assert - All should succeed with same results
|
||
|
|
foreach ($promises as $response) {
|
||
|
|
$response->assertOk();
|
||
|
|
$formulas = $response->json('data.calculated_formulas');
|
||
|
|
$this->assertEquals(1120, $formulas['W1']);
|
||
|
|
$this->assertEquals(900, $formulas['H1']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|