startupcache/test/TestStartupCache.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "TestHarness.h"
michael@0 7
michael@0 8 #include "nsThreadUtils.h"
michael@0 9 #include "nsIClassInfo.h"
michael@0 10 #include "nsIOutputStream.h"
michael@0 11 #include "nsIObserver.h"
michael@0 12 #include "nsISerializable.h"
michael@0 13 #include "nsISupports.h"
michael@0 14 #include "nsIStartupCache.h"
michael@0 15 #include "nsIStringStream.h"
michael@0 16 #include "nsIStorageStream.h"
michael@0 17 #include "nsIObjectInputStream.h"
michael@0 18 #include "nsIObjectOutputStream.h"
michael@0 19 #include "nsIURI.h"
michael@0 20 #include "nsStringAPI.h"
michael@0 21 #include "nsIPrefBranch.h"
michael@0 22 #include "nsIPrefService.h"
michael@0 23 #include "nsIXPConnect.h"
michael@0 24 #include "prio.h"
michael@0 25 #include "mozilla/Maybe.h"
michael@0 26
michael@0 27 using namespace JS;
michael@0 28
michael@0 29 namespace mozilla {
michael@0 30 namespace scache {
michael@0 31
michael@0 32 NS_IMPORT nsresult
michael@0 33 NewObjectInputStreamFromBuffer(char* buffer, uint32_t len,
michael@0 34 nsIObjectInputStream** stream);
michael@0 35
michael@0 36 // We can't retrieve the wrapped stream from the objectOutputStream later,
michael@0 37 // so we return it here.
michael@0 38 NS_IMPORT nsresult
michael@0 39 NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
michael@0 40 nsIStorageStream** stream);
michael@0 41
michael@0 42 NS_IMPORT nsresult
michael@0 43 NewBufferFromStorageStream(nsIStorageStream *storageStream,
michael@0 44 char** buffer, uint32_t* len);
michael@0 45 }
michael@0 46 }
michael@0 47
michael@0 48 using namespace mozilla::scache;
michael@0 49
michael@0 50 #define NS_ENSURE_STR_MATCH(str1, str2, testname) \
michael@0 51 PR_BEGIN_MACRO \
michael@0 52 if (0 != strcmp(str1, str2)) { \
michael@0 53 fail("failed " testname); \
michael@0 54 return NS_ERROR_FAILURE; \
michael@0 55 } \
michael@0 56 passed("passed " testname); \
michael@0 57 PR_END_MACRO
michael@0 58
michael@0 59 nsresult
michael@0 60 WaitForStartupTimer() {
michael@0 61 nsresult rv;
michael@0 62 nsCOMPtr<nsIStartupCache> sc
michael@0 63 = do_GetService("@mozilla.org/startupcache/cache;1");
michael@0 64 PR_Sleep(10 * PR_TicksPerSecond());
michael@0 65
michael@0 66 bool complete;
michael@0 67 while (true) {
michael@0 68
michael@0 69 NS_ProcessPendingEvents(nullptr);
michael@0 70 rv = sc->StartupWriteComplete(&complete);
michael@0 71 if (NS_FAILED(rv) || complete)
michael@0 72 break;
michael@0 73 PR_Sleep(1 * PR_TicksPerSecond());
michael@0 74 }
michael@0 75 return rv;
michael@0 76 }
michael@0 77
michael@0 78 nsresult
michael@0 79 TestStartupWriteRead() {
michael@0 80 nsresult rv;
michael@0 81 nsCOMPtr<nsIStartupCache> sc
michael@0 82 = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
michael@0 83 if (!sc) {
michael@0 84 fail("didn't get a pointer...");
michael@0 85 return NS_ERROR_FAILURE;
michael@0 86 } else {
michael@0 87 passed("got a pointer?");
michael@0 88 }
michael@0 89 sc->InvalidateCache();
michael@0 90
michael@0 91 const char* buf = "Market opportunities for BeardBook";
michael@0 92 const char* id = "id";
michael@0 93 char* outbufPtr = nullptr;
michael@0 94 nsAutoArrayPtr<char> outbuf;
michael@0 95 uint32_t len;
michael@0 96
michael@0 97 rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
michael@0 98 NS_ENSURE_SUCCESS(rv, rv);
michael@0 99
michael@0 100 rv = sc->GetBuffer(id, &outbufPtr, &len);
michael@0 101 NS_ENSURE_SUCCESS(rv, rv);
michael@0 102 outbuf = outbufPtr;
michael@0 103 NS_ENSURE_STR_MATCH(buf, outbuf, "pre-write read");
michael@0 104
michael@0 105 rv = sc->ResetStartupWriteTimer();
michael@0 106 rv = WaitForStartupTimer();
michael@0 107 NS_ENSURE_SUCCESS(rv, rv);
michael@0 108
michael@0 109 rv = sc->GetBuffer(id, &outbufPtr, &len);
michael@0 110 NS_ENSURE_SUCCESS(rv, rv);
michael@0 111 outbuf = outbufPtr;
michael@0 112 NS_ENSURE_STR_MATCH(buf, outbuf, "simple write/read");
michael@0 113
michael@0 114 return NS_OK;
michael@0 115 }
michael@0 116
michael@0 117 nsresult
michael@0 118 TestWriteInvalidateRead() {
michael@0 119 nsresult rv;
michael@0 120 const char* buf = "BeardBook competitive analysis";
michael@0 121 const char* id = "id";
michael@0 122 char* outbuf = nullptr;
michael@0 123 uint32_t len;
michael@0 124 nsCOMPtr<nsIStartupCache> sc
michael@0 125 = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
michael@0 126 sc->InvalidateCache();
michael@0 127
michael@0 128 rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
michael@0 129 NS_ENSURE_SUCCESS(rv, rv);
michael@0 130
michael@0 131 sc->InvalidateCache();
michael@0 132
michael@0 133 rv = sc->GetBuffer(id, &outbuf, &len);
michael@0 134 delete[] outbuf;
michael@0 135 if (rv == NS_ERROR_NOT_AVAILABLE) {
michael@0 136 passed("buffer not available after invalidate");
michael@0 137 } else if (NS_SUCCEEDED(rv)) {
michael@0 138 fail("GetBuffer succeeded unexpectedly after invalidate");
michael@0 139 return NS_ERROR_UNEXPECTED;
michael@0 140 } else {
michael@0 141 fail("GetBuffer gave an unexpected failure, expected NOT_AVAILABLE");
michael@0 142 return rv;
michael@0 143 }
michael@0 144
michael@0 145 sc->InvalidateCache();
michael@0 146 return NS_OK;
michael@0 147 }
michael@0 148
michael@0 149 nsresult
michael@0 150 TestWriteObject() {
michael@0 151 nsresult rv;
michael@0 152
michael@0 153 nsCOMPtr<nsIURI> obj
michael@0 154 = do_CreateInstance("@mozilla.org/network/simple-uri;1");
michael@0 155 if (!obj) {
michael@0 156 fail("did not create object in test write object");
michael@0 157 return NS_ERROR_UNEXPECTED;
michael@0 158 }
michael@0 159 NS_NAMED_LITERAL_CSTRING(spec, "http://www.mozilla.org");
michael@0 160 obj->SetSpec(spec);
michael@0 161 nsCOMPtr<nsIStartupCache> sc = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
michael@0 162
michael@0 163 sc->InvalidateCache();
michael@0 164
michael@0 165 // Create an object stream. Usually this is done with
michael@0 166 // NewObjectOutputWrappedStorageStream, but that uses
michael@0 167 // StartupCache::GetSingleton in debug builds, and we
michael@0 168 // don't have access to that here. Obviously.
michael@0 169 const char* id = "id";
michael@0 170 nsCOMPtr<nsIStorageStream> storageStream
michael@0 171 = do_CreateInstance("@mozilla.org/storagestream;1");
michael@0 172 NS_ENSURE_ARG_POINTER(storageStream);
michael@0 173
michael@0 174 rv = storageStream->Init(256, (uint32_t) -1);
michael@0 175 NS_ENSURE_SUCCESS(rv, rv);
michael@0 176
michael@0 177 nsCOMPtr<nsIObjectOutputStream> objectOutput
michael@0 178 = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
michael@0 179 if (!objectOutput)
michael@0 180 return NS_ERROR_OUT_OF_MEMORY;
michael@0 181
michael@0 182 nsCOMPtr<nsIOutputStream> outputStream
michael@0 183 = do_QueryInterface(storageStream);
michael@0 184
michael@0 185 rv = objectOutput->SetOutputStream(outputStream);
michael@0 186
michael@0 187 if (NS_FAILED(rv)) {
michael@0 188 fail("failed to create output stream");
michael@0 189 return rv;
michael@0 190 }
michael@0 191 nsCOMPtr<nsISupports> objQI(do_QueryInterface(obj));
michael@0 192 rv = objectOutput->WriteObject(objQI, true);
michael@0 193 if (NS_FAILED(rv)) {
michael@0 194 fail("failed to write object");
michael@0 195 return rv;
michael@0 196 }
michael@0 197
michael@0 198 char* bufPtr = nullptr;
michael@0 199 nsAutoArrayPtr<char> buf;
michael@0 200 uint32_t len;
michael@0 201 NewBufferFromStorageStream(storageStream, &bufPtr, &len);
michael@0 202 buf = bufPtr;
michael@0 203
michael@0 204 // Since this is a post-startup write, it should be written and
michael@0 205 // available.
michael@0 206 rv = sc->PutBuffer(id, buf, len);
michael@0 207 if (NS_FAILED(rv)) {
michael@0 208 fail("failed to insert input stream");
michael@0 209 return rv;
michael@0 210 }
michael@0 211
michael@0 212 char* buf2Ptr = nullptr;
michael@0 213 nsAutoArrayPtr<char> buf2;
michael@0 214 uint32_t len2;
michael@0 215 nsCOMPtr<nsIObjectInputStream> objectInput;
michael@0 216 rv = sc->GetBuffer(id, &buf2Ptr, &len2);
michael@0 217 if (NS_FAILED(rv)) {
michael@0 218 fail("failed to retrieve buffer");
michael@0 219 return rv;
michael@0 220 }
michael@0 221 buf2 = buf2Ptr;
michael@0 222
michael@0 223 rv = NewObjectInputStreamFromBuffer(buf2, len2, getter_AddRefs(objectInput));
michael@0 224 if (NS_FAILED(rv)) {
michael@0 225 fail("failed to created input stream");
michael@0 226 return rv;
michael@0 227 }
michael@0 228 buf2.forget();
michael@0 229
michael@0 230 nsCOMPtr<nsISupports> deserialized;
michael@0 231 rv = objectInput->ReadObject(true, getter_AddRefs(deserialized));
michael@0 232 if (NS_FAILED(rv)) {
michael@0 233 fail("failed to read object");
michael@0 234 return rv;
michael@0 235 }
michael@0 236
michael@0 237 bool match = false;
michael@0 238 nsCOMPtr<nsIURI> uri(do_QueryInterface(deserialized));
michael@0 239 if (uri) {
michael@0 240 nsCString outSpec;
michael@0 241 uri->GetSpec(outSpec);
michael@0 242 match = outSpec.Equals(spec);
michael@0 243 }
michael@0 244 if (!match) {
michael@0 245 fail("deserialized object has incorrect information");
michael@0 246 return rv;
michael@0 247 }
michael@0 248
michael@0 249 passed("write object");
michael@0 250 return NS_OK;
michael@0 251 }
michael@0 252
michael@0 253 nsresult
michael@0 254 LockCacheFile(bool protect, nsIFile* profileDir) {
michael@0 255 NS_ENSURE_ARG(profileDir);
michael@0 256
michael@0 257 nsCOMPtr<nsIFile> startupCache;
michael@0 258 profileDir->Clone(getter_AddRefs(startupCache));
michael@0 259 NS_ENSURE_STATE(startupCache);
michael@0 260 startupCache->AppendNative(NS_LITERAL_CSTRING("startupCache"));
michael@0 261
michael@0 262 nsresult rv;
michael@0 263 #ifndef XP_WIN
michael@0 264 static uint32_t oldPermissions;
michael@0 265 #else
michael@0 266 static PRFileDesc* fd = nullptr;
michael@0 267 #endif
michael@0 268
michael@0 269 // To prevent deletion of the startupcache file, we change the containing
michael@0 270 // directory's permissions on Linux/Mac, and hold the file open on Windows
michael@0 271 if (protect) {
michael@0 272 #ifndef XP_WIN
michael@0 273 rv = startupCache->GetPermissions(&oldPermissions);
michael@0 274 NS_ENSURE_SUCCESS(rv, rv);
michael@0 275 rv = startupCache->SetPermissions(0555);
michael@0 276 NS_ENSURE_SUCCESS(rv, rv);
michael@0 277 #else
michael@0 278 // Filename logic from StartupCache.cpp
michael@0 279 #ifdef IS_BIG_ENDIAN
michael@0 280 #define SC_ENDIAN "big"
michael@0 281 #else
michael@0 282 #define SC_ENDIAN "little"
michael@0 283 #endif
michael@0 284
michael@0 285 #if PR_BYTES_PER_WORD == 4
michael@0 286 #define SC_WORDSIZE "4"
michael@0 287 #else
michael@0 288 #define SC_WORDSIZE "8"
michael@0 289 #endif
michael@0 290 char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN;
michael@0 291 startupCache->AppendNative(NS_LITERAL_CSTRING(sStartupCacheName));
michael@0 292
michael@0 293 rv = startupCache->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
michael@0 294 NS_ENSURE_SUCCESS(rv, rv);
michael@0 295 #endif
michael@0 296 } else {
michael@0 297 #ifndef XP_WIN
michael@0 298 rv = startupCache->SetPermissions(oldPermissions);
michael@0 299 NS_ENSURE_SUCCESS(rv, rv);
michael@0 300 #else
michael@0 301 PR_Close(fd);
michael@0 302 #endif
michael@0 303 }
michael@0 304
michael@0 305 return NS_OK;
michael@0 306 }
michael@0 307
michael@0 308 nsresult
michael@0 309 TestIgnoreDiskCache(nsIFile* profileDir) {
michael@0 310 nsresult rv;
michael@0 311 nsCOMPtr<nsIStartupCache> sc
michael@0 312 = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
michael@0 313 sc->InvalidateCache();
michael@0 314
michael@0 315 const char* buf = "Get a Beardbook app for your smartphone";
michael@0 316 const char* id = "id";
michael@0 317 char* outbuf = nullptr;
michael@0 318 uint32_t len;
michael@0 319
michael@0 320 rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
michael@0 321 NS_ENSURE_SUCCESS(rv, rv);
michael@0 322 rv = sc->ResetStartupWriteTimer();
michael@0 323 rv = WaitForStartupTimer();
michael@0 324 NS_ENSURE_SUCCESS(rv, rv);
michael@0 325
michael@0 326 // Prevent StartupCache::InvalidateCache from deleting the disk file
michael@0 327 rv = LockCacheFile(true, profileDir);
michael@0 328 NS_ENSURE_SUCCESS(rv, rv);
michael@0 329
michael@0 330 sc->IgnoreDiskCache();
michael@0 331
michael@0 332 rv = sc->GetBuffer(id, &outbuf, &len);
michael@0 333
michael@0 334 nsresult r = LockCacheFile(false, profileDir);
michael@0 335 NS_ENSURE_SUCCESS(r, r);
michael@0 336
michael@0 337 delete[] outbuf;
michael@0 338
michael@0 339 if (rv == NS_ERROR_NOT_AVAILABLE) {
michael@0 340 passed("buffer not available after ignoring disk cache");
michael@0 341 } else if (NS_SUCCEEDED(rv)) {
michael@0 342 fail("GetBuffer succeeded unexpectedly after ignoring disk cache");
michael@0 343 return NS_ERROR_UNEXPECTED;
michael@0 344 } else {
michael@0 345 fail("GetBuffer gave an unexpected failure, expected NOT_AVAILABLE");
michael@0 346 return rv;
michael@0 347 }
michael@0 348
michael@0 349 sc->InvalidateCache();
michael@0 350 return NS_OK;
michael@0 351 }
michael@0 352
michael@0 353 nsresult
michael@0 354 TestEarlyShutdown() {
michael@0 355 nsresult rv;
michael@0 356 nsCOMPtr<nsIStartupCache> sc
michael@0 357 = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
michael@0 358 sc->InvalidateCache();
michael@0 359
michael@0 360 const char* buf = "Find your soul beardmate on BeardBook";
michael@0 361 const char* id = "id";
michael@0 362 uint32_t len;
michael@0 363 char* outbuf = nullptr;
michael@0 364
michael@0 365 sc->ResetStartupWriteTimer();
michael@0 366 rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
michael@0 367 NS_ENSURE_SUCCESS(rv, rv);
michael@0 368
michael@0 369 nsCOMPtr<nsIObserver> obs;
michael@0 370 sc->GetObserver(getter_AddRefs(obs));
michael@0 371 obs->Observe(nullptr, "xpcom-shutdown", nullptr);
michael@0 372 rv = WaitForStartupTimer();
michael@0 373 NS_ENSURE_SUCCESS(rv, rv);
michael@0 374
michael@0 375 rv = sc->GetBuffer(id, &outbuf, &len);
michael@0 376 delete[] outbuf;
michael@0 377
michael@0 378 if (NS_SUCCEEDED(rv)) {
michael@0 379 passed("GetBuffer succeeded after early shutdown");
michael@0 380 } else {
michael@0 381 fail("GetBuffer failed after early shutdown");
michael@0 382 return rv;
michael@0 383 }
michael@0 384
michael@0 385 const char* other_id = "other_id";
michael@0 386 rv = sc->PutBuffer(other_id, buf, strlen(buf) + 1);
michael@0 387
michael@0 388 if (rv == NS_ERROR_NOT_AVAILABLE) {
michael@0 389 passed("PutBuffer not available after early shutdown");
michael@0 390 } else if (NS_SUCCEEDED(rv)) {
michael@0 391 fail("PutBuffer succeeded unexpectedly after early shutdown");
michael@0 392 return NS_ERROR_UNEXPECTED;
michael@0 393 } else {
michael@0 394 fail("PutBuffer gave an unexpected failure, expected NOT_AVAILABLE");
michael@0 395 return rv;
michael@0 396 }
michael@0 397
michael@0 398 return NS_OK;
michael@0 399 }
michael@0 400
michael@0 401 int main(int argc, char** argv)
michael@0 402 {
michael@0 403 ScopedXPCOM xpcom("Startup Cache");
michael@0 404 if (xpcom.failed())
michael@0 405 return 1;
michael@0 406
michael@0 407 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 408 prefs->SetIntPref("hangmonitor.timeout", 0);
michael@0 409
michael@0 410 int rv = 0;
michael@0 411 nsresult scrv;
michael@0 412
michael@0 413 // Register TestStartupCacheTelemetry
michael@0 414 nsCOMPtr<nsIFile> manifest;
michael@0 415 scrv = NS_GetSpecialDirectory(NS_GRE_DIR,
michael@0 416 getter_AddRefs(manifest));
michael@0 417 if (NS_FAILED(scrv)) {
michael@0 418 fail("NS_XPCOM_CURRENT_PROCESS_DIR");
michael@0 419 return 1;
michael@0 420 }
michael@0 421
michael@0 422 manifest->AppendNative(NS_LITERAL_CSTRING("TestStartupCacheTelemetry.manifest"));
michael@0 423 XRE_AddManifestLocation(NS_COMPONENT_LOCATION, manifest);
michael@0 424
michael@0 425 nsCOMPtr<nsIObserver> telemetryThing =
michael@0 426 do_GetService("@mozilla.org/testing/startup-cache-telemetry.js");
michael@0 427 if (!telemetryThing) {
michael@0 428 fail("telemetryThing");
michael@0 429 return 1;
michael@0 430 }
michael@0 431 scrv = telemetryThing->Observe(nullptr, "save-initial", nullptr);
michael@0 432 if (NS_FAILED(scrv)) {
michael@0 433 fail("save-initial");
michael@0 434 rv = 1;
michael@0 435 }
michael@0 436
michael@0 437 nsCOMPtr<nsIStartupCache> sc
michael@0 438 = do_GetService("@mozilla.org/startupcache/cache;1", &scrv);
michael@0 439 if (NS_FAILED(scrv))
michael@0 440 rv = 1;
michael@0 441 else
michael@0 442 sc->RecordAgesAlways();
michael@0 443 if (NS_FAILED(TestStartupWriteRead()))
michael@0 444 rv = 1;
michael@0 445 if (NS_FAILED(TestWriteInvalidateRead()))
michael@0 446 rv = 1;
michael@0 447 if (NS_FAILED(TestWriteObject()))
michael@0 448 rv = 1;
michael@0 449 nsCOMPtr<nsIFile> profileDir = xpcom.GetProfileDirectory();
michael@0 450 if (NS_FAILED(TestIgnoreDiskCache(profileDir)))
michael@0 451 rv = 1;
michael@0 452 if (NS_FAILED(TestEarlyShutdown()))
michael@0 453 rv = 1;
michael@0 454
michael@0 455 scrv = telemetryThing->Observe(nullptr, "save-initial", nullptr);
michael@0 456 if (NS_FAILED(scrv)) {
michael@0 457 fail("check-final");
michael@0 458 rv = 1;
michael@0 459 }
michael@0 460
michael@0 461 return rv;
michael@0 462 }

mercurial