From 8824da87f3193da6c2027a3d48748df8faa13d90 Mon Sep 17 00:00:00 2001 From: pedro Date: Mon, 18 Sep 2023 20:28:17 +0200 Subject: [PATCH] fix bitratemanager tests and add TimeUtils to rtmp --- .../java/com/pedro/rtmp/amf/v0/AmfDate.kt | 3 +- .../com/pedro/rtmp/rtmp/CommandsManager.kt | 7 +- .../java/com/pedro/rtmp/rtmp/Handshake.kt | 3 +- .../java/com/pedro/rtmp/rtmp/RtmpClient.kt | 5 +- .../com/pedro/rtmp/utils/BitrateManager.kt | 6 +- .../java/com/pedro/rtmp/utils/TimeUtils.kt | 29 +++++++ .../rtmp/utils/socket/TcpTunneledSocket.kt | 5 +- .../java/com/pedro/rtmp/MainDispatcherRule.kt | 23 ++++++ rtmp/src/test/java/com/pedro/rtmp/Utils.kt | 38 +++++++++ .../pedro/rtmp/utils/BitrateManagerTest.kt | 53 ++++++++---- .../java/com/pedro/rtsp/MainDispatcherRule.kt | 23 ++++++ .../pedro/rtsp/utils/BitrateManagerTest.kt | 55 +++++++++---- srt/build.gradle | 1 + .../com/pedro/srt/utils/BitrateManager.kt | 6 +- .../java/com/pedro/srt/utils/TimeUtils.kt | 3 + .../java/com/pedro/srt/BitrateManagerTest.kt | 58 -------------- .../java/com/pedro/srt/MainDispatcherRule.kt | 23 ++++++ srt/src/test/java/com/pedro/srt/Utils.kt | 2 +- .../java/com/pedro/srt/mpeg2ts/PesTest.kt | 3 +- .../java/com/pedro/srt/mpeg2ts/PsiTest.kt | 7 +- .../com/pedro/srt/utils/BitrateManagerTest.kt | 80 +++++++++++++++++++ 21 files changed, 325 insertions(+), 108 deletions(-) create mode 100644 rtmp/src/main/java/com/pedro/rtmp/utils/TimeUtils.kt create mode 100644 rtmp/src/test/java/com/pedro/rtmp/MainDispatcherRule.kt create mode 100644 rtmp/src/test/java/com/pedro/rtmp/Utils.kt create mode 100644 rtsp/src/test/java/com/pedro/rtsp/MainDispatcherRule.kt delete mode 100644 srt/src/test/java/com/pedro/srt/BitrateManagerTest.kt create mode 100644 srt/src/test/java/com/pedro/srt/MainDispatcherRule.kt create mode 100644 srt/src/test/java/com/pedro/srt/utils/BitrateManagerTest.kt diff --git a/rtmp/src/main/java/com/pedro/rtmp/amf/v0/AmfDate.kt b/rtmp/src/main/java/com/pedro/rtmp/amf/v0/AmfDate.kt index 0cf2c2e70..d49aae73e 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/amf/v0/AmfDate.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/amf/v0/AmfDate.kt @@ -16,6 +16,7 @@ package com.pedro.rtmp.amf.v0 +import com.pedro.rtmp.utils.TimeUtils import com.pedro.rtmp.utils.readUntil import java.io.IOException import java.io.InputStream @@ -28,7 +29,7 @@ import java.nio.ByteBuffer * milliseconds from 1st Jan 1970 in UTC time zone. * timeZone value is a reserved value that should be 0x0000 */ -class AmfDate(var date: Double = System.currentTimeMillis().toDouble()): AmfData() { +class AmfDate(var date: Double = TimeUtils.getCurrentTimeMillis().toDouble()): AmfData() { @Throws(IOException::class) override fun readBody(input: InputStream) { diff --git a/rtmp/src/main/java/com/pedro/rtmp/rtmp/CommandsManager.kt b/rtmp/src/main/java/com/pedro/rtmp/rtmp/CommandsManager.kt index 4f0e76f4c..cff396006 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/rtmp/CommandsManager.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/rtmp/CommandsManager.kt @@ -25,6 +25,7 @@ import com.pedro.rtmp.rtmp.message.control.Type import com.pedro.rtmp.rtmp.message.control.UserControl import com.pedro.rtmp.utils.CommandSessionHistory import com.pedro.rtmp.utils.RtmpConfig +import com.pedro.rtmp.utils.TimeUtils import com.pedro.rtmp.utils.socket.RtmpSocket import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -80,7 +81,7 @@ abstract class CommandsManager { } protected fun getCurrentTimestamp(): Int { - return (System.currentTimeMillis() / 1000 - timestamp).toInt() + return (TimeUtils.getCurrentTimeMillis() / 1000 - timestamp).toInt() } @Throws(IOException::class) @@ -182,7 +183,7 @@ abstract class CommandsManager { writeSync.withLock { val output = socket.getOutStream() if (akamaiTs) { - flvPacket.timeStamp = ((System.nanoTime() / 1000 - startTs) / 1000) + flvPacket.timeStamp = ((TimeUtils.getCurrentTimeNano() / 1000 - startTs) / 1000) } val video = Video(flvPacket, streamId) video.writeHeader(output) @@ -197,7 +198,7 @@ abstract class CommandsManager { writeSync.withLock { val output = socket.getOutStream() if (akamaiTs) { - flvPacket.timeStamp = ((System.nanoTime() / 1000 - startTs) / 1000) + flvPacket.timeStamp = ((TimeUtils.getCurrentTimeNano() / 1000 - startTs) / 1000) } val audio = Audio(flvPacket, streamId) audio.writeHeader(output) diff --git a/rtmp/src/main/java/com/pedro/rtmp/rtmp/Handshake.kt b/rtmp/src/main/java/com/pedro/rtmp/rtmp/Handshake.kt index 856a739a2..fec7ad636 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/rtmp/Handshake.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/rtmp/Handshake.kt @@ -17,6 +17,7 @@ package com.pedro.rtmp.rtmp import android.util.Log +import com.pedro.rtmp.utils.TimeUtils import com.pedro.rtmp.utils.readUntil import com.pedro.rtmp.utils.socket.RtmpSocket import java.io.IOException @@ -102,7 +103,7 @@ class Handshake { Log.i(TAG, "writing C1") val c1 = ByteArray(handshakeSize) - timestampC1 = (System.currentTimeMillis() / 1000).toInt() + timestampC1 = (TimeUtils.getCurrentTimeMillis() / 1000).toInt() Log.i(TAG, "writing time $timestampC1 to c1") val timestampData = ByteArray(4) timestampData[0] = (timestampC1 ushr 24).toByte() diff --git a/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt b/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt index 2717f0688..f298d8a57 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt @@ -27,6 +27,7 @@ import com.pedro.rtmp.rtmp.message.control.UserControl import com.pedro.rtmp.utils.AuthUtil import com.pedro.rtmp.utils.ConnectCheckerRtmp import com.pedro.rtmp.utils.RtmpConfig +import com.pedro.rtmp.utils.TimeUtils import com.pedro.rtmp.utils.onMainThread import com.pedro.rtmp.utils.socket.RtmpSocket import com.pedro.rtmp.utils.socket.TcpSocket @@ -304,11 +305,11 @@ class RtmpClient(private val connectCheckerRtmp: ConnectCheckerRtmp) { this.socket = socket socket.connect() if (!socket.isConnected()) return false - val timestamp = System.currentTimeMillis() / 1000 + val timestamp = TimeUtils.getCurrentTimeMillis() / 1000 val handshake = Handshake() if (!handshake.sendHandshake(socket)) return false commandsManager.timestamp = timestamp.toInt() - commandsManager.startTs = System.nanoTime() / 1000 + commandsManager.startTs = TimeUtils.getCurrentTimeNano() / 1000 return true } diff --git a/rtmp/src/main/java/com/pedro/rtmp/utils/BitrateManager.kt b/rtmp/src/main/java/com/pedro/rtmp/utils/BitrateManager.kt index 61127f4e0..1a8affab1 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/utils/BitrateManager.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/utils/BitrateManager.kt @@ -24,16 +24,16 @@ package com.pedro.rtmp.utils open class BitrateManager(private val connectCheckerRtmp: ConnectCheckerRtmp) { private var bitrate: Long = 0 - private var timeStamp = System.currentTimeMillis() + private var timeStamp = TimeUtils.getCurrentTimeMillis() suspend fun calculateBitrate(size: Long) { bitrate += size - val timeDiff = System.currentTimeMillis() - timeStamp + val timeDiff = TimeUtils.getCurrentTimeMillis() - timeStamp if (timeDiff >= 1000) { onMainThread { connectCheckerRtmp.onNewBitrateRtmp((bitrate / (timeDiff / 1000f)).toLong()) } - timeStamp = System.currentTimeMillis() + timeStamp = TimeUtils.getCurrentTimeMillis() bitrate = 0 } } diff --git a/rtmp/src/main/java/com/pedro/rtmp/utils/TimeUtils.kt b/rtmp/src/main/java/com/pedro/rtmp/utils/TimeUtils.kt new file mode 100644 index 000000000..9aaeea3ca --- /dev/null +++ b/rtmp/src/main/java/com/pedro/rtmp/utils/TimeUtils.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 pedroSG94. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pedro.rtmp.utils + +/** + * Created by pedro on 30/8/23. + */ +object TimeUtils { + + @JvmStatic + fun getCurrentTimeMillis(): Long = System.currentTimeMillis() + + @JvmStatic + fun getCurrentTimeNano(): Long = System.nanoTime() +} \ No newline at end of file diff --git a/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpTunneledSocket.kt b/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpTunneledSocket.kt index e3fb954b3..fba10a870 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpTunneledSocket.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpTunneledSocket.kt @@ -17,6 +17,7 @@ package com.pedro.rtmp.utils.socket import android.util.Log +import com.pedro.rtmp.utils.TimeUtils import java.io.* import java.net.HttpURLConnection import java.net.SocketTimeoutException @@ -49,12 +50,12 @@ class TcpTunneledSocket(private val host: String, private val port: Int, private override fun getInputStream(): InputStream { synchronized(sync) { - val start = System.currentTimeMillis() + val start = TimeUtils.getCurrentTimeMillis() while (input.available() <= 1 && connected) { val i = index.addAndGet(1) val bytes = requestRead("idle/$connectionId/$i", secured) input = ByteArrayInputStream(bytes, 1, bytes.size) - if (System.currentTimeMillis() - start >= timeout) { + if (TimeUtils.getCurrentTimeMillis() - start >= timeout) { throw SocketTimeoutException("couldn't receive a valid packet") } } diff --git a/rtmp/src/test/java/com/pedro/rtmp/MainDispatcherRule.kt b/rtmp/src/test/java/com/pedro/rtmp/MainDispatcherRule.kt new file mode 100644 index 000000000..aef4ba6e4 --- /dev/null +++ b/rtmp/src/test/java/com/pedro/rtmp/MainDispatcherRule.kt @@ -0,0 +1,23 @@ +package com.pedro.rtmp + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +@OptIn(ExperimentalCoroutinesApi::class) +class MainDispatcherRule( + private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() +) : TestWatcher() { + override fun starting(description: Description) { + Dispatchers.setMain(testDispatcher) + } + + override fun finished(description: Description) { + Dispatchers.resetMain() + } +} \ No newline at end of file diff --git a/rtmp/src/test/java/com/pedro/rtmp/Utils.kt b/rtmp/src/test/java/com/pedro/rtmp/Utils.kt new file mode 100644 index 000000000..9a10e2fcc --- /dev/null +++ b/rtmp/src/test/java/com/pedro/rtmp/Utils.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 pedroSG94. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pedro.rtmp + +import org.mockito.MockedStatic + +/** + * Created by pedro on 1/9/23. + */ +object Utils { + + suspend fun useStatics(statics: List>, callback: suspend () -> Unit) { + val list = statics.toMutableList() + if (list.isEmpty()) callback() + else if (list.size == 1) { + list[0].use { + callback() + } + } else { + val value = list.removeAt(0) + value.use { useStatics(list, callback) } + } + } +} diff --git a/rtmp/src/test/java/com/pedro/rtmp/utils/BitrateManagerTest.kt b/rtmp/src/test/java/com/pedro/rtmp/utils/BitrateManagerTest.kt index 97b80a74b..031b5c8ca 100644 --- a/rtmp/src/test/java/com/pedro/rtmp/utils/BitrateManagerTest.kt +++ b/rtmp/src/test/java/com/pedro/rtmp/utils/BitrateManagerTest.kt @@ -16,10 +16,17 @@ package com.pedro.rtmp.utils +import com.pedro.rtmp.MainDispatcherRule +import com.pedro.rtmp.Utils +import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.times @@ -32,25 +39,41 @@ import org.mockito.kotlin.verify @RunWith(MockitoJUnitRunner::class) class BitrateManagerTest { + @get:Rule + val mainDispatcherRule = MainDispatcherRule() @Mock private lateinit var connectCheckerRtmp: ConnectCheckerRtmp + private val timeUtilsMocked = Mockito.mockStatic(TimeUtils::class.java) + private var fakeTime = 7502849023L + + @Before + fun setup() { + timeUtilsMocked.`when`(TimeUtils::getCurrentTimeMillis).then { fakeTime } + } + + @After + fun teardown() { + fakeTime = 7502849023L + } @Test - fun `WHEN set multiple values THEN return total of values each second`() { - val bitrateManager = BitrateManager(connectCheckerRtmp) - val fakeValues = arrayOf(100L, 200L, 300L, 400L, 500L) - var expectedResult = 0L - fakeValues.forEach { - bitrateManager.calculateBitrate(it) - expectedResult += it + fun `WHEN set multiple values THEN return total of values each second`() = runTest { + Utils.useStatics(listOf(timeUtilsMocked)) { + val bitrateManager = BitrateManager(connectCheckerRtmp) + val fakeValues = arrayOf(100L, 200L, 300L, 400L, 500L) + var expectedResult = 0L + fakeValues.forEach { + bitrateManager.calculateBitrate(it) + expectedResult += it + } + fakeTime += 1000 + val value = 100L + bitrateManager.calculateBitrate(value) + expectedResult += value + val resultValue = argumentCaptor() + verify(connectCheckerRtmp, times(1)).onNewBitrateRtmp(resultValue.capture()) + val marginError = 20 + assertTrue(expectedResult - marginError <= resultValue.firstValue && resultValue.firstValue <= expectedResult + marginError) } - Thread.sleep(1000) - val value = 100L - bitrateManager.calculateBitrate(value) - expectedResult += value - val resultValue = argumentCaptor() - verify(connectCheckerRtmp, times(1)).onNewBitrateRtmp(resultValue.capture()) - val marginError = 20 - assertTrue(expectedResult - marginError <= resultValue.firstValue && resultValue.firstValue <= expectedResult + marginError) } } \ No newline at end of file diff --git a/rtsp/src/test/java/com/pedro/rtsp/MainDispatcherRule.kt b/rtsp/src/test/java/com/pedro/rtsp/MainDispatcherRule.kt new file mode 100644 index 000000000..6de44ca54 --- /dev/null +++ b/rtsp/src/test/java/com/pedro/rtsp/MainDispatcherRule.kt @@ -0,0 +1,23 @@ +package com.pedro.rtsp + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +@OptIn(ExperimentalCoroutinesApi::class) +class MainDispatcherRule( + private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() +) : TestWatcher() { + override fun starting(description: Description) { + Dispatchers.setMain(testDispatcher) + } + + override fun finished(description: Description) { + Dispatchers.resetMain() + } +} \ No newline at end of file diff --git a/rtsp/src/test/java/com/pedro/rtsp/utils/BitrateManagerTest.kt b/rtsp/src/test/java/com/pedro/rtsp/utils/BitrateManagerTest.kt index 9e32e6864..d54cd9e1e 100644 --- a/rtsp/src/test/java/com/pedro/rtsp/utils/BitrateManagerTest.kt +++ b/rtsp/src/test/java/com/pedro/rtsp/utils/BitrateManagerTest.kt @@ -16,10 +16,19 @@ package com.pedro.rtsp.utils +import com.pedro.rtsp.MainDispatcherRule +import com.pedro.rtsp.Utils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.times @@ -32,25 +41,41 @@ import org.mockito.kotlin.verify @RunWith(MockitoJUnitRunner::class) class BitrateManagerTest { + @get:Rule + val mainDispatcherRule = MainDispatcherRule() @Mock private lateinit var connectCheckerRtsp: ConnectCheckerRtsp + private val timeUtilsMocked = Mockito.mockStatic(TimeUtils::class.java) + private var fakeTime = 7502849023L + + @Before + fun setup() { + timeUtilsMocked.`when`(TimeUtils::getCurrentTimeMillis).then { fakeTime } + } + + @After + fun teardown() { + fakeTime = 7502849023L + } @Test - fun `WHEN set multiple values THEN return total of values each second`() { - val bitrateManager = BitrateManager(connectCheckerRtsp) - val fakeValues = arrayOf(100L, 200L, 300L, 400L, 500L) - var expectedResult = 0L - fakeValues.forEach { - bitrateManager.calculateBitrate(it) - expectedResult += it + fun `WHEN set multiple values THEN return total of values each second`() = runTest { + Utils.useStatics(listOf(timeUtilsMocked)) { + val bitrateManager = BitrateManager(connectCheckerRtsp) + val fakeValues = arrayOf(100L, 200L, 300L, 400L, 500L) + var expectedResult = 0L + fakeValues.forEach { + bitrateManager.calculateBitrate(it) + expectedResult += it + } + fakeTime += 1000 + val value = 100L + bitrateManager.calculateBitrate(value) + expectedResult += value + val resultValue = argumentCaptor() + verify(connectCheckerRtsp, times(1)).onNewBitrateRtsp(resultValue.capture()) + val marginError = 20 + assertTrue(expectedResult - marginError <= resultValue.firstValue && resultValue.firstValue <= expectedResult + marginError) } - Thread.sleep(1000) - val value = 100L - bitrateManager.calculateBitrate(value) - expectedResult += value - val resultValue = argumentCaptor() - verify(connectCheckerRtsp, times(1)).onNewBitrateRtsp(resultValue.capture()) - val marginError = 20 - assertTrue(expectedResult - marginError <= resultValue.firstValue && resultValue.firstValue <= expectedResult + marginError) } } \ No newline at end of file diff --git a/srt/build.gradle b/srt/build.gradle index 0f6ae95ab..13314c4f1 100644 --- a/srt/build.gradle +++ b/srt/build.gradle @@ -48,6 +48,7 @@ afterEvaluate { dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3" testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito.kotlin:mockito-kotlin:5.1.0" } diff --git a/srt/src/main/java/com/pedro/srt/utils/BitrateManager.kt b/srt/src/main/java/com/pedro/srt/utils/BitrateManager.kt index 607a7b9d1..0075f2678 100644 --- a/srt/src/main/java/com/pedro/srt/utils/BitrateManager.kt +++ b/srt/src/main/java/com/pedro/srt/utils/BitrateManager.kt @@ -24,16 +24,16 @@ package com.pedro.srt.utils open class BitrateManager(private val connectCheckerSrt: ConnectCheckerSrt) { private var bitrate: Long = 0 - private var timeStamp = System.currentTimeMillis() + private var timeStamp = TimeUtils.getCurrentTimeMillis() suspend fun calculateBitrate(size: Long) { bitrate += size - val timeDiff = System.currentTimeMillis() - timeStamp + val timeDiff = TimeUtils.getCurrentTimeMillis() - timeStamp if (timeDiff >= 1000) { onMainThread { connectCheckerSrt.onNewBitrateSrt((bitrate / (timeDiff / 1000f)).toLong()) } - timeStamp = System.currentTimeMillis() + timeStamp = TimeUtils.getCurrentTimeMillis() bitrate = 0 } } diff --git a/srt/src/main/java/com/pedro/srt/utils/TimeUtils.kt b/srt/src/main/java/com/pedro/srt/utils/TimeUtils.kt index 0c0c5b24a..77b578473 100644 --- a/srt/src/main/java/com/pedro/srt/utils/TimeUtils.kt +++ b/srt/src/main/java/com/pedro/srt/utils/TimeUtils.kt @@ -23,4 +23,7 @@ object TimeUtils { @JvmStatic fun getCurrentTimeMicro(): Long = System.nanoTime() / 1000 + + @JvmStatic + fun getCurrentTimeMillis(): Long = System.currentTimeMillis() } \ No newline at end of file diff --git a/srt/src/test/java/com/pedro/srt/BitrateManagerTest.kt b/srt/src/test/java/com/pedro/srt/BitrateManagerTest.kt deleted file mode 100644 index d558e2cc8..000000000 --- a/srt/src/test/java/com/pedro/srt/BitrateManagerTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2021 pedroSG94. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pedro.srt - -import com.pedro.srt.utils.BitrateManager -import com.pedro.srt.utils.ConnectCheckerSrt -import org.junit.Assert.assertTrue -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.times -import org.mockito.kotlin.verify - - -/** - * Created by pedro on 9/9/23. - */ -@RunWith(MockitoJUnitRunner::class) -class BitrateManagerTest { - - @Mock - private lateinit var connectCheckerSrt: ConnectCheckerSrt - - @Test - fun `WHEN set multiple values THEN return total of values each second`() { - val bitrateManager = BitrateManager(connectCheckerSrt) - val fakeValues = arrayOf(100L, 200L, 300L, 400L, 500L) - var expectedResult = 0L - fakeValues.forEach { - bitrateManager.calculateBitrate(it) - expectedResult += it - } - Thread.sleep(1000) - val value = 100L - bitrateManager.calculateBitrate(value) - expectedResult += value - val resultValue = argumentCaptor() - verify(connectCheckerSrt, times(1)).onNewBitrateSrt(resultValue.capture()) - val marginError = 20 - assertTrue(expectedResult - marginError <= resultValue.firstValue && resultValue.firstValue <= expectedResult + marginError) - } -} \ No newline at end of file diff --git a/srt/src/test/java/com/pedro/srt/MainDispatcherRule.kt b/srt/src/test/java/com/pedro/srt/MainDispatcherRule.kt new file mode 100644 index 000000000..df3049c48 --- /dev/null +++ b/srt/src/test/java/com/pedro/srt/MainDispatcherRule.kt @@ -0,0 +1,23 @@ +package com.pedro.srt + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +@OptIn(ExperimentalCoroutinesApi::class) +class MainDispatcherRule( + private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() +) : TestWatcher() { + override fun starting(description: Description) { + Dispatchers.setMain(testDispatcher) + } + + override fun finished(description: Description) { + Dispatchers.resetMain() + } +} \ No newline at end of file diff --git a/srt/src/test/java/com/pedro/srt/Utils.kt b/srt/src/test/java/com/pedro/srt/Utils.kt index cc84be340..e700c1148 100644 --- a/srt/src/test/java/com/pedro/srt/Utils.kt +++ b/srt/src/test/java/com/pedro/srt/Utils.kt @@ -27,7 +27,7 @@ object Utils { assertEquals(actual.toString(), expected.toString()) } - fun useStatics(statics: List>, callback: () -> Unit) { + suspend fun useStatics(statics: List>, callback: suspend () -> Unit) { val list = statics.toMutableList() if (list.isEmpty()) callback() else if (list.size == 1) { diff --git a/srt/src/test/java/com/pedro/srt/mpeg2ts/PesTest.kt b/srt/src/test/java/com/pedro/srt/mpeg2ts/PesTest.kt index cf93938e9..9cda0bdc3 100644 --- a/srt/src/test/java/com/pedro/srt/mpeg2ts/PesTest.kt +++ b/srt/src/test/java/com/pedro/srt/mpeg2ts/PesTest.kt @@ -18,6 +18,7 @@ package com.pedro.srt.mpeg2ts import com.pedro.srt.Utils import com.pedro.srt.utils.TimeUtils +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertArrayEquals import org.junit.Before import org.junit.Test @@ -38,7 +39,7 @@ class PesTest { } @Test - fun `GIVEN a fake aac buffer WHEN create a mpegts packet with pes packet THEN get the expected buffer`() { + fun `GIVEN a fake aac buffer WHEN create a mpegts packet with pes packet THEN get the expected buffer`() = runTest { Utils.useStatics(listOf(timeUtilsMock)) { val data = ByteBuffer.wrap( ByteArray(188) { 0xAA.toByte() } diff --git a/srt/src/test/java/com/pedro/srt/mpeg2ts/PsiTest.kt b/srt/src/test/java/com/pedro/srt/mpeg2ts/PsiTest.kt index c2a56cdbe..fa6320edc 100644 --- a/srt/src/test/java/com/pedro/srt/mpeg2ts/PsiTest.kt +++ b/srt/src/test/java/com/pedro/srt/mpeg2ts/PsiTest.kt @@ -22,6 +22,7 @@ import com.pedro.srt.mpeg2ts.psi.Pmt import com.pedro.srt.mpeg2ts.psi.Sdt import com.pedro.srt.mpeg2ts.service.Mpeg2TsService import com.pedro.srt.utils.TimeUtils +import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Assert.assertArrayEquals import org.junit.Before @@ -50,7 +51,7 @@ class PsiTest { } @Test - fun `GIVEN a sdt table WHEN create mpegts packet with that table THEN get expected buffer`() { + fun `GIVEN a sdt table WHEN create mpegts packet with that table THEN get expected buffer`() = runTest { Utils.useStatics(listOf(timeUtilsMock, pidMock)) { val expected = ByteBuffer.wrap( byteArrayOf(71, 64, 17, 16, 0, 66, -16, 49, 0, 1, -63, 0, 0, -1, 1, -1, 70, -104, -4, -128, 32, 72, 30, 1, 13, 99, 111, 109, 46, 112, 101, 100, 114, 111, 46, 115, 114, 116, 14, 77, 112, 101, 103, 50, 84, 115, 83, 101, 114, 118, 105, 99, 101, 72, 33, 81, -10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1) @@ -69,7 +70,7 @@ class PsiTest { } @Test - fun `GIVEN a pmt table WHEN create mpegts packet with that table THEN get expected buffer`() { + fun `GIVEN a pmt table WHEN create mpegts packet with that table THEN get expected buffer`() = runTest { Utils.useStatics(listOf(timeUtilsMock, pidMock)) { service.addTrack(Codec.AAC) val expected = ByteBuffer.wrap( @@ -89,7 +90,7 @@ class PsiTest { } @Test - fun `GIVEN a pat table WHEN create mpegts packet with that table THEN get expected buffer`() { + fun `GIVEN a pat table WHEN create mpegts packet with that table THEN get expected buffer`() = runTest { Utils.useStatics(listOf(timeUtilsMock, pidMock)) { val expected = ByteBuffer.wrap( byteArrayOf(71, 64, 0, 16, 0, 0, -80, 13, 1, 0, -61, 0, 0, 70, -104, -32, 0, -30, -46, -114, -23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1) diff --git a/srt/src/test/java/com/pedro/srt/utils/BitrateManagerTest.kt b/srt/src/test/java/com/pedro/srt/utils/BitrateManagerTest.kt new file mode 100644 index 000000000..66189e557 --- /dev/null +++ b/srt/src/test/java/com/pedro/srt/utils/BitrateManagerTest.kt @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 pedroSG94. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pedro.srt.utils + +import com.pedro.srt.MainDispatcherRule +import com.pedro.srt.Utils +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + + +/** + * Created by pedro on 9/9/23. + */ +@RunWith(MockitoJUnitRunner::class) +class BitrateManagerTest { + + @get:Rule + val mainDispatcherRule = MainDispatcherRule() + @Mock + private lateinit var connectCheckerSrt: ConnectCheckerSrt + private val timeUtilsMocked = Mockito.mockStatic(TimeUtils::class.java) + private var fakeTime = 7502849023L + + @Before + fun setup() { + timeUtilsMocked.`when`(TimeUtils::getCurrentTimeMillis).then { fakeTime } + } + + @After + fun teardown() { + fakeTime = 7502849023L + } + + @Test + fun `WHEN set multiple values THEN return total of values each second`() = runTest { + Utils.useStatics(listOf(timeUtilsMocked)) { + val bitrateManager = BitrateManager(connectCheckerSrt) + val fakeValues = arrayOf(100L, 200L, 300L, 400L, 500L) + var expectedResult = 0L + fakeValues.forEach { + bitrateManager.calculateBitrate(it) + expectedResult += it + } + fakeTime += 1000 + val value = 100L + bitrateManager.calculateBitrate(value) + expectedResult += value + val resultValue = argumentCaptor() + verify(connectCheckerSrt, times(1)).onNewBitrateSrt(resultValue.capture()) + val marginError = 20 + assertTrue(expectedResult - marginError <= resultValue.firstValue && resultValue.firstValue <= expectedResult + marginError) + } + } +} \ No newline at end of file