Skip to content

Commit ac88a6d

Browse files
authored
Implement firebase-functions-ktx Kotlin library. (#452)
* Initial version of firebase-functions ktx module. * Nullability fixes. * Add functions supporting region param. * Add instruction on how to run the integration tests.
1 parent 50feba3 commit ac88a6d

File tree

12 files changed

+354
-8
lines changed

12 files changed

+354
-8
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
android.enableUnitTestBinaryResources=true
2+

firebase-functions/ktx/ktx.gradle

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2019 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+
plugins {
16+
id 'firebase-library'
17+
id 'kotlin-android'
18+
}
19+
20+
firebaseLibrary {
21+
releaseWith project(':firebase-functions')
22+
publishJavadoc = false
23+
publishSources = true
24+
testLab.enabled = true
25+
}
26+
27+
android {
28+
compileSdkVersion project.targetSdkVersion
29+
defaultConfig {
30+
minSdkVersion project.minSdkVersion
31+
multiDexEnabled true
32+
targetSdkVersion project.targetSdkVersion
33+
versionName version
34+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
35+
}
36+
sourceSets {
37+
main.java.srcDirs += 'src/main/kotlin'
38+
test.java {
39+
srcDir 'src/test/kotlin'
40+
}
41+
androidTest.java.srcDirs += 'src/androidTest/kotlin'
42+
}
43+
testOptions.unitTests.includeAndroidResources = true
44+
}
45+
46+
dependencies {
47+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
48+
49+
implementation project(':firebase-common')
50+
implementation project(':firebase-common:ktx')
51+
implementation project(':firebase-functions')
52+
implementation 'com.android.support:support-annotations:28.0.0'
53+
implementation 'com.google.android.gms:play-services-tasks:16.0.1'
54+
55+
androidTestImplementation 'junit:junit:4.12'
56+
androidTestImplementation "com.google.truth:truth:$googleTruthVersion"
57+
androidTestImplementation 'com.android.support.test:runner:1.0.2'
58+
59+
testImplementation "org.robolectric:robolectric:$robolectricVersion"
60+
testImplementation 'junit:junit:4.12'
61+
testImplementation "com.google.truth:truth:$googleTruthVersion"
62+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.google.firebase.functions.ktx">
3+
<!--Although the *SdkVersion is captured in gradle build files, this is required for non gradle builds-->
4+
<!--<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="23" />-->
5+
<uses-permission android:name="android.permission.INTERNET"/>
6+
<application
7+
android:usesCleartextTraffic="true">
8+
<uses-library android:name="android.test.runner" />
9+
</application>
10+
11+
<instrumentation
12+
android:name="com.google.android.apps.common.testing.testrunner.Google3InstrumentationTestRunner"
13+
android:targetPackage="com.google.firebase.functions.ktx" />
14+
</manifest>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Running integration tests
2+
3+
To run these integration tests, please deploy the required functions as
4+
described in `../../../src/androidTest/backend/README.md`
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2019 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+
package com.google.firebase.functions.ktx
16+
17+
import com.google.common.truth.Truth.assertThat
18+
import com.google.firebase.FirebaseApp
19+
import com.google.firebase.ktx.Firebase
20+
import com.google.firebase.ktx.app
21+
import com.google.firebase.ktx.initialize
22+
import com.google.android.gms.tasks.Tasks
23+
import org.junit.AfterClass
24+
import org.junit.BeforeClass
25+
import org.junit.Test
26+
import org.junit.runner.RunWith
27+
import android.support.test.InstrumentationRegistry
28+
import android.support.test.runner.AndroidJUnit4
29+
30+
const val APP_ID = "APP_ID"
31+
const val API_KEY = "API_KEY"
32+
33+
@RunWith(AndroidJUnit4::class)
34+
class CallTests {
35+
companion object {
36+
lateinit var app: FirebaseApp
37+
38+
@BeforeClass @JvmStatic fun setup() {
39+
app = Firebase.initialize(InstrumentationRegistry.getContext())!!
40+
}
41+
42+
@AfterClass @JvmStatic fun cleanup() {
43+
app.delete()
44+
}
45+
}
46+
47+
@Test
48+
fun testDataCall() {
49+
val functions = Firebase.functions(app)
50+
val input = hashMapOf(
51+
"bool" to true,
52+
"int" to 2,
53+
"long" to 3L,
54+
"string" to "four",
55+
"array" to listOf(5, 6),
56+
"null" to null
57+
)
58+
59+
var function = functions.getHttpsCallable("dataTest")
60+
val actual = Tasks.await(function.call(input)).getData()
61+
62+
assertThat(actual).isInstanceOf(Map::class.java)
63+
@Suppress("UNCHECKED_CAST")
64+
val map = actual as Map<String, *>
65+
assertThat(map["message"]).isEqualTo("stub response")
66+
assertThat(map["code"]).isEqualTo(42)
67+
assertThat(map["long"]).isEqualTo(420L)
68+
}
69+
70+
@Test
71+
fun testNullDataCall() {
72+
val functions = Firebase.functions(app)
73+
var function = functions.getHttpsCallable("nullTest")
74+
val actual = Tasks.await(function.call(null)).getData()
75+
76+
assertThat(actual).isNull()
77+
}
78+
79+
@Test
80+
fun testEmptyDataCall() {
81+
val functions = Firebase.functions(app)
82+
var function = functions.getHttpsCallable("nullTest")
83+
val actual = Tasks.await(function.call()).getData()
84+
85+
assertThat(actual).isNull()
86+
}
87+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.google.firebase.functions.ktx">
4+
<!--Although the *SdkVersion is captured in gradle build files, this is required for non gradle builds-->
5+
<!--<uses-sdk android:minSdkVersion="14"/>-->
6+
<application>
7+
<service android:name="com.google.firebase.components.ComponentDiscoveryService" android:exported="false">
8+
<meta-data android:name="com.google.firebase.components:com.google.firebase.functions.ktx.FirebaseFunctionsKtxRegistrar"
9+
android:value="com.google.firebase.components.ComponentRegistrar" />
10+
</service>
11+
</application>
12+
</manifest>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2019 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+
package com.google.firebase.functions.ktx
16+
17+
import android.support.annotation.Keep
18+
import com.google.firebase.FirebaseApp
19+
import com.google.firebase.functions.FirebaseFunctions
20+
import com.google.firebase.components.Component
21+
import com.google.firebase.components.ComponentRegistrar
22+
23+
import com.google.firebase.ktx.Firebase
24+
import com.google.firebase.platforminfo.LibraryVersionComponent
25+
26+
/** Returns the [FirebaseFunctions] instance of the default [FirebaseApp]. */
27+
val Firebase.functions: FirebaseFunctions
28+
get() = FirebaseFunctions.getInstance()
29+
30+
/** Returns the [FirebaseFunctions] instance of a given [region]. */
31+
fun Firebase.functions(region: String): FirebaseFunctions = FirebaseFunctions.getInstance(region)
32+
33+
/** Returns the [FirebaseFunctions] instance of a given [FirebaseApp]. */
34+
fun Firebase.functions(app: FirebaseApp): FirebaseFunctions = FirebaseFunctions.getInstance(app)
35+
36+
/** Returns the [FirebaseFunctions] instance of a given [FirebaseApp] and [region]. */
37+
fun Firebase.functions(app: FirebaseApp, region: String): FirebaseFunctions =
38+
FirebaseFunctions.getInstance(app, region)
39+
40+
internal const val LIBRARY_NAME: String = "fire-fun-ktx"
41+
42+
/** @suppress */
43+
@Keep
44+
class FirebaseFunctionsKtxRegistrar : ComponentRegistrar {
45+
override fun getComponents(): List<Component<*>> =
46+
listOf(LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME))
47+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright 2019 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+
package com.google.firebase.functions.ktx
16+
17+
import com.google.common.truth.Truth.assertThat
18+
import com.google.firebase.FirebaseApp
19+
import com.google.firebase.FirebaseOptions
20+
import com.google.firebase.functions.FirebaseFunctions
21+
import com.google.firebase.ktx.Firebase
22+
import com.google.firebase.ktx.app
23+
import com.google.firebase.ktx.initialize
24+
import com.google.firebase.platforminfo.UserAgentPublisher
25+
import org.junit.After
26+
import org.junit.Before
27+
import org.junit.Test
28+
import org.junit.runner.RunWith
29+
import org.robolectric.RobolectricTestRunner
30+
import org.robolectric.RuntimeEnvironment
31+
32+
const val APP_ID = "APP_ID"
33+
const val API_KEY = "API_KEY"
34+
35+
const val EXISTING_APP = "existing"
36+
37+
abstract class BaseTestCase {
38+
@Before
39+
fun setUp() {
40+
Firebase.initialize(
41+
RuntimeEnvironment.application,
42+
FirebaseOptions.Builder()
43+
.setApplicationId(APP_ID)
44+
.setApiKey(API_KEY)
45+
.setProjectId("123")
46+
.build()
47+
)
48+
49+
Firebase.initialize(
50+
RuntimeEnvironment.application,
51+
FirebaseOptions.Builder()
52+
.setApplicationId(APP_ID)
53+
.setApiKey(API_KEY)
54+
.setProjectId("123")
55+
.build(),
56+
EXISTING_APP
57+
)
58+
}
59+
60+
@After
61+
fun cleanUp() {
62+
FirebaseApp.clearInstancesForTest()
63+
}
64+
}
65+
66+
@RunWith(RobolectricTestRunner::class)
67+
class FunctionsTests : BaseTestCase() {
68+
69+
@Test
70+
fun `functions should delegate to FirebaseFunctions#getInstance()`() {
71+
assertThat(Firebase.functions).isSameAs(FirebaseFunctions.getInstance())
72+
}
73+
74+
@Test
75+
fun `FirebaseApp#functions should delegate to FirebaseFunctions#getInstance(FirebaseApp)`() {
76+
val app = Firebase.app(EXISTING_APP)
77+
assertThat(Firebase.functions(app)).isSameAs(FirebaseFunctions.getInstance(app))
78+
}
79+
80+
@Test
81+
fun `Firebase#functions should delegate to FirebaseFunctions#getInstance(region)`() {
82+
val region = "valid_region"
83+
assertThat(Firebase.functions(region)).isSameAs(FirebaseFunctions.getInstance(region))
84+
}
85+
86+
@Test
87+
fun `Firebase#functions should delegate to FirebaseFunctions#getInstance(FirebaseApp, region)`() {
88+
val app = Firebase.app(EXISTING_APP)
89+
val region = "valid_region"
90+
assertThat(Firebase.functions(app, region)).isSameAs(FirebaseFunctions.getInstance(app, region))
91+
}
92+
}
93+
94+
@RunWith(RobolectricTestRunner::class)
95+
class LibraryVersionTest : BaseTestCase() {
96+
@Test
97+
fun `library version should be registered with runtime`() {
98+
val publisher = Firebase.app.get(UserAgentPublisher::class.java)
99+
assertThat(publisher.userAgent).contains(LIBRARY_NAME)
100+
}
101+
}

0 commit comments

Comments
 (0)