Back to Repositories

Validating Application Version Signatures in Glide Library

This test suite validates the ApplicationVersionSignature functionality in Glide, focusing on signature key generation and handling for Android application versioning. It ensures consistent key generation and proper error handling for package information retrieval.

Test Coverage Overview

The test suite provides comprehensive coverage of ApplicationVersionSignature functionality, including key generation consistency and error handling scenarios.

  • Validates basic key generation functionality
  • Tests key consistency across multiple calls
  • Covers error cases for unresolvable package info
  • Handles missing package information scenarios

Implementation Analysis

The implementation uses JUnit with Robolectric for Android context simulation and Mockito for mocking dependencies.

Key testing patterns include:
  • Setup/teardown lifecycle management
  • Mock context creation for error scenarios
  • Equivalence group testing for key consistency
  • Regression testing with expected hash values

Technical Details

Testing infrastructure includes:
  • RobolectricTestRunner for Android environment simulation
  • Custom KeyTester rule for signature validation
  • Mockito framework for context mocking
  • JUnit test annotations and assertions
  • ApplicationProvider for context management

Best Practices Demonstrated

The test suite exemplifies several testing best practices in Android development.

  • Proper test isolation with @Before and @After methods
  • Comprehensive error case coverage
  • Effective use of mocking for external dependencies
  • Clear test method naming conventions
  • Regression test implementation for key verification

bumptech/glide

library/test/src/test/java/com/bumptech/glide/signature/ApplicationVersionSignatureTest.java

            
package com.bumptech.glide.signature;

import static com.bumptech.glide.RobolectricConstants.ROBOLECTRIC_SDK;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import androidx.test.core.app.ApplicationProvider;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.tests.KeyTester;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = ROBOLECTRIC_SDK)
public class ApplicationVersionSignatureTest {
  @Rule public final KeyTester keyTester = new KeyTester();
  private Context context;

  @Before
  public void setUp() {
    context = ApplicationProvider.getApplicationContext();
  }

  @After
  public void tearDown() {
    ApplicationVersionSignature.reset();
  }

  @Test
  public void testCanGetKeyForSignature() {
    Key key = ApplicationVersionSignature.obtain(context);
    assertNotNull(key);
  }

  @Test
  public void testKeyForSignatureIsTheSameAcrossCallsInTheSamePackage()
      throws NoSuchAlgorithmException, UnsupportedEncodingException {
    keyTester
        .addEquivalenceGroup(
            ApplicationVersionSignature.obtain(context),
            ApplicationVersionSignature.obtain(context))
        .addEquivalenceGroup(new ObjectKey("test"))
        .addRegressionTest(
            ApplicationVersionSignature.obtain(context),
            "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9")
        .test();
  }

  @Test
  public void testUnresolvablePackageInfo() throws NameNotFoundException {
    Context context = mock(Context.class, Answers.RETURNS_DEEP_STUBS);
    String packageName = "my.package";
    when(context.getPackageName()).thenReturn(packageName);
    when(context.getPackageManager().getPackageInfo(packageName, 0))
        .thenThrow(new NameNotFoundException("test"));

    Key key = ApplicationVersionSignature.obtain(context);

    assertNotNull(key);
  }

  @Test
  public void testMissingPackageInfo() throws NameNotFoundException {
    Context context = mock(Context.class, Answers.RETURNS_DEEP_STUBS);
    String packageName = "my.package";
    when(context.getPackageName()).thenReturn(packageName);
    when(context.getPackageManager().getPackageInfo(packageName, 0)).thenReturn(null);

    Key key = ApplicationVersionSignature.obtain(context);

    assertNotNull(key);
  }
}