public void SnapshotFromChanges() { var query = s_db.Collection("col1"); var readTime = new Timestamp(10, 2); var doc1 = GetSampleSnapshot(s_db, "doc1"); var doc2 = GetSampleSnapshot(s_db, "doc2"); var documentSet = DocumentSet.Empty(query.CreateDocumentSnapshotComparer()) .WithDocumentAdded(doc1) .WithDocumentAdded(doc2); var changes = new[] { new DocumentChange(doc2, DocumentChange.Type.Added, null, 1) }; // It's fine for the list to be a different length; the document set is *all* the // documents, whereas changes is just the delta from the previous snapshot. var snapshot = QuerySnapshot.ForChanges(query, documentSet, changes, readTime); Assert.Equal(changes, snapshot.Changes); Assert.Equal(new[] { doc1, doc2 }, snapshot.Documents); Assert.Equal(new[] { doc1, doc2 }, snapshot.ToList()); }
public async Task Listen(SerializableTest wrapper) { ListenTest test = wrapper.Test.Listen; var db = FirestoreDb.Create(ProjectId, DatabaseId, new FakeFirestoreClient()); var query = db.Collection("C").OrderBy("a"); Func <Task> action = async() => { List <QuerySnapshot> snapshots = new List <QuerySnapshot>(); var watchState = new WatchState(query, (snapshot, token) => { snapshots.Add(snapshot); return(Task.FromResult(1)); }); watchState.OnStreamInitialization(StreamInitializationCause.WatchStarting); foreach (var response in test.Responses) { // Fix up the test response to use our watch target ID. ReplaceWatchTargetId(response.TargetChange?.TargetIds); ReplaceWatchTargetId(response.DocumentChange?.TargetIds); ReplaceWatchTargetId(response.DocumentChange?.RemovedTargetIds); ReplaceWatchTargetId(response.DocumentDelete?.RemovedTargetIds); ReplaceWatchTargetId(response.DocumentRemove?.RemovedTargetIds); var result = await watchState.HandleResponseAsync(response, default); if (result == WatchResponseResult.ResetStream) { watchState.OnStreamInitialization(StreamInitializationCause.ResetRequested); } } var expectedSnapshots = test.Snapshots.Select(snapshot => ConvertSnapshot(snapshot)).ToList(); Assert.Equal(expectedSnapshots, snapshots); }; if (test.IsError) { // TODO: Should we actually check that it's only the last response that causes the exception? var exception = await Assert.ThrowsAnyAsync <Exception>(action); Assert.True(exception is ArgumentException || exception is InvalidOperationException, $"Exception type: {exception.GetType()}"); } else { await action(); } // Different clients use different watch target IDs. The test data always uses 1 // to mean "the target ID that the client uses". void ReplaceWatchTargetId(RepeatedField <int> ids) { if (ids == null) { return; } for (int i = 0; i < ids.Count; i++) { if (ids[i] == 1) { ids[i] = WatchStream.WatchTargetId; } } } // Converts from a test proto snapshot to a QuerySnapshot QuerySnapshot ConvertSnapshot(Snapshot snapshot) { var readTime = Timestamp.FromProto(snapshot.ReadTime); var changes = snapshot.Changes.Select(change => ConvertChange(change, readTime)).ToList(); var docs = snapshot.Docs.Select(doc => DocumentSnapshot.ForDocument(db, doc, readTime)).ToList(); return(QuerySnapshot.ForChanges(query, docs, changes, readTime)); } DocumentChange ConvertChange(DocChange change, Timestamp readTime) { var snapshot = DocumentSnapshot.ForDocument(db, change.Doc, readTime); return(new DocumentChange(snapshot, (DocumentChange.Type)change.Kind, change.OldIndex == -1 ? default(int?) : change.OldIndex, change.NewIndex == -1 ? default(int?) : change.NewIndex)); } }