1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "gtest/gtest.h"
8 #include "mozilla/scache/StartupCache.h"
9 #include "mozilla/scache/StartupCacheUtils.h"
11 #include "nsDirectoryServiceDefs.h"
12 #include "nsIOutputStream.h"
13 #include "nsISupports.h"
14 #include "nsIStorageStream.h"
15 #include "nsIObjectInputStream.h"
16 #include "nsIObjectOutputStream.h"
18 #include "nsThreadUtils.h"
22 #include "mozilla/gtest/MozAssertions.h"
23 #include "mozilla/Maybe.h"
24 #include "mozilla/Printf.h"
25 #include "mozilla/UniquePtr.h"
26 #include "mozilla/UniquePtrExtensions.h"
28 #include "nsIURIMutator.h"
32 using namespace mozilla::scache
;
33 using mozilla::UniquePtr
;
35 void WaitForStartupTimer() {
36 StartupCache
* sc
= StartupCache::GetSingleton();
37 PR_Sleep(3 * PR_TicksPerSecond());
40 NS_ProcessPendingEvents(nullptr);
41 if (sc
->StartupWriteComplete()) {
44 PR_Sleep(1 * PR_TicksPerSecond());
48 class TestStartupCache
: public ::testing::Test
{
53 nsCOMPtr
<nsIFile
> mSCFile
;
56 TestStartupCache::TestStartupCache() {
57 NS_GetSpecialDirectory(NS_OS_TEMP_DIR
, getter_AddRefs(mSCFile
));
58 mSCFile
->AppendNative("test-startupcache.tmp"_ns
);
60 nsAutoString
env(u
"MOZ_STARTUP_CACHE="_ns
);
61 env
.Append(mSCFile
->NativePath());
65 mSCFile
->GetNativePath(path
);
66 char* env
= mozilla::Smprintf("MOZ_STARTUP_CACHE=%s", path
.get()).release();
68 // We intentionally leak `env` here because it is required by PR_SetEnv
69 MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(env
);
71 StartupCache::GetSingleton()->InvalidateCache();
73 TestStartupCache::~TestStartupCache() {
74 PR_SetEnv("MOZ_STARTUP_CACHE=");
75 StartupCache::GetSingleton()->InvalidateCache();
78 TEST_F(TestStartupCache
, StartupWriteRead
) {
80 StartupCache
* sc
= StartupCache::GetSingleton();
82 const char* buf
= "Market opportunities for BeardBook";
83 const char* id
= "id";
87 rv
= sc
->PutBuffer(id
, mozilla::UniqueFreePtr
<char[]>(strdup(buf
)),
89 EXPECT_NS_SUCCEEDED(rv
);
91 rv
= sc
->GetBuffer(id
, &outbuf
, &len
);
92 EXPECT_NS_SUCCEEDED(rv
);
93 EXPECT_STREQ(buf
, outbuf
);
95 rv
= sc
->ResetStartupWriteTimerAndLock();
96 EXPECT_NS_SUCCEEDED(rv
);
97 WaitForStartupTimer();
99 rv
= sc
->GetBuffer(id
, &outbuf
, &len
);
100 EXPECT_NS_SUCCEEDED(rv
);
101 EXPECT_STREQ(buf
, outbuf
);
104 TEST_F(TestStartupCache
, WriteInvalidateRead
) {
106 const char* buf
= "BeardBook competitive analysis";
107 const char* id
= "id";
110 StartupCache
* sc
= StartupCache::GetSingleton();
113 rv
= sc
->PutBuffer(id
, mozilla::UniqueFreePtr
<char[]>(strdup(buf
)),
115 EXPECT_NS_SUCCEEDED(rv
);
117 sc
->InvalidateCache();
119 rv
= sc
->GetBuffer(id
, &outbuf
, &len
);
120 EXPECT_EQ(rv
, NS_ERROR_NOT_AVAILABLE
);
123 TEST_F(TestStartupCache
, WriteObject
) {
126 nsCOMPtr
<nsIURI
> obj
;
128 constexpr auto spec
= "http://www.mozilla.org"_ns
;
129 rv
= NS_MutateURI(NS_SIMPLEURIMUTATOR_CONTRACTID
).SetSpec(spec
).Finalize(obj
);
130 EXPECT_NS_SUCCEEDED(rv
);
132 StartupCache
* sc
= StartupCache::GetSingleton();
134 // Create an object stream. Usually this is done with
135 // NewObjectOutputWrappedStorageStream, but that uses
136 // StartupCache::GetSingleton in debug builds, and we
137 // don't have access to that here. Obviously.
138 const char* id
= "id";
139 nsCOMPtr
<nsIStorageStream
> storageStream
=
140 do_CreateInstance("@mozilla.org/storagestream;1");
141 ASSERT_TRUE(storageStream
);
143 rv
= storageStream
->Init(256, (uint32_t)-1);
144 EXPECT_NS_SUCCEEDED(rv
);
146 nsCOMPtr
<nsIObjectOutputStream
> objectOutput
=
147 do_CreateInstance("@mozilla.org/binaryoutputstream;1");
148 ASSERT_TRUE(objectOutput
);
150 nsCOMPtr
<nsIOutputStream
> outputStream
= do_QueryInterface(storageStream
);
152 rv
= objectOutput
->SetOutputStream(outputStream
);
153 EXPECT_NS_SUCCEEDED(rv
);
155 nsCOMPtr
<nsISupports
> objQI(do_QueryInterface(obj
));
156 rv
= objectOutput
->WriteObject(objQI
, true);
157 EXPECT_NS_SUCCEEDED(rv
);
159 mozilla::UniqueFreePtr
<char[]> buf
;
161 NewBufferFromStorageStream(storageStream
, &buf
, &len
);
163 // Since this is a post-startup write, it should be written and
165 rv
= sc
->PutBuffer(id
, std::move(buf
), len
);
166 EXPECT_NS_SUCCEEDED(rv
);
170 nsCOMPtr
<nsIObjectInputStream
> objectInput
;
171 rv
= sc
->GetBuffer(id
, &buf2
, &len2
);
172 EXPECT_NS_SUCCEEDED(rv
);
174 rv
= NewObjectInputStreamFromBuffer(buf2
, len2
, getter_AddRefs(objectInput
));
175 EXPECT_NS_SUCCEEDED(rv
);
177 nsCOMPtr
<nsISupports
> deserialized
;
178 rv
= objectInput
->ReadObject(true, getter_AddRefs(deserialized
));
179 EXPECT_NS_SUCCEEDED(rv
);
181 nsCOMPtr
<nsIURI
> uri(do_QueryInterface(deserialized
));
185 rv
= uri
->GetSpec(outSpec
);
186 EXPECT_NS_SUCCEEDED(rv
);
187 ASSERT_TRUE(outSpec
.Equals(spec
));