Skip to content

Commit 71c9658

Browse files
committed
Manual integration test for sync progress.
1 parent e41617e commit 71c9658

File tree

3 files changed

+189
-131
lines changed

3 files changed

+189
-131
lines changed

PowerSync/PowerSync.Common/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
- Add `trackPreviousValues` option on `TableOptions` which sets `CrudEntry.PreviousValues` to previous values on updates.
55
- Add `trackMetadata` option on `TableOptions` which adds a `_metadata` column that can be used for updates. The configured metadata is available through `CrudEntry.Metadata`.
66
- Add `ignoreEmptyUpdates` option on `TableOptions` which skips creating CRUD entries for updates that don't change any values.
7-
7+
- Report progress information about downloaded rows. Sync progress is available through `SyncStatus.DownloadProgress()`.
88

99
## 0.0.5-alpha.1
1010
- Using the latest (0.4.9) version of the core extension, it introduces support for the Rust Sync implementation and also makes it the default - users can still opt out and use the legacy C# sync implementation as option when calling `connect()`.

PowerSync/PowerSync.Common/DB/Crud/SyncProgress.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public class ProgressWithOperations
6868
public int TotalOperations { get; set; }
6969

7070
/// <summary>
71-
/// The numnber of operations that have already been downloaded.
71+
/// The number of operations that have already been downloaded.
7272
/// </summary>
7373
public int DownloadedOperations { get; set; }
7474

Tests/PowerSync/PowerSync.Common.IntegrationTests/SyncIntegrationTests.cs

Lines changed: 187 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -66,160 +66,218 @@ public async Task DisposeAsync()
6666
await db.Close();
6767
}
6868

