Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion powersync/src/sync/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl UploadActor {
.env
.pool
.update_notifiers()
.listen(ListenerConfiguration::if_matches(tables, false));
.listen(ListenerConfiguration::if_matches(tables, true));
ConnectedUploadActor {
connector,
crud_stream: stream.map(|_| ()).boxed(),
Expand Down
55 changes: 55 additions & 0 deletions powersync/tests/sync_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,61 @@ fn dropping_database_completes_actors() {
}));
}

#[test]
fn reconnect_uploads_pending_writes_after_an_early_trigger() {
struct Connector {
db: PowerSyncDatabase,
uploads: Arc<AtomicUsize>,
}

#[async_trait]
impl BackendConnector for Connector {
async fn fetch_credentials(&self) -> Result<PowerSyncCredentials, PowerSyncError> {
TestConnector.fetch_credentials().await
}

async fn upload_data(&self) -> Result<(), PowerSyncError> {
while let Some(tx) = self.db.next_crud_transaction().await? {
self.uploads.fetch_add(1, Ordering::SeqCst);
tx.complete().await?;
}
Ok(())
}
}

future::block_on(async {
let test = DatabaseTest::new();
let db = test.in_memory_database();
powersync_test_utils::execute(
&db,
"INSERT INTO users (id, name) VALUES ('1', 'offline')",
[],
)
.await;
let uploads = Arc::new(AtomicUsize::new(0));
let mut actors = db.async_tasks().spawn_with(|task| task);
let mut upload = actors.pop().unwrap();
let mut download = actors.pop().unwrap();
let mut connect = Box::pin(db.connect(SyncOptions::new(Connector {
db: db.clone(),
uploads: uploads.clone(),
})));

// Let the download actor's upload trigger arrive before the upload
// actor receives Connect. No new writes should be needed afterward.
assert!(future::poll_once(connect.as_mut()).await.is_none());
assert!(future::poll_once(&mut download).await.is_none());
assert!(future::poll_once(&mut upload).await.is_none());
assert!(future::poll_once(&mut download).await.is_none());
assert!(future::poll_once(connect.as_mut()).await.is_none());
assert!(future::poll_once(&mut upload).await.is_none());
assert!(future::poll_once(connect.as_mut()).await.is_some());

assert_eq!(uploads.load(Ordering::SeqCst), 1);
assert!(db.next_crud_transaction().await.unwrap().is_none());
Comment on lines +135 to +146

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels absurdly specific and fragile.

What we want to test is that calling connect() eventually emits upload_data even without any additional local writes. So give the connector the writing end of an async channel, send in upload_data and make the test wait on the reading end.

});
}

#[test]
fn can_disable_default_stream() {
let sync = SyncStreamTest::new();
Expand Down