Skip to content
Merged
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
119 changes: 108 additions & 11 deletions .github/workflows/sdk.firestore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,63 @@ jobs:
export CCACHE_DIR=${{ runner.temp }}/ccache
scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake

xcodetest_prod:
build_xcodetest:
needs: check
if: |
(github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') ||
(github.event_name == 'pull_request')
runs-on: macos-26
timeout-minutes: 60

strategy:
fail-fast: false
matrix:
target: [iOS, macOS, tvOS]

steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false

- uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0

- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_26.4.app/Contents/Developer

- name: Setup simulator
if: matrix.target != 'macOS'
uses: ./.github/actions/setup_simulator
with:
platform: ${{ matrix.target }}

- name: Cache Pods
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/Pods
key: ${{ runner.os }}-pods-${{ matrix.target }}-${{ hashFiles('Firestore/Example/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-${{ matrix.target }}-

- name: Cache DerivedData Products
id: cache-products
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/DerivedData/Build/Products
key: ${{ runner.os }}-xctest-products-${{ matrix.target }}-${{ github.sha }}

- name: Setup build
if: steps.cache-products.outputs.cache-hit != 'true'
run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild

- name: Build Standard and Enterprise Test Products
if: steps.cache-products.outputs.cache-hit != 'true'
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 60
command: scripts/build.sh Firestore ${{ matrix.target }} xcodebuild

xcodetest_prod:
needs: [check, build_xcodetest]
# Either a scheduled run from public repo, or a pull request with firestore changes.
if: |
(github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') ||
Expand All @@ -303,14 +358,13 @@ jobs:

env:
plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }}
USE_FIRESTORE_EMULATOR: 'false'

steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false

- uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0

- name: Install Secret GoogleService-Info.plist for prod
run: |
scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore.plist.gpg \
Expand All @@ -325,7 +379,18 @@ jobs:
with:
platform: ${{ matrix.target }}

- name: Restore DerivedData Products
id: cache-products
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/DerivedData/Build/Products
key: ${{ runner.os }}-xctest-products-${{ matrix.target }}-${{ github.sha }}

- if: steps.cache-products.outputs.cache-hit != 'true'
uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0

- name: Cache Pods
if: steps.cache-products.outputs.cache-hit != 'true'
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/Pods
Expand All @@ -335,9 +400,11 @@ jobs:

# 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used.
- name: Setup build
if: steps.cache-products.outputs.cache-hit != 'true'
run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild

- name: Build
if: steps.cache-products.outputs.cache-hit != 'true'
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 60
Expand All @@ -353,7 +420,7 @@ jobs:
if-no-files-found: error

xcodetest_nightly:
needs: check
needs: [check, build_xcodetest]
# Either a scheduled run from public repo, or a pull request with firestore changes.
if: |
(github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') ||
Expand All @@ -368,14 +435,13 @@ jobs:

env:
plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }}
USE_FIRESTORE_EMULATOR: 'false'

steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false

- uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0

- name: Install Secret GoogleService-Info.plist for nightly
run: |
scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore-nightly.plist.gpg \
Expand All @@ -390,7 +456,18 @@ jobs:
with:
platform: ${{ matrix.target }}

- name: Restore DerivedData Products
id: cache-products
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/DerivedData/Build/Products
key: ${{ runner.os }}-xctest-products-${{ matrix.target }}-${{ github.sha }}

- if: steps.cache-products.outputs.cache-hit != 'true'
uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0

- name: Cache Pods
if: steps.cache-products.outputs.cache-hit != 'true'
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/Pods
Expand All @@ -400,15 +477,16 @@ jobs:

# 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used.
- name: Setup build
if: steps.cache-products.outputs.cache-hit != 'true'
run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild

# XCTest dynamically isolates the test runner app from standard terminal environment variables.
# To successfully pass TARGET_BACKEND and PROJECT_ID down to FSTIntegrationTestCase, we must physically inject them
# into the Xcode Schemes rather than using traditional YAML `env:` variables or `export` commands.
# into the Xcode Schemes and prebuilt .xctestrun files rather than using traditional YAML `env:` variables or `export` commands.
- name: Inject Nightly Backend into Schemes
run: |
python3 -c '
import glob, re
import glob, plistlib, re
for f in glob.glob("Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_*.xcscheme"):
with open(f, "r") as file: content = file.read()
content = re.sub(r"<EnvironmentVariables>", """<EnvironmentVariables>
Expand All @@ -423,9 +501,17 @@ jobs:
isEnabled = "YES">
</EnvironmentVariable>""", content)
with open(f, "w") as file: file.write(content)
for p in glob.glob("Firestore/Example/DerivedData/Build/Products/*.xctestrun"):
with open(p, "rb") as file: data = plistlib.load(file)
for k, v in data.items():
if isinstance(v, dict) and "EnvironmentVariables" in v:
v["EnvironmentVariables"]["TARGET_BACKEND"] = "nightly"
v["EnvironmentVariables"]["PROJECT_ID"] = "firestore-sdk-nightly"
with open(p, "wb") as file: plistlib.dump(data, file)
'

- name: Build
if: steps.cache-products.outputs.cache-hit != 'true'
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 60
Expand All @@ -442,7 +528,7 @@ jobs:


xcodetest_emulator:
needs: check
needs: [check, build_xcodetest]
# Either a scheduled run from public repo, or a pull request with firestore changes.
if: |
(github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') ||
Expand All @@ -460,8 +546,6 @@ jobs:
with:
persist-credentials: false

- uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0

- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_26.4.app/Contents/Developer

Expand All @@ -471,7 +555,18 @@ jobs:
with:
platform: ${{ matrix.target }}

- name: Restore DerivedData Products
id: cache-products
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/DerivedData/Build/Products
key: ${{ runner.os }}-xctest-products-${{ matrix.target }}-${{ github.sha }}

- if: steps.cache-products.outputs.cache-hit != 'true'
uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0

- name: Cache Pods
if: steps.cache-products.outputs.cache-hit != 'true'
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: Firestore/Example/Pods
Expand All @@ -480,10 +575,12 @@ jobs:
${{ runner.os }}-pods-${{ matrix.target }}-

- name: Setup build
if: steps.cache-products.outputs.cache-hit != 'true'
# 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used.
run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild

- name: Build
if: steps.cache-products.outputs.cache-hit != 'true'
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 60
Expand Down
21 changes: 14 additions & 7 deletions Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm
Comment thread
cherylEnkidu marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@

FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
XCTAssertTrue(result.exists);
XCTAssertEqualObjects(result.data, finalData);

Check failure on line 150 in Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm

View workflow job for this annotation

GitHub Actions / xcodetest_prod (macOS, Firestore)

testCanDeleteAFieldWithAnUpdate, ((result.data) equal to (finalData)) failed: ("{
}

- (void)testDeleteDocument {
Expand All @@ -155,7 +155,7 @@
NSDictionary<NSString *, id> *data = @{@"value" : @"foo"};
[self writeDocumentRef:doc data:data];
FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
XCTAssertEqualObjects(result.data, data);

Check failure on line 158 in Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm

View workflow job for this annotation

GitHub Actions / xcodetest_nightly (macOS, Firestore)

testDeleteDocument, ((result.data) equal to (data)) failed: ("{
[self deleteDocumentRef:doc];
result = [self readDocumentForRef:doc];
XCTAssertFalse(result.exists);
Expand Down Expand Up @@ -1490,8 +1490,10 @@

- (void)testRestartFirestoreLeadsToNewInstance {
FIRApp *app = AppForUnitTesting(MakeString([FSTIntegrationTestCase projectID]));
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app];
FIRFirestore *sameInstance = [FIRFirestore firestoreForApp:app];
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app
database:[FSTIntegrationTestCase databaseID]];
FIRFirestore *sameInstance = [FIRFirestore firestoreForApp:app
database:[FSTIntegrationTestCase databaseID]];
firestore.settings = [FSTIntegrationTestCase settings];

XCTAssertEqual(firestore, sameInstance);
Expand All @@ -1503,7 +1505,8 @@
[self terminateFirestore:firestore];

// Create a new instance, check it's a different instance.
FIRFirestore *newInstance = [FIRFirestore firestoreForApp:app];
FIRFirestore *newInstance = [FIRFirestore firestoreForApp:app
database:[FSTIntegrationTestCase databaseID]];
newInstance.settings = [FSTIntegrationTestCase settings];
XCTAssertNotEqual(firestore, newInstance);

Expand All @@ -1515,7 +1518,8 @@

- (void)testAppDeleteLeadsToFirestoreTermination {
FIRApp *app = AppForUnitTesting(MakeString([FSTIntegrationTestCase projectID]));
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app];
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app
database:[FSTIntegrationTestCase databaseID]];
firestore.settings = [FSTIntegrationTestCase settings];
NSDictionary<NSString *, id> *data =
@{@"owner" : @{@"name" : @"Jonny", @"email" : @"abc@xyz.com"}};
Expand All @@ -1529,7 +1533,8 @@
// Ensures b/172958106 doesn't regress.
- (void)testDeleteAppWorksWhenLastReferenceToFirestoreIsInListener {
FIRApp *app = AppForUnitTesting(MakeString([FSTIntegrationTestCase projectID]));
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app];
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app
database:[FSTIntegrationTestCase databaseID]];

FIRDocumentReference *doc = [firestore documentWithPath:@"abc/123"];
// Make sure there is a listener.
Expand All @@ -1548,7 +1553,8 @@

- (void)testTerminateCanBeCalledMultipleTimes {
FIRApp *app = AppForUnitTesting(MakeString([FSTIntegrationTestCase projectID]));
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app];
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app
database:[FSTIntegrationTestCase databaseID]];

[firestore terminateWithCompletion:[self completionForExpectationWithName:@"Terminate1"]];
[self awaitExpectations];
Expand All @@ -1565,7 +1571,8 @@

- (void)testCanRemoveListenerAfterTermination {
FIRApp *app = AppForUnitTesting(MakeString([FSTIntegrationTestCase projectID]));
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app];
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app
database:[FSTIntegrationTestCase databaseID]];
firestore.settings = [FSTIntegrationTestCase settings];

