'docs', 'token_hash' => hash('sha256', 'x')]); $user = User::create(['login' => 'n', 'tz' => 'UTC', 'quiet_start' => '22:00:00', 'quiet_end' => '09:00:00']); $channel = Channel::create(['user_id' => $user->id, 'type' => ChannelType::Webhook, 'config' => ['deliver_url' => 'u', 'presence_url' => 'p'], 'enabled' => true]); $event = Event::create([ 'source_id' => $source->id, 'user_id' => $user->id, 'source_ref' => 'r', 'topic' => '', 'due_mode' => DueMode::Local, 'due_date' => '2026-09-30', 'due_time' => '24:00:00', 'fire_on' => '2026-08-31', 'after_due' => AfterDue::Keep, 'payload' => ['title' => 'T'], 'state' => EventState::Preparing, 'quiet_until' => CarbonImmutable::parse('2000-01-01Z'), ]); $this->delivery = Delivery::create([ 'event_id' => $event->id, 'channel_id' => $channel->id, 'window_start' => CarbonImmutable::parse('2026-09-05T09:00:00Z'), 'action_token' => 'tok', 'result' => DeliveryResult::Pending, ]); $this->driver = new FakeChannel; $this->app->instance(ChannelRegistry::class, new FakeRegistry(['webhook' => $this->driver])); } public function test_success_marks_ok_with_meta(): void { (new DeliverJob($this->delivery->id))->handle(app(ChannelRegistry::class)); $d = $this->delivery->fresh(); $this->assertSame(DeliveryResult::Ok, $d->result); $this->assertNotNull($d->sent_at); $this->assertSame(['n' => 1], $d->meta); } public function test_failure_records_error_and_throws_for_retry(): void { $this->driver->succeed = false; $this->expectException(DeliveryFailed::class); try { (new DeliverJob($this->delivery->id))->handle(app(ChannelRegistry::class)); } finally { $d = $this->delivery->fresh(); $this->assertSame(DeliveryResult::Pending, $d->result, 'ещё pending — будут ретраи'); $this->assertSame('boom', $d->error); } } public function test_failed_hook_marks_failed(): void { (new DeliverJob($this->delivery->id))->failed(new DeliveryFailed('boom')); $this->assertSame(DeliveryResult::Failed, $this->delivery->fresh()->result); } public function test_skips_when_already_done_or_event_terminal(): void { $this->delivery->update(['result' => DeliveryResult::Ok]); (new DeliverJob($this->delivery->id))->handle(app(ChannelRegistry::class)); $this->assertSame([], $this->driver->delivered); $this->delivery->update(['result' => DeliveryResult::Pending]); $this->delivery->event->update(['state' => EventState::Done]); (new DeliverJob($this->delivery->id))->handle(app(ChannelRegistry::class)); $this->assertSame([], $this->driver->delivered); $this->assertSame(DeliveryResult::Failed, $this->delivery->fresh()->result); } }