Skip to content

Commit

Permalink
Add Firestore conformance tests (#2207)
Browse files Browse the repository at this point in the history
* Update Query#select to replace not add if called repeatedly. [BREAKING CHANGE]

* Update Batch/Transaction#update validations:
  * Raise ArgumentError for duplicate field paths.
  * Raise ArgumentError if one field is the prefix of another.

* Update Query#where to raise ArgumentError for operators unknown to Firestore.

* Remove previous handwritten versions of these conformance tests.
  • Loading branch information
quartzmo authored Jul 26, 2018
1 parent 61ab8c0 commit de0faa8
Show file tree
Hide file tree
Showing 18 changed files with 819 additions and 1,928 deletions.
1 change: 1 addition & 0 deletions google-cloud-firestore/.rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ AllCops:
- "support/**/*"
- "Rakefile"
- "acceptance/**/*"
- "conformance/*"
- "test/**/*"

Documentation:
Expand Down
6 changes: 6 additions & 0 deletions google-cloud-firestore/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ namespace :test do

Rake::Task["test"].invoke
end

desc "Run conformance tests separately from other unit tests."
task :conformance do
$LOAD_PATH.unshift "lib", "test"
require_relative "test/google/cloud/firestore/conformance_test.rb"
end
end

# Acceptance tests
Expand Down
196 changes: 196 additions & 0 deletions google-cloud-firestore/conformance/test-definition.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Tests for firestore clients.

syntax = "proto3";

package tests;

option php_namespace = "Google\\Cloud\\Firestore\\Tests\\Conformance";
option csharp_namespace = "Google.Cloud.Firestore.Tests.Proto";
option java_package = "com.google.cloud.firestore.conformance";

import "google/firestore/v1beta1/common.proto";
import "google/firestore/v1beta1/document.proto";
import "google/firestore/v1beta1/firestore.proto";
import "google/firestore/v1beta1/query.proto";
import "google/protobuf/timestamp.proto";

// A collection of tests.
message TestSuite {
repeated Test tests = 1;
}

// A Test describes a single client method call and its expected result.
message Test {
string description = 1; // short description of the test

oneof test {
GetTest get = 2;
CreateTest create = 3;
SetTest set = 4;
UpdateTest update = 5;
UpdatePathsTest update_paths = 6;
DeleteTest delete = 7;
QueryTest query = 8;
ListenTest listen = 9;
}
}

// Call to the DocumentRef.Get method.
message GetTest {
// The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
string doc_ref_path = 1;

// The request that the call should send to the Firestore service.
google.firestore.v1beta1.GetDocumentRequest request = 2;
}

// Call to DocumentRef.Create.
message CreateTest {
// The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
string doc_ref_path = 1;

// The data passed to Create, as JSON. The strings "Delete" and "ServerTimestamp"
// denote the two special sentinel values. Values that could be interpreted as integers
// (i.e. digit strings) should be treated as integers.
string json_data = 2;

// The request that the call should generate.
google.firestore.v1beta1.CommitRequest request = 3;

// If true, the call should result in an error without generating a request.
// If this is true, request should not be set.
bool is_error = 4;
}

// A call to DocumentRef.Set.
message SetTest {
string doc_ref_path = 1; // path of doc
SetOption option = 2; // option to the Set call, if any
string json_data = 3; // data (see CreateTest.json_data)
google.firestore.v1beta1.CommitRequest request = 4; // expected request
bool is_error = 5; // call signals an error
}

// A call to the form of DocumentRef.Update that represents the data as a map
// or dictionary.
message UpdateTest {
string doc_ref_path = 1; // path of doc
google.firestore.v1beta1.Precondition precondition = 2; // precondition in call, if any
string json_data = 3; // data (see CreateTest.json_data)
google.firestore.v1beta1.CommitRequest request = 4; // expected request
bool is_error = 5; // call signals an error
}

// A call to the form of DocumentRef.Update that represents the data as a list
// of field paths and their values.
message UpdatePathsTest {
string doc_ref_path = 1; // path of doc
google.firestore.v1beta1.Precondition precondition = 2; // precondition in call, if any
// parallel sequences: field_paths[i] corresponds to json_values[i]
repeated FieldPath field_paths = 3; // the argument field paths
repeated string json_values = 4; // the argument values, as JSON
google.firestore.v1beta1.CommitRequest request = 5; // expected rquest
bool is_error = 6; // call signals an error
}

// A call to DocmentRef.Delete
message DeleteTest {
string doc_ref_path = 1; // path of doc
google.firestore.v1beta1.Precondition precondition = 2;
google.firestore.v1beta1.CommitRequest request = 3; // expected rquest
bool is_error = 4; // call signals an error
}

// An option to the DocumentRef.Set call.
message SetOption {
bool all = 1; // if true, merge all fields ("fields" is ignored).
repeated FieldPath fields = 2; // field paths for a Merge option
}

message QueryTest {
string coll_path = 1; // path of collection, e.g. "projects/projectID/databases/(default)/documents/C"
repeated Clause clauses = 2;
google.firestore.v1beta1.StructuredQuery query = 3;
bool is_error = 4;
}

message Clause {
oneof clause {
Select select = 1;
Where where = 2;
OrderBy order_by = 3;
int32 offset = 4;
int32 limit = 5;
Cursor start_at = 6;
Cursor start_after = 7;
Cursor end_at = 8;
Cursor end_before = 9;
}
}

message Select {
repeated FieldPath fields = 1;
}

message Where {
FieldPath path = 1;
string op = 2;
string json_value = 3;
}

message OrderBy {
FieldPath path = 1;
string direction = 2; // "asc" or "desc"
}

message Cursor {
// one of:
DocSnapshot doc_snapshot = 1;
repeated string json_values = 2;
}

message DocSnapshot {
string path = 1;
string json_data = 2;
}

message FieldPath {
repeated string field = 1;
}

// A test of the Listen streaming RPC (a.k.a. FireStore watch).
// If the sequence of responses is provided to the implementation,
// it should produce the sequence of snapshots.
// If is_error is true, an error should occur after the snapshots.
//
// The tests assume that the query is
// Collection("projects/projectID/databases/(default)/documents/C").OrderBy("a", Ascending)
//
// The watch target ID used in these tests is 1. Test interpreters
// should either change their client's ID for testing,
// or change the ID in the tests before running them.
message ListenTest {
repeated google.firestore.v1beta1.ListenResponse responses = 1;
repeated Snapshot snapshots = 2;
bool is_error = 3;
}

message Snapshot {
repeated google.firestore.v1beta1.Document docs = 1;
repeated DocChange changes = 2;
google.protobuf.Timestamp read_time = 3;
}

message DocChange {
enum Kind {
KIND_UNSPECIFIED = 0;
ADDED = 1;
REMOVED = 2;
MODIFIED = 3;
}

Kind kind = 1;
google.firestore.v1beta1.Document doc = 2;
int32 old_index = 3;
int32 new_index = 4;
}
158 changes: 158 additions & 0 deletions google-cloud-firestore/conformance/test-definition_pb.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Loading

0 comments on commit de0faa8

Please sign in to comment.