MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 3 / 0 / 3
Functions: 100.0% 3 / 0 / 3
Branches: -% 0 / 0 / 0

data/DavPushStore.h
Line Branch Exec Source
1 #pragma once
2
3 #include <QByteArray>
4 #include <QHash>
5 #include <QList>
6 #include <QSqlDatabase>
7 #include <QString>
8 #include <optional>
9
10 #include "DavPushModels.h"
11
12 // Sprint 96 S96.1.3: local, profile-bound DAV-Push metadata in
13 // <profile>/dav-push.sqlite (ADR-96-4). Never synchronised between
14 // installations; secrets (channel, private key, auth secret, provider
15 // token) are NOT stored here — only keyring references.
16 //
17 // A persisted registration is historical metadata: after a restart it is
18 // renewed/checked before anything is shown as "connected".
19 struct DavPushCollectionRecord {
20 QString accountId;
21 QString path;
22 DavPushOffer offer;
23 qint64 checkedAt = 0; // last completed capability check (epoch s)
24 QString registrationUrl; // confirmed Location ("" = none); confidential
25 QString registrationReceiver; // receiver id the registration points to
26 QString registrationEndpoint; // hash of the push endpoint registered ("" = unknown, schema v1)
27 qint64 expiresAt = 0; // confirmed Expires (epoch s)
28 qint64 registeredAt = 0;
29 qint64 renewedAt = 0;
30 QString lastError; // redacted technical reason
31 qint64 lastErrorAt = 0;
32 qint64 nextRetryAt = 0;
33 int failures = 0;
34 qint64 lastPushAt = 0; // last valid, mapped push message
35 qint64 lastSyncAt = 0; // last complete data sync of this collection
36 };
37
38 struct DavPushReceiverRecord {
39 QString accountId;
40 QString receiverId; // random; names the keyring entry
41 QString provider; // "ntfy"
42 QString server; // https origin of the push service
43 qint64 createdAt = 0;
44 int generation = 0; // incremented on every replacement
45 };
46
47 struct DavPushCleanupEntry {
48 qint64 id = 0;
49 QString accountId;
50 QString registrationUrl;
51 qint64 createdAt = 0;
52 int attempts = 0;
53 };
54
55 class DavPushStore {
56 public:
57 // v2 (2026-10-04): collections.endpoint_hash for push services whose
58 // endpoint can change (UnifiedPush distributors).
59 static constexpr int SchemaVersion = 2;
60 // Bounded history (SPRINT-96.md §5.3).
61 static constexpr int kMaxLatencySamples = 256;
62 static constexpr int kMaxEvents = 50;
63 static constexpr int kHourlyRetentionHours = 7 * 24;
64 static constexpr int kMaxCleanupEntries = 200;
65 static constexpr int kMaxCleanupAttempts = 10; // S106-078
66
67 868 DavPushStore() = default;
68 ~DavPushStore();
69 DavPushStore(const DavPushStore &) = delete;
70 DavPushStore &operator=(const DavPushStore &) = delete;
71
72 bool open(const QString &path);
73 // One transaction around a batch of writes (statistics flush): one
74 // commit instead of one per statement.
75 bool beginTransaction();
76 bool commitTransaction();
77 void rollbackTransaction();
78 5364 bool isOpen() const { return m_db.isOpen(); }
79 3 QString lastError() const { return m_lastError; }
80
81 // Random per-profile installation id (names keyring entries).
82 QString installationId();
83
84 // --- collections ---
85 std::optional<DavPushCollectionRecord> collection(const QString &accountId, const QString &path) const;
86 QList<DavPushCollectionRecord> collections(const QString &accountId = {}) const;
87 bool saveCollection(const DavPushCollectionRecord &record);
88 bool removeCollection(const QString &accountId, const QString &path);
89
90 // --- receivers ---
91 std::optional<DavPushReceiverRecord> receiver(const QString &accountId) const;
92 bool saveReceiver(const DavPushReceiverRecord &record);
93 bool removeReceiver(const QString &accountId);
94 QStringList receiverAccounts() const;
95
96 // --- registrations waiting for an unsubscribe (bounded) ---
97 bool queueCleanup(const QString &accountId, const QString &registrationUrl, qint64 now);
98 QList<DavPushCleanupEntry> cleanupEntries(const QString &accountId = {}) const;
99 bool updateCleanupAttempt(qint64 id);
100 bool removeCleanup(qint64 id);
101 bool removeCleanupForAccount(const QString &accountId);
102
103 // --- statistics (scope = "account:<id>" or "collection:<key>") ---
104 bool addCounter(const QString &scope, const QString &name, qint64 delta, qint64 now);
105 qint64 counter(const QString &scope, const QString &name) const;
106 // Sum of the hourly aggregates of `name` with hour >= since.
107 qint64 periodSum(const QString &scope, const QString &name, qint64 since) const;
108 bool addLatency(const QString &scope, const QString &kind, qint64 millis, qint64 now);
109 QList<qint64> latencies(const QString &scope, const QString &kind) const;
110 bool addEvent(const QString &scope, const QString &kind, const QString &detail, qint64 now);
111 struct Event { qint64 at = 0; QString kind; QString detail; };
112 QList<Event> events(const QString &scope) const;
113 // Local reset: counters, hourly aggregates, samples and events of the
114 // scope. Registrations, tokens and credentials are untouched.
115 bool resetStatistics(const QString &scope, qint64 now);
116 qint64 statisticsSince(const QString &scope) const;
117 bool pruneHourly(qint64 now);
118
119 private:
120 bool createSchema();
121 bool exec(const QString &sql, const QVariantList &values = {}) const;
122
123 QSqlDatabase m_db;
124 QString m_connectionName;
125 mutable QString m_lastError;
126 };
127