1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <errno.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <sys/mman.h>
23
24#include "pmemalloc.h"
25
26class DepsStub : public PmemUserspaceAllocator::Deps, public PmemKernelAllocator::Deps {
27
28 public:
29
30    virtual size_t getPmemTotalSize(int fd, size_t* size) {
31        return 0;
32    }
33
34    virtual int connectPmem(int fd, int master_fd) {
35        return 0;
36    }
37
38    virtual int mapPmem(int fd, int offset, size_t size) {
39        return 0;
40    }
41
42    virtual int unmapPmem(int fd, int offset, size_t size) {
43        return 0;
44    }
45
46    virtual int getErrno() {
47        return 0;
48    }
49
50    virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
51            off_t offset) {
52        return 0;
53    }
54
55    virtual int munmap(void* start, size_t length) {
56        return 0;
57    }
58
59    virtual int open(const char* pathname, int flags, int mode) {
60        return 0;
61    }
62
63    virtual int close(int fd) {
64        return 0;
65    }
66};
67
68/******************************************************************************/
69
70class AllocatorStub : public PmemUserspaceAllocator::Deps::Allocator {
71    virtual ssize_t setSize(size_t size) {
72        return 0;
73    }
74
75    virtual size_t  size() const {
76        return 0;
77    }
78
79    virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
80        return 0;
81    }
82
83    virtual ssize_t deallocate(size_t offset) {
84        return 0;
85    }
86};
87
88/******************************************************************************/
89
90static const char* fakePmemDev = "/foo/bar";
91
92/******************************************************************************/
93
94struct Deps_InitPmemAreaLockedWithSuccessfulCompletion : public DepsStub {
95
96    virtual int open(const char* pathname, int flags, int mode) {
97        EXPECT_EQ(fakePmemDev, pathname);
98        EXPECT_EQ(O_RDWR, flags);
99        EXPECT_EQ(0, mode);
100        return 1234;
101    }
102
103    virtual size_t getPmemTotalSize(int fd, size_t* size) {
104        EXPECT_EQ(1234, fd);
105        *size = 16 << 20;
106        return 0;
107    }
108
109    virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
110            off_t offset) {
111        EXPECT_EQ(1234, fd);
112        return (void*)0x87654321;
113    }
114
115};
116
117struct Allocator_InitPmemAreaLockedWithSuccessfulCompletion : public AllocatorStub {
118
119    virtual ssize_t setSize(size_t size) {
120        EXPECT_EQ(size_t(16 << 20), size);
121        return 0;
122    }
123};
124
125TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithSuccessfulCompletion) {
126    Deps_InitPmemAreaLockedWithSuccessfulCompletion depsMock;
127    Allocator_InitPmemAreaLockedWithSuccessfulCompletion allocMock;
128    PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
129
130    int result = pma.init_pmem_area_locked();
131    ASSERT_EQ(0, result);
132}
133
134/******************************************************************************/
135
136struct Deps_InitPmemAreaLockedWithEnomemOnMmap : public DepsStub {
137
138    virtual int open(const char* pathname, int flags, int mode) {
139        EXPECT_EQ(fakePmemDev, pathname);
140        EXPECT_EQ(O_RDWR, flags);
141        EXPECT_EQ(0, mode);
142        return 1234;
143    }
144
145    virtual size_t getPmemTotalSize(int fd, size_t* size) {
146        EXPECT_EQ(1234, fd);
147        *size = 16 << 20;
148        return 0;
149    }
150
151    virtual int getErrno() {
152        return ENOMEM;
153    }
154
155    virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
156            off_t offset) {
157        return (void*)MAP_FAILED;
158    }
159
160};
161
162struct Allocator_InitPmemAreaLockedWithEnomemOnMmap : public AllocatorStub {
163
164    virtual ssize_t setSize(size_t size) {
165        EXPECT_EQ(size_t(16 << 20), size);
166        return 0;
167    }
168};
169
170TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEnomemOnMmap) {
171    Deps_InitPmemAreaLockedWithEnomemOnMmap depsMock;
172    Allocator_InitPmemAreaLockedWithEnomemOnMmap allocMock;
173    PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
174
175    int result = pma.init_pmem_area_locked();
176    ASSERT_EQ(-ENOMEM, result);
177}
178
179/******************************************************************************/
180
181struct Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize : public DepsStub {
182
183    virtual int open(const char* pathname, int flags, int mode) {
184        EXPECT_EQ(fakePmemDev, pathname);
185        EXPECT_EQ(O_RDWR, flags);
186        EXPECT_EQ(0, mode);
187        return 1234;
188    }
189
190    virtual size_t getPmemTotalSize(int fd, size_t* size) {
191        EXPECT_EQ(1234, fd);
192        return -EACCES;
193    }
194};
195
196TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEaccesOnGetPmemTotalSize) {
197    Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize depsMock;
198    AllocatorStub allocStub;
199    PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
200
201    int result = pma.init_pmem_area_locked();
202    ASSERT_EQ(-EACCES, result);
203}
204
205/******************************************************************************/
206
207struct Deps_InitPmemAreaLockedWithEaccesOnOpen : public DepsStub {
208
209    virtual int getErrno() {
210        return EACCES;
211    }
212
213    virtual int open(const char* pathname, int flags, int mode) {
214        EXPECT_EQ(fakePmemDev, pathname);
215        EXPECT_EQ(O_RDWR, flags);
216        EXPECT_EQ(0, mode);
217        return -1;
218    }
219};
220
221TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithEaccesOnOpenMaster) {
222    Deps_InitPmemAreaLockedWithEaccesOnOpen depsMock;
223    AllocatorStub allocStub;
224    PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
225
226    int result = pma.init_pmem_area_locked();
227    ASSERT_EQ(-EACCES, result);
228}
229
230/******************************************************************************/
231
232typedef Deps_InitPmemAreaLockedWithSuccessfulCompletion Deps_InitPmemAreaWithSuccessfulInitialCompletion;
233
234TEST(test_pmem_userspace_allocator, testInitPmemAreaWithSuccessfulInitialCompletion) {
235    Deps_InitPmemAreaWithSuccessfulInitialCompletion depsMock;
236    AllocatorStub allocStub;
237    PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
238
239    int result = pma.init_pmem_area();
240    ASSERT_EQ(0, result);
241}
242
243/******************************************************************************/
244
245typedef Deps_InitPmemAreaLockedWithEaccesOnOpen Deps_InitPmemAreaWithEaccesOnInitLocked;
246
247TEST(test_pmem_userspace_allocator, testInitPmemAreaWithEaccesOnInitLocked) {
248    Deps_InitPmemAreaWithEaccesOnInitLocked depsMock;
249    AllocatorStub allocStub;
250    PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
251
252    int result = pma.init_pmem_area();
253    ASSERT_EQ(-EACCES, result);
254}
255
256/******************************************************************************/
257
258TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterSuccessfulInitialCompletion) {
259    DepsStub depsStub;
260    AllocatorStub allocStub;
261    PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
262
263    pma.set_master_values(1234, 0); // Indicate that the pma has been successfully init'd
264
265    int result = pma.init_pmem_area();
266    ASSERT_EQ(0, result);
267    //XXX JMG: Add this back in maybe? ASSERT_EQ(1234, pmi.master); // Make sure the master fd wasn't changed
268}
269
270/******************************************************************************/
271
272TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterFailedInit) {
273    DepsStub depsStub;
274    AllocatorStub allocStub;
275    PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
276
277    pma.set_master_values(-EACCES, 0); // Indicate that the pma has failed init
278
279    int result = pma.init_pmem_area();
280    ASSERT_EQ(-EACCES, result);
281}
282
283/******************************************************************************/
284
285struct Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags : public DepsStub {
286
287    virtual int open(const char* pathname, int flags, int mode) {
288        EXPECT_EQ(fakePmemDev, pathname);
289        EXPECT_EQ(O_RDWR, flags & O_RDWR);
290        EXPECT_EQ(0, mode);
291        return 5678;
292    }
293
294    virtual int connectPmem(int fd, int master_fd) {
295        EXPECT_EQ(5678, fd);
296        EXPECT_EQ(1234, master_fd);
297        return 0;
298    }
299
300    virtual int mapPmem(int fd, int offset, size_t size) {
301        EXPECT_EQ(5678, fd);
302        EXPECT_EQ(0x300, offset);
303        EXPECT_EQ(size_t(0x100), size);
304        return 0;
305    }
306};
307
308
309struct Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags : public AllocatorStub {
310
311    virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
312        EXPECT_EQ(size_t(0x100), size);
313        EXPECT_EQ(uint32_t(0x0), flags);
314        return 0x300;
315    }
316};
317
318TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
319    Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags depsMock;
320    Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags allocMock;
321    PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
322
323    uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
324    pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
325
326    void* base = 0;
327    int offset = -9182, fd = -9182;
328    int size = 0x100;
329    int flags = 0;
330    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
331    ASSERT_EQ(0, result);
332    ASSERT_EQ(0x300, offset);
333    ASSERT_EQ(5678, fd);
334    for (int i = 0x300; i < 0x400; ++i) {
335        ASSERT_EQ(uint8_t(0), buf[i]);
336    }
337}
338
339/******************************************************************************/
340
341typedef Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags;
342
343typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags;
344
345TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
346    Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags depsMock;
347    Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags allocMock;
348    PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
349
350    uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
351    pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
352
353    void* base = 0;
354    int offset = -9182, fd = -9182;
355    int size = 0x100;
356    int flags = ~0;
357    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
358    ASSERT_EQ(0, result);
359    ASSERT_EQ(0x300, offset);
360    ASSERT_EQ(5678, fd);
361    for (int i = 0x300; i < 0x400; ++i) {
362        ASSERT_EQ(0, buf[i]);
363    }
364}
365
366/******************************************************************************/
367
368struct Deps_InitPmemAreaLockedWithEnodevOnOpen : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
369
370    virtual int getErrno() {
371        return ENODEV;
372    }
373
374    virtual int open(const char* pathname, int flags, int mode) {
375        EXPECT_EQ(fakePmemDev, pathname);
376        EXPECT_EQ(O_RDWR, flags & O_RDWR);
377        EXPECT_EQ(0, mode);
378        return -1;
379    }
380};
381
382typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnodevOnOpen;
383
384TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnodevOnOpen) {
385    Deps_InitPmemAreaLockedWithEnodevOnOpen depsMock;
386    Allocator_AllocPmemBufferWithEnodevOnOpen allocMock;
387    PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
388
389    uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
390    pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
391
392    void* base = 0;
393    int offset = -9182, fd = -9182;
394    int size = 0x100;
395    int flags = ~0;
396    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
397    ASSERT_EQ(-ENODEV, result);
398}
399
400/******************************************************************************/
401
402struct Deps_InitPmemAreaLockedWithEnomemOnConnectPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
403
404    virtual int getErrno() {
405        return ENOMEM;
406    }
407
408    virtual int connectPmem(int fd, int master_fd) {
409        EXPECT_EQ(5678, fd);
410        EXPECT_EQ(1234, master_fd);
411        return -1;
412    }
413};
414
415typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnConnectPmem;
416
417TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnomemOnConnectPmem) {
418    Deps_InitPmemAreaLockedWithEnomemOnConnectPmem depsMock;
419    Allocator_AllocPmemBufferWithEnomemOnConnectPmem allocMock;
420    PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
421
422    uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
423    pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
424
425    void* base = 0;
426    int offset = -9182, fd = -9182;
427    int size = 0x100;
428    int flags = ~0;
429    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
430    ASSERT_EQ(-ENOMEM, result);
431}
432
433/******************************************************************************/
434
435struct Deps_InitPmemAreaLockedWithEnomemOnMapPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
436
437    virtual int getErrno() {
438        return ENOMEM;
439    }
440
441    virtual int mapPmem(int fd, int offset, size_t size) {
442        EXPECT_EQ(5678, fd);
443        EXPECT_EQ(0x300, offset);
444        EXPECT_EQ(size_t(0x100), size);
445        return -1;
446    }
447};
448
449typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnMapPmem;
450
451TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithEnomemOnMapPmem) {
452    Deps_InitPmemAreaLockedWithEnomemOnMapPmem depsMock;
453    Allocator_AllocPmemBufferWithEnomemOnMapPmem allocMock;
454    PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
455
456    uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
457    pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
458
459    void* base = 0;
460    int offset = -9182, fd = -9182;
461    int size = 0x100;
462    int flags = ~0;
463    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
464    ASSERT_EQ(-ENOMEM, result);
465}
466
467/******************************************************************************/
468
469struct Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags : public DepsStub {
470
471    void* mmapResult;
472
473    Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags(void* mmapResult) :
474            mmapResult(mmapResult) {}
475
476    virtual int open(const char* pathname, int flags, int mode) {
477        EXPECT_EQ(fakePmemDev, pathname);
478        EXPECT_EQ(O_RDWR, flags & O_RDWR);
479        EXPECT_EQ(0, mode);
480        return 5678;
481    }
482
483    virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
484            off_t offset) {
485        EXPECT_EQ(5678, fd);
486        return mmapResult;
487    }
488};
489
490TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
491    uint8_t buf[0x100]; // Create a buffer to get memzero'd
492    Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags depsMock(buf);
493    PmemKernelAllocator pma(depsMock, fakePmemDev);
494
495    void* base = 0;
496    int offset = -9182, fd = -9182;
497    int size = 0x100;
498    int flags = 0;
499    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
500    ASSERT_EQ(0, result);
501    ASSERT_EQ(buf, base);
502    ASSERT_EQ(0, offset);
503    ASSERT_EQ(5678, fd);
504    for (int i = 0; i < 0x100; ++i) {
505        ASSERT_EQ(0, buf[i]);
506    }
507}
508
509/******************************************************************************/
510
511typedef Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags;
512
513TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
514    uint8_t buf[0x100]; // Create a buffer to get memzero'd
515    Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags depsMock(buf);
516    PmemKernelAllocator pma(depsMock, fakePmemDev);
517
518    void* base = 0;
519    int offset = -9182, fd = -9182;
520    int size = 0x100;
521    int flags = ~0;
522    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
523    ASSERT_EQ(0, result);
524    ASSERT_EQ(buf, base);
525    ASSERT_EQ(0, offset);
526    ASSERT_EQ(5678, fd);
527    for (int i = 0; i < 0x100; ++i) {
528        ASSERT_EQ(0, buf[i]);
529    }
530}
531
532/******************************************************************************/
533
534struct Deps_KernelAllocPmemBufferWithEpermOnOpen : public DepsStub {
535
536    virtual int getErrno() {
537        return EPERM;
538    }
539
540    virtual int open(const char* pathname, int flags, int mode) {
541        EXPECT_EQ(fakePmemDev, pathname);
542        EXPECT_EQ(O_RDWR, flags & O_RDWR);
543        EXPECT_EQ(0, mode);
544        return -1;
545    }
546};
547
548
549TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEpermOnOpen) {
550    Deps_KernelAllocPmemBufferWithEpermOnOpen depsMock;
551    PmemKernelAllocator pma(depsMock, fakePmemDev);
552
553    void* base = 0;
554    int offset = -9182, fd = -9182;
555    int size = 0x100;
556    int flags = ~0;
557    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
558    ASSERT_EQ(-EPERM, result);
559    ASSERT_EQ(0, base);
560    ASSERT_EQ(0, offset);
561    ASSERT_EQ(-1, fd);
562}
563
564/******************************************************************************/
565
566struct Deps_KernelAllocPmemBufferWithEnomemOnMmap : DepsStub {
567
568    virtual int open(const char* pathname, int flags, int mode) {
569        EXPECT_EQ(fakePmemDev, pathname);
570        EXPECT_EQ(O_RDWR, flags & O_RDWR);
571        EXPECT_EQ(0, mode);
572        return 5678;
573    }
574
575    virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
576            off_t offset) {
577        return (void*)MAP_FAILED;
578    }
579
580    virtual int getErrno() {
581        return ENOMEM;
582    }
583};
584
585
586TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEnomemOnMmap) {
587    Deps_KernelAllocPmemBufferWithEnomemOnMmap depsMock;
588    PmemKernelAllocator pma(depsMock, fakePmemDev);
589
590    void* base = 0;
591    int offset = -9182, fd = -9182;
592    int size = 0x100;
593    int flags = ~0;
594    int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
595    ASSERT_EQ(-ENOMEM, result);
596    ASSERT_EQ(0, base);
597    ASSERT_EQ(0, offset);
598    ASSERT_EQ(-1, fd);
599}
600
601/******************************************************************************/
602