public void Delete(SerializableTest wrapper) { DeleteTest test = wrapper.Test.Delete; Check(test.IsError, test.Request, batch => { DocumentReference doc = GetDocumentReference(test.DocRefPath); var precondition = Precondition.FromProto(test.Precondition); batch.Delete(doc, precondition); }); }
public void Create(SerializableTest wrapper) { CreateTest test = wrapper.Test.Create; Check(test.IsError, test.Request, batch => { DocumentReference doc = GetDocumentReference(test.DocRefPath); object documentData = DeserializeJson(test.JsonData); batch.Create(doc, documentData); }); }
public void Update(SerializableTest wrapper) { UpdateTest test = wrapper.Test.Update; Check(test.IsError, test.Request, batch => { DocumentReference doc = GetDocumentReference(test.DocRefPath); var documentData = (Dictionary<string, object>) DeserializeJson(test.JsonData); var precondition = Precondition.FromProto(test.Precondition); var updates = documentData.ToDictionary(pair => Firestore.FieldPath.FromDotSeparatedString(pair.Key), pair => pair.Value); batch.Update(doc, updates, precondition); }); }
public void Set(SerializableTest wrapper) { SetTest test = wrapper.Test.Set; Check(test.IsError, test.Request, batch => { DocumentReference doc = GetDocumentReference(test.DocRefPath); object documentData = DeserializeJson(test.JsonData); var setOptions = test.Option == null ? null : test.Option.All ? SetOptions.MergeAll : SetOptions.MergeFields(test.Option.Fields.Select(ConvertFieldPath).ToArray()); batch.Set(doc, documentData, setOptions); }); }
public void UpdatePaths(SerializableTest wrapper) { UpdatePathsTest test = wrapper.Test.UpdatePaths; Check(test.IsError, test.Request, batch => { DocumentReference doc = GetDocumentReference(test.DocRefPath); Dictionary<Firestore.FieldPath, object> updates = test.FieldPaths .Zip(test.JsonValues, (path, value) => (path, value)) .ToDictionary(tuple => ConvertFieldPath(tuple.path), tuple => (object) DeserializeJson(tuple.value)); var precondition = Precondition.FromProto(test.Precondition); batch.Update(doc, updates, precondition); }); }
public void Query(SerializableTest wrapper) { QueryTest test = wrapper.Test.Query; if (test.IsError) { var exception = Assert.ThrowsAny <Exception>(() => BuildQuery()); Assert.True(exception is ArgumentException || exception is InvalidOperationException, $"Exception type: {exception.GetType()}"); } else { var query = BuildQuery(); Assert.Equal(test.Query, query.ToStructuredQuery()); } Query BuildQuery() { Query query = GetCollectionReference(test.CollPath); foreach (var clause in test.Clauses) { switch (clause.ClauseCase) { case Clause.ClauseOneofCase.EndAt: query = query.EndAt(ConvertCursor(clause.EndAt)); break; case Clause.ClauseOneofCase.EndBefore: query = query.EndBefore(ConvertCursor(clause.EndBefore)); break; case Clause.ClauseOneofCase.Limit: query = query.Limit(clause.Limit); break; case Clause.ClauseOneofCase.Offset: query = query.Offset(clause.Offset); break; case Clause.ClauseOneofCase.OrderBy: var ordering = clause.OrderBy; var path = ConvertFieldPath(ordering.Path); query = ordering.Direction == "asc" ? query.OrderBy(path) : query.OrderByDescending(path); break; case Clause.ClauseOneofCase.Select: query = query.Select(clause.Select.Fields.Select(ConvertFieldPath).ToArray()); break; case Clause.ClauseOneofCase.StartAfter: query = query.StartAfter(ConvertCursor(clause.StartAfter)); break; case Clause.ClauseOneofCase.StartAt: query = query.StartAt(ConvertCursor(clause.StartAt)); break; case Clause.ClauseOneofCase.Where: var filterPath = ConvertFieldPath(clause.Where.Path); if (!QueryOperators.TryGetValue(clause.Where.Op, out var filterProvider)) { throw new ArgumentException($"Invalid where operator: {clause.Where.Op}"); } var value = DeserializeJson(clause.Where.JsonValue); query = filterProvider(query, filterPath, value); break; default: throw new InvalidOperationException($"Unexpected clause case: {clause.ClauseCase}"); } } return(query); } // Note: dynamic to allow a DocumentSnapshot to be returned and used in overload resolution. dynamic ConvertCursor(Cursor cursor) { var docSnapshot = cursor.DocSnapshot; if (docSnapshot == null) { return(cursor.JsonValues.Select(DeserializeJson).ToArray()); } var docRef = GetDocumentReference(docSnapshot.Path); return(DocumentSnapshot.ForDocument( docRef.Database, new Document { Name = docRef.Path, Fields = { ValueSerializer.SerializeMap(DeserializeJson(cursor.DocSnapshot.JsonData)) }, CreateTime = wkt::Timestamp.FromDateTimeOffset(DateTimeOffset.MinValue), UpdateTime = wkt::Timestamp.FromDateTimeOffset(DateTimeOffset.MinValue), }, Timestamp.FromDateTimeOffset(DateTimeOffset.MinValue))); } }
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)); } }