| /* |
| * 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)) |
| } |
| } |