1 // Copyright (c) 2012 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 #ifndef PPAPI_TESTS_TEST_UTILS_H_
6 #define PPAPI_TESTS_TEST_UTILS_H_
7 
8 #include <string>
9 
10 #include "ppapi/c/pp_instance.h"
11 #include "ppapi/c/pp_stdint.h"
12 #include "ppapi/c/private/ppb_testing_private.h"
13 #include "ppapi/cpp/completion_callback.h"
14 #include "ppapi/cpp/message_loop.h"
15 #include "ppapi/utility/completion_callback_factory.h"
16 
17 namespace pp {
18 class NetAddress;
19 class URLLoader;
20 class URLRequestInfo;
21 }
22 
23 // Timeout to wait for some action to complete.
24 extern const int kActionTimeoutMs;
25 
26 const PPB_Testing_Private* GetTestingInterface();
27 std::string ReportError(const char* method, int32_t error);
28 void PlatformSleep(int duration_ms);
29 
30 // Returns the host and port of the current document's URL (Which is generally
31 // served by an EmbeddedTestServer). Returns false on failure.
32 bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port);
33 
34 uint16_t ConvertFromNetEndian16(uint16_t x);
35 uint16_t ConvertToNetEndian16(uint16_t x);
36 bool EqualNetAddress(const pp::NetAddress& addr1, const pp::NetAddress& addr2);
37 // Only returns the first address if there are more than one available.
38 bool ResolveHost(PP_Instance instance,
39                  const std::string& host,
40                  uint16_t port,
41                  pp::NetAddress* addr);
42 bool ReplacePort(PP_Instance instance,
43                  const pp::NetAddress& input_addr,
44                  uint16_t port,
45                  pp::NetAddress* output_addr);
46 uint16_t GetPort(const pp::NetAddress& addr);
47 
48 // NestedEvent allows you to run a nested MessageLoop and wait for a particular
49 // event to complete. For example, you can use it to wait for a callback on a
50 // PPP interface, which will "Signal" the event and make the loop quit.
51 // "Wait()" will return immediately if it has already been signalled. Otherwise,
52 // it will run a nested run loop (using PPB_Testing.RunMessageLoop) and will
53 // return only after it has been signalled.
54 // Example:
55 //  std::string TestFullscreen::TestNormalToFullscreen() {
56 //    pp::Fullscreen screen_mode(instance);
57 //    screen_mode.SetFullscreen(true);
58 //    SimulateUserGesture();
59 //    // Let DidChangeView run in a nested run loop.
60 //    nested_event_.Wait();
61 //    Pass();
62 //  }
63 //
64 //  void TestFullscreen::DidChangeView(const pp::View& view) {
65 //    nested_event_.Signal();
66 //  }
67 //
68 // All methods except Signal and PostSignal must be invoked on the main thread.
69 // It's OK to signal from a background thread, so you can (for example) Signal()
70 // from the Audio thread.
71 class NestedEvent {
72  public:
NestedEvent(PP_Instance instance)73   explicit NestedEvent(PP_Instance instance)
74       : instance_(instance), waiting_(false), signalled_(false) {
75   }
76   // Run a nested run loop and wait until Signal() is called. If Signal()
77   // has already been called, return immediately without running a nested loop.
78   void Wait();
79   // Signal the NestedEvent. If Wait() has been called, quit the message loop.
80   // This can be called from any thread.
81   void Signal();
82   // Signal the NestedEvent in |wait_ms| milliseconds. This can be called from
83   // any thread.
84   void PostSignal(int32_t wait_ms);
85 
86   // Reset the NestedEvent so it can be used again.
87   void Reset();
88 
89  private:
90   void SignalOnMainThread();
91   static void SignalThunk(void* async_event, int32_t result);
92 
93   PP_Instance instance_;
94   bool waiting_;
95   bool signalled_;
96   // Disable copy and assign.
97   NestedEvent(const NestedEvent&);
98   NestedEvent& operator=(const NestedEvent&);
99 };
100 
101 // Returns a callback that does nothing, so can be invoked when the current
102 // function is out of scope, unlike TestCompletionCallback.
103 pp::CompletionCallback DoNothingCallback();
104 
105 template <typename OutputT>
DeleteStorage(void * user_data,int32_t flags)106 void DeleteStorage(void* user_data, int32_t flags) {
107   typename pp::CompletionCallbackWithOutput<OutputT>::OutputStorageType*
108       storage = reinterpret_cast<typename pp::CompletionCallbackWithOutput<
109           OutputT>::OutputStorageType*>(user_data);
110   delete storage;
111 }
112 
113 // Same as DoNothingCallback(), but with an OutputStorageType, which it deletes
114 // when the callback is invoked.
115 template <typename OutputT>
DoNothingCallbackWithOutput()116 pp::CompletionCallbackWithOutput<OutputT> DoNothingCallbackWithOutput() {
117   typename pp::CompletionCallbackWithOutput<OutputT>::OutputStorageType*
118       storage = new
119       typename pp::CompletionCallbackWithOutput<OutputT>::OutputStorageType();
120   return pp::CompletionCallbackWithOutput<OutputT>(
121       &DeleteStorage<OutputT>, storage, PP_COMPLETIONCALLBACK_FLAG_OPTIONAL,
122       storage);
123 }
124 
125 enum CallbackType { PP_REQUIRED, PP_OPTIONAL, PP_BLOCKING };
126 class TestCompletionCallback {
127  public:
128   class Delegate {
129    public:
~Delegate()130     virtual ~Delegate() {}
131     virtual void OnCallback(void* user_data, int32_t result) = 0;
132   };
133   explicit TestCompletionCallback(PP_Instance instance);
134   // TODO(dmichael): Remove this constructor.
135   TestCompletionCallback(PP_Instance instance, bool force_async);
136 
137   TestCompletionCallback(PP_Instance instance, CallbackType callback_type);
138 
139   // Sets a Delegate instance. OnCallback() of this instance will be invoked
140   // when the completion callback is invoked.
141   // The delegate will be reset when Reset() or GetCallback() is called.
SetDelegate(Delegate * delegate)142   void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
143 
144   // Wait for a result, given the return from the call which took this callback
145   // as a parameter. If |result| is PP_OK_COMPLETIONPENDING, WaitForResult will
146   // block until its callback has been invoked (in some cases, this will already
147   // have happened, and WaitForCallback can return immediately).
148   // For any other values, WaitForResult will simply set its internal "result_"
149   // field. To retrieve the final result of the operation (i.e., the result
150   // the callback has run, if necessary), call result(). You can call result()
151   // as many times as necessary until a new pp::CompletionCallback is retrieved.
152   //
153   // In some cases, you may want to check that the callback was invoked in the
154   // expected way (i.e., if the callback was "Required", then it should be
155   // invoked asynchronously). Within the body of a test (where returning a non-
156   // empty string indicates test failure), you can use the
157   // CHECK_CALLBACK_BEHAVIOR(callback) macro. From within a helper function,
158   // you can use failed() and errors().
159   //
160   // Example usage within a test:
161   //  callback.WaitForResult(foo.DoSomething(callback));
162   //  CHECK_CALLBACK_BEHAVIOR(callback);
163   //  ASSERT_EQ(PP_OK, callback.result());
164   //
165   // Example usage within a helper function:
166   //  void HelperFunction(std::string* error_message) {
167   //    callback.WaitForResult(foo.DoSomething(callback));
168   //    if (callback.failed())
169   //      error_message->assign(callback.errors());
170   //  }
171   void WaitForResult(int32_t result);
172 
173   // Used when you expect to receive either synchronous completion with PP_OK
174   // or a PP_ERROR_ABORTED asynchronously.
175   //  Example usage:
176   //  int32_t result = 0;
177   //  {
178   //    pp::URLLoader temp(instance_);
179   //    result = temp.Open(request, callback);
180   //  }
181   //  callback.WaitForAbortResult(result);
182   //  CHECK_CALLBACK_BEHAVIOR(callback);
183   void WaitForAbortResult(int32_t result);
184 
185   // Retrieve a pp::CompletionCallback for use in testing. This Reset()s the
186   // TestCompletionCallback.
187   pp::CompletionCallback GetCallback();
188 
failed()189   bool failed() { return !errors_.empty(); }
errors()190   const std::string& errors() { return errors_; }
191 
result()192   int32_t result() const { return result_; }
193 
194   // Reset so that this callback can be used again.
195   void Reset();
196 
callback_type()197   CallbackType callback_type() { return callback_type_; }
set_target_loop(const pp::MessageLoop & loop)198   void set_target_loop(const pp::MessageLoop& loop) { target_loop_ = loop; }
199   static void Handler(void* user_data, int32_t result);
200 
201  protected:
202   void RunMessageLoop();
203   void QuitMessageLoop();
204 
205   // Used to check that WaitForResult is only called once for each usage of the
206   // callback.
207   bool wait_for_result_called_;
208   // Indicates whether we have already been invoked.
209   bool have_result_;
210   // The last result received (or PP_OK_COMPLETIONCALLBACK if none).
211   int32_t result_;
212   CallbackType callback_type_;
213   bool post_quit_task_;
214   std::string errors_;
215   PP_Instance instance_;
216   Delegate* delegate_;
217   pp::MessageLoop target_loop_;
218 };
219 
220 template <typename OutputT>
221 class TestCompletionCallbackWithOutput {
222  public:
TestCompletionCallbackWithOutput(PP_Instance instance)223   explicit TestCompletionCallbackWithOutput(PP_Instance instance)
224       : callback_(instance),
225         output_storage_() {
226     pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_);
227   }
228 
TestCompletionCallbackWithOutput(PP_Instance instance,bool force_async)229   TestCompletionCallbackWithOutput(PP_Instance instance, bool force_async)
230       : callback_(instance, force_async),
231         output_storage_() {
232     pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_);
233   }
234 
TestCompletionCallbackWithOutput(PP_Instance instance,CallbackType callback_type)235   TestCompletionCallbackWithOutput(PP_Instance instance,
236                                    CallbackType callback_type)
237       : callback_(instance, callback_type),
238         output_storage_() {
239     pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_);
240   }
241 
242   pp::CompletionCallbackWithOutput<OutputT> GetCallback();
output()243   OutputT output() {
244     return pp::internal::CallbackOutputTraits<OutputT>::StorageToPluginArg(
245         output_storage_);
246   }
247 
248   // Delegate functions to TestCompletionCallback
SetDelegate(TestCompletionCallback::Delegate * delegate)249   void SetDelegate(TestCompletionCallback::Delegate* delegate) {
250     callback_.SetDelegate(delegate);
251   }
WaitForResult(int32_t result)252   void WaitForResult(int32_t result) { callback_.WaitForResult(result); }
WaitForAbortResult(int32_t result)253   void WaitForAbortResult(int32_t result) {
254     callback_.WaitForAbortResult(result);
255   }
failed()256   bool failed() { return callback_.failed(); }
errors()257   const std::string& errors() { return callback_.errors(); }
result()258   int32_t result() const { return callback_.result(); }
Reset()259   void Reset() {
260     pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_);
261     return callback_.Reset();
262   }
263 
264  private:
265   TestCompletionCallback callback_;
266   typename pp::CompletionCallbackWithOutput<OutputT>::OutputStorageType
267       output_storage_;
268 };
269 
270 template <typename OutputT>
271 pp::CompletionCallbackWithOutput<OutputT>
GetCallback()272 TestCompletionCallbackWithOutput<OutputT>::GetCallback() {
273   this->Reset();
274   if (callback_.callback_type() == PP_BLOCKING) {
275     pp::CompletionCallbackWithOutput<OutputT> cc(&output_storage_);
276     return cc;
277   }
278 
279   callback_.set_target_loop(pp::MessageLoop::GetCurrent());
280   pp::CompletionCallbackWithOutput<OutputT> cc(
281       &TestCompletionCallback::Handler,
282       this,
283       &output_storage_);
284   if (callback_.callback_type() == PP_OPTIONAL)
285     cc.set_flags(PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
286   return cc;
287 }
288 
289 // Verifies that the callback didn't record any errors. If the callback is run
290 // in an unexpected way (e.g., if it's invoked asynchronously when the call
291 // should have blocked), this returns an appropriate error string.
292 #define CHECK_CALLBACK_BEHAVIOR(callback) \
293 do { \
294   if ((callback).failed()) \
295     return MakeFailureMessage(__FILE__, __LINE__, \
296                               (callback).errors().c_str()); \
297 } while (false)
298 
299 /*
300  * A set of macros to use for platform detection. These were largely copied
301  * from chromium's build_config.h.
302  */
303 #if defined(__APPLE__)
304 #define PPAPI_OS_MACOSX 1
305 #elif defined(ANDROID)
306 #define PPAPI_OS_ANDROID 1
307 #elif defined(__native_client__)
308 #define PPAPI_OS_NACL 1
309 #elif defined(__linux__)
310 #define PPAPI_OS_LINUX 1
311 #elif defined(_WIN32)
312 #define PPAPI_OS_WIN 1
313 #elif defined(__FreeBSD__)
314 #define PPAPI_OS_FREEBSD 1
315 #elif defined(__DragonFly__)
316 #define PPAPI_OS_DRAGONFLY 1
317 #elif defined(__OpenBSD__)
318 #define PPAPI_OS_OPENBSD 1
319 #elif defined(__sun)
320 #define PPAPI_OS_SOLARIS 1
321 #else
322 #error Please add support for your platform in ppapi/tests/test_utils.h
323 #endif
324 
325 /* These are used to determine POSIX-like implementations vs Windows. */
326 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
327     defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || \
328     defined(__native_client__)
329 #define PPAPI_POSIX 1
330 #endif
331 
332 // By default, ArrayBuffers over a certain size are sent via shared memory. In
333 // order to test for this without sending huge buffers, tests can use this
334 // class to set the minimum array buffer size used for shared memory temporarily
335 // lower.
336 class ScopedArrayBufferSizeSetter {
337  public:
ScopedArrayBufferSizeSetter(const PPB_Testing_Private * interface,PP_Instance instance,uint32_t threshold)338   ScopedArrayBufferSizeSetter(const PPB_Testing_Private* interface,
339                               PP_Instance instance,
340                               uint32_t threshold)
341      : interface_(interface),
342        instance_(instance) {
343     interface_->SetMinimumArrayBufferSizeForShmem(instance_, threshold);
344   }
~ScopedArrayBufferSizeSetter()345   ~ScopedArrayBufferSizeSetter() {
346     interface_->SetMinimumArrayBufferSizeForShmem(instance_, 0);
347   }
348 
349  private:
350   const PPB_Testing_Private* interface_;
351   PP_Instance instance_;
352 };
353 
354 // Opens |request| in |loader| and returns the results of the URLRequest.  The
355 // caller may provide the optional |response_body| argument to get the contents
356 // of the body of the response to the URLRequest.
357 //
358 // Returns PP_OK upon success.
359 int32_t OpenURLRequest(PP_Instance instance,
360                        pp::URLLoader* loader,
361                        const pp::URLRequestInfo& request,
362                        CallbackType callback_type,
363                        std::string* response_body);
364 
365 #endif  // PPAPI_TESTS_TEST_UTILS_H_
366