Delete {{$device->name}}?
diff --git a/routes/console.php b/routes/console.php
index e125176..8265a81 100644
--- a/routes/console.php
+++ b/routes/console.php
@@ -1,8 +1,11 @@
cron(
config('services.trmnl.proxy_refresh_cron') ? config('services.trmnl.proxy_refresh_cron') :
sprintf('*/%s * * * *', intval(config('services.trmnl.proxy_refresh_minutes', 15)))
);
+
+Schedule::job(FirmwarePollJob::class)->daily();
diff --git a/tests/Feature/Jobs/FirmwareDownloadJobTest.php b/tests/Feature/Jobs/FirmwareDownloadJobTest.php
new file mode 100644
index 0000000..30d9e29
--- /dev/null
+++ b/tests/Feature/Jobs/FirmwareDownloadJobTest.php
@@ -0,0 +1,38 @@
+makeDirectory('/firmwares');
+});
+
+test('it creates firmwares directory if it does not exist', function () {
+ $firmware = Firmware::factory()->create([
+ 'url' => 'https://example.com/firmware.bin',
+ 'version_tag' => '1.0.0',
+ ]);
+
+ (new FirmwareDownloadJob($firmware))->handle();
+
+ expect(Storage::disk('public')->exists('firmwares'))->toBeTrue();
+});
+
+test('it downloads firmware and updates storage location', function () {
+ Http::fake([
+ 'https://example.com/firmware.bin' => Http::response('fake firmware content', 200),
+ ]);
+
+ $firmware = Firmware::factory()->create([
+ 'url' => 'https://example.com/firmware.bin',
+ 'version_tag' => '1.0.0',
+ ]);
+
+ (new FirmwareDownloadJob($firmware))->handle();
+
+ expect($firmware->fresh()->storage_location)->toBe('firmwares/FW1.0.0.bin');
+});
diff --git a/tests/Feature/Jobs/FirmwarePollJobTest.php b/tests/Feature/Jobs/FirmwarePollJobTest.php
new file mode 100644
index 0000000..4b91180
--- /dev/null
+++ b/tests/Feature/Jobs/FirmwarePollJobTest.php
@@ -0,0 +1,116 @@
+ Http::response([
+ 'version' => '1.0.0',
+ 'url' => 'https://example.com/firmware.bin'
+ ], 200)
+ ]);
+
+ (new FirmwarePollJob())->handle();
+
+ expect(Firmware::where('version_tag', '1.0.0')->exists())->toBeTrue()
+ ->and(Firmware::where('version_tag', '1.0.0')->first())
+ ->url->toBe('https://example.com/firmware.bin')
+ ->latest->toBeTrue();
+});
+
+test('it updates existing firmware record when polling', function () {
+ $existingFirmware = Firmware::factory()->create([
+ 'version_tag' => '1.0.0',
+ 'url' => 'https://old-url.com/firmware.bin',
+ 'latest' => true
+ ]);
+
+ Http::fake([
+ 'usetrmnl.com/api/firmware/latest' => Http::response([
+ 'version' => '1.0.0',
+ 'url' => 'https://new-url.com/firmware.bin'
+ ], 200)
+ ]);
+
+ (new FirmwarePollJob())->handle();
+
+ expect($existingFirmware->fresh())
+ ->url->toBe('https://new-url.com/firmware.bin')
+ ->latest->toBeTrue();
+});
+
+test('it marks previous firmware as not latest when new version is found', function () {
+ $oldFirmware = Firmware::factory()->create([
+ 'version_tag' => '1.0.0',
+ 'latest' => true
+ ]);
+
+ Http::fake([
+ 'usetrmnl.com/api/firmware/latest' => Http::response([
+ 'version' => '1.1.0',
+ 'url' => 'https://example.com/firmware.bin'
+ ], 200)
+ ]);
+
+ (new FirmwarePollJob())->handle();
+
+ expect($oldFirmware->fresh()->latest)->toBeFalse()
+ ->and(Firmware::where('version_tag', '1.1.0')->first()->latest)->toBeTrue();
+});
+
+test('it handles connection exception gracefully', function () {
+ Http::fake([
+ 'usetrmnl.com/api/firmware/latest' => function () {
+ throw new ConnectionException('Connection failed');
+ }
+ ]);
+
+ (new FirmwarePollJob())->handle();
+
+ // Verify no firmware records were created
+ expect(Firmware::count())->toBe(0);
+});
+
+test('it handles invalid response gracefully', function () {
+ Http::fake([
+ 'usetrmnl.com/api/firmware/latest' => Http::response(null, 200)
+ ]);
+
+ (new FirmwarePollJob())->handle();
+
+ // Verify no firmware records were created
+ expect(Firmware::count())->toBe(0);
+});
+
+test('it handles missing version in response gracefully', function () {
+ Http::fake([
+ 'usetrmnl.com/api/firmware/latest' => Http::response([
+ 'url' => 'https://example.com/firmware.bin'
+ ], 200)
+ ]);
+
+ (new FirmwarePollJob())->handle();
+
+ // Verify no firmware records were created
+ expect(Firmware::count())->toBe(0);
+});
+
+test('it handles missing url in response gracefully', function () {
+ Http::fake([
+ 'usetrmnl.com/api/firmware/latest' => Http::response([
+ 'version' => '1.0.0'
+ ], 200)
+ ]);
+
+ (new FirmwarePollJob())->handle();
+
+ // Verify no firmware records were created
+ expect(Firmware::count())->toBe(0);
+});