Skip to content

Commit fa4800f

Browse files
Merge branch 'develop'
2 parents 723c42e + 1c9a672 commit fa4800f

File tree

51 files changed

+1117
-516
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1117
-516
lines changed

.github/workflows/app-distribute.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
name: demo-app-release
2929
path: demo-app/build/outputs/apk/demo-app/release/
3030
- name: Upload artifact to Firebase App Distribution
31-
uses: wzieba/Firebase-Distribution-Github-Action@v1.5.0
31+
uses: wzieba/Firebase-Distribution-Github-Action@v1.7.1
3232
with:
3333
appId: ${{secrets.FIREBASE_DOGFOODING_SAMPLE_APP_ID}}
3434
serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}

.github/workflows/e2e-test-cron.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jobs:
3939
fail-fast: false
4040
env:
4141
ANDROID_API_LEVEL: ${{ matrix.android_api_level }}
42+
STREAM_SDK_TEST_APP: ${{ vars.STREAM_SDK_TEST_APP }}
4243
steps:
4344
- uses: actions/[email protected]
4445
- uses: actions/[email protected]

.github/workflows/e2e-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ jobs:
5151
env:
5252
ANDROID_API_LEVEL: 34
5353
LAUNCH_ID: ${{ needs.allure_testops_launch.outputs.launch_id }}
54+
STREAM_SDK_TEST_APP: ${{ vars.STREAM_SDK_TEST_APP }}
5455
steps:
5556
- uses: actions/[email protected]
5657
- uses: actions/[email protected]

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
<img src=".readme-assets/Github-Graphic-Android.jpg" alt="Stream Video for Android Header image" style="box-shadow: 0 3px 10px rgb(0 0 0 / 0.2); border-radius: 1rem" />
44

55
<p align="center">
6-
<a href="https://github.com/GetStream/stream-video-android/actions"><img src="https://github.com/GetStream/stream-video-android/workflows/App%20Distribute%20CI/badge.svg" /></a>
6+
<a href="https://github.com/GetStream/stream-video-android/actions/workflows/artifact-upload.yaml"><img src="https://github.com/GetStream/stream-video-android/actions/workflows/artifact-upload.yaml/badge.svg" /></a>
77
<a href="https://android-arsenal.com/api?level=24"><img alt="API" src="https://img.shields.io/badge/API-24%2B-brightgreen.svg?style=flat"/></a>
88
<a href="https://search.maven.org/search?q=stream-video-android"><img src="https://img.shields.io/maven-central/v/io.getstream/stream-video-android-core.svg?label=Maven%20Central" /></a>
99
</p>
1010

1111
<div align="center">
1212

