Skip to content

Commit e15bb36

Browse files
authored
Add GoogleService-Info.plist for integration testing. (#7037)
* Restores ML Pods after M77. * Fix Package.swift * Add GoogleService-Info.plist to secrets for integration tests. * Configure FirebaseApp in tests to read from GoogleService-Info.plist. * Lint fix. * Plist WIP * Plist WIP * Add GoogleService-Info.plist to secrets for (future) integration tests. * Add GoogleService-Info.plist to secrets for (future) integration tests. * Add GoogleService-Info.plist to secrets for (future) integration tests. * Split tests into unit and integration, configure FirebaseApp. * Move GoogleService-Info.plist to Integration/ * Split tests into unit and integration. * Fix workflow step to copy plist over to project.
1 parent e4ccbe2 commit e15bb36

File tree

5 files changed

+151
-71
lines changed

5 files changed

+151
-71
lines changed

.github/workflows/mlmodeldownloader.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ jobs:
1616
if: github.repository != 'FirebasePrivate/firebase-ios-sdk' || github.event_name == 'pull_request'
1717

1818
runs-on: macOS-latest
19-
19+
env:
20+
plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }}
2021
strategy:
2122
matrix:
2223
target: [ios, tvos, macos]
2324
steps:
2425
- uses: actions/checkout@v2
2526
- name: Setup Bundler
2627
run: scripts/setup_bundler.sh
28+
- name: Install GoogleService-Info.plist
29+
run: |
30+
mkdir FirebaseMLModelDownloader/Tests/Integration/Resources
31+
scripts/decrypt_gha_secret.sh scripts/gha-encrypted/MLModelDownloader/GoogleService-Info.plist.gpg \
32+
FirebaseMLModelDownloader/Tests/Integration/Resources/GoogleService-Info.plist "$plist_secret"
2733
- name: Build and test
2834
run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseMLModelDownloader.podspec --platforms=${{ matrix.target }}
2935

