Back to Repositories

Testing GlideExecutor Priority Queue Management in Bumptech Glide

This test suite validates the execution order and priority handling of the GlideExecutor component in the Bumptech Glide library. It focuses on ensuring disk cache operations are performed in the correct sequence with proper thread management and priority queuing.

Test Coverage Overview

The test suite provides comprehensive coverage of GlideExecutor’s task prioritization mechanism.

Key areas tested include:
  • Task execution order verification
  • Priority queue implementation
  • Thread synchronization handling
  • Concurrent operation management

Implementation Analysis

The testing approach utilizes JUnit with Robolectric for Android environment simulation. It implements a CountDownLatch for synchronized execution control and uses MockRunnable implementations to verify priority ordering.

Key patterns include:
  • Synchronized list operations
  • Comparable interface implementation for priority sorting
  • Controlled thread execution with timeouts

Technical Details

Testing infrastructure includes:
  • JUnit 4 test framework
  • Robolectric test runner
  • Custom SDK configuration
  • Truth assertion library
  • CountDownLatch for thread synchronization
  • TimeUnit millisecond precision timing

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Clear separation of test setup and verification
  • Proper thread handling and cleanup
  • Deterministic execution order verification
  • Effective mock object implementation
  • Timeout-based execution boundaries
  • Thread-safe collection usage

bumptech/glide

library/test/src/test/java/com/bumptech/glide/load/engine/executor/GlideExecutorTest.java

            
package com.bumptech.glide.load.engine.executor;

import static com.bumptech.glide.RobolectricConstants.ROBOLECTRIC_SDK;
import static com.google.common.truth.Truth.assertThat;

import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = ROBOLECTRIC_SDK)
public class GlideExecutorTest {

  @Test
  public void testLoadsAreExecutedInOrder() throws InterruptedException {
    final List<Integer> resultPriorities = Collections.synchronizedList(new ArrayList<Integer>());
    CountDownLatch latch = new CountDownLatch(1);
    GlideExecutor executor = GlideExecutor.newDiskCacheExecutor();
    for (int i = 5; i > 0; i--) {
      executor.execute(
          new MockRunnable(
              i,
              new MockRunnable.OnRun() {
                @Override
                public void onRun(int priority) {
                  try {
                    latch.await();
                  } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException(e);
                  }
                  resultPriorities.add(priority);
                }
              }));
    }
    latch.countDown();

    executor.shutdown();
    executor.awaitTermination(500, TimeUnit.MILLISECONDS);

    // Since no jobs are queued, the first item added will be run immediately, regardless of
    // priority.
    assertThat(resultPriorities).containsExactly(5, 1, 2, 3, 4).inOrder();
  }

  private static final class MockRunnable implements Runnable, Comparable<MockRunnable> {
    private final int priority;
    private final OnRun onRun;

    @Override
    public int compareTo(@NonNull MockRunnable another) {
      return priority - another.priority;
    }

    interface OnRun {
      void onRun(int priority);
    }

    MockRunnable(int priority, OnRun onRun) {
      this.priority = priority;
      this.onRun = onRun;
    }

    @Override
    public void run() {
      onRun.onRun(priority);
    }
  }
}