'company-alpha', 'tenancy_db_name' => 'tenant_company-alpha', 'company_name' => 'Alpha Co', 'email' => 'alpha@company.com', ]); Domain::create([ 'domain' => 'company-alpha.localhost', 'tenant_id' => 'company-alpha', ]); $response = $this->postJson('/api/inquiries', [ 'company_name' => 'Alpha Copycat', 'contact_name' => 'John Doe', 'email' => 'john@copycat.com', 'phone' => '1234567890', 'desired_subdomain' => 'company-alpha', ]); $response->assertStatus(422) ->assertJsonValidationErrors(['desired_subdomain']); }); test('executive cannot approve inquiry with an already taken subdomain', function () { $executive = User::factory()->create(['type' => 'company admin']); Tenant::create([ 'id' => 'existing-tenant', 'tenancy_db_name' => 'tenant_existing-tenant', 'company_name' => 'Existing', 'email' => 'existing@tenant.com', ]); $inquiry = Inquiry::create([ 'company_name' => 'New Corp', 'contact_name' => 'Jane Doe', 'email' => 'jane@newcorp.com', 'desired_subdomain' => 'new-corp', 'status' => 'pending_payment_approval', ]); $response = $this->actingAs($executive, 'sanctum') ->postJson("/api/executive/inquiries/{$inquiry->id}/approve", [ 'desired_subdomain' => 'existing-tenant', ]); $response->assertStatus(422) ->assertJson(['success' => false]); }); test('provisioning tenant creates isolated database file', function () { $subdomain = 'beta-tech-' . strtolower(Str::random(4)); $inquiry = Inquiry::create([ 'company_name' => 'Beta Tech', 'contact_name' => 'Beta Admin', 'email' => 'admin@betatech.com', 'desired_subdomain' => $subdomain, 'status' => 'approved', ]); $job = new ProvisionTenantJob($inquiry); $job->handle(); $this->assertDatabaseHas('tenants', [ 'id' => $subdomain, ]); $dbFile = database_path('tenant_' . $subdomain); $this->assertTrue(file_exists($dbFile) || file_exists($dbFile . '.sqlite')); if (file_exists($dbFile)) { @unlink($dbFile); } if (file_exists($dbFile . '.sqlite')) { @unlink($dbFile . '.sqlite'); } }); test('user from Tenant A cannot log in on Tenant B subdomain', function () { $subA = 'ten-a-' . strtolower(Str::random(5)); $inquiryA = Inquiry::create([ 'company_name' => 'Company A', 'contact_name' => 'Admin A', 'email' => 'admin@tenanta.com', 'desired_subdomain' => $subA, 'status' => 'approved', ]); (new ProvisionTenantJob($inquiryA))->handle(); $subB = 'ten-b-' . strtolower(Str::random(5)); $inquiryB = Inquiry::create([ 'company_name' => 'Company B', 'contact_name' => 'Admin B', 'email' => 'admin@tenantb.com', 'desired_subdomain' => $subB, 'status' => 'approved', ]); (new ProvisionTenantJob($inquiryB))->handle(); $tenantB = Tenant::find($subB); // Attempting login on Tenant B with Tenant A credentials tenancy()->initialize($tenantB); $loginRequest = new \App\Http\Requests\Auth\LoginRequest(); $loginRequest->merge([ 'email' => 'admin@tenanta.com', 'password' => '12345678', ]); try { $loginRequest->authenticate(); $this->fail('Expected ValidationException was not thrown for cross-login attempt.'); } catch (\Illuminate\Validation\ValidationException $e) { $this->assertArrayHasKey('email', $e->errors()); } finally { tenancy()->end(); DB::purge('tenant'); } }); test('HTTP POST login request from Tenant A user fails on Tenant B subdomain', function () { $subA = 'ca-' . strtolower(Str::random(5)); $inquiryA = Inquiry::create([ 'company_name' => 'Company A', 'contact_name' => 'Admin A', 'email' => 'admin@compa.com', 'desired_subdomain' => $subA, 'status' => 'approved', ]); (new ProvisionTenantJob($inquiryA))->handle(); $subB = 'cb-' . strtolower(Str::random(5)); $inquiryB = Inquiry::create([ 'company_name' => 'Company B', 'contact_name' => 'Admin B', 'email' => 'admin@compb.com', 'desired_subdomain' => $subB, 'status' => 'approved', ]); (new ProvisionTenantJob($inquiryB))->handle(); try { // Attempt POST to login on Company B domain with Company A credentials $response = $this->withServerVariables(['HTTP_HOST' => "{$subB}.localhost"]) ->post("http://{$subB}.localhost/login", [ 'email' => 'admin@compa.com', 'password' => '12345678', ]); $this->assertGuest(); $this->assertNotSame('/dashboard', parse_url($response->headers->get('Location', ''), PHP_URL_PATH)); } finally { DB::purge('tenant'); } });