예제 #1
0
        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));
            }
        }