shell_unittests.cc 11.7 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9 10
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#define FML_USED_ON_EMBEDDER

#include <functional>
#include <future>
#include <memory>

11
#include "flutter/fml/command_line.h"
12
#include "flutter/fml/make_copyable.h"
13
#include "flutter/fml/message_loop.h"
14
#include "flutter/fml/synchronization/count_down_latch.h"
15
#include "flutter/fml/synchronization/waitable_event.h"
16 17
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
18
#include "flutter/shell/common/shell_test.h"
19
#include "flutter/shell/common/switches.h"
20
#include "flutter/shell/common/thread_host.h"
21
#include "flutter/testing/testing.h"
22

23
namespace flutter {
24
namespace testing {
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
static bool ValidateShell(Shell* shell) {
  if (!shell) {
    return false;
  }

  if (!shell->IsSetup()) {
    return false;
  }

  {
    fml::AutoResetWaitableEvent latch;
    fml::TaskRunner::RunNowOrPostTask(
        shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
          shell->GetPlatformView()->NotifyCreated();
          latch.Signal();
        });
    latch.Wait();
  }

  {
    fml::AutoResetWaitableEvent latch;
    fml::TaskRunner::RunNowOrPostTask(
        shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
          shell->GetPlatformView()->NotifyDestroyed();
          latch.Signal();
        });
    latch.Wait();
  }

  return true;
}