FIRDocumentReference *doc = [[firestore collectionWithPath:@"rooms"] documentWithAutoID];
Expand Down Expand Up @@ -1828,7 +1835,7 @@
NSDictionary<NSString *, id> *data = @{@"value" : @"foo"};
[self writeDocumentRef:doc data:data];
FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
XCTAssertEqualObjects(result.data, data);

Check failure on line 1838 in Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm

View workflow job for this annotation

GitHub Actions / xcodetest_prod (tvOS, Firestore)

testUnlimitedCacheSize, ((result.data) equal to (data)) failed: ("{
}

- (void)testGetValidPersistentCacheIndexManager {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,19 +272,25 @@ - (void)testServerTimestampsPreviousValueFromLocalMutation {
}

- (void)testServerTimestampsWorkViaTransactionSet {
[_listenerRegistration remove];
_listenerRegistration = nil;

[self runTransactionBlock:^(FIRTransaction *transaction) {
[transaction setData:self->_setData forDocument:self->_docRef];
}];

[self verifySnapshotWithResolvedTimestamps:[_accumulator awaitRemoteEvent]];
[self verifySnapshotWithResolvedTimestamps:[self readDocumentForRef:_docRef]];
}

- (void)testServerTimestampsWorkViaTransactionUpdate {
[self writeInitialData];
[_listenerRegistration remove];
_listenerRegistration = nil;

[self runTransactionBlock:^(FIRTransaction *transaction) {
[transaction updateData:self->_updateData forDocument:self->_docRef];
}];
[self verifySnapshotWithResolvedTimestamps:[_accumulator awaitRemoteEvent]];
[self verifySnapshotWithResolvedTimestamps:[self readDocumentForRef:_docRef]];
}

- (void)testServerTimestampsFailViaUpdateOnNonexistentDocument {
Expand Down
2 changes: 1 addition & 1 deletion Firestore/Example/Tests/Integration/FSTDatastoreTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ - (void)setUp {
GrpcConnection::UseInsecureChannel(MakeString(settings.host));
}

DatabaseId database_id(MakeString(projectID));
DatabaseId database_id(MakeString(projectID), MakeString([FSTIntegrationTestCase databaseID]));

_databaseInfo =
DatabaseInfo(database_id, "test-key", MakeString(settings.host), settings.sslEnabled);
Expand Down
10 changes: 9 additions & 1 deletion Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,15 @@ + (void)setUpDefaults {
} else if ([targetBackend isEqualToString:@"qa"]) {
host = @"staging-firestore.sandbox.googleapis.com";
} else if ([targetBackend isEqualToString:@"nightly"]) {
host = @"test-firestore.sandbox.googleapis.com";
// Workaround for UberProxy auth blocking external IPs (e.g. GitHub Actions runners) on
// test-firestore.sandbox.googleapis.com (b/552991017). Regional nightly endpoints are
// exempted; select the region matching where the test database is located in
// firestore-sdk-nightly (enterprise is in us-central1, default is in nam5).
if ([FSTIntegrationTestCase backendEdition] == FSTBackendEditionEnterprise) {
host = @"us-central1-test-firestore.sandbox.googleapis.com";
} else {
host = @"nam5-test-firestore.sandbox.googleapis.com";
}
} else if ([targetBackend isEqualToString:@"prod"]) {
host = @"firestore.googleapis.com";
} else {
Expand Down
5 changes: 5 additions & 0 deletions Firestore/core/src/remote/grpc_connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ std::shared_ptr<grpc::Channel> GrpcConnection::CreateChannel() const {
args.SetMaxReceiveMessageSize(GRPC_MAX_MESSAGE_SIZE);
args.SetMaxSendMessageSize(GRPC_MAX_MESSAGE_SIZE);

// Increase max metadata size to 1MB (from default 8KB) to accommodate large
// error details (e.g. grpc-status-details-bin with index creation URLs in
// prod, or google.rpc.debuginfo-bin stack traces in staging/nightly).
args.SetInt(GRPC_ARG_MAX_METADATA_SIZE, 1024 * 1024);

const HostConfig* host_config = Config().find(host);
if (!host_config) {
std::string root_certificate = LoadGrpcRootCertificate();
Expand Down
Loading
Loading