1313
![stream-video-android-core](https://img.shields.io/badge/stream--video--android--core-11.21%20MB-lightgreen)
14-
![stream-video-android-ui-xml](https://img.shields.io/badge/stream--video--android--ui--xml-5.66%20MB-lightgreen)
15-
![stream-video-android-ui-compose](https://img.shields.io/badge/stream--video--android--ui--compose-5.84%20MB-lightgreen)
14+
![stream-video-android-ui-xml](https://img.shields.io/badge/stream--video--android--ui--xml-5.67%20MB-lightgreen)
15+
![stream-video-android-ui-compose](https://img.shields.io/badge/stream--video--android--ui--compose-5.82%20MB-lightgreen)
1616

1717
</div>
1818

buildSrc/src/main/kotlin/io/getstream/video/android/Configuration.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ object Configuration {
55
const val targetSdk = 35
66
const val minSdk = 24
77
const val majorVersion = 1
8-
const val minorVersion = 5
8+
const val minorVersion = 6
99
const val patchVersion = 0
1010
const val versionName = "$majorVersion.$minorVersion.$patchVersion"
11-
const val versionCode = 55
11+
const val versionCode = 56
1212
const val snapshotVersionName = "$majorVersion.$minorVersion.${patchVersion + 1}-SNAPSHOT"
1313
const val artifactGroup = "io.getstream"
14-
const val streamVideoCallGooglePlayVersion = "1.5.0"
14+
const val streamVideoCallGooglePlayVersion = "1.6.0"
1515
const val streamWebRtcVersionName = "1.3.6"
1616
}

demo-app/src/androidTestE2etestingDebug/kotlin/io/getstream/video/android/pages/CallPage.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class CallPage {
6666
val cameraDisabled = By.res("Stream_ParticipantsListUserCamera_Enabled_false")
6767
val microphoneEnabled = By.res("Stream_ParticipantsListUserMicrophone_Enabled_true")
6868
val microphoneDisabled = By.res("Stream_ParticipantsListUserMicrophone_Enabled_false")
69-
val closeButton = LobbyPage.closeButton
69+
val closeButton = By.res("Stream_ParticipantsListCloseButton")
7070
}
7171
}
7272

demo-app/src/androidTestE2etestingDebug/kotlin/io/getstream/video/android/pages/LobbyPage.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import androidx.test.uiautomator.BySelector
2222
class LobbyPage {
2323

2424
companion object {
25-
val closeButton = By.res("Stream_CloseButton")
25+
val closeButton = By.res("Stream_LobbyCloseButton")
2626
val cameraEnabledToggle = By.res("Stream_CameraToggle_Enabled_true")
2727
val cameraDisabledToggle = By.res("Stream_CameraToggle_Enabled_false")
2828
val microphoneEnabledToggle = By.res("Stream_MicrophoneToggle_Enabled_true")

demo-app/src/androidTestE2etestingDebug/kotlin/io/getstream/video/android/robots/ParticipantRobot.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import org.json.JSONObject
2828
import org.junit.Assert.fail
2929

3030
class ParticipantRobot(
31-
val debug: Boolean = false,
31+
val testName: String,
32+
val headless: Boolean = true,
3233
val record: Boolean = false,
3334
val logs: Boolean = true,
3435
) {
@@ -58,6 +59,7 @@ class ParticipantRobot(
5859
}
5960

6061
private enum class Config(val value: String) {
62+
TEST_NAME("test-name"),
6163
CALL_ID("call-id"),
6264
USER_COUNT("user-count"),
6365
MESSAGE_COUNT("message-count"),
@@ -98,11 +100,12 @@ class ParticipantRobot(
98100
async: Boolean = true,
99101
) {
100102
val params = mutableMapOf<String, Any>()
103+
params[Config.TEST_NAME.value] = testName
101104
params[Config.CALL_ID.value] = callId
102105
params[Config.USER_COUNT.value] = userCount
103106
messageCount?.let { params[Config.MESSAGE_COUNT.value] = it }
104107
params[Config.CALL_DURATION.value] = callDuration
105-
params[DebugActions.SHOW_WINDOW.value] = debug
108+
params[DebugActions.SHOW_WINDOW.value] = !headless
106109
params[DebugActions.PRINT_CONSOLE_LOGS.value] = logs
107110
params[DebugActions.RECORD_SESSION.value] = record
108111

demo-app/src/androidTestE2etestingDebug/kotlin/io/getstream/video/android/robots/UserRobot.kt

Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import io.getstream.video.android.uiautomator.defaultTimeout
2727
import io.getstream.video.android.uiautomator.device
2828
import io.getstream.video.android.uiautomator.findObject
2929
import io.getstream.video.android.uiautomator.findObjects
30+
import io.getstream.video.android.uiautomator.seconds
3031
import io.getstream.video.android.uiautomator.typeText
32+
import io.getstream.video.android.uiautomator.waitForText
3133
import io.getstream.video.android.uiautomator.waitToAppear
3234

3335
class UserRobot {
@@ -55,9 +57,20 @@ class UserRobot {
5557
return this
5658
}
5759

58-
fun joinCall(callId: String? = null, camera: Boolean = true, mic: Boolean = true): UserRobot {
60+
fun joinCall(
61+
callId: String? = null,
62+
camera: UserControls? = null,
63+
microphone: UserControls? = null,
64+
): UserRobot {
5965
enterLobby(callId)
60-
joinCallFromLobby(camera = camera, mic = mic)
66+
if (camera != null) {
67+
camera(camera, hard = true)
68+
}
69+
if (microphone != null) {
70+
microphone(microphone, hard = true)
71+
}
72+
joinCallFromLobby()
73+
waitForCallToStart()
6174
return this
6275
}
6376

@@ -66,29 +79,20 @@ class UserRobot {
6679
CallDetailsPage.callIdInputField.waitToAppear().typeText(callId)
6780
}
6881
CallDetailsPage.joinCallButton.waitToAppear().click()
82+
waitForLobbyToOpen()
6983
return this
7084
}
7185

7286
// LobbyPage actions
7387

74-
fun joinCallFromLobby(camera: Boolean = true, mic: Boolean = true): UserRobot {
75-
LobbyPage.joinCallButton.waitToAppear()
76-
val cameraIsEnabled = LobbyPage.cameraEnabledToggle.findObjects().isNotEmpty()
77-
val micIsEnabled = LobbyPage.microphoneEnabledToggle.findObjects().isNotEmpty()
78-
79-
if (camera && !cameraIsEnabled) {
80-
LobbyPage.cameraDisabledToggle.findObject().click()
81-
} else if (!camera && cameraIsEnabled) {
82-
LobbyPage.cameraEnabledToggle.findObject().click()
83-
}
84-
85-
if (mic && !micIsEnabled) {
86-
LobbyPage.microphoneDisabledToggle.findObject().click()
87-
} else if (!mic && micIsEnabled) {
88-
LobbyPage.microphoneEnabledToggle.findObject().click()
89-
}
90-
88+
fun joinCallFromLobby(): UserRobot {
9189
LobbyPage.joinCallButton.findObject().click()
90+
waitForCallToStart()
91+
return this
92+
}
93+
94+
private fun waitForLobbyToOpen(): UserRobot {
95+
LobbyPage.closeButton.waitToAppear()
9296
return this
9397
}
9498

@@ -107,34 +111,79 @@ class UserRobot {
107111
return this
108112
}
109113

110-
fun camera(action: UserControls): UserRobot {
111-
CallPage.callInfoView.waitToAppear()
114+
fun camera(
115+
action: UserControls,
116+
hard: Boolean = false, // When true, hard-toggles to ensure server state syncs properly
117+
): UserRobot {
112118
val isEnabled = CallPage.cameraEnabledToggle.findObjects().isNotEmpty()
113119

114-
if (action == UserControls.ENABLE && !isEnabled) {
115-
CallPage.cameraDisabledToggle.findObject().click()
116-
} else if (action == UserControls.DISABLE && isEnabled) {
117-
CallPage.cameraEnabledToggle.findObject().click()
120+
when {
121+
hard -> when (action) {
122+
UserControls.ENABLE -> {
123+
if (isEnabled) {
124+
CallPage.cameraEnabledToggle.findObject().click()
125+
CallPage.cameraDisabledToggle.waitToAppear().click()
126+
} else {
127+
CallPage.cameraDisabledToggle.findObject().click()
128+
}
129+
}
130+
UserControls.DISABLE -> {
131+
if (isEnabled) {
132+
CallPage.cameraEnabledToggle.findObject().click()
133+
} else {
134+
CallPage.cameraDisabledToggle.findObject().click()
135+
CallPage.cameraEnabledToggle.waitToAppear().click()
136+
}
137+
}
138+
}
139+
action == UserControls.ENABLE && !isEnabled -> {
140+
CallPage.cameraDisabledToggle.findObject().click()
141+
}
142+
action == UserControls.DISABLE && isEnabled -> {
143+
CallPage.cameraEnabledToggle.findObject().click()
144+
}
118145
}
119146

120147
return this
121148
}
122149

123-
fun microphone(action: UserControls): UserRobot {
124-
CallPage.callInfoView.waitToAppear()
150+
fun microphone(
151+
action: UserControls,
152+
hard: Boolean = false, // When true, hard-toggles to ensure server state syncs properly
153+
): UserRobot {
125154
val isEnabled = CallPage.microphoneEnabledToggle.findObjects().isNotEmpty()
126155

127-
if (action == UserControls.ENABLE && !isEnabled) {
128-
CallPage.microphoneDisabledToggle.findObject().click()
129-
} else if (action == UserControls.DISABLE && isEnabled) {
130-
CallPage.microphoneEnabledToggle.findObject().click()
156+
when {
157+
hard -> when (action) {
158+
UserControls.ENABLE -> {
159+
if (isEnabled) {
160+
CallPage.microphoneEnabledToggle.findObject().click()
161+
CallPage.microphoneDisabledToggle.waitToAppear().click()
162+
} else {
163+
CallPage.microphoneDisabledToggle.findObject().click()
164+
}
165+
}
166+
UserControls.DISABLE -> {
167+
if (isEnabled) {
168+
CallPage.microphoneEnabledToggle.findObject().click()
169+
} else {
170+
CallPage.microphoneDisabledToggle.findObject().click()
171+
CallPage.microphoneEnabledToggle.waitToAppear().click()
172+
}
173+
}
174+
}
175+
action == UserControls.ENABLE && !isEnabled -> {
176+
CallPage.microphoneDisabledToggle.findObject().click()
177+
}
178+
action == UserControls.DISABLE && isEnabled -> {
179+
CallPage.microphoneEnabledToggle.findObject().click()
180+
}
131181
}
132182

133183
return this
134184
}
135185

136186
fun settings(action: UserControls): UserRobot {
137-
CallPage.callInfoView.waitToAppear()
138187
val isEnabled = CallPage.callSettingsOpenToggle.findObjects().isNotEmpty()
139188

140189
if (action == UserControls.ENABLE && !isEnabled) {
@@ -175,6 +224,20 @@ class UserRobot {
175224
CallPage.cornerDraggableView.waitToAppear().swipe(direction, 1.0f)
176225
return this
177226
}
227+
228+
fun waitForParticipantsToJoin(count: Int, timeOutMillis: Long = 30.seconds): UserRobot {
229+
val user = 1
230+
val participants = user + count
231+
CallPage.participantsCountBadge
232+
.waitToAppear()
233+
.waitForText(expectedText = participants.toString(), timeOutMillis = timeOutMillis)
234+
return this
235+
}
236+
237+
private fun waitForCallToStart(): UserRobot {
238+
CallPage.callInfoView.waitToAppear()
239+
return this
240+
}
178241
}
179242

180243
enum class UserControls {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2014-2024 Stream.io Inc. All rights reserved.
3+
*
4+
* Licensed under the Stream License;
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://github.com/GetStream/stream-video-android/blob/main/LICENSE
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.getstream.video.android.robots
18+
19+
import io.getstream.video.android.pages.CallPage
20+
import io.getstream.video.android.uiautomator.isDisplayed
21+
import io.getstream.video.android.uiautomator.waitForText
22+
import io.getstream.video.android.uiautomator.waitToAppear
23+
import org.junit.Assert.assertTrue
24+
25+
fun UserRobot.assertCallControls(microphone: Boolean, camera: Boolean): UserRobot {
26+
assertTrue(CallPage.callSettingsClosedToggle.waitToAppear().isDisplayed())
27+
assertTrue(CallPage.hangUpButton.isDisplayed())
28+
assertTrue(CallPage.chatButton.isDisplayed())
29+
assertTrue(CallPage.cameraPositionToggleFront.isDisplayed())
30+
31+
if (microphone) {
32+
assertTrue(CallPage.microphoneEnabledToggle.isDisplayed())
33+
} else {
34+
assertTrue(CallPage.microphoneDisabledToggle.isDisplayed())
35+
}
36+
37+
if (camera) {
38+
assertTrue(CallPage.cameraEnabledToggle.isDisplayed())
39+
} else {
40+
assertTrue(CallPage.cameraDisabledToggle.isDisplayed())
41+
}
42+
43+
return this
44+
}
45+
46+
fun UserRobot.assertParticipantsCountOnCall(count: Int): UserRobot {
47+
val user = 1
48+
val participants = user + count
49+
CallPage.participantsCountBadge
50+
.waitToAppear()
51+
.waitForText(expectedText = participants.toString())
52+
return this
53+
}

0 commit comments

Comments
 (0)