Updates the mic icon status based on the device's audio state (2nd)
[chromium-blink-merge.git] / chrome / common / mac / mock_launchd.cc
blob237e3ed38b8cb2e779c21d2241eae23c20ea8f60
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.
5 #include "chrome/common/mac/mock_launchd.h"
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
11 #include "base/basictypes.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/mac/foundation_util.h"
15 #include "base/mac/scoped_cftyperef.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/strings/sys_string_conversions.h"
20 #include "chrome/common/chrome_version_info.h"
21 #include "chrome/common/mac/launchd.h"
22 #include "chrome/common/service_process_util.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 static sockaddr_un* throwaway_sockaddr_un;
26 static const size_t kMaxPipeNameLength =
27 sizeof(throwaway_sockaddr_un->sun_path);
29 // static
30 bool MockLaunchd::MakeABundle(const base::FilePath& dst,
31 const std::string& name,
32 base::FilePath* bundle_root,
33 base::FilePath* executable) {
34 *bundle_root = dst.Append(name + std::string(".app"));
35 base::FilePath contents = bundle_root->AppendASCII("Contents");
36 base::FilePath mac_os = contents.AppendASCII("MacOS");
37 *executable = mac_os.Append(name);
38 base::FilePath info_plist = contents.Append("Info.plist");
40 if (!base::CreateDirectory(mac_os)) {
41 return false;
43 const char *data = "#! testbundle\n";
44 int len = strlen(data);
45 if (base::WriteFile(*executable, data, len) != len) {
46 return false;
48 if (chmod(executable->value().c_str(), 0555) != 0) {
49 return false;
52 chrome::VersionInfo version_info;
54 const char info_plist_format[] =
55 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
56 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
57 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
58 "<plist version=\"1.0\">\n"
59 "<dict>\n"
60 " <key>CFBundleDevelopmentRegion</key>\n"
61 " <string>English</string>\n"
62 " <key>CFBundleExecutable</key>\n"
63 " <string>%s</string>\n"
64 " <key>CFBundleIdentifier</key>\n"
65 " <string>com.test.%s</string>\n"
66 " <key>CFBundleInfoDictionaryVersion</key>\n"
67 " <string>6.0</string>\n"
68 " <key>CFBundleShortVersionString</key>\n"
69 " <string>%s</string>\n"
70 " <key>CFBundleVersion</key>\n"
71 " <string>1</string>\n"
72 "</dict>\n"
73 "</plist>\n";
74 std::string info_plist_data =
75 base::StringPrintf(info_plist_format,
76 name.c_str(),
77 name.c_str(),
78 version_info.Version().c_str());
79 len = info_plist_data.length();
80 if (base::WriteFile(info_plist, info_plist_data.c_str(), len) != len) {
81 return false;
83 const UInt8* bundle_root_path =
84 reinterpret_cast<const UInt8*>(bundle_root->value().c_str());
85 base::ScopedCFTypeRef<CFURLRef> url(
86 CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
87 bundle_root_path,
88 bundle_root->value().length(),
89 true));
90 base::ScopedCFTypeRef<CFBundleRef> bundle(
91 CFBundleCreate(kCFAllocatorDefault, url));
92 return bundle.get();
95 MockLaunchd::MockLaunchd(const base::FilePath& file,
96 base::MessageLoop* loop,
97 bool create_socket,
98 bool as_service)
99 : file_(file),
100 message_loop_(loop),
101 create_socket_(create_socket),
102 as_service_(as_service),
103 restart_called_(false),
104 remove_called_(false),
105 checkin_called_(false),
106 write_called_(false),
107 delete_called_(false) {
108 std::string pipe_suffix("_SOCKET");
109 base::FilePath socket_path = file_;
110 while (socket_path.value().length() + pipe_suffix.length() >
111 kMaxPipeNameLength - 2) {
112 socket_path = socket_path.DirName();
114 pipe_name_ = socket_path.value() + pipe_suffix;
117 MockLaunchd::~MockLaunchd() {
120 CFDictionaryRef MockLaunchd::CopyExports() {
121 if (!create_socket_) {
122 ADD_FAILURE();
123 return NULL;
126 CFStringRef env_var =
127 base::mac::NSToCFCast(GetServiceProcessLaunchDSocketEnvVar());
128 base::ScopedCFTypeRef<CFStringRef> socket_path(CFStringCreateWithCString(
129 kCFAllocatorDefault, pipe_name_.c_str(), kCFStringEncodingUTF8));
130 const void *keys[] = { env_var };
131 const void *values[] = { socket_path };
132 COMPILE_ASSERT(arraysize(keys) == arraysize(values), array_sizes_must_match);
133 return CFDictionaryCreate(kCFAllocatorDefault,
134 keys,
135 values,
136 arraysize(keys),
137 &kCFTypeDictionaryKeyCallBacks,
138 &kCFTypeDictionaryValueCallBacks);
141 CFDictionaryRef MockLaunchd::CopyJobDictionary(CFStringRef label) {
142 if (!as_service_) {
143 scoped_ptr<MultiProcessLock> running_lock(
144 TakeNamedLock(pipe_name_, false));
145 if (running_lock.get())
146 return NULL;
149 CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM);
150 CFStringRef program_pid = CFSTR(LAUNCH_JOBKEY_PID);
151 const void *keys[] = { program, program_pid };
152 base::ScopedCFTypeRef<CFStringRef> path(
153 base::SysUTF8ToCFStringRef(file_.value()));
154 int process_id = base::GetCurrentProcId();
155 base::ScopedCFTypeRef<CFNumberRef> pid(
156 CFNumberCreate(NULL, kCFNumberIntType, &process_id));
157 const void *values[] = { path, pid };
158 COMPILE_ASSERT(arraysize(keys) == arraysize(values), array_sizes_must_match);
159 return CFDictionaryCreate(kCFAllocatorDefault,
160 keys,
161 values,
162 arraysize(keys),
163 &kCFTypeDictionaryKeyCallBacks,
164 &kCFTypeDictionaryValueCallBacks);
167 CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
168 checkin_called_ = true;
169 CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM);
170 CFStringRef program_args = CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS);
171 base::ScopedCFTypeRef<CFStringRef> path(
172 base::SysUTF8ToCFStringRef(file_.value()));
173 const void *array_values[] = { path.get() };
174 base::ScopedCFTypeRef<CFArrayRef> args(CFArrayCreate(
175 kCFAllocatorDefault, array_values, 1, &kCFTypeArrayCallBacks));
177 if (!create_socket_) {
178 const void *keys[] = { program, program_args };
179 const void *values[] = { path, args };
180 COMPILE_ASSERT(arraysize(keys) == arraysize(values),
181 array_sizes_must_match);
182 return CFDictionaryCreate(kCFAllocatorDefault,
183 keys,
184 values,
185 arraysize(keys),
186 &kCFTypeDictionaryKeyCallBacks,
187 &kCFTypeDictionaryValueCallBacks);
190 CFStringRef socket_key = CFSTR(LAUNCH_JOBKEY_SOCKETS);
191 int local_pipe = -1;
192 EXPECT_TRUE(as_service_);
194 // Create unix_addr structure.
195 struct sockaddr_un unix_addr = {0};
196 unix_addr.sun_family = AF_UNIX;
197 size_t path_len =
198 base::strlcpy(unix_addr.sun_path, pipe_name_.c_str(), kMaxPipeNameLength);
199 DCHECK_EQ(pipe_name_.length(), path_len);
200 unix_addr.sun_len = SUN_LEN(&unix_addr);
202 CFSocketSignature signature;
203 signature.protocolFamily = PF_UNIX;
204 signature.socketType = SOCK_STREAM;
205 signature.protocol = 0;
206 size_t unix_addr_len = offsetof(struct sockaddr_un,
207 sun_path) + path_len + 1;
208 base::ScopedCFTypeRef<CFDataRef> address(
209 CFDataCreate(NULL, reinterpret_cast<UInt8*>(&unix_addr), unix_addr_len));
210 signature.address = address;
212 CFSocketRef socket =
213 CFSocketCreateWithSocketSignature(NULL, &signature, 0, NULL, NULL);
215 local_pipe = CFSocketGetNative(socket);
216 EXPECT_NE(-1, local_pipe);
217 if (local_pipe == -1) {
218 if (error) {
219 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX,
220 errno, NULL);
222 return NULL;
225 base::ScopedCFTypeRef<CFNumberRef> socket_fd(
226 CFNumberCreate(NULL, kCFNumberIntType, &local_pipe));
227 const void *socket_array_values[] = { socket_fd };
228 base::ScopedCFTypeRef<CFArrayRef> sockets(CFArrayCreate(
229 kCFAllocatorDefault, socket_array_values, 1, &kCFTypeArrayCallBacks));
230 CFStringRef socket_dict_key = CFSTR("ServiceProcessSocket");
231 const void *socket_keys[] = { socket_dict_key };
232 const void *socket_values[] = { sockets };
233 COMPILE_ASSERT(arraysize(socket_keys) == arraysize(socket_values),
234 socket_array_sizes_must_match);
235 base::ScopedCFTypeRef<CFDictionaryRef> socket_dict(
236 CFDictionaryCreate(kCFAllocatorDefault,
237 socket_keys,
238 socket_values,
239 arraysize(socket_keys),
240 &kCFTypeDictionaryKeyCallBacks,
241 &kCFTypeDictionaryValueCallBacks));
242 const void *keys[] = { program, program_args, socket_key };
243 const void *values[] = { path, args, socket_dict };
244 COMPILE_ASSERT(arraysize(keys) == arraysize(values), array_sizes_must_match);
245 return CFDictionaryCreate(kCFAllocatorDefault,
246 keys,
247 values,
248 arraysize(keys),
249 &kCFTypeDictionaryKeyCallBacks,
250 &kCFTypeDictionaryValueCallBacks);
253 bool MockLaunchd::RemoveJob(CFStringRef label, CFErrorRef* error) {
254 remove_called_ = true;
255 message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
256 return true;
259 bool MockLaunchd::RestartJob(Domain domain,
260 Type type,
261 CFStringRef name,
262 CFStringRef session_type) {
263 restart_called_ = true;
264 message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
265 return true;
268 CFMutableDictionaryRef MockLaunchd::CreatePlistFromFile(
269 Domain domain,
270 Type type,
271 CFStringRef name) {
272 base::ScopedCFTypeRef<CFDictionaryRef> dict(CopyDictionaryByCheckingIn(NULL));
273 return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict);
276 bool MockLaunchd::WritePlistToFile(Domain domain,
277 Type type,
278 CFStringRef name,
279 CFDictionaryRef dict) {
280 write_called_ = true;
281 return true;
284 bool MockLaunchd::DeletePlist(Domain domain,
285 Type type,
286 CFStringRef name) {
287 delete_called_ = true;
288 return true;
291 void MockLaunchd::SignalReady() {
292 ASSERT_TRUE(as_service_);
293 running_lock_.reset(TakeNamedLock(pipe_name_, true));