Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/tests/gtest/TestRacingServiceManager.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
5
6
#include "nsIFactory.h"
7
#include "mozilla/Module.h"
8
#include "nsXULAppAPI.h"
9
#include "nsIThread.h"
10
#include "nsIComponentRegistrar.h"
11
12
#include "nsAutoPtr.h"
13
#include "nsThreadUtils.h"
14
#include "nsXPCOMCIDInternal.h"
15
#include "pratom.h"
16
#include "prmon.h"
17
#include "mozilla/Assertions.h"
18
#include "mozilla/Attributes.h"
19
20
#include "mozilla/ReentrantMonitor.h"
21
22
#include "gtest/gtest.h"
23
24
using namespace mozilla;
25
26
/* f93f6bdc-88af-42d7-9d64-1b43c649a3e5 */
27
#define FACTORY_CID1                                 \
28
{                                                    \
29
  0xf93f6bdc,                                        \
30
  0x88af,                                            \
31
  0x42d7,                                            \
32
  { 0x9d, 0x64, 0x1b, 0x43, 0xc6, 0x49, 0xa3, 0xe5 } \
33
}
34
NS_DEFINE_CID(kFactoryCID1, FACTORY_CID1);
35
36
/* ef38ad65-6595-49f0-8048-e819f81d15e2 */
37
#define FACTORY_CID2                                 \
38
{                                                    \
39
  0xef38ad65,                                        \
40
  0x6595,                                            \
41
  0x49f0,                                            \
42
  { 0x80, 0x48, 0xe8, 0x19, 0xf8, 0x1d, 0x15, 0xe2 } \
43
}
44
NS_DEFINE_CID(kFactoryCID2, FACTORY_CID2);
45
46
#define FACTORY_CONTRACTID                           \
47
0
  "TestRacingThreadManager/factory;1"