FirebaseMLModelDownloader.podspec

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,11 @@ Pod::Spec.new do |s|
4545
unit_tests.source_files = 'FirebaseMLModelDownloader/Tests/Unit/**/*.swift'
4646
unit_tests.requires_app_host = true
4747
end
48+
49+
s.test_spec 'integration' do |int_tests|
50+
int_tests.platforms = {:ios => '10.0', :osx => '10.12', :tvos => '10.0'}
51+
int_tests.source_files = 'FirebaseMLModelDownloader/Tests/Integration/**/*.swift'
52+
int_tests.resources = 'FirebaseMLModelDownloader/Tests/Integration/Resources/GoogleService-Info.plist'
53+
int_tests.requires_app_host = true
54+
end
4855
end
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import XCTest
16+
@testable import FirebaseCore
17+
@testable import FirebaseMLModelDownloader
18+
19+
extension UserDefaults {
20+
/// For testing: returns a new cleared instance of user defaults.
21+
static func getTestInstance() -> UserDefaults {
22+
let suiteName = "com.google.firebase.ml.test"
23+
// TODO: reconsider force unwrapping
24+
let defaults = UserDefaults(suiteName: suiteName)!
25+
defaults.removePersistentDomain(forName: suiteName)
26+
return defaults
27+
}
28+
}
29+
30+
final class ModelDownloaderIntegrationTests: XCTestCase {
31+
override class func setUp() {
32+
super.setUp()
33+
let bundle = Bundle(for: self)
34+
if let plistPath = bundle.path(forResource: "GoogleService-Info", ofType: "plist"),
35+
let options = FirebaseOptions(contentsOfFile: plistPath) {
36+
FirebaseApp.configure(options: options)
37+
} else {
38+
XCTFail("Could not locate GoogleService-Info.plist.")
39+
}
40+
}
41+
42+
/// Test to retrieve FIS token - makes an actual network call.
43+
func testGetAuthToken() {
44+
guard let testApp = FirebaseApp.app() else {
45+
XCTFail("Default app was not configured.")
46+
return
47+
}
48+
let testModelName = "image-classification"
49+
let modelInfoRetriever = ModelInfoRetriever(
50+
app: testApp,
51+
modelName: testModelName,
52+
defaults: .getTestInstance()
53+
)
54+
let expectation = self.expectation(description: "Wait for FIS auth token.")
55+
modelInfoRetriever.getAuthToken(completion: { result in
56+
switch result {
57+
case let .success(token):
58+
XCTAssertNotNil(token)
59+
case let .failure(error):
60+
XCTFail(error.localizedDescription)
61+
}
62+
expectation.fulfill()
63+
64+
})
65+
waitForExpectations(timeout: 5, handler: nil)
66+
}
67+
68+
/// Test to download model info - makes an actual network call.
69+
func testDownloadModelInfo() {
70+
guard let testApp = FirebaseApp.app() else {
71+
XCTFail("Default app was not configured.")
72+
return
73+
}
74+
let testModelName = "pose-detection"
75+
let modelInfoRetriever = ModelInfoRetriever(
76+
app: testApp,
77+
modelName: testModelName,
78+
defaults: .getTestInstance()
79+
)
80+
let downloadExpectation = expectation(description: "Wait for model info to download.")
81+
modelInfoRetriever.downloadModelInfo(completion: { error in
82+
XCTAssertNil(error)
83+
guard let modelInfo = modelInfoRetriever.modelInfo else {
84+
XCTFail("Empty model info.")
85+
return
86+
}
87+
XCTAssertNotEqual(modelInfo.downloadURL, "")
88+
XCTAssertNotEqual(modelInfo.modelHash, "")
89+
XCTAssertGreaterThan(modelInfo.size, 0)
90+
downloadExpectation.fulfill()
91+
})
92+
93+
waitForExpectations(timeout: 5, handler: nil)
94+
95+
let retrieveExpectation = expectation(description: "Wait for model info to be retrieved.")
96+
modelInfoRetriever.downloadModelInfo(completion: { error in
97+
XCTAssertNil(error)
98+
guard let modelInfo = modelInfoRetriever.modelInfo else {
99+
XCTFail("Empty model info.")
100+
return
101+
}
102+
XCTAssertNotEqual(modelInfo.downloadURL, "")
103+
XCTAssertNotEqual(modelInfo.modelHash, "")
104+
XCTAssertGreaterThan(modelInfo.size, 0)
105+
retrieveExpectation.fulfill()
106+
})
107+
108+
waitForExpectations(timeout: 500, handler: nil)
109+
}
110+
}

FirebaseMLModelDownloader/Tests/Unit/ModelDownloaderTests.swift renamed to FirebaseMLModelDownloader/Tests/Unit/ModelDownloaderUnitTests.swift

Lines changed: 27 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ import XCTest
1616
@testable import FirebaseCore
1717
@testable import FirebaseMLModelDownloader
1818

