mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
123 lines
4.5 KiB
PHP
123 lines
4.5 KiB
PHP
<?php
|
|
|
|
use App\Models\Project;
|
|
use App\Models\Server;
|
|
use App\Models\Subscription;
|
|
use App\Models\Team;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
config()->set('constants.coolify.self_hosted', false);
|
|
});
|
|
|
|
function endedSubscription(Team $team, array $attributes = []): Subscription
|
|
{
|
|
return Subscription::factory()->create([
|
|
'team_id' => $team->id,
|
|
'updated_at' => now()->subMonths(7),
|
|
...$attributes,
|
|
]);
|
|
}
|
|
|
|
test('it refuses to run outside Coolify Cloud', function () {
|
|
config()->set('constants.coolify.self_hosted', true);
|
|
$team = Team::factory()->create();
|
|
endedSubscription($team);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams', ['--yes' => true])
|
|
->expectsOutput('This command can only be run on Coolify Cloud.')
|
|
->assertFailed();
|
|
|
|
$this->assertModelExists($team);
|
|
});
|
|
|
|
test('it rejects a months value that is not a positive integer', function (string $months) {
|
|
$team = Team::factory()->create();
|
|
endedSubscription($team);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams', ['--months' => $months, '--yes' => true])
|
|
->expectsOutput('The --months option must be a positive integer.')
|
|
->assertFailed();
|
|
|
|
$this->assertModelExists($team);
|
|
})->with(['0', '-1', 'abc']);
|
|
|
|
test('it previews eligible teams without deleting them', function () {
|
|
$team = Team::factory()->create(['name' => 'Acme Corp']);
|
|
endedSubscription($team);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams')
|
|
->expectsOutputToContain('Found 1 team')
|
|
->expectsOutputToContain('Acme Corp')
|
|
->expectsOutput('Dry run only. Use --yes to delete eligible teams.')
|
|
->assertSuccessful();
|
|
|
|
$this->assertModelExists($team);
|
|
});
|
|
|
|
test('it deletes an eligible team with its subscription, servers, projects, and orphaned owner', function () {
|
|
$owner = User::factory()->create();
|
|
$team = $owner->teams()->first();
|
|
$subscription = endedSubscription($team);
|
|
$server = Server::factory()->create(['team_id' => $team->id]);
|
|
$trashedServer = Server::factory()->create(['team_id' => $team->id]);
|
|
$trashedServer->delete();
|
|
$project = Project::factory()->create(['team_id' => $team->id]);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams', ['--yes' => true])
|
|
->expectsOutput('Deleted 1 team and 1 user.')
|
|
->assertSuccessful();
|
|
|
|
$this->assertModelMissing($team);
|
|
$this->assertModelMissing($subscription);
|
|
$this->assertModelMissing($project);
|
|
$this->assertModelMissing($owner);
|
|
expect(Server::withTrashed()->whereKey([$server->id, $trashedServer->id])->exists())->toBeFalse();
|
|
});
|
|
|
|
test('it keeps members with another team and detaches them from the deleted team', function () {
|
|
$team = Team::factory()->create();
|
|
endedSubscription($team);
|
|
$member = User::factory()->create();
|
|
$team->members()->attach($member, ['role' => 'member']);
|
|
$member->update(['current_team_id' => $team->id]);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams', ['--yes' => true])->assertSuccessful();
|
|
|
|
$this->assertModelMissing($team);
|
|
$member->refresh();
|
|
expect($member->current_team_id)->toBeNull()
|
|
->and($member->teams()->count())->toBe(1);
|
|
$this->assertDatabaseMissing('team_user', ['team_id' => $team->id]);
|
|
});
|
|
|
|
test('it keeps teams that are not eligible', function (array $attributes) {
|
|
$team = Team::factory()->create();
|
|
endedSubscription($team, $attributes);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams', ['--yes' => true])
|
|
->expectsOutput('Deleted 0 teams and 0 users.')
|
|
->assertSuccessful();
|
|
|
|
$this->assertModelExists($team);
|
|
})->with([
|
|
'paid subscription' => [['stripe_invoice_paid' => true, 'stripe_subscription_id' => 'sub_paid']],
|
|
'paused subscription that still exists in Stripe' => [['stripe_subscription_id' => 'sub_paused']],
|
|
'subscription ended within the cutoff' => [['updated_at' => now()->subMonths(3)]],
|
|
'subscription without a Stripe customer' => [['stripe_customer_id' => null]],
|
|
]);
|
|
|
|
test('it respects the months option', function () {
|
|
$team = Team::factory()->create();
|
|
endedSubscription($team, ['updated_at' => now()->subMonths(4)]);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams', ['--yes' => true])->assertSuccessful();
|
|
$this->assertModelExists($team);
|
|
|
|
$this->artisan('cloud:cleanup-unsubscribed-teams', ['--months' => 3, '--yes' => true])->assertSuccessful();
|
|
$this->assertModelMissing($team);
|
|
});
|