58
TEST_F(ShellTest, InitializeWithInvalidThreads) {
59
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
60 61
  Settings settings = CreateSettingsForFixture();
  TaskRunners task_runners("test", nullptr, nullptr, nullptr, nullptr);
62 63 64
  auto shell = Shell::Create(
      std::move(task_runners), settings,
      [](Shell& shell) {
65 66
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
67 68 69 70 71
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
  ASSERT_FALSE(shell);
72
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
73 74
}

75
TEST_F(ShellTest, InitializeWithDifferentThreads) {
76
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
77
  Settings settings = CreateSettingsForFixture();
78 79 80
  ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
                         ThreadHost::Type::Platform | ThreadHost::Type::GPU |
                             ThreadHost::Type::IO | ThreadHost::Type::UI);
81 82 83 84
  TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
                           thread_host.gpu_thread->GetTaskRunner(),
                           thread_host.ui_thread->GetTaskRunner(),
                           thread_host.io_thread->GetTaskRunner());
85 86 87
  auto shell = Shell::Create(
      std::move(task_runners), settings,
      [](Shell& shell) {
88 89
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
90 91 92 93
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
94
  ASSERT_TRUE(ValidateShell(shell.get()));
95 96 97
  ASSERT_TRUE(DartVMRef::IsInstanceRunning());
  shell.reset();
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
98 99
}

100
TEST_F(ShellTest, InitializeWithSingleThread) {
101
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
102
  Settings settings = CreateSettingsForFixture();
103 104
  ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
                         ThreadHost::Type::Platform);
105
  auto task_runner = thread_host.platform_thread->GetTaskRunner();
106 107
  TaskRunners task_runners("test", task_runner, task_runner, task_runner,
                           task_runner);
108 109 110
  auto shell = Shell::Create(
      std::move(task_runners), settings,
      [](Shell& shell) {
111 112
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
113 114 115 116
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
117
  ASSERT_TRUE(DartVMRef::IsInstanceRunning());
118
  ASSERT_TRUE(ValidateShell(shell.get()));
119 120
  shell.reset();
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
121 122
}

123
TEST_F(ShellTest, InitializeWithSingleThreadWhichIsTheCallingThread) {
124
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
125
  Settings settings = CreateSettingsForFixture();
126 127
  fml::MessageLoop::EnsureInitializedForCurrentThread();
  auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
128 129
  TaskRunners task_runners("test", task_runner, task_runner, task_runner,
                           task_runner);
130 131 132
  auto shell = Shell::Create(
      std::move(task_runners), settings,
      [](Shell& shell) {
133 134
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
135 136 137 138
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
139
  ASSERT_TRUE(ValidateShell(shell.get()));
140 141 142
  ASSERT_TRUE(DartVMRef::IsInstanceRunning());
  shell.reset();
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
143 144
}

145 146
TEST_F(ShellTest,
       InitializeWithMultipleThreadButCallingThreadAsPlatformThread) {
147
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
148
  Settings settings = CreateSettingsForFixture();
149
  ThreadHost thread_host(
150
      "io.flutter.test." + GetCurrentTestName() + ".",
151 152
      ThreadHost::Type::GPU | ThreadHost::Type::IO | ThreadHost::Type::UI);
  fml::MessageLoop::EnsureInitializedForCurrentThread();
153 154 155 156 157
  TaskRunners task_runners("test",
                           fml::MessageLoop::GetCurrent().GetTaskRunner(),
                           thread_host.gpu_thread->GetTaskRunner(),
                           thread_host.ui_thread->GetTaskRunner(),
                           thread_host.io_thread->GetTaskRunner());
158 159 160
  auto shell = Shell::Create(
      std::move(task_runners), settings,
      [](Shell& shell) {
161 162
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
163 164 165 166 167
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
  ASSERT_TRUE(ValidateShell(shell.get()));
168 169 170
  ASSERT_TRUE(DartVMRef::IsInstanceRunning());
  shell.reset();
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
171 172
}

173
TEST_F(ShellTest, InitializeWithGPUAndPlatformThreadsTheSame) {
174
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
175
  Settings settings = CreateSettingsForFixture();
176
  ThreadHost thread_host(
177
      "io.flutter.test." + GetCurrentTestName() + ".",
178
      ThreadHost::Type::Platform | ThreadHost::Type::IO | ThreadHost::Type::UI);
179
  TaskRunners task_runners(
180 181 182 183 184 185 186 187 188
      "test",
      thread_host.platform_thread->GetTaskRunner(),  // platform
      thread_host.platform_thread->GetTaskRunner(),  // gpu
      thread_host.ui_thread->GetTaskRunner(),        // ui
      thread_host.io_thread->GetTaskRunner()         // io
  );
  auto shell = Shell::Create(
      std::move(task_runners), settings,
      [](Shell& shell) {
189 190
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
191 192 193 194
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
195
  ASSERT_TRUE(DartVMRef::IsInstanceRunning());
196
  ASSERT_TRUE(ValidateShell(shell.get()));
197 198
  shell.reset();
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
199 200
}

201
TEST_F(ShellTest, FixturesAreFunctional) {
202
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
203 204 205 206
  const auto settings = CreateSettingsForFixture();
  auto shell = Shell::Create(
      GetTaskRunnersForFixture(), settings,
      [](Shell& shell) {
207 208
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
  ASSERT_TRUE(ValidateShell(shell.get()));

  auto configuration = RunConfiguration::InferFromSettings(settings);
  ASSERT_TRUE(configuration.IsValid());
  configuration.SetEntrypoint("fixturesAreFunctionalMain");

  fml::AutoResetWaitableEvent main_latch;
  AddNativeCallback(
      "SayHiFromFixturesAreFunctionalMain",
      CREATE_NATIVE_ENTRY([&main_latch](auto args) { main_latch.Signal(); }));

  fml::AutoResetWaitableEvent latch;
  fml::TaskRunner::RunNowOrPostTask(
      shell->GetTaskRunners().GetUITaskRunner(),
      fml::MakeCopyable([&latch, config = std::move(configuration),
                         engine = shell->GetEngine()]() mutable {
        ASSERT_TRUE(engine);
        ASSERT_EQ(engine->Run(std::move(config)), Engine::RunStatus::Success);
        latch.Signal();
      }));

  latch.Wait();
  main_latch.Wait();
236 237 238
  ASSERT_TRUE(DartVMRef::IsInstanceRunning());
  shell.reset();
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
239 240
}

241 242 243 244 245 246
TEST_F(ShellTest, SecondaryIsolateBindingsAreSetupViaShellSettings) {
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
  const auto settings = CreateSettingsForFixture();
  auto shell = Shell::Create(
      GetTaskRunnersForFixture(), settings,
      [](Shell& shell) {
247 248
        return std::make_unique<ShellTestPlatformView>(shell,
                                                       shell.GetTaskRunners());
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
      },
      [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell.GetTaskRunners());
      });
  ASSERT_TRUE(ValidateShell(shell.get()));

  auto configuration = RunConfiguration::InferFromSettings(settings);
  ASSERT_TRUE(configuration.IsValid());
  configuration.SetEntrypoint("testCanLaunchSecondaryIsolate");

  fml::CountDownLatch latch(2);
  AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&latch](auto args) {
                      latch.CountDown();
                    }));

  fml::TaskRunner::RunNowOrPostTask(
      shell->GetTaskRunners().GetUITaskRunner(),
      fml::MakeCopyable([config = std::move(configuration),
                         engine = shell->GetEngine()]() mutable {
        ASSERT_TRUE(engine);
        ASSERT_EQ(engine->Run(std::move(config)), Engine::RunStatus::Success);
      }));

  latch.Wait();

  ASSERT_TRUE(DartVMRef::IsInstanceRunning());
  shell.reset();
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
TEST_F(ShellTest, BlacklistedDartVMFlag) {
  // Run this test in a thread-safe manner, otherwise gtest will complain.
  ::testing::FLAGS_gtest_death_test_style = "threadsafe";

  const std::vector<fml::CommandLine::Option> options = {
      fml::CommandLine::Option("dart-flags", "--verify_after_gc")};
  fml::CommandLine command_line("", options, std::vector<std::string>());

#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
    FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
  // Upon encountering a non-whitelisted Dart flag the process terminates.
  const char* expected =
      "Encountered blacklisted Dart VM flag: --verify_after_gc";
  ASSERT_DEATH(flutter::SettingsFromCommandLine(command_line), expected);
#else
  flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
  EXPECT_EQ(settings.dart_flags.size(), 0u);
#endif
}

TEST_F(ShellTest, WhitelistedDartVMFlag) {
  const std::vector<fml::CommandLine::Option> options = {
      fml::CommandLine::Option("dart-flags",
                               "--max_profile_depth 1,--trace_service")};
  fml::CommandLine command_line("", options, std::vector<std::string>());
  flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);

#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
    FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
  EXPECT_EQ(settings.dart_flags.size(), 2u);
  EXPECT_EQ(settings.dart_flags[0], "--max_profile_depth 1");
  EXPECT_EQ(settings.dart_flags[1], "--trace_service");
#else
  EXPECT_EQ(settings.dart_flags.size(), 0u);
#endif
}

316
}  // namespace testing
317
}  // namespace flutter