19+
/// Mock options to configure default Firebase app.
20+
private enum MockOptions {
21+
static let appID = "1:123:ios:123abc"
22+
static let gcmSenderID = "mock-sender-id"
23+
static let projectID = "mock-project-id"
24+
static let apiKey = "ABcdEf-APIKeyWithValidFormat_0123456789"
25+
}
26+
1927
extension UserDefaults {
2028
/// For testing: returns a new cleared instance of user defaults.
2129
static func getTestInstance() -> UserDefaults {
@@ -27,16 +35,23 @@ extension UserDefaults {
2735
}
2836
}
2937

30-
// TODO: break this up into separate unit and integration tests
31-
final class ModelDownloaderTests: XCTestCase {
38+
final class ModelDownloaderUnitTests: XCTestCase {
3239
override class func setUp() {
33-
super.setUp()
34-
FirebaseApp.configure()
40+
let options = FirebaseOptions(
41+
googleAppID: MockOptions.appID,
42+
gcmSenderID: MockOptions.gcmSenderID
43+
)
44+
options.apiKey = MockOptions.apiKey
45+
options.projectID = MockOptions.projectID
46+
FirebaseApp.configure(options: options)
3547
}
3648

3749
/// Unit test for reading and writing to user defaults.
3850
func testUserDefaults() {
39-
let testApp = FirebaseApp.app()!
51+
guard let testApp = FirebaseApp.app() else {
52+
XCTFail("Default app was not configured.")
53+
return
54+
}
4055
let functionName = #function
4156
let testModelName = "\(functionName)-test-model"
4257
let modelInfo = ModelInfo(
@@ -52,74 +67,16 @@ final class ModelDownloaderTests: XCTestCase {
5267
XCTAssertEqual(modelInfo.path, nil)
5368
}
5469

55-
/// Test to retrieve FIS token - makes an actual network call.
56-
// TODO: Move this into a separate integration test and add unit test with mocks.
57-
func testGetAuthToken() {
58-
let testApp = FirebaseApp.app()!
59-
let testModelName = "image-classification"
60-
let modelInfoRetriever = ModelInfoRetriever(
61-
app: testApp,
62-
modelName: testModelName,
63-
defaults: .getTestInstance()
64-
)
65-
let expectation = self.expectation(description: "Wait for FIS auth token.")
66-
modelInfoRetriever.getAuthToken(completion: { result in
67-
switch result {
68-
case let .success(token):
69-
XCTAssertNotNil(token)
70-
case let .failure(error):
71-
XCTFail(error.localizedDescription)
72-
}
73-
expectation.fulfill()
74-
75-
})
76-
waitForExpectations(timeout: 5, handler: nil)
77-
}
78-
79-
/// Test to download model info - makes an actual network call.
80-
// TODO: Move this into a separate integration test and add unit test with mocks.
81-
func testDownloadModelInfo() {
82-
let testApp = FirebaseApp.app()!
83-
let testModelName = "pose-detection"
84-
let modelInfoRetriever = ModelInfoRetriever(
85-
app: testApp,
86-
modelName: testModelName,
87-
defaults: .getTestInstance()
88-
)
89-
let downloadExpectation = expectation(description: "Wait for model info to download.")
90-
modelInfoRetriever.downloadModelInfo(completion: { error in
91-
XCTAssertNil(error)
92-
guard let modelInfo = modelInfoRetriever.modelInfo else {
93-
XCTFail("Empty model info.")
94-
return
95-
}
96-
XCTAssertNotEqual(modelInfo.downloadURL, "")
97-
XCTAssertNotEqual(modelInfo.modelHash, "")
98-
XCTAssertGreaterThan(modelInfo.size, 0)
99-
downloadExpectation.fulfill()
100-
})
101-
102-
waitForExpectations(timeout: 5, handler: nil)
103-
104-
let retrieveExpectation = expectation(description: "Wait for model info to be retrieved.")
105-
modelInfoRetriever.downloadModelInfo(completion: { error in
106-
XCTAssertNil(error)
107-
guard let modelInfo = modelInfoRetriever.modelInfo else {
108-
XCTFail("Empty model info.")
109-
return
110-
}
111-
XCTAssertNotEqual(modelInfo.downloadURL, "")
112-
XCTAssertNotEqual(modelInfo.modelHash, "")
113-
XCTAssertGreaterThan(modelInfo.size, 0)
114-
retrieveExpectation.fulfill()
115-
})
116-
117-
waitForExpectations(timeout: 500, handler: nil)
118-
}
70+
/// Test to download model info.
71+
// TODO: Add unit test with mocks.
72+
func testDownloadModelInfo() {}
11973

12074
/// Unit test to save model info to user defaults.
12175
func testSaveModelInfo() {
122-
let testApp = FirebaseApp.app()!
76+
guard let testApp = FirebaseApp.app() else {
77+
XCTFail("Default app was not configured.")
78+
return
79+
}
12380
let functionName = #function
12481
let testModelName = "\(functionName)-test-model"
12582
let modelInfoRetriever = ModelInfoRetriever(
Binary file not shown.

0 commit comments

Comments
 (0)