blob: fdcc604bdea7391c15253bde55bd90b1106eec0c [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* 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 androidx.work.impl.foreground
import android.app.Notification
import android.content.Context
import android.util.Log
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.work.Configuration
import androidx.work.Constraints
import androidx.work.ForegroundInfo
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.impl.Processor
import androidx.work.impl.Scheduler
import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkManagerImpl
import androidx.work.impl.constraints.WorkConstraintsCallback
import androidx.work.impl.constraints.WorkConstraintsTracker
import androidx.work.impl.foreground.SystemForegroundDispatcher.createCancelWorkIntent
import androidx.work.impl.foreground.SystemForegroundDispatcher.createNotifyIntent
import androidx.work.impl.foreground.SystemForegroundDispatcher.createStartForegroundIntent
import androidx.work.impl.foreground.SystemForegroundDispatcher.createStopForegroundIntent
import androidx.work.impl.utils.SynchronousExecutor
import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor
import androidx.work.impl.utils.taskexecutor.TaskExecutor
import androidx.work.worker.TestWorker
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
import java.util.UUID
@RunWith(AndroidJUnit4::class)
@MediumTest
class SystemForegroundDispatcherTest {
private lateinit var context: Context
private lateinit var config: Configuration
private lateinit var taskExecutor: TaskExecutor
private lateinit var workManager: WorkManagerImpl
private lateinit var workDatabase: WorkDatabase
private lateinit var processor: Processor
private lateinit var tracker: WorkConstraintsTracker
private lateinit var constraintsCallback: WorkConstraintsCallback
private lateinit var dispatcher: SystemForegroundDispatcher
private lateinit var dispatcherCallback: SystemForegroundDispatcher.Callback
@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
config = Configuration.Builder()
.setExecutor(SynchronousExecutor())
.setMinimumLoggingLevel(Log.DEBUG)
.build()
taskExecutor = InstantWorkTaskExecutor()
val scheduler = mock(Scheduler::class.java)
workDatabase = WorkDatabase.create(context, taskExecutor.backgroundExecutor, true)
processor = Processor(context, config, taskExecutor, workDatabase, listOf(scheduler))
workManager = spy(
WorkManagerImpl(
context,
config,
taskExecutor,
workDatabase,
listOf(scheduler),
processor
)
)
workDatabase = workManager.workDatabase
// Initialize WorkConstraintsTracker
constraintsCallback = mock(WorkConstraintsCallback::class.java)
tracker = spy(WorkConstraintsTracker(context, taskExecutor, constraintsCallback))
// Initialize dispatcher
dispatcherCallback = mock(SystemForegroundDispatcher.Callback::class.java)
dispatcher = spy(SystemForegroundDispatcher(context, workManager, tracker))
dispatcher.setCallback(dispatcherCallback)
}
@Test
fun testStartForeground_noInteractions_workSpecHasNoConstraints() {
val request = OneTimeWorkRequest.Builder(TestWorker::class.java).build()
workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
val intent = createStartForegroundIntent(context, request.stringId)
dispatcher.onStartCommand(intent)
verifyZeroInteractions(tracker)
}
@Test
fun testStartForeground_trackConstraints_workSpecHasConstraints() {
val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
).build()
workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
val intent = createStartForegroundIntent(context, request.stringId)
dispatcher.onStartCommand(intent)
verify(tracker, times(1)).replace(setOf(request.workSpec))
}
@Test
fun testStopForeground() {
val intent = createStopForegroundIntent(context)
dispatcher.onStartCommand(intent)
verify(dispatcherCallback, times(1)).stop()
}
@Test
fun testHandleNotify() {
val workSpecId = "workSpecId"
val notificationId = 1
val notification = mock(Notification::class.java)
val metadata = ForegroundInfo(notificationId, notification)
val intent = createNotifyIntent(context, workSpecId, metadata)
dispatcher.onStartCommand(intent)
verify(dispatcherCallback, times(1))
.notify(eq(notificationId), eq(0), eq(workSpecId), any<Notification>())
}
@Test
fun testStartForeground_trackConstraints_constraintsUnMet() {
val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
).build()
workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
val intent = createStartForegroundIntent(context, request.stringId)
dispatcher.onStartCommand(intent)
verify(tracker, times(1)).replace(setOf(request.workSpec))
dispatcher.onAllConstraintsNotMet(listOf(request.workSpec.id))
verify(workManager, times(1)).stopForegroundWork(eq(request.workSpec.id))
}
@Test
fun testCancelForegroundWork() {
val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
).build()
workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
val intent = createStartForegroundIntent(context, request.stringId)
dispatcher.onStartCommand(intent)
verify(tracker, times(1)).replace(setOf(request.workSpec))
val stopIntent = createCancelWorkIntent(context, request.stringId)
dispatcher.onStartCommand(stopIntent)
verify(workManager, times(1)).cancelWorkById(eq(UUID.fromString(request.workSpec.id)))
assertThat(processor.hasWork(), `is`(false))
}
}