blob: a5415b5425199778e54edbc49f447376b004d029 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package dev.flutter.scenarios;
import static org.junit.Assert.fail;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.internal.runner.junit4.statement.UiThreadStatement;
import androidx.test.runner.AndroidJUnit4;
import com.google.common.util.concurrent.SettableFuture;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.dart.DartExecutor;
import java.util.Arrays;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class EngineLaunchE2ETest {
@Test
public void smokeTestEngineLaunch() throws Throwable {
Context applicationContext = InstrumentationRegistry.getTargetContext();
// Specifically, create the engine without running FlutterMain first.
final AtomicReference<FlutterEngine> engine = new AtomicReference<>();
// Run the production under test on the UI thread instead of annotating the whole test
// as @UiThreadTest because having the message handler and the CompletableFuture both being
// on the same thread will create deadlocks.
UiThreadStatement.runOnUiThread(() -> engine.set(new FlutterEngine(applicationContext)));
SettableFuture<Boolean> statusReceived = SettableFuture.create();
// Resolve locale to `en_US`.
// This is required, so `window.locale` in populated in dart.
// TODO: Fix race condition between sending this over the channel and starting the entrypoint.
// https://github.com/flutter/flutter/issues/55999
UiThreadStatement.runOnUiThread(
() -> engine.get().getLocalizationChannel().sendLocales(Arrays.asList(Locale.US)));
// The default Dart main entrypoint sends back a platform message on the "waiting_for_status"
// channel. That will be our launch success assertion condition.
engine
.get()
.getDartExecutor()
.setMessageHandler(
"waiting_for_status", (byteBuffer, binaryReply) -> statusReceived.set(Boolean.TRUE));
// Launching the entrypoint will run the Dart code that sends the "waiting_for_status" platform
// message.
UiThreadStatement.runOnUiThread(
() ->
engine
.get()
.getDartExecutor()
.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault()));
try {
Boolean result = statusReceived.get(10, TimeUnit.SECONDS);
if (!result) {
fail("expected message on waiting_for_status not received");
}
} catch (ExecutionException e) {
fail(e.getMessage());
} catch (InterruptedException e) {
fail(e.getMessage());
} catch (TimeoutException e) {
fail("timed out waiting for engine started signal");
}
// If it gets to here, statusReceived is true.
}
}