48
49
namespace TestRacingServiceManager
50
{
51
int32_t gComponent1Count = 0;
52
int32_t gComponent2Count = 0;
53
54
ReentrantMonitor* gReentrantMonitor = nullptr;
55
56
bool gCreateInstanceCalled = false;
57
bool gMainThreadWaiting = false;
58
59
class AutoCreateAndDestroyReentrantMonitor
60
{
61
public:
62
  explicit AutoCreateAndDestroyReentrantMonitor(ReentrantMonitor** aReentrantMonitorPtr)
63
0
  : mReentrantMonitorPtr(aReentrantMonitorPtr) {
64
0
    *aReentrantMonitorPtr =
65
0
      new ReentrantMonitor("TestRacingServiceManager::AutoMon");
66
0
    MOZ_RELEASE_ASSERT(*aReentrantMonitorPtr, "Out of memory!");
67
0
  }
68
69
0
  ~AutoCreateAndDestroyReentrantMonitor() {
70
0
    if (*mReentrantMonitorPtr) {
71
0
      delete *mReentrantMonitorPtr;
72
0
      *mReentrantMonitorPtr = nullptr;
73
0
    }
74
0
  }
75
76
private:
77
  ReentrantMonitor** mReentrantMonitorPtr;
78
};
79
80
class Factory final : public nsIFactory
81
{
82
0
  ~Factory() {}
83
84
public:
85
  NS_DECL_THREADSAFE_ISUPPORTS
86
87
0
  Factory() : mFirstComponentCreated(false) { }
88
89
  NS_IMETHOD CreateInstance(nsISupports* aDelegate,
90
                            const nsIID& aIID,
91
                            void** aResult) override;
92
93
0
  NS_IMETHOD LockFactory(bool aLock) override {
94
0
    return NS_OK;
95
0
  }
96
97
  bool mFirstComponentCreated;
98
};
99
100
NS_IMPL_ISUPPORTS(Factory, nsIFactory)
101
102
class Component1 final : public nsISupports
103
{
104
0
  ~Component1() {}
105
106
public:
107
  NS_DECL_THREADSAFE_ISUPPORTS
108
109
0
  Component1() {
110
0
    // This is the real test - make sure that only one instance is ever created.
111
0
    int32_t count = PR_AtomicIncrement(&gComponent1Count);
112
0
    MOZ_RELEASE_ASSERT(count == 1, "Too many components created!");
113
0
  }
114
};
115
116
NS_IMPL_ADDREF(Component1)
117
NS_IMPL_RELEASE(Component1)
118
119
0
NS_INTERFACE_MAP_BEGIN(Component1)
120
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
121
0
NS_INTERFACE_MAP_END
122
123
class Component2 final : public nsISupports
124
{
125
0
  ~Component2() {}
126
127
public:
128
  NS_DECL_THREADSAFE_ISUPPORTS
129
130
0
  Component2() {
131
0
    // This is the real test - make sure that only one instance is ever created.
132
0
    int32_t count = PR_AtomicIncrement(&gComponent2Count);
133
0
    EXPECT_EQ(count, int32_t(1)) << "Too many components created!";
134
0
  }
135
};
136
137
NS_IMPL_ADDREF(Component2)
138
NS_IMPL_RELEASE(Component2)
139
140
0
NS_INTERFACE_MAP_BEGIN(Component2)
141
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
142
0
NS_INTERFACE_MAP_END
143
144
NS_IMETHODIMP
145
Factory::CreateInstance(nsISupports* aDelegate,
146
                        const nsIID& aIID,
147
                        void** aResult)
148
0
{
149
0
  // Make sure that the second thread beat the main thread to the getService
150
0
  // call.
151
0
  MOZ_RELEASE_ASSERT(!NS_IsMainThread(), "Wrong thread!");
152
0
153
0
  {
154
0
    ReentrantMonitorAutoEnter mon(*gReentrantMonitor);
155
0
156
0
    gCreateInstanceCalled = true;
157
0
    mon.Notify();
158
0
159
0
    mon.Wait(PR_MillisecondsToInterval(3000));
160
0
  }
161
0
162
0
  NS_ENSURE_FALSE(aDelegate, NS_ERROR_NO_AGGREGATION);
163
0
  NS_ENSURE_ARG_POINTER(aResult);
164
0
165
0
  nsCOMPtr<nsISupports> instance;
166
0
167
0
  if (!mFirstComponentCreated) {
168
0
    instance = new Component1();
169
0
  }
170
0
  else {
171
0
    instance = new Component2();
172
0
  }
173
0
  NS_ENSURE_TRUE(instance, NS_ERROR_OUT_OF_MEMORY);
174
0
175
0
  nsresult rv = instance->QueryInterface(aIID, aResult);
176
0
  NS_ENSURE_SUCCESS(rv, rv);
177
0
178
0
  return NS_OK;
179
0
}
180
181
class TestRunnable : public Runnable
182
{
183
public:
184
  NS_DECL_NSIRUNNABLE
185
186
  TestRunnable()
187
    : mozilla::Runnable("TestRacingServiceManager::TestRunnable")
188
    , mFirstRunnableDone(false)
189
0
  {
190
0
  }
191
192
  bool mFirstRunnableDone;
193
};
194
195
NS_IMETHODIMP
196
TestRunnable::Run()
197
0
{
198
0
  {
199
0
    ReentrantMonitorAutoEnter mon(*gReentrantMonitor);
200
0
201
0
    while (!gMainThreadWaiting) {
202
0
      mon.Wait();
203
0
    }
204
0
  }
205
0
206
0
  nsresult rv;
207
0
  nsCOMPtr<nsISupports> component;
208
0
209
0
  if (!mFirstRunnableDone) {
210
0
    component = do_GetService(kFactoryCID1, &rv);
211
0
  }
212
0
  else {
213
0
    component = do_GetService(FACTORY_CONTRACTID, &rv);
214
0
  }
215
0
  EXPECT_TRUE(NS_SUCCEEDED(rv)) << "GetService failed!";
216
0
217
0
  return NS_OK;
218
0
}
219
220
static Factory* gFactory;
221
222
static already_AddRefed<nsIFactory>
223
CreateFactory(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry)
224
0
{
225
0
    if (!gFactory) {
226
0
        gFactory = new Factory();
227
0
        NS_ADDREF(gFactory);
228
0
    }
229
0
    nsCOMPtr<nsIFactory> ret = gFactory;
230
0
    return ret.forget();
231
0
}
232
233
static const mozilla::Module::CIDEntry kLocalCIDs[] = {
234
    { &kFactoryCID1, false, CreateFactory, nullptr },
235
    { &kFactoryCID2, false, CreateFactory, nullptr },
236
    { nullptr }
237
};
238
239
static const mozilla::Module::ContractIDEntry kLocalContracts[] = {
240
    { FACTORY_CONTRACTID, &kFactoryCID2 },
241
    { nullptr }
242
};
243
244
static const mozilla::Module kLocalModule = {
245
    mozilla::Module::kVersion,
246
    kLocalCIDs,
247
    kLocalContracts
248
};
249
250
TEST(RacingServiceManager, Test)
251
0
{
252
0
  nsresult rv;
253
0
  XRE_AddStaticComponent(&kLocalModule);
254
0
255
0
  AutoCreateAndDestroyReentrantMonitor mon1(&gReentrantMonitor);
256
0
257
0
  RefPtr<TestRunnable> runnable = new TestRunnable();
258
0
  ASSERT_TRUE(runnable);
259
0
260
0
  // Run the classID test
261
0
  nsCOMPtr<nsIThread> newThread;
262
0
  rv = NS_NewNamedThread("RacingServMan", getter_AddRefs(newThread), runnable);
263
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
264
0
265
0
  {
266
0
    ReentrantMonitorAutoEnter mon2(*gReentrantMonitor);
267
0
268
0
    gMainThreadWaiting = true;
269
0
    mon2.Notify();
270
0
271
0
    while (!gCreateInstanceCalled) {
272
0
      mon2.Wait();
273
0
    }
274
0
  }
275
0
276
0
  nsCOMPtr<nsISupports> component(do_GetService(kFactoryCID1, &rv));
277
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
278
0
279
0
  // Reset for the contractID test
280
0
  gMainThreadWaiting = gCreateInstanceCalled = false;
281
0
  gFactory->mFirstComponentCreated = runnable->mFirstRunnableDone = true;
282
0
  component = nullptr;
283
0
284
0
  rv = newThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
285
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
286
0
287
0
  {
288
0
    ReentrantMonitorAutoEnter mon3(*gReentrantMonitor);
289
0
290
0
    gMainThreadWaiting = true;
291
0
    mon3.Notify();
292
0
293
0
    while (!gCreateInstanceCalled) {
294
0
      mon3.Wait();
295
0
    }
296
0
  }
297
0
298
0
  component = do_GetService(FACTORY_CONTRACTID, &rv);
299
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
300
0
301
0
  NS_RELEASE(gFactory);
302
0
}
303
304
} // namespace TestRacingServiceManager