ExoPlayerFSMTest.java
Overview
`ExoPlayerFSMTest.java` is a comprehensive JUnit4 test class designed to validate the behavior of the Finite State Machine (FSM) that governs the playback lifecycle within the ExoPlayer-based media player system. The FSM coordinates media playback states, including cue point fetching, preroll and midroll ad handling, VPAID ad interactions, and the transition to the finished state.
This file primarily tests the `FsmPlayerImperial` implementation of the FSM by simulating sequences of input events (`Input` enum) and asserting the correctness of state transitions. It covers multiple playback scenarios such as flows with and without preroll ads, VPAID and non-VPAID ad playback, and error handling paths.
The tests leverage dependency injection (via Dagger) to obtain a `StateFactory` that provides concrete instances of playback states, facilitating realistic and isolated state transition testing.
Classes
ExoPlayerFSMTest
**Purpose:** Unit test suite for verifying the correctness and robustness of the FSM controlling media playback and ad states in the player.
**Annotations:**
@RunWith(JUnit4.class)— Specifies JUnit4 as the test runner.
**Fields:**
Field | Type | Description |
|---|---|---|
`playerFsm` | `FsmPlayer` | The FSM player instance under test. |
`movieMedia` | `MediaModel` | Mocked media model representing movie content. |
`adMedia` | `MediaModel` | Mocked media model representing ads. |
`retriever` | `AdRetriever` | Mocked ad retriever. |
`adServerInterface` | `AdInterface` | Mocked interface for ad server callbacks. |
`controller` | `PlayerUIController` | Mocked UI controller for the player. |
`factory` | `StateFactory` | Injected factory to create FSM states. |
`comonent` | `FsmComonent` | Dagger component used for dependency injection. |
**Setup Method:**
@Before
public void setup() {
comonent = DaggerFsmComonent.builder().playerModuleDefault(new PlayerModuleDefault()).build();
}
Initializes the Dagger component to inject dependencies, especially the
StateFactory.
Methods (Tests)
Each test initializes a fresh FSM instance and injects a real `StateFactory`. The FSM is often subclassed to override the initial state.
testFSMFlowWithVpaid_No_PreRollAd()
**Purpose:** Tests a complete FSM flow where there is no preroll ad, but VPAID ads are included midroll.
**Flow:**
Initialize FSM starting at
FetchCuePointState.Transition through inputs representing no preroll ad (
NO_PREROLL_AD) toMoviePlayingState.Simulate making an ad call, receiving an ad, showing ads.
Test transitions within ad playback states, including:
Ad clicks leading to
VastAdInteractionSandBoxState.Transitions to and from
VpaidStatefor VPAID ads.
Continue ad calls and finishing playback with
FinishState.
**Assertions:** After each input, the current FSM state is asserted to be the expected class.
**Usage Example:**
playerFsm.transit(Input.INITIALIZE);
assertTrue(playerFsm.getCurrentState() instanceof FetchCuePointState);
playerFsm.transit(Input.NO_PREROLL_AD);
assertTrue(playerFsm.getCurrentState() instanceof MoviePlayingState);
testFSMFlowWithVpaid_With_PreRollAd()
**Purpose:** Tests the FSM flow including preroll ads with VPAID support.
**Flow:**
Starts at
FetchCuePointState.Handles
HAS_PREROLL_ADinput transitioning toMakingPrerollAdCallState.Receives and plays preroll ads.
Tests midroll ad calls, ad clicks, VPAID manifests, and finishing playback.
testFSMFlowWithNoVpaid()
**Purpose:** Simulates playback with no VPAID ads, exercising ad calls and ad playback states multiple times.
**Highlights:**
Starts directly in
MoviePlayingState.Iterates through a loop of ad calls, ad receptions, ad showing, ad clicks, and returns from VAST ad interactions.
Includes transitions to
VpaidStateand back.Ends with an empty ad and finish state.
testErrorFlow()
**Purpose:** Tests the FSM's robustness by injecting ad click and ad finish inputs in unexpected states after a no-VPAID flow.
**Flow:**
Runs the no-VPAID flow.
Sends inputs that might represent unusual or error cases.
Asserts the FSM returns to a stable
MoviePlayingState.
testNewFSMFlowWithPreroll()
**Purpose:** Similar to `testFSMFlowWithVpaid_With_PreRollAd`, verifies FSM flow with preroll ads and multiple VPAID manifests.
testNewFSMFlowNoPreroll()
**Purpose:** Tests FSM flow with no preroll ads and multiple ad calls, similar to `testFSMFlowWithNoVpaid` but starting from `FetchCuePointState`.
Important Implementation Details
FSM Initialization:
The FSM is initialized via subclassingFsmPlayerImperialand overridinginitializeState()to specify the starting state class.State Transitions:
Transitions are triggered by callingplayerFsm.transit(Input), whereInputis an enum representing player or ad events.Assertions:
After each transition, assertions verify that the FSM's current state matches the expected class, ensuring correct state machine behavior.Dependency Injection:
Uses Dagger 2 (DaggerFsmComonent) to inject theStateFactorythat provides singleton instances of all concrete states, ensuring consistent and testable state instances.Mocks:
Various media and ad-related components are mocked but not deeply interacted with in these tests; focus is on FSM state transitions.
Interaction with Other System Components
StateFactory:
Provides concrete state instances to the FSM. The tests ensure the factory correctly supports the FSM lifecycle.FsmPlayerImperial:
The actual FSM implementation under test. It manages state transitions according to inputs.Input Enum:
Represents events that trigger state transitions (e.g.,INITIALIZE,MAKE_AD_CALL,AD_RECEIVED,VPAID_MANIFEST, etc.).Ad and Media Models:
Mocked dependencies represent ads and media content but are not the focus in this test file.Dagger Components:
The tests rely on dependency injection to configure the FSM and state factory, reflecting the production setup.PlayerUIController and AdInterface:
Mocked for completeness, representing UI and ad server interactions.
Usage Summary
This test class is critical for validating the FSM behavior within the media player system. By simulating realistic sequences of playback and ad events, it ensures that:
The FSM transitions through expected states without deadlocks or invalid states.
Ad integration (including VPAID) is handled correctly.
Error and edge cases do not break FSM stability.
The state factory and dependency injection setup operate as expected.
Example Usage Snippet
// Initialize FSM starting at FetchCuePointState
playerFsm = new FsmPlayerImperial(factory) {
@Override
public Class initializeState() {
return FetchCuePointState.class;
}
};
playerFsm.transit(Input.INITIALIZE);
assertTrue(playerFsm.getCurrentState() instanceof FetchCuePointState);
playerFsm.transit(Input.NO_PREROLL_AD);
assertTrue(playerFsm.getCurrentState() instanceof MoviePlayingState);
playerFsm.transit(Input.MAKE_AD_CALL);
assertTrue(playerFsm.getCurrentState() instanceof MakingAdCallState);
Mermaid Diagram: Class Structure of ExoPlayerFSMTest
classDiagram
class ExoPlayerFSMTest {
-FsmPlayer playerFsm
-MediaModel movieMedia
-MediaModel adMedia
-AdRetriever retriever
-AdInterface adServerInterface
-PlayerUIController controller
-StateFactory factory
-FsmComonent comonent
+void setup()
+void testFSMFlowWithVpaid_No_PreRollAd()
+void testFSMFlowWithVpaid_With_PreRollAd()
+void testFSMFlowWithNoVpaid()
+void testErrorFlow()
+void testNewFSMFlowWithPreroll()
+void testNewFSMFlowNoPreroll()
}
Summary
`ExoPlayerFSMTest.java` is a vital test suite that asserts the correctness of the FSM managing media playback and ad states in the ExoPlayer-based player. It uses dependency injection and mock objects to isolate FSM behavior, comprehensively covering ad playback flows, VPAID integration, preroll handling, and error scenarios. The file ensures the FSM transitions correctly through complex playback states, maintaining the integrity and robustness of the playback engine.