69-
[IntegrationFact(Timeout = 3000)]
70-
public async Task SyncDownCreateOperationTest()
69+
// [IntegrationFact(Timeout = 3000)]
70+
// public async Task SyncDownCreateOperationTest()
71+
// {
72+
// var watched = new TaskCompletionSource<bool>();
73+
// var cts = new CancellationTokenSource();
74+
// var id = Uuid();
75+
76+
// await db.Watch("select * from lists where id = ?", [id], new WatchHandler<ListResult>
77+
// {
78+
// OnResult = (x) =>
79+
// {
80+
// // Verify that the item was added locally
81+
// if (x.Length == 1)
82+
// {
83+
// watched.SetResult(true);
84+
// cts.Cancel();
85+
// }
86+
// }
87+
// }, new SQLWatchOptions
88+
// {
89+
// Signal = cts.Token
90+
// });
91+
92+
// await nodeClient.CreateList(id, name: "Test List magic");
93+
// await watched.Task;
94+
// }
95+
96+
// [IntegrationFact(Timeout = 3000)]
97+
// public async Task SyncDownDeleteOperationTest()
98+
// {
99+
// var watched = new TaskCompletionSource<bool>();
100+
// var cts = new CancellationTokenSource();
101+
// var id = Uuid();
102+
103+
// await nodeClient.CreateList(id, name: "Test List to delete");
104+
105+
// await db.Watch("select * from lists where id = ?", [id], new WatchHandler<ListResult>
106+
// {
107+
// OnResult = (x) =>
108+
// {
109+
// // Verify that the item was added locally
110+
// if (x.Length == 1)
111+
// {
112+
// watched.SetResult(true);
113+
// cts.Cancel();
114+
// }
115+
// }
116+
// }, new SQLWatchOptions
117+
// {
118+
// Signal = cts.Token
119+
// });
120+
121+
// await watched.Task;
122+
// await nodeClient.DeleteList(id);
123+
124+
// watched = new TaskCompletionSource<bool>();
125+
// cts = new CancellationTokenSource();
126+
127+
// await db.Watch("select * from lists where id = ?", [id], new WatchHandler<ListResult>
128+
// {
129+
// OnResult = (x) =>
130+
// {
131+
// // Verify that the item was deleted locally
132+
// if (x.Length == 0)
133+
// {
134+
// watched.SetResult(true);
135+
// cts.Cancel();
136+
// }
137+
// }
138+
// }, new SQLWatchOptions
139+
// {
140+
// Signal = cts.Token
141+
// });
142+
143+
// await watched.Task;
144+
// }
145+
146+
// [IntegrationFact(Timeout = 5000)]
147+
// public async Task SyncDownLargeCreateOperationTest()
148+
// {
149+
// var watched = new TaskCompletionSource<bool>();
150+
// var cts = new CancellationTokenSource();
151+
// var id = Uuid();
152+
// var listName = Uuid();
153+
154+
// await db.Watch("select * from lists where name = ?", [listName], new WatchHandler<ListResult>
155+
// {
156+
// OnResult = (x) =>
157+
// {
158+
// // Verify that the item was added locally
159+
// if (x.Length == 100)
160+
// {
161+
// watched.SetResult(true);
162+
// cts.Cancel();
163+
// }
164+
// }
165+
// }, new SQLWatchOptions
166+
// {
167+
// Signal = cts.Token
168+
// });
169+
170+
// for (int i = 0; i < 100; i++)
171+
// {
172+
// await nodeClient.CreateList(Uuid(), listName);
173+
// }
174+
// await watched.Task;
175+
// }
176+
177+
// [IntegrationFact(Timeout = 5000)]
178+
// public async Task SyncDownCreateOperationAfterLargeUploadTest()
179+
// {
180+
// var localInsertWatch = new TaskCompletionSource<bool>();
181+
// var backendInsertWatch = new TaskCompletionSource<bool>();
182+
// var cts = new CancellationTokenSource();
183+
// var id = Uuid();
184+
// var listName = Uuid();
185+
186+
// await db.Watch("select * from lists where name = ?", [listName], new WatchHandler<ListResult>
187+
// {
188+
// OnResult = (x) =>
189+
// {
190+
// // Verify that the items were added locally
191+
// if (x.Length == 100)
192+
// {
193+
// localInsertWatch.SetResult(true);
194+
// }
195+
// // Verify that the new item added to backend was synced down
196+
// else if (x.Length == 101)
197+
// {
198+
// backendInsertWatch.SetResult(true);
199+
// cts.Cancel();
200+
// }
201+
// }
202+
// }, new SQLWatchOptions
203+
// {
204+
// Signal = cts.Token
205+
// });
206+
207+
// for (int i = 0; i < 100; i++)
208+
// {
209+
// await db.Execute("insert into lists (id, name, owner_id, created_at) values (uuid(), ?, ?, datetime())",
210+
// [listName, userId]);
211+
// }
212+
// await localInsertWatch.Task;
213+
214+
// // let the crud upload finish
215+
// await Task.Delay(2000);
216+
217+
// await nodeClient.CreateList(Uuid(), listName);
218+
// await backendInsertWatch.Task;
219+
// }
220+
221+
222+
/// <summary>
223+
/// Helper that requires manual setup of the data to verify that download progress updates are working.
224+
/// Ensure backend has 5000+ entries, then run this test to see progress updates in the console.
225+
/// </summary>
226+
[IntegrationFact(Timeout = 10000)]
227+
public async Task InitialSyncDownloadProgressTest()
71228
{
72-
var watched = new TaskCompletionSource<bool>();
73-
var cts = new CancellationTokenSource();
74-
var id = Uuid();
75-
76-
await db.Watch("select * from lists where id = ?", [id], new WatchHandler<ListResult>
77-
{
78-
OnResult = (x) =>
79-
{
80-
// Verify that the item was added locally
81-
if (x.Length == 1)
82-
{
83-
watched.SetResult(true);
84-
cts.Cancel();
85-
}
86-
}
87-
}, new SQLWatchOptions
229+
ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
88230
{
89-
Signal = cts.Token
231+
builder.AddConsole();
232+
builder.SetMinimumLevel(LogLevel.Information);
90233
});
91234

92-
await nodeClient.CreateList(id, name: "Test List magic");
93-
await watched.Task;
94-
}
95-
96-
[IntegrationFact(Timeout = 3000)]
97-
public async Task SyncDownDeleteOperationTest()
98-
{
99-
var watched = new TaskCompletionSource<bool>();
100-
var cts = new CancellationTokenSource();
101-
var id = Uuid();
102-
103-
await nodeClient.CreateList(id, name: "Test List to delete");
235+
var logger = loggerFactory.CreateLogger("PowerSyncLogger");
104236

105-
await db.Watch("select * from lists where id = ?", [id], new WatchHandler<ListResult>
106-
{
107-
OnResult = (x) =>
108-
{
109-
// Verify that the item was added locally
110-
if (x.Length == 1)
111-
{
112-
watched.SetResult(true);
113-
cts.Cancel();
114-
}
115-
}
116-
}, new SQLWatchOptions
237+
nodeClient = new NodeClient(userId);
238+
db = new PowerSyncDatabase(new PowerSyncDatabaseOptions
117239
{
118-
Signal = cts.Token
119-
});
120-
121-
await watched.Task;
122-
await nodeClient.DeleteList(id);
123-
124-
watched = new TaskCompletionSource<bool>();
125-
cts = new CancellationTokenSource();
240+
Database = new SQLOpenOptions { DbFilename = "powersync-sync-progress-tests.db" },
241+
Schema = TestSchema.PowerSyncSchema,
242+
Logger = logger
126243

127-
await db.Watch("select * from lists where id = ?", [id], new WatchHandler<ListResult>
128-
{
129-
OnResult = (x) =>
130-
{
131-
// Verify that the item was deleted locally
132-
if (x.Length == 0)
133-
{
134-
watched.SetResult(true);
135-
cts.Cancel();
136-
}
137-
}
138-
}, new SQLWatchOptions
139-
{
140-
Signal = cts.Token
141244
});
245+
await db.Init();
246+
await db.DisconnectAndClear();
142247

143-
await watched.Task;
144-
}
145-
146-
[IntegrationFact(Timeout = 5000)]
147-
public async Task SyncDownLargeCreateOperationTest()
148-
{
149-
var watched = new TaskCompletionSource<bool>();
150-
var cts = new CancellationTokenSource();
151-
var id = Uuid();
152-
var listName = Uuid();
153248

154-
await db.Watch("select * from lists where name = ?", [listName], new WatchHandler<ListResult>
249+
var clearListener = db.RunListener((update) =>
155250
{
156-
OnResult = (x) =>
251+
if (update.StatusChanged != null)
157252
{
158-
// Verify that the item was added locally
159-
if (x.Length == 100)
253+
try
160254
{
161-
watched.SetResult(true);
162-
cts.Cancel();
163-
}
164-
}
165-
}, new SQLWatchOptions
166-
{
167-
Signal = cts.Token
168-
});
169-
170-
for (int i = 0; i < 100; i++)
171-
{
172-
await nodeClient.CreateList(Uuid(), listName);
173-
}
174-
await watched.Task;
175-
}
255+
Console.WriteLine("Total: " + update.StatusChanged.DownloadProgress()?.TotalOperations + " Downloaded: " + update.StatusChanged.DownloadProgress()?.DownloadedOperations);
256+
Console.WriteLine("Synced: " + Math.Round((decimal)(update.StatusChanged.DownloadProgress()?.DownloadedFraction * 100)) + "%");
176257

177-
[IntegrationFact(Timeout = 5000)]
178-
public async Task SyncDownCreateOperationAfterLargeUploadTest()
179-
{
180-
var localInsertWatch = new TaskCompletionSource<bool>();
181-
var backendInsertWatch = new TaskCompletionSource<bool>();
182-
var cts = new CancellationTokenSource();
183-
var id = Uuid();
184-
var listName = Uuid();
185-
186-
await db.Watch("select * from lists where name = ?", [listName], new WatchHandler<ListResult>
187-
{
188-
OnResult = (x) =>
189-
{
190-
// Verify that the items were added locally
191-
if (x.Length == 100)
192-
{
193-
localInsertWatch.SetResult(true);
194258
}
195-
// Verify that the new item added to backend was synced down
196-
else if (x.Length == 101)
259+
catch (Exception ex)
197260
{
198-
backendInsertWatch.SetResult(true);
199-
cts.Cancel();
261+
Console.WriteLine("Exception reading DownloadProgress: " + ex);
200262
}
201263
}
202-
}, new SQLWatchOptions
203-
{
204-
Signal = cts.Token
205264
});
206265

207-
for (int i = 0; i < 100; i++)
208-
{
209-
await db.Execute("insert into lists (id, name, owner_id, created_at) values (uuid(), ?, ?, datetime())",
210-
[listName, userId]);
211-
}
212-
await localInsertWatch.Task;
213-
214-
// let the crud upload finish
215-
await Task.Delay(2000);
266+
var connector = new NodeConnector(userId);
267+
await db.Connect(connector);
268+
await db.WaitForFirstSync();
216269

217-
await nodeClient.CreateList(Uuid(), listName);
218-
await backendInsertWatch.Task;
270+
clearListener.Dispose();
271+
await db.DisconnectAndClear();
272+
await db.Close();
219273
}
220274

221275
private async Task ClearAllData()
222276
{
277+
if (db.Closed)
278+
{
279+
return;
280+
}
223281
// Inefficient but simple way to clear all data, avoiding payload limitations
224282
var results = await db.GetAll<ListResult>("select * from lists");
225283
foreach (var item in results)

0 commit comments

Comments
 (0)