feat: check every subscription in the background and add the posts page
This commit is contained in:
parent
953ae798eb
commit
1b426ccd8b
15 changed files with 688 additions and 58 deletions
|
|
@ -8,6 +8,8 @@ import 'package:mews/application/controllers/subscriptions_controller.dart';
|
|||
import 'package:mews/database/database.dart';
|
||||
import 'package:mews/mews/document.dart';
|
||||
|
||||
import 'fake_fetch.dart';
|
||||
|
||||
void main() {
|
||||
late MewsDatabase db;
|
||||
|
||||
|
|
@ -61,7 +63,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('subscribing takes on the back catalogue without flagging it', () async {
|
||||
final subscriptions = SubscriptionsController(db);
|
||||
final subscriptions = SubscriptionsController(db: db, fetch: FakeFetch(const {}));
|
||||
await subscriptions.load();
|
||||
|
||||
final firstPost = MewsEntry(
|
||||
|
|
@ -97,7 +99,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('unread posts survive a restart', () async {
|
||||
final subscriptions = SubscriptionsController(db);
|
||||
final subscriptions = SubscriptionsController(db: db, fetch: FakeFetch(const {}));
|
||||
await subscriptions.load();
|
||||
await subscriptions.toggle(_page('https://example.com/', const []));
|
||||
await subscriptions.refreshSite(_page('https://example.com/', [
|
||||
|
|
@ -109,14 +111,14 @@ void main() {
|
|||
|
||||
// A fresh controller over the same database sees the same unread post,
|
||||
// which the old in-memory count could not do.
|
||||
final restarted = SubscriptionsController(db);
|
||||
final restarted = SubscriptionsController(db: db, fetch: FakeFetch(const {}));
|
||||
await restarted.load();
|
||||
expect(restarted.isSubscribed('https://example.com/'), isTrue);
|
||||
expect(await db.unreadCount(), 1);
|
||||
});
|
||||
|
||||
test('leaving a site takes its posts with it', () async {
|
||||
final subscriptions = SubscriptionsController(db);
|
||||
final subscriptions = SubscriptionsController(db: db, fetch: FakeFetch(const {}));
|
||||
await subscriptions.load();
|
||||
await subscriptions.toggle(_page('https://example.com/', const []));
|
||||
await subscriptions.refreshSite(_page('https://example.com/', [
|
||||
|
|
@ -132,6 +134,79 @@ void main() {
|
|||
expect(await db.unreadCount(), 0);
|
||||
});
|
||||
|
||||
test('a check finds new posts on every subscribed site', () async {
|
||||
const siteA = 'https://a.example/';
|
||||
const siteB = 'https://b.example/';
|
||||
final sources = {
|
||||
siteA: _entriesPage('Site A', const []),
|
||||
siteB: _entriesPage('Site B', const []),
|
||||
};
|
||||
final subscriptions =
|
||||
SubscriptionsController(db: db, fetch: FakeFetch(sources));
|
||||
await subscriptions.load();
|
||||
await subscriptions.toggle(_page(siteA, const []));
|
||||
await subscriptions.toggle(_page(siteB, const []));
|
||||
|
||||
// Both sites publish something after the reader subscribed.
|
||||
sources[siteA] = _entriesPage('Site A', const [
|
||||
('2026-10-09', 'a-one.html', 'A newer post'),
|
||||
]);
|
||||
sources[siteB] = _entriesPage('Site B', const [
|
||||
('2026-10-10', 'b-one.html', 'Another post'),
|
||||
('2026-10-09', 'b-two.html', 'And one more'),
|
||||
]);
|
||||
|
||||
await subscriptions.refreshAll();
|
||||
expect(await db.unreadCount(), 3);
|
||||
expect(await db.unreadCount(siteUrl: siteA), 1);
|
||||
expect(subscriptions.refreshing.value, isFalse);
|
||||
|
||||
// Every site was recorded as checked.
|
||||
for (final site in await db.allSubscriptions()) {
|
||||
expect(site.lastCheckedAt, isNotNull);
|
||||
}
|
||||
});
|
||||
|
||||
test('one unreachable site does not stop the rest of the check', () async {
|
||||
const reachable = 'https://a.example/';
|
||||
const unreachable = 'https://down.example/';
|
||||
final subscriptions = SubscriptionsController(
|
||||
db: db,
|
||||
// Only the first site answers; the other has no source at all.
|
||||
fetch: FakeFetch({
|
||||
reachable: _entriesPage('Site A', const [
|
||||
('2026-10-09', 'a-one.html', 'A newer post'),
|
||||
]),
|
||||
}),
|
||||
);
|
||||
await subscriptions.load();
|
||||
await subscriptions.toggle(_page(unreachable, const []));
|
||||
await subscriptions.toggle(_page(reachable, const []));
|
||||
|
||||
await subscriptions.refreshAll();
|
||||
expect(await db.unreadCount(siteUrl: reachable), 1);
|
||||
expect(subscriptions.refreshing.value, isFalse);
|
||||
// The site that could not be reached is still marked as checked.
|
||||
final down = (await db.allSubscriptions())
|
||||
.firstWhere((s) => s.url == unreachable);
|
||||
expect(down.lastCheckedAt, isNotNull);
|
||||
});
|
||||
|
||||
test('a check already running is not started again', () async {
|
||||
final subscriptions = SubscriptionsController(
|
||||
db: db,
|
||||
fetch: FakeFetch({'https://a.example/': _entriesPage('Site A', const [])}),
|
||||
);
|
||||
await subscriptions.load();
|
||||
await subscriptions.toggle(_page('https://a.example/', const []));
|
||||
|
||||
var redraws = 0;
|
||||
subscriptions.onChanged = () => redraws++;
|
||||
await Future.wait([subscriptions.refreshAll(), subscriptions.refreshAll()]);
|
||||
// One pass: it starts and finishes once, so two redraws, not four.
|
||||
expect(redraws, 2);
|
||||
});
|
||||
|
||||
test('caches pages for offline reopening', () async {
|
||||
await db.saveCachedPage(CachedPagesCompanion.insert(
|
||||
url: 'https://example.com/page.html',
|
||||
|
|
@ -161,3 +236,20 @@ MewsPage _page(String url, List<MewsEntry> entries) => MewsPage(
|
|||
entries: entries,
|
||||
specVersion: '0.1',
|
||||
);
|
||||
|
||||
/// A Mews page whose list holds dated links (spec 6.1), one per entry given as
|
||||
/// (date, file name, title).
|
||||
String _entriesPage(
|
||||
String title, List<(String, String, String)> entries) =>
|
||||
'''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head><title>$title</title><meta name="mews-profile" content="0.1" /></head>
|
||||
<body>
|
||||
<h1>$title</h1>
|
||||
<ul>
|
||||
${entries.map((e) => ' <li><a href="${e.$2}">${e.$1} ${e.$3}</a></li>').join('\n')}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
''';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue