/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "pmemalloc.h"
class DepsStub : public PmemUserspaceAllocator::Deps, public PmemKernelAllocator::Deps {
public:
virtual size_t getPmemTotalSize(int fd, size_t* size) {
return 0;
}
virtual int connectPmem(int fd, int master_fd) {
return 0;
}
virtual int mapPmem(int fd, int offset, size_t size) {
return 0;
}
virtual int unmapPmem(int fd, int offset, size_t size) {
return 0;
}
virtual int getErrno() {
return 0;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return 0;
}
virtual int munmap(void* start, size_t length) {
return 0;
}
virtual int open(const char* pathname, int flags, int mode) {
return 0;
}
virtual int close(int fd) {
return 0;
}
};
/******************************************************************************/
class AllocatorStub : public PmemUserspaceAllocator::Deps::Allocator {
virtual ssize_t setSize(size_t size) {
return 0;
}
virtual size_t size() const {
return 0;
}
virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
return 0;
}
virtual ssize_t deallocate(size_t offset) {
return 0;
}
};
/******************************************************************************/
static const char* fakePmemDev = "/foo/bar";
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithSuccessfulCompletion : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return 1234;
}
virtual size_t getPmemTotalSize(int fd, size_t* size) {
EXPECT_EQ(1234, fd);
*size = 16 << 20;
return 0;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
EXPECT_EQ(1234, fd);
return (void*)0x87654321;
}
};
struct Allocator_InitPmemAreaLockedWithSuccessfulCompletion : public AllocatorStub {
virtual ssize_t setSize(size_t size) {
EXPECT_EQ(size_t(16 << 20), size);
return 0;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithSuccessfulCompletion) {
Deps_InitPmemAreaLockedWithSuccessfulCompletion depsMock;
Allocator_InitPmemAreaLockedWithSuccessfulCompletion allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(0, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnomemOnMmap : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return 1234;
}
virtual size_t getPmemTotalSize(int fd, size_t* size) {
EXPECT_EQ(1234, fd);
*size = 16 << 20;
return 0;
}
virtual int getErrno() {
return ENOMEM;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return (void*)MAP_FAILED;
}
};
struct Allocator_InitPmemAreaLockedWithEnomemOnMmap : public AllocatorStub {
virtual ssize_t setSize(size_t size) {
EXPECT_EQ(size_t(16 << 20), size);
return 0;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEnomemOnMmap) {
Deps_InitPmemAreaLockedWithEnomemOnMmap depsMock;
Allocator_InitPmemAreaLockedWithEnomemOnMmap allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(-ENOMEM, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return 1234;
}
virtual size_t getPmemTotalSize(int fd, size_t* size) {
EXPECT_EQ(1234, fd);
return -EACCES;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEaccesOnGetPmemTotalSize) {
Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEaccesOnOpen : public DepsStub {
virtual int getErrno() {
return EACCES;
}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return -1;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithEaccesOnOpenMaster) {
Deps_InitPmemAreaLockedWithEaccesOnOpen depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
typedef Deps_InitPmemAreaLockedWithSuccessfulCompletion Deps_InitPmemAreaWithSuccessfulInitialCompletion;
TEST(test_pmem_userspace_allocator, testInitPmemAreaWithSuccessfulInitialCompletion) {
Deps_InitPmemAreaWithSuccessfulInitialCompletion depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area();
ASSERT_EQ(0, result);
}
/******************************************************************************/
typedef Deps_InitPmemAreaLockedWithEaccesOnOpen Deps_InitPmemAreaWithEaccesOnInitLocked;
TEST(test_pmem_userspace_allocator, testInitPmemAreaWithEaccesOnInitLocked) {
Deps_InitPmemAreaWithEaccesOnInitLocked depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterSuccessfulInitialCompletion) {
DepsStub depsStub;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
pma.set_master_values(1234, 0); // Indicate that the pma has been successfully init'd
int result = pma.init_pmem_area();
ASSERT_EQ(0, result);
//XXX JMG: Add this back in maybe? ASSERT_EQ(1234, pmi.master); // Make sure the master fd wasn't changed
}
/******************************************************************************/
TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterFailedInit) {
DepsStub depsStub;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
pma.set_master_values(-EACCES, 0); // Indicate that the pma has failed init
int result = pma.init_pmem_area();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return 5678;
}
virtual int connectPmem(int fd, int master_fd) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(1234, master_fd);
return 0;
}
virtual int mapPmem(int fd, int offset, size_t size) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(0x300, offset);
EXPECT_EQ(size_t(0x100), size);
return 0;
}
};
struct Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags : public AllocatorStub {
virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
EXPECT_EQ(size_t(0x100), size);
EXPECT_EQ(uint32_t(0x0), flags);
return 0x300;
}
};
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags depsMock;
Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = 0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(0x300, offset);
ASSERT_EQ(5678, fd);
for (int i = 0x300; i < 0x400; ++i) {
ASSERT_EQ(uint8_t(0), buf[i]);
}
}
/******************************************************************************/
typedef Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags;
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags depsMock;
Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(0x300, offset);
ASSERT_EQ(5678, fd);
for (int i = 0x300; i < 0x400; ++i) {
ASSERT_EQ(0, buf[i]);
}
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnodevOnOpen : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
virtual int getErrno() {
return ENODEV;
}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return -1;
}
};
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnodevOnOpen;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnodevOnOpen) {
Deps_InitPmemAreaLockedWithEnodevOnOpen depsMock;
Allocator_AllocPmemBufferWithEnodevOnOpen allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENODEV, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnomemOnConnectPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
virtual int getErrno() {
return ENOMEM;
}
virtual int connectPmem(int fd, int master_fd) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(1234, master_fd);
return -1;
}
};
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnConnectPmem;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnomemOnConnectPmem) {
Deps_InitPmemAreaLockedWithEnomemOnConnectPmem depsMock;
Allocator_AllocPmemBufferWithEnomemOnConnectPmem allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENOMEM, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnomemOnMapPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
virtual int getErrno() {
return ENOMEM;
}
virtual int mapPmem(int fd, int offset, size_t size) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(0x300, offset);
EXPECT_EQ(size_t(0x100), size);
return -1;
}
};
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnMapPmem;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithEnomemOnMapPmem) {
Deps_InitPmemAreaLockedWithEnomemOnMapPmem depsMock;
Allocator_AllocPmemBufferWithEnomemOnMapPmem allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENOMEM, result);
}
/******************************************************************************/
struct Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags : public DepsStub {
void* mmapResult;
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags(void* mmapResult) :
mmapResult(mmapResult) {}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return 5678;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
EXPECT_EQ(5678, fd);
return mmapResult;
}
};
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
uint8_t buf[0x100]; // Create a buffer to get memzero'd
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags depsMock(buf);
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = 0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(buf, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(5678, fd);
for (int i = 0; i < 0x100; ++i) {
ASSERT_EQ(0, buf[i]);
}
}
/******************************************************************************/
typedef Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags;
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
uint8_t buf[0x100]; // Create a buffer to get memzero'd
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags depsMock(buf);
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(buf, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(5678, fd);
for (int i = 0; i < 0x100; ++i) {
ASSERT_EQ(0, buf[i]);
}
}
/******************************************************************************/
struct Deps_KernelAllocPmemBufferWithEpermOnOpen : public DepsStub {
virtual int getErrno() {
return EPERM;
}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return -1;
}
};
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEpermOnOpen) {
Deps_KernelAllocPmemBufferWithEpermOnOpen depsMock;
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-EPERM, result);
ASSERT_EQ(0, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(-1, fd);
}
/******************************************************************************/
struct Deps_KernelAllocPmemBufferWithEnomemOnMmap : DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return 5678;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return (void*)MAP_FAILED;
}
virtual int getErrno() {
return ENOMEM;
}
};
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEnomemOnMmap) {
Deps_KernelAllocPmemBufferWithEnomemOnMmap depsMock;
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENOMEM, result);
ASSERT_EQ(0, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(-1, fd);
}
/******************************************************************************/