170 lines
5.3 KiB
PHP
170 lines
5.3 KiB
PHP
<?php
|
|
|
|
use App\Models\User;
|
|
use App\Models\Inquiry;
|
|
use App\Models\Tenant;
|
|
use App\Jobs\ProvisionTenantJob;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Stancl\Tenancy\Database\Models\Domain;
|
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
test('subdomain inquiry requires a unique desired_subdomain', function () {
|
|
Tenant::create([
|
|
'id' => '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');
|
|
}
|
|
});
|