Home | History | Annotate | Download | only in plugin
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #define UNIT_TEST  // To get the ShadowingAtExitManager.
      6 #include "base/at_exit.h"
      7 
      8 #include "content/test/plugin/plugin_thread_async_call_test.h"
      9 
     10 #include "base/bind.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/threading/thread.h"
     14 #include "content/test/plugin/plugin_client.h"
     15 
     16 namespace NPAPIClient {
     17 
     18 namespace {
     19 
     20 // There are two plugin instances in this test. The long lived instance is used
     21 // for reporting errors and signalling test completion. The short lived one is
     22 // used to verify that async callbacks are not invoked after NPP_Destroy.
     23 PluginThreadAsyncCallTest* g_short_lived_instance;
     24 PluginThreadAsyncCallTest* g_long_lived_instance;
     25 
     26 void OnCallSucceededHelper(void* data) {
     27   static_cast<PluginThreadAsyncCallTest*>(data)->OnCallSucceeded();
     28 }
     29 
     30 void OnCallFailed(void* data) {
     31   g_long_lived_instance->SetError("Async callback invoked after NPP_Destroy");
     32 }
     33 
     34 void OnCallCompletedHelper(void* data) {
     35   static_cast<PluginThreadAsyncCallTest*>(data)->OnCallCompleted();
     36 }
     37 }
     38 
     39 PluginThreadAsyncCallTest::PluginThreadAsyncCallTest(
     40     NPP id, NPNetscapeFuncs *host_functions)
     41     : PluginTest(id, host_functions), at_exit_manager_(NULL) {
     42 }
     43 
     44 PluginThreadAsyncCallTest::~PluginThreadAsyncCallTest() {
     45   delete at_exit_manager_;
     46 }
     47 
     48 NPError PluginThreadAsyncCallTest::New(
     49     uint16 mode, int16 argc, const char* argn[], const char* argv[],
     50     NPSavedData* saved) {
     51   NPError error = PluginTest::New(mode, argc, argn, argv, saved);
     52   if (error != NPERR_NO_ERROR)
     53     return error;
     54 
     55   // Determine whether this is the short lived instance.
     56   for (int i = 0; i < argc; ++i) {
     57     if (base::strcasecmp(argn[i], "short_lived") == 0) {
     58       if (base::strcasecmp(argv[i], "true") == 0) {
     59         g_short_lived_instance = this;
     60       } else {
     61         g_long_lived_instance = this;
     62       }
     63     }
     64   }
     65 
     66   // Schedule an async call that will succeed.  Make sure to call that API from
     67   // a different thread to fully test it.
     68   if (this == g_short_lived_instance) {
     69     // This is slightly complicated thanks to the Linux shared library build,
     70     // which shares more compilation units between the NPAPI plug-in and
     71     // the base code.
     72     at_exit_manager_ = new base::ShadowingAtExitManager();
     73     base::Thread random_thread("random_thread");
     74     random_thread.Start();
     75     random_thread.message_loop()->PostTask(
     76         FROM_HERE, base::Bind(&PluginThreadAsyncCallTest::AsyncCall,
     77                               base::Unretained(this)));
     78   }
     79 
     80   return NPERR_NO_ERROR;
     81 }
     82 
     83 void PluginThreadAsyncCallTest::AsyncCall() {
     84   HostFunctions()->pluginthreadasynccall(id(), OnCallSucceededHelper, this);
     85 }
     86 
     87 void PluginThreadAsyncCallTest::OnCallSucceeded() {
     88   // Delete the short lived instance.
     89   NPIdentifier delete_id = HostFunctions()->getstringidentifier(
     90       "deleteShortLivedInstance");
     91 
     92   NPObject *window_obj = NULL;
     93   HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
     94 
     95   NPVariant result;
     96   HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &result);
     97 }
     98 
     99 NPError PluginThreadAsyncCallTest::Destroy() {
    100   if (this == g_short_lived_instance) {
    101     // Schedule an async call that should not be called.
    102     HostFunctions()->pluginthreadasynccall(id(), OnCallFailed, NULL);
    103 
    104     // Schedule an async call to end the test using the long lived instance.
    105     HostFunctions()->pluginthreadasynccall(g_long_lived_instance->id(),
    106                                            OnCallCompletedHelper,
    107                                            g_long_lived_instance);
    108   }
    109 
    110   return NPERR_NO_ERROR;
    111 }
    112 
    113 void PluginThreadAsyncCallTest::OnCallCompleted() {
    114   SignalTestCompleted();
    115 }
    116 
    117 }  // namespace NPAPIClient
    118