Add an exponential backoff to rechecking the app list doodle.
[chromium-blink-merge.git] / ppapi / tests / extensions / packaged_app / test_packaged_app.cc
blob0f47205a37398f22ab6eb687be3e70da7a77dc43
1 // Copyright (c) 2014 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.
5 #include <pthread.h>
6 #include <unistd.h>
8 #include <sstream>
9 #include <string>
11 #include "native_client/src/untrusted/irt/irt.h"
13 #include "ppapi/cpp/completion_callback.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/module.h"
16 #include "ppapi/cpp/tcp_socket.h"
17 #include "ppapi/cpp/var.h"
18 #include "ppapi/utility/completion_callback_factory.h"
20 #if defined(__clang__)
21 // ipc_message_attachment_set.h depends on C++11 which nacl-g++ does not
22 // fully support.
23 #include "ipc/ipc_message_attachment_set.h"
24 #endif
26 namespace {
28 std::string g_last_error;
29 pp::Instance* g_instance = NULL;
31 // This should be the same as MessageAttachmentSet::kMaxDescriptorsPerMessage in
32 // ipc/ipc_message_attachment_set.h.
33 const size_t kMaxDescriptorsPerMessage = 128;
35 #if defined(__clang__)
36 static_assert(kMaxDescriptorsPerMessage ==
37 IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage,
38 "kMaxDescriptorsPerMessage is not up to date");
39 #endif
41 // Returns true if the resource file whose name is |key| exists and its content
42 // matches |content|.
43 bool LoadManifestInternal(nacl_irt_resource_open* nacl_irt_resource_open,
44 const std::string& key,
45 const std::string& content) {
46 int desc;
47 int error;
48 error = nacl_irt_resource_open->open_resource(key.c_str(), &desc);
49 if (0 != error) {
50 g_last_error = "Can't open file " + key;
51 return false;
54 std::string str;
56 char buffer[4096];
57 int len;
58 while ((len = read(desc, buffer, sizeof(buffer) - 1)) > 0) {
59 // Null terminate.
60 buffer[len] = '\0';
61 str += buffer;
63 if (close(desc)) {
64 g_last_error = "Close failed: file=" + key;
65 return false;
68 if (str != content) {
69 g_last_error = "Wrong file content: file=" + key + ", expected=" + content +
70 ", actual=" + str;
71 return false;
74 return true;
77 // Tests if open_resource works in a packaged app. This test is similar to
78 // NaClBrowserTest*.IrtManifestFile, but unlike the NaCl test, this one tests
79 // the "fast path" in DownloadNexe() in ppb_nacl_private_impl.cc which opens
80 // resource files without using URLLoader.
81 void LoadManifest() {
82 if (pthread_detach(pthread_self())) {
83 g_last_error = "pthread_detach failed";
84 return;
87 struct nacl_irt_resource_open nacl_irt_resource_open;
88 if (sizeof(nacl_irt_resource_open) !=
89 nacl_interface_query(NACL_IRT_RESOURCE_OPEN_v0_1,
90 &nacl_irt_resource_open,
91 sizeof(nacl_irt_resource_open))) {
92 g_last_error = "NACL_IRT_RESOURCE_OPEN_v0_1 not found";
93 return;
96 for (size_t i = 0; i <= kMaxDescriptorsPerMessage; ++i) {
97 std::stringstream key;
98 key << "test_file" << i;
99 std::string content = "Example contents for open_resource test" +
100 std::string(i % 2 ? "2" : "");
101 if (!LoadManifestInternal(&nacl_irt_resource_open, key.str(), content))
102 break;
103 // Open the same resource file again to make sure each file descriptor
104 // returned from open_resource has its own file offset.
105 if (!LoadManifestInternal(&nacl_irt_resource_open, key.str(), content))
106 break;
110 void PostReply(void* user_data, int32_t status) {
111 if (!g_last_error.empty())
112 g_instance->PostMessage(g_last_error.c_str());
113 else
114 g_instance->PostMessage("PASS");
117 void* RunTestsOnBackgroundThread(void* thread_id) {
118 LoadManifest();
119 pp::Module::Get()->core()->CallOnMainThread(
120 0, pp::CompletionCallback(&PostReply, NULL));
121 return NULL;
124 class MyInstance : public pp::Instance {
125 public:
126 explicit MyInstance(PP_Instance instance)
127 : pp::Instance(instance), socket_(this), factory_(this) {
128 g_instance = this;
130 virtual ~MyInstance() { }
132 void DidBindSocket(int32_t result) {
133 // We didn't ask for socket permission in our manifest, so it should fail.
134 if (result == PP_ERROR_NOACCESS)
135 PostMessage("PASS");
136 else
137 PostMessage(result);
140 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
141 pthread_t thread;
142 // irt_open_resource() isn't allowed to be called on the main thread once
143 // Pepper starts, so the test must happen on a background thread.
144 if (pthread_create(&thread, NULL, &RunTestsOnBackgroundThread, NULL)) {
145 g_last_error = "pthread_create failed";
146 PostReply(NULL, 0);
148 // Attempt to bind a socket. We don't have permissions, so it should fail.
149 PP_NetAddress_IPv4 ipv4_address = {80, {127, 0, 0, 1} };
150 pp::NetAddress address(this, ipv4_address);
151 socket_.Bind(address, factory_.NewCallback(&MyInstance::DidBindSocket));
152 return true;
155 private:
156 pp::TCPSocket socket_;
157 pp::CompletionCallbackFactory<MyInstance> factory_;
160 class MyModule : public pp::Module {
161 public:
162 MyModule() : pp::Module() { }
163 virtual ~MyModule() { }
165 virtual pp::Instance* CreateInstance(PP_Instance instance) {
166 return new MyInstance(instance);
170 } // namespace
172 namespace pp {
174 Module* CreateModule() {
175 return new MyModule();
178 } // namespace pp