hnvram: Support x86 compiler & changing target_mtd
- Some minor type changes to support x86 compiler
- Adds option to read/write to file instead of flash
These changes together allow for unit testing which has been added.
Depends on go/fibercl/XXXXX
In reference to b/31822982
Change-Id: Ica9bfc28fcb6d32361427c9f5ebc56cf0aa6c14c
diff --git a/libupgrade/Makefile b/libupgrade/Makefile
index df9c334..b829f46 100644
--- a/libupgrade/Makefile
+++ b/libupgrade/Makefile
@@ -9,7 +9,7 @@
RANLIB:=$(CROSS_PREFIX)ranlib
STRIP:=$(CROSS_PREFIX)strip
-CFLAGS = -g -Os -Wall -Werror
+CFLAGS = -g -Os -Wall -Werror -I.
SRCS = hmx_upgrade_flash.c hmx_upgrade_nvram.c
INCS = hmx_upgrade_nvram.h hnvram_dlist.h
@@ -20,8 +20,19 @@
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
+unit_test: test
+test: hmx_upgrade_flash_test hmx_upgrade_nvram_test
+ ./test/hmx_upgrade_flash_test
+ ./test/hmx_upgrade_nvram_test
+
libhmxupgrade.a: $(OBJS) $(INCS)
$(AR) rcs $@ $(OBJS)
+hmx_upgrade_flash_test:
+ $(CPP) $(CFLAGS) ./test/hmx_upgrade_flash_test.cc hmx_upgrade_flash.c -o ./test/$@ -lgtest -lpthread
+
+hmx_upgrade_nvram_test:
+ $(CPP) $(CFLAGS) -std=gnu++11 ./test/hmx_upgrade_nvram_test.cc -o ./test/$@ -lgtest -lpthread
+
clean:
- rm -f libhmxupgrade.a *.o
+ rm -f ./test/hmx_upgrade_nvram_test ./test/hmx_upgrade_flash_test libhmxupgrade.a *.o
diff --git a/libupgrade/hmx_upgrade_flash.c b/libupgrade/hmx_upgrade_flash.c
index 86833af..d01f8b2 100644
--- a/libupgrade/hmx_upgrade_flash.c
+++ b/libupgrade/hmx_upgrade_flash.c
@@ -81,8 +81,7 @@
/****************************** define *****************************/
/*******************************************************************/
/* Start #define */
-/* this is for test */
-#define TARGET_NVRAM_MTD "/dev/mtd/hnvram"
+#define HNVRAM_PARTITION_DEFAULT "/dev/mtd/hnvram"
/* End #define */
/*******************************************************************/
@@ -104,12 +103,27 @@
/************************ static variables *************************/
/*******************************************************************/
/* Start static variable */
+static const char *hnvram_partition = HNVRAM_PARTITION_DEFAULT;
/* End static variable */
/*******************************************************************/
/************************ static funtions **************************/
/*******************************************************************/
-int HMX_UPGRADE_NVRAM_Write(unsigned long offset, unsigned char * data,
+void HMX_UPGRADE_NVRAM_Init(const char * location)
+{
+ if (location == NULL) {
+ hnvram_partition = HNVRAM_PARTITION_DEFAULT;
+ } else {
+ hnvram_partition = location;
+ }
+}
+
+const char* HMX_UPGRADE_NVRAM_Get_Partition_Path(void)
+{
+ return hnvram_partition;
+}
+
+int HMX_UPGRADE_NVRAM_Write(unsigned long offset, const unsigned char * data,
unsigned int size )
{
int ret;
@@ -127,7 +141,7 @@
return -1;
}
- rpath = realpath(TARGET_NVRAM_MTD, NULL);
+ rpath = realpath(hnvram_partition, NULL);
if (!rpath) {
perror("realpath");
free(buf);
@@ -154,7 +168,7 @@
}
/* Only write to flash if data is different from what is already there. */
- if (ret == size && !memcmp(data, buf, size)) {
+ if ((unsigned int)ret == size && !memcmp(data, buf, size)) {
ret = 0;
goto out_close;
}
@@ -193,15 +207,21 @@
}
/*
- * Writes to /dev/mtdblockX are cached indefinitely until the last file
- * descriptor is closed. Flush this cache after writing. The user depends on
- * data being physically written to flash when this function returns.
- * Requires CAP_SYS_ADMIN.
+ * BLKFLSBUF will fail if we are writing to a file (-f) instead of a device
+ * If realpath is under /dev, then we are writing to a device and can proceed
*/
- ret = ioctl(fd_nvram, BLKFLSBUF, 0);
- if (ret < 0) {
- perror("ioctl(hnvram, BLKFLSBUF, 0)");
- goto out_close;
+ if (strncmp(rpath, "/dev/", 5) == 0) {
+ /*
+ * Writes to /dev/mtdblockX are cached indefinitely until the last file
+ * descriptor is closed. Flush this cache after writing. The user depends on
+ * data being physically written to flash when this function returns.
+ * Requires CAP_SYS_ADMIN.
+ */
+ ret = ioctl(fd_nvram, BLKFLSBUF, 0);
+ if (ret < 0) {
+ perror("ioctl(hnvram, BLKFLSBUF, 0)");
+ goto out_close;
+ }
}
ret = 0;
@@ -224,7 +244,7 @@
if (libupgrade_verbose) printf("[%s] offset %08lx, size %d, data = %02x\n",
__FUNCTION__, offset, size, data[0] );
- rpath = realpath(TARGET_NVRAM_MTD, NULL);
+ rpath = realpath(hnvram_partition, NULL);
if (!rpath) {
perror("realpath");
return -1;
diff --git a/libupgrade/hmx_upgrade_nvram.c b/libupgrade/hmx_upgrade_nvram.c
index 315c5e3..6031444 100644
--- a/libupgrade/hmx_upgrade_nvram.c
+++ b/libupgrade/hmx_upgrade_nvram.c
@@ -239,11 +239,9 @@
static int drv_NVRAM_Read(unsigned char *buffer, unsigned int offset,
unsigned int length)
{
- DRV_Error drv_error;
-
- drv_error = HMX_UPGRADE_NVRAM_Read(offset, buffer, length);
- if (drv_error != 0) {
- return -1;
+ int ret = HMX_UPGRADE_NVRAM_Read(offset, buffer, length);
+ if (ret != 0) {
+ return ret;
}
return length;
@@ -262,13 +260,11 @@
* Return value:
* number of bytes written, or -1 if error occured
********************************************************************* */
-static int drv_NVRAM_Write(unsigned char *buffer, unsigned int offset,
+static int drv_NVRAM_Write(const unsigned char *buffer, unsigned int offset,
unsigned int length)
{
- DRV_Error drv_error;
-
- drv_error = HMX_UPGRADE_NVRAM_Write(offset, buffer, length);
- if (drv_error != 0) {
+ int ret = HMX_UPGRADE_NVRAM_Write(offset, buffer, length);
+ if (ret != 0) {
return -1;
}
@@ -474,7 +470,8 @@
********************************************************************* */
static DRV_Error drv_NVRAM_SetEnv(HMX_NVRAM_PARTITION_E partition,
const unsigned char *name,
- unsigned char *value, unsigned int valueLen)
+ const unsigned char *value,
+ unsigned int valueLen)
{
NVRAM_EVNVAR_T *env;
unsigned int namelen;
@@ -486,7 +483,8 @@
}
namelen = strlen((char*)name);
- env = malloc(sizeof(NVRAM_EVNVAR_T) + namelen + 1 + valueLen);
+ env = (NVRAM_EVNVAR_T*)
+ malloc(sizeof(NVRAM_EVNVAR_T) + namelen + 1 + valueLen);
if (!env) {
return DRV_ERR_OUTOFMEMORY;
}
@@ -531,13 +529,13 @@
unsigned int recLen;
unsigned int recType;
unsigned int offset;
- unsigned int retval;
+ DRV_Error retval;
unsigned char fileName[MAX_NAME_LEN];
unsigned char nameLen;
unsigned int dataLen;
nvram_size = size;
- buffer = malloc(MAX_FIELD_LEN);
+ buffer = (unsigned char*)malloc(MAX_FIELD_LEN);
if (buffer == NULL)
{
return DRV_ERR_OUTOFMEMORY;
@@ -677,7 +675,7 @@
DRV_Error result;
nvram_size = s_nvram_size[partition];
- buffer = malloc(nvram_size);
+ buffer = (unsigned char*)malloc(nvram_size);
if (buffer == NULL) {
return DRV_ERR_OUTOFMEMORY;
}
@@ -694,6 +692,7 @@
if ((ptr + NVRAM_TYPE_LEN + NVRAM_RECORD_LENG_LEN + recLen) > buffer_end) {
/* One or more variables don't fit into the partition. Fail the write. */
+ free(buffer);
return DRV_ERR_OUTOFMEMORY;
}
@@ -738,8 +737,6 @@
return ((A << 24) | ((A << 8) & 0xFF0000) | ((A >> 8) & 0xFF00) |(A >> 24));
}
-static unsigned long s_nvramSema;
-
static DRV_Error drv_NVRAM_GetFieldInfo(const NVRAM_FIELD_T type,
HMX_NVRAM_PARTITION_E *pPartition,
unsigned char *pszFileName,
@@ -765,16 +762,17 @@
}
-DRV_Error HMX_NVRAM_Init(void)
+DRV_Error HMX_NVRAM_Init(const char *location)
{
+ HMX_UPGRADE_NVRAM_Init(location);
drv_NVRAM_Load(HMX_NVRAM_PARTITION_RO);
drv_NVRAM_Load(HMX_NVRAM_PARTITION_RW);
return DRV_OK;
}
DRV_Error HMX_NVRAM_Write(HMX_NVRAM_PARTITION_E partition,
- unsigned char *pName, unsigned int offset,
- unsigned char *pValue, unsigned int ulSize)
+ const unsigned char *pName, unsigned int offset,
+ const unsigned char *pValue, unsigned int ulSize)
{
DRV_Error drv_error;
@@ -787,9 +785,10 @@
return drv_error;
}
-DRV_Error HMX_NVRAM_Read(HMX_NVRAM_PARTITION_E partition, unsigned char *pName,
- unsigned int offset, unsigned char *pValue,
- unsigned int ulSize, unsigned int *pLen)
+DRV_Error HMX_NVRAM_Read(HMX_NVRAM_PARTITION_E partition,
+ const unsigned char *pName, unsigned int offset,
+ unsigned char *pValue, unsigned int ulSize,
+ unsigned int *pLen)
{
DRV_Error drv_error;
@@ -828,7 +827,8 @@
case HMX_NVRAM_PARTITION_RO :
case HMX_NVRAM_PARTITION_RW :
if (defaultSize == 0) {
- errCode = HMX_NVRAM_Read(partition, szFileName, offset, data, nDataSize, pDataSize);
+ errCode = HMX_NVRAM_Read(partition, szFileName, offset,
+ (unsigned char*)data, nDataSize, pDataSize);
if (errCode != DRV_OK) {
return errCode;
}
@@ -838,10 +838,10 @@
} else {
unsigned char *pBuf;
- pBuf = malloc(defaultSize);
+ pBuf = (unsigned char*)malloc(defaultSize);
if (pBuf == NULL) {
DEBUG_ERR("[HMX_NVRAM_GetField] malloc\n");
- return 3;
+ return DRV_ERR_INITIALIZATION;
}
errCode = HMX_NVRAM_Read(partition, szFileName, 0, pBuf, defaultSize, pDataSize);
if (errCode != DRV_OK) {
@@ -896,7 +896,8 @@
systemId = NVRAM_SWAP32((unsigned int)*(unsigned int*)data);
data = (void*)&systemId;
}
- errCode = HMX_NVRAM_Write(partition, szFileName, 0, data, nDataSize);
+ errCode = HMX_NVRAM_Write(partition, szFileName, 0,
+ (unsigned char*)data, nDataSize);
if (errCode != DRV_OK) {
DEBUG_ERR("[HMX_NVRAM_SetField] field(%d)-%s error(%08X) : "
"HMX_NVRAM_Write\n", field, szFileName, errCode);
@@ -905,7 +906,7 @@
} else {
unsigned char *pBuf;
- pBuf = malloc(defaultSize);
+ pBuf = (unsigned char*)malloc(defaultSize);
if (pBuf == NULL) {
DEBUG_ERR("[HMX_NVRAM_SetField] malloc\n");
return DRV_ERR_INITIALIZATION;
@@ -959,14 +960,14 @@
return DRV_OK;
}
-DRV_Error HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_E partition,
- unsigned char *pName)
+DRV_Error HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_E partition,
+ const unsigned char *pName)
{
- int result;
+ DRV_Error result;
SEM_Get(s_nvramSema);
result = drv_NVRAM_Delete(partition, pName);
- if (result == 0) {
+ if (result == DRV_OK) {
result = drv_NVRAM_Save(partition);
}
SEM_Release(s_nvramSema);
@@ -1005,7 +1006,7 @@
int nameLen, valueLen;
int idx;
- value = malloc(MAX_DATA_LEN);
+ value = (char*)malloc(MAX_DATA_LEN);
if (value == NULL)
{
return DRV_ERR_OUTOFMEMORY;
diff --git a/libupgrade/hmx_upgrade_nvram.h b/libupgrade/hmx_upgrade_nvram.h
index 209dc20..bfc54e3 100644
--- a/libupgrade/hmx_upgrade_nvram.h
+++ b/libupgrade/hmx_upgrade_nvram.h
@@ -146,7 +146,10 @@
/*******************************************************************/
/******************** global function prototype ********************/
/*******************************************************************/
-extern int HMX_UPGRADE_NVRAM_Write(unsigned long offset, unsigned char * data,
+extern void HMX_UPGRADE_NVRAM_Init(const char * location);
+extern const char* HMX_UPGRADE_NVRAM_Get_Partition_Path(void);
+extern int HMX_UPGRADE_NVRAM_Write(unsigned long offset,
+ const unsigned char * data,
unsigned int size );
extern int HMX_UPGRADE_NVRAM_Read(unsigned long offset, unsigned char * data,
unsigned int size );
@@ -154,12 +157,12 @@
/*******************************************************************/
/******************** global function prototype ********************/
/*******************************************************************/
-DRV_Error HMX_NVRAM_Init(void);
+DRV_Error HMX_NVRAM_Init(const char *location);
DRV_Error HMX_NVRAM_Write(HMX_NVRAM_PARTITION_E partition,
- unsigned char *pName, unsigned int offset,
- unsigned char *pValue, unsigned int ulSize);
+ const unsigned char *pName, unsigned int offset,
+ const unsigned char *pValue, unsigned int ulSize);
DRV_Error HMX_NVRAM_Read(HMX_NVRAM_PARTITION_E partition,
- unsigned char *pName, unsigned int offset,
+ const unsigned char *pName, unsigned int offset,
unsigned char *pValue, unsigned int ulSize,
unsigned int *pLen);
DRV_Error HMX_NVRAM_GetField(NVRAM_FIELD_T field, unsigned int offset,
@@ -168,7 +171,7 @@
void *data, int nDataSize);
DRV_Error HMX_NVRAM_GetLength(NVRAM_FIELD_T field, unsigned int *pLen);
DRV_Error HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_E partition,
- unsigned char *pName);
+ const unsigned char *pName);
DRV_Error HMX_NVRAM_Dir(void);
/* End global function prototypes */
diff --git a/libupgrade/test/hmx_test_base.cc b/libupgrade/test/hmx_test_base.cc
new file mode 100644
index 0000000..484838d
--- /dev/null
+++ b/libupgrade/test/hmx_test_base.cc
@@ -0,0 +1,92 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+// Author: germuth@google.com (Aaron Germuth)
+
+// Humax Hnvram Base Testing Class
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include "gtest/gtest.h"
+
+#define TEST_MAIN
+
+// Tests can change this variable to temporarily write to another file
+// Value restored to staticFileName at end of test
+const char* hnvramFileName;
+const char* staticFileName;
+const int hnvramFileSize = 2048000;
+
+// Helper Testing Methods
+int hnvram_empty() {
+ unsigned char buff[hnvramFileSize + 1];
+ int fp = open(hnvramFileName, O_RDONLY);
+ EXPECT_GT(fp, 0);
+ EXPECT_EQ(hnvramFileSize, read(fp, buff, hnvramFileSize));
+ EXPECT_EQ(0, close(fp));
+
+ for(int i = 0; i < hnvramFileSize; i++) {
+ if (buff[i] != '\0') {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int delete_hnvram_file() {
+ char cmd[30];
+ sprintf(cmd, "rm -f %s", hnvramFileName);
+ int ret = system(cmd);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to delete hnvram partition file: %s\n",
+ hnvramFileName);
+ }
+ return ret;
+}
+
+// Base testing class
+class HnvramTest : public ::testing::Test {
+ public:
+ HnvramTest() {}
+ virtual ~HnvramTest() {}
+
+ virtual void SetUp() {
+ hnvramFileName = staticFileName;
+
+ // Create new blank hnvram partition
+ char cmd[255];
+ sprintf(cmd, "dd if=/dev/zero of=%s bs=1024 count=2KB >& /dev/null",
+ hnvramFileName);
+ int ret = system(cmd);
+
+ if (ret != 0) {
+ fprintf(stderr, "Failed to create hnvram partition file: %s\n",
+ hnvramFileName);
+ }
+
+ EXPECT_TRUE(hnvram_empty());
+ }
+
+ virtual void TearDown() {
+ delete_hnvram_file();
+ }
+};
+
+class HnvramEnvironment : public ::testing::Environment {
+ public:
+ virtual ~HnvramEnvironment() {}
+ virtual void SetUp() {
+ // Get Unique File Name
+ // use mktemp instead of mkstemp, since we don't want to open file yet
+ char fileName[255] = "/tmp/hnvram-test-XXXXXX";
+ mktemp(fileName);
+ if (fileName[0] == '\0') {
+ fprintf(stderr, "Failed to create unique file name\n");
+ }
+ staticFileName = strdup(fileName);
+ }
+
+ virtual void TearDown() {
+ // Just incase test case was interrupted, delete file here too
+ delete_hnvram_file();
+ }
+};
diff --git a/libupgrade/test/hmx_upgrade_flash_test.cc b/libupgrade/test/hmx_upgrade_flash_test.cc
new file mode 100644
index 0000000..a0dcbe2
--- /dev/null
+++ b/libupgrade/test/hmx_upgrade_flash_test.cc
@@ -0,0 +1,142 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+// Author: germuth@google.com (Aaron Germuth)
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include "gtest/gtest.h"
+
+#define TEST_MAIN
+#include "hmx_test_base.cc"
+#include "hmx_upgrade_nvram.c"
+
+// Tests Constants
+const unsigned char* writeData = (unsigned char*)"ABC123def";
+const unsigned int writeLen = 10;
+
+// Test Parameterization
+const unsigned int offsets[] = {NVRAM_RO_OFFSET, NVRAM_RW_OFFSET, NVRAM_RWB_OFFSET};
+unsigned int offset;
+
+class HnvramFlashTest : public HnvramTest,
+ public ::testing::WithParamInterface<unsigned int> {
+ public:
+ HnvramFlashTest() {}
+ virtual ~HnvramFlashTest() {}
+
+ virtual void SetUp() {
+ libupgrade_verbose = 0;
+ offset = GetParam();
+
+ HnvramTest::SetUp();
+ }
+
+ virtual void TearDown() {
+ HnvramTest::TearDown();
+ offset = 0;
+ }
+};
+
+TEST_P(HnvramFlashTest, TestHnvramInit) {
+ EXPECT_STREQ("/dev/mtd/hnvram", HMX_UPGRADE_NVRAM_Get_Partition_Path());
+
+ HMX_UPGRADE_NVRAM_Init("/tmp/abctest123");
+ EXPECT_STREQ("/tmp/abctest123", HMX_UPGRADE_NVRAM_Get_Partition_Path());
+
+ HMX_UPGRADE_NVRAM_Init(NULL);
+ EXPECT_STREQ("/dev/mtd/hnvram", HMX_UPGRADE_NVRAM_Get_Partition_Path());
+}
+
+TEST_P(HnvramFlashTest, TestFlashWrite) {
+ const unsigned char test[2] = "A";
+
+ // bad realpath
+ HMX_UPGRADE_NVRAM_Init("/fake/doesnotexist915");
+ EXPECT_EQ(-1, HMX_UPGRADE_NVRAM_Write(0, test, 1));
+
+ // Can't open file (because its a directory)
+ HMX_UPGRADE_NVRAM_Init("/tmp");
+ EXPECT_EQ(-1, HMX_UPGRADE_NVRAM_Write(0, test, 1));
+
+ // Can't flush device (BLKFLSBUF)
+ HMX_UPGRADE_NVRAM_Init("/dev/zero");
+ EXPECT_EQ(-1, HMX_UPGRADE_NVRAM_Write(0, test, 1));
+
+ // should succeed without actually writing, if there would is no difference
+ // write zeros to zero'd file
+ HMX_UPGRADE_NVRAM_Init(hnvramFileName);
+
+ // can check by comparing file mtime, before and after
+ struct stat statbuf;
+ EXPECT_NE(-1, stat(hnvramFileName, &statbuf));
+ time_t before = statbuf.st_mtime;
+
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Write(0, (unsigned char*)"\0\0\0", 3));
+ unsigned char buff[255];
+ HMX_UPGRADE_NVRAM_Read(0, buff, 10);
+ EXPECT_EQ(0, memcmp((char*)buff, "\0\0\0\0\0\0\0\0\0\0", 10));
+ memset(buff, 0, sizeof(buff));
+
+ EXPECT_NE(-1, stat(hnvramFileName, &statbuf));
+ time_t after = statbuf.st_mtime;
+
+ EXPECT_EQ(before, after);
+
+ // verify writes with read and HMX_Read
+ HMX_UPGRADE_NVRAM_Init(hnvramFileName);
+ int fp = open(hnvramFileName, O_RDONLY);
+
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Write(offset, writeData, writeLen));
+
+ EXPECT_EQ(offset, lseek(fp, offset, SEEK_SET));
+ EXPECT_EQ(writeLen, read(fp, buff, writeLen));
+ EXPECT_EQ(0, memcmp((char*)buff, (char*)writeData, writeLen));
+ memset(buff, 0, sizeof(buff));
+
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(offset, buff, writeLen));
+ EXPECT_EQ(0, memcmp((char*)buff, (char*)writeData, writeLen));
+
+ close(fp);
+}
+
+TEST_P(HnvramFlashTest, TestFlashRead) {
+ unsigned char read_buffer[10];
+ // bad realpath
+ HMX_UPGRADE_NVRAM_Init("/fake/doesnotexist915");
+ EXPECT_EQ(-1, HMX_UPGRADE_NVRAM_Read(0, read_buffer, 0));
+
+ // Can't open file (because its a directory)
+ HMX_UPGRADE_NVRAM_Init("/tmp");
+ EXPECT_EQ(-1, HMX_UPGRADE_NVRAM_Read(0, read_buffer, 0));
+
+ // Can't read file because permissions
+ HMX_UPGRADE_NVRAM_Init("/proc/version");
+ EXPECT_EQ(-1, HMX_UPGRADE_NVRAM_Read(0, read_buffer, 10000000));
+
+ // File should be completely empty
+ HMX_UPGRADE_NVRAM_Init(hnvramFileName);
+ unsigned char buff[255];
+
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(offset, buff, writeLen));
+ EXPECT_EQ(0, memcmp((char*)buff, "\0\0\0\0\0\0\0\0\0\0", writeLen));
+ memset((char*)buff, 0, sizeof(buff));
+
+ // Should be able to HMX_Read data from raw C writes
+ int fp = open(hnvramFileName, O_WRONLY);
+ EXPECT_EQ(offset, lseek(fp, offset, SEEK_SET));
+ EXPECT_EQ(writeLen, write(fp, writeData, writeLen));
+ close(fp);
+
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(offset, buff, writeLen));
+ EXPECT_EQ(0, memcmp((char*)buff, writeData, writeLen));
+}
+
+INSTANTIATE_TEST_CASE_P(TryAllOffsets, HnvramFlashTest,
+ ::testing::ValuesIn(offsets));
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::AddGlobalTestEnvironment(new HnvramEnvironment());
+ return RUN_ALL_TESTS();
+}
diff --git a/libupgrade/test/hmx_upgrade_nvram_test.cc b/libupgrade/test/hmx_upgrade_nvram_test.cc
new file mode 100644
index 0000000..08fe339
--- /dev/null
+++ b/libupgrade/test/hmx_upgrade_nvram_test.cc
@@ -0,0 +1,700 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+// Author: germuth@google.com (Aaron Germuth)
+
+// Humax Hnvram Testing
+// Methods from hmx_upgrade_flash.c have been replaced with mock methods below.
+//
+// Fields are tested by trying to read/write two different fields:
+// MAC_ADDR and ACTIVATED_KERNEL_NAME, one for each partition.
+//
+// Variables are tested by trying to read/write the same variable, but
+// in each partition seperately (ReadOnly and ReadWrite)
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <tuple>
+#include "gtest/gtest.h"
+
+#define TEST_MAIN
+#include "hmx_test_base.cc"
+#include "hmx_upgrade_nvram.c"
+
+using ::testing::TestWithParam;
+using Partition = HMX_NVRAM_PARTITION_E;
+
+// Field Parameters
+// partition, fieldType, fieldName, fieldVal1, fieldVal2, fieldValLen
+std::tuple<Partition, NVRAM_FIELD_T, unsigned char*, unsigned char*,
+ unsigned char*,unsigned int> field_tuples[] = {
+ std::make_tuple(HMX_NVRAM_PARTITION_RO, NVRAM_FIELD_MAC_ADDR,
+ (unsigned char*)"MAC_ADDR",
+ (unsigned char*)"\x02\x04:\xAE\x06:\xFF\xE2",
+ (unsigned char*)"\x0\x40:\xDD\x16:\x20\x41",
+ (unsigned int) 8),
+ std::make_tuple(HMX_NVRAM_PARTITION_RW, NVRAM_FIELD_ACTIVATED_KERNEL_NAME,
+ (unsigned char*)"ACTIVATED_KERNEL_NAME",
+ (unsigned char*)"kernel0",
+ (unsigned char*)"kernel1",
+ (unsigned int) 7)
+};
+
+// Variable Parameters
+// partition, partitionOther, partitionOffset
+std::tuple<Partition, Partition, int> var_tuples[] = {
+ std::make_tuple(HMX_NVRAM_PARTITION_RO, // Read only
+ HMX_NVRAM_PARTITION_RW, NVRAM_RO_OFFSET),
+ std::make_tuple(HMX_NVRAM_PARTITION_RW, // Read Write
+ HMX_NVRAM_PARTITION_RO, NVRAM_RW_OFFSET)
+};
+
+// Global Test Parameters, populated by var_tuples and field_tuples
+NVRAM_FIELD_T fieldType;
+unsigned char* fieldName;
+unsigned char* fieldVal;
+unsigned char* fieldValOther;
+unsigned int fieldValLen;
+Partition part;
+Partition partOther;
+int offset;
+
+// Global Test Constants
+const unsigned char* name = (unsigned char*)"test_name";
+const unsigned char* nameOther = (unsigned char*)"test_name2";
+const unsigned char* val = (unsigned char*)"TEST\0\x02\x11";
+const unsigned int nameLen = 9;
+const unsigned int nameOtherLen = 10;
+const unsigned int valLen = 7;
+
+// Helper Testing Methods
+int dlist_size(Partition part) {
+ int i = 0;
+ dlist_hdr_t *entry;
+ DLIST_FOR_EACH(&s_nvram_envvars[part], entry) {
+ i++;
+ }
+ return i;
+}
+
+int dlist_contains(Partition part, const unsigned char* name) {
+ dlist_hdr_t *entry;
+ NVRAM_EVNVAR_T *env;
+ DLIST_FOR_EACH(&s_nvram_envvars[part], entry) {
+ env = (NVRAM_EVNVAR_T *) entry;
+ if (strcmp((char*)env->name, (char*)name) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void clear_dlist() {
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RO, name);
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RW, name);
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RO, nameOther);
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RW, nameOther);
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RO, fieldName);
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RW, fieldName);
+
+ // Ensure dlist empty
+ EXPECT_EQ(0, dlist_size(HMX_NVRAM_PARTITION_RO));
+ EXPECT_EQ(0, dlist_size(HMX_NVRAM_PARTITION_RW));
+}
+
+// Hnvram byte formatting - Used to verify tests
+// One byte to store name length, 4 bytes for value length
+const unsigned int recLen = 1 + nameLen + 4 + valLen;
+// Include 5 intro bytes (1 start byte + 4 bytes for recLen)
+const unsigned int totalLen = recLen + 5;
+char* raw_hnvram_bytes(char* bytes) {
+ // Start Byte
+ bytes[0] = '\x01';
+
+ // Record Length
+ bytes[1] = '\0';
+ bytes[2] = '\0';
+ bytes[3] = '\0';
+ bytes[4] = recLen;
+
+ // Name Length
+ bytes[5] = nameLen;
+
+ // Name
+ memcpy(bytes + 6, name, nameLen);
+
+ // Val Length
+ bytes[6 + nameLen] = '\0';
+ bytes[7 + nameLen] = '\0';
+ bytes[8 + nameLen] = '\0';
+ bytes[9 + nameLen] = valLen;
+
+ //Val
+ memcpy(bytes + 10 + nameLen, val, valLen);
+
+ return bytes;
+}
+
+// Replacement methods for hmx_upgrade_flash.c
+// We always use a file instead of flash memory
+const char* hnvram_location = NULL;
+void HMX_UPGRADE_NVRAM_Init(const char * location) {
+ return;
+}
+
+const char* HMX_UPGRADE_NVRAM_Get_Partition_Path(void) {
+ return "/dev/mtd/hnvram";
+}
+
+int HMX_UPGRADE_NVRAM_Write(unsigned long offset, const unsigned char * data,
+ unsigned int size ) {
+ int fp = open(hnvramFileName, O_WRONLY);
+ if (fp < 0) {
+ return -1;
+ }
+ int ret = lseek(fp, offset, SEEK_SET);
+ if (ret < 0) {
+ return -1;
+ }
+ ret = write(fp, data, size);
+ if (ret < 0) {
+ return -1;
+ }
+ ret = close(fp);
+ if (ret < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+int HMX_UPGRADE_NVRAM_Read(unsigned long offset, unsigned char * data,
+ unsigned int size ) {
+ int fp = open(hnvramFileName, O_RDONLY);
+ if (fp < 0) {
+ return -1;
+ }
+ int ret = lseek(fp, offset, SEEK_SET);
+ if (ret < 0) {
+ return -1;
+ }
+ ret = read(fp, data, size);
+ if (ret < 0) {
+ return -1;
+ }
+ ret = close(fp);
+ if (ret < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+class HnvramFieldTest :
+ public HnvramTest, public ::testing::WithParamInterface<
+ std::tuple<Partition, NVRAM_FIELD_T, unsigned char*,
+ unsigned char*, unsigned char*,unsigned int> > {
+ public:
+ virtual void SetUp() {
+ // Initialize test Parameters
+ part = std::get<0>(GetParam());
+ fieldType = std::get<1>(GetParam());
+ fieldName = std::get<2>(GetParam());
+ fieldVal = std::get<3>(GetParam());
+ fieldValOther = std::get<4>(GetParam());
+ fieldValLen = std::get<5>(GetParam());
+
+ HnvramTest::SetUp();
+
+ clear_dlist();
+ // Shouldn't be able to find anything in a empty partition
+ EXPECT_EQ(NULL, drv_NVRAM_FindEnv(HMX_NVRAM_PARTITION_RO, name));
+ EXPECT_EQ(NULL, drv_NVRAM_FindEnv(HMX_NVRAM_PARTITION_RW, name));
+ }
+
+ virtual void TearDown() {
+ clear_dlist();
+ HnvramTest::TearDown();
+
+ part = HMX_NVRAM_PARTITION_UNSPECIFIED;
+ fieldType = NVRAM_FIELD_DUMMY;
+ fieldName = NULL;
+ fieldVal = NULL;
+ fieldValOther = NULL;
+ fieldValLen = 0;
+ }
+};
+
+TEST_P(HnvramFieldTest, TestGetFieldInfo) {
+ unsigned char buff[255];
+ unsigned int defSize = 0;
+ HMX_NVRAM_PARTITION_E partUsed;
+
+ EXPECT_EQ(DRV_ERR,
+ drv_NVRAM_GetFieldInfo(NVRAM_FIELD_DUMMY,
+ &partUsed, buff, &defSize));
+
+ EXPECT_EQ(DRV_OK,
+ drv_NVRAM_GetFieldInfo(fieldType, &partUsed, buff, &defSize));
+ EXPECT_STREQ((char*) buff, (char*)fieldName);
+ EXPECT_EQ(part, partUsed);
+ EXPECT_EQ(defSize, 0);
+}
+
+TEST_P(HnvramFieldTest, TestGetFieldAndSize) {
+ unsigned char buff[255];
+ unsigned int dataSize = sizeof(buff);
+ unsigned int pDataSize = 0;
+
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_GetFieldAndSize(NVRAM_FIELD_DUMMY,
+ 0, buff, dataSize, &pDataSize));
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_GetFieldAndSize(fieldType,
+ 0, NULL, dataSize, &pDataSize));
+ // Nothing to Read
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_GetFieldAndSize(fieldType,
+ 0, buff, dataSize, &pDataSize));
+ // Write MAC_ADDR
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_Write(part, fieldName, 0, fieldVal, fieldValLen));
+
+ // Read it back
+ EXPECT_EQ(DRV_OK,
+ HMX_NVRAM_GetFieldAndSize(fieldType,
+ 0, buff, dataSize, &pDataSize));
+ EXPECT_EQ(0, memcmp((char*)buff, (char*)fieldVal, fieldValLen));
+ EXPECT_EQ(dataSize, 255);
+ EXPECT_EQ(pDataSize, fieldValLen);
+}
+
+TEST_P(HnvramFieldTest, TestSetField) {
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_SetField(NVRAM_FIELD_DUMMY, 0, fieldVal, fieldValLen));
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_SetField(fieldType, 0, NULL, fieldValLen));
+
+ // Should add variable
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_SetField(fieldType, 0, fieldVal, fieldValLen));
+ EXPECT_EQ(1, dlist_size(part));
+ EXPECT_EQ(1, dlist_contains(part, fieldName));
+ EXPECT_FALSE(hnvram_empty());
+
+ // Should be able to read it back
+ unsigned char buff[255];
+ unsigned int dataSize = sizeof(buff);
+
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_GetField(fieldType, 0, buff, dataSize));
+ EXPECT_EQ(0, memcmp((char*)buff, (char*)fieldVal, fieldValLen));
+
+ // Try changing value
+ EXPECT_EQ(DRV_OK,
+ HMX_NVRAM_SetField(fieldType, 0, fieldValOther, fieldValLen));
+ EXPECT_EQ(1, dlist_size(part));
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_GetField(fieldType, 0, buff, dataSize));
+ EXPECT_EQ(0, memcmp((char*)buff, (char*)fieldValOther, fieldValLen));
+
+ // Test with Offset
+ int offset = 3;
+ EXPECT_EQ(DRV_OK,
+ HMX_NVRAM_SetField(fieldType, offset, fieldVal, fieldValLen));
+ EXPECT_EQ(1, dlist_size(part));
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_GetField(fieldType, offset, buff, dataSize));
+ EXPECT_EQ(0, memcmp((char*)buff, (char*)(fieldVal + offset),
+ fieldValLen - offset));
+}
+
+TEST_P(HnvramFieldTest, TestGetLength) {
+ unsigned int readLen;
+
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_GetLength(fieldType, NULL));
+ EXPECT_EQ(DRV_ERR,
+ HMX_NVRAM_GetLength(NVRAM_FIELD_DUMMY, &readLen));
+
+ // No field length to grab
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_GetLength(fieldType, &readLen));
+ EXPECT_EQ(readLen, 0);
+
+ // Should work after adding
+ EXPECT_EQ(DRV_OK,
+ HMX_NVRAM_SetField(fieldType, 0, fieldVal, fieldValLen));
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_GetLength(fieldType, &readLen));
+ EXPECT_EQ(readLen, fieldValLen);
+}
+
+class HnvramVariableTest :
+ public HnvramTest, public ::testing::WithParamInterface<
+ std::tuple<Partition, Partition, int> > {
+ public:
+ virtual void SetUp() {
+ // Initialize test Parameters
+ part = std::get<0>(GetParam());
+ partOther = std::get<1>(GetParam());
+ offset = std::get<2>(GetParam());
+
+ HnvramTest::SetUp();
+
+ clear_dlist();
+ // Initialize test Parameters
+ }
+ virtual void TearDown() {
+ clear_dlist();
+ HnvramTest::TearDown();
+
+ part = HMX_NVRAM_PARTITION_UNSPECIFIED;
+ partOther = HMX_NVRAM_PARTITION_UNSPECIFIED;
+ offset = -1;
+ }
+};
+
+TEST_P(HnvramVariableTest, TestDrvRead) {
+ unsigned char read[30];
+ // Should be able to read 0s
+ EXPECT_EQ(10, drv_NVRAM_Read(read, offset, 10));
+ EXPECT_STREQ("\0\0\0\0\0\0\0\0\0\0", (char*)read);
+ EXPECT_EQ(22, drv_NVRAM_Read(read, offset, 22));
+ EXPECT_STREQ("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", (char*) read);
+
+ // Should be able to read back a raw write
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Write(offset, val, valLen));
+ EXPECT_EQ(valLen, drv_NVRAM_Read(read, offset, valLen));
+ EXPECT_STREQ((char*)val, (char*)read);
+}
+
+TEST_P(HnvramVariableTest, TestDrvWrite) {
+ unsigned char read[255];
+ EXPECT_EQ(valLen, drv_NVRAM_Write(val, offset, valLen));
+
+ // raw read should return same string
+ EXPECT_EQ(0, hnvram_empty());
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(offset, read, valLen));
+ EXPECT_EQ(0, memcmp((char*)read, (char*) val, valLen));
+}
+
+TEST_P(HnvramVariableTest, TestFindEnv) {
+ // Should be able to read after SetEnv
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+ NVRAM_EVNVAR_T* env = drv_NVRAM_FindEnv(part, name);
+ EXPECT_FALSE(NULL == env);
+ EXPECT_EQ(0, memcmp((char*)env->value, (char*)val, valLen));
+ EXPECT_EQ(1, dlist_size(part));
+ EXPECT_EQ(1, dlist_contains(part, name));
+
+ EXPECT_EQ(NULL, drv_NVRAM_FindEnv(partOther, name));
+ EXPECT_EQ(NULL, drv_NVRAM_FindEnv(part, nameOther));
+
+ // Don't mix up with 2nd one
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, nameOther, val, valLen));
+ env = drv_NVRAM_FindEnv(part, nameOther);
+ EXPECT_FALSE(NULL == env);
+ EXPECT_EQ(0, memcmp((char*)env->name, (char*)nameOther, nameOtherLen));
+
+ env = drv_NVRAM_FindEnv(part, name);
+ EXPECT_FALSE(NULL == env);
+ EXPECT_EQ(0, memcmp((char*)env->name, (char*)name, nameLen));
+}
+
+TEST_P(HnvramVariableTest, TestScanDir) {
+ unsigned char readName[255];
+ unsigned int readNameLen;
+ unsigned char readVal[255];
+ unsigned int readValLen;
+
+ // Ask for 5th var when empty
+ EXPECT_EQ(DRV_ERR, drv_NVRAM_ScanDir(part, 4, readName, &readNameLen,
+ readVal, &readValLen));
+
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+
+ // Ask for 5th again, still fail
+ EXPECT_EQ(DRV_ERR, drv_NVRAM_ScanDir(part, 4, readName, &readNameLen,
+ readVal, &readValLen));
+
+ // Get back 1st var, should suceed
+ EXPECT_EQ(DRV_OK, drv_NVRAM_ScanDir(part, 0, readName, &readNameLen,
+ readVal, &readValLen));
+ EXPECT_EQ(readNameLen, nameLen);
+ EXPECT_EQ(readValLen, valLen);
+ EXPECT_EQ(0, memcmp((char*)name, readName, nameLen));
+ EXPECT_EQ(0, memcmp((char*)val, readVal, valLen));
+
+ // Add second, make it doesn't mix them up
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, nameOther, val, valLen));
+
+ EXPECT_EQ(DRV_OK, drv_NVRAM_ScanDir(part, 1, readName, &readNameLen,
+ readVal, &readValLen));
+ EXPECT_EQ(readNameLen, nameOtherLen);
+ EXPECT_EQ(0, memcmp((char*)nameOther, readName, nameOtherLen));
+
+ EXPECT_EQ(DRV_OK, drv_NVRAM_ScanDir(part, 0, readName, &readNameLen,
+ readVal, &readValLen));
+ EXPECT_EQ(readNameLen, nameLen);
+ EXPECT_EQ(0, memcmp((char*)name, readName, nameLen));
+}
+
+TEST_P(HnvramVariableTest, TestDrvDelete) {
+ // Nothing to delete
+ EXPECT_EQ(DRV_ERR, drv_NVRAM_Delete(part, name));
+
+ // Add single variable to delete
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+ EXPECT_EQ(DRV_OK, drv_NVRAM_Delete(part, name));
+ EXPECT_EQ(0, dlist_size(part));
+
+ // Don't mix them up
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, nameOther, val, valLen));
+ EXPECT_EQ(2, dlist_size(part));
+
+ EXPECT_EQ(DRV_OK, drv_NVRAM_Delete(part, name));
+ EXPECT_EQ(1, dlist_size(part));
+ NVRAM_EVNVAR_T* env = drv_NVRAM_FindEnv(part, nameOther);
+ EXPECT_TRUE(NULL != env);
+ EXPECT_EQ(0, memcmp(env->name, nameOther, nameOtherLen));
+
+ EXPECT_EQ(DRV_OK, drv_NVRAM_Delete(part, nameOther));
+ EXPECT_EQ(0, dlist_size(part));
+}
+
+TEST_P(HnvramVariableTest, TestDrvGetEnv) {
+ unsigned char read[255];
+ unsigned int readLen;
+ unsigned int maxCopied = 10;
+
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ drv_NVRAM_GetEnv(part, NULL, 0, read, maxCopied, &readLen));
+
+ // Try to read empty dlist
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ drv_NVRAM_GetEnv(part, name, 0, read, maxCopied, &readLen));
+
+ // Should be able to read after SetEnv
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+ EXPECT_EQ(DRV_OK, drv_NVRAM_GetEnv(part, name, 0, read, maxCopied, &readLen));
+ EXPECT_EQ(0, memcmp((char*)val, read, readLen));
+
+ // Should work with offset (2)
+ EXPECT_EQ(DRV_OK, drv_NVRAM_GetEnv(part, name, 2, read, maxCopied, &readLen));
+ EXPECT_EQ(0, memcmp((char*)(val + 2), read, readLen));
+
+ // Should respect maxCopied, and not overwrite
+ read[3] = '\xAE';
+ maxCopied = 3;
+ EXPECT_EQ(DRV_OK, drv_NVRAM_GetEnv(part, name, 0, read, maxCopied, &readLen));
+ EXPECT_EQ(0, memcmp((char*)val, read, maxCopied));
+ EXPECT_EQ('\xAE', (char)read[3]);
+
+ // Shouldn't be able to find other variables
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ drv_NVRAM_GetEnv(part, nameOther, 0, read, maxCopied, &readLen));
+}
+
+TEST_P(HnvramVariableTest, TestDrvGetLength) {
+ unsigned int readLen;
+
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ drv_NVRAM_GetLength(part, NULL, &readLen));
+
+ // Try to read empty dlist
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ drv_NVRAM_GetLength(part, name, &readLen));
+
+ // Should be able to read after SetEnv
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+ EXPECT_EQ(DRV_OK, drv_NVRAM_GetLength(part, name, &readLen));
+ EXPECT_EQ(valLen, readLen);
+
+ // Shouldn't be able to find other variables
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ drv_NVRAM_GetLength(part, nameOther, &readLen));
+}
+
+TEST_P(HnvramVariableTest, TestSetEnv) {
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+
+ // Check dlists
+ EXPECT_EQ(1, dlist_size(part));
+ EXPECT_EQ(1, dlist_contains(part, name));
+ EXPECT_EQ(0, dlist_size(partOther));
+
+ // Should be findable by findEnv
+ NVRAM_EVNVAR_T* env = drv_NVRAM_FindEnv(part, name);
+ EXPECT_TRUE(env != NULL);
+
+ // Params should match
+ EXPECT_STREQ((char*)env->name, (char*)name);
+ EXPECT_EQ(0, memcmp((char*)env->value, (char*)val, valLen));
+
+ EXPECT_EQ(env->nameLen, nameLen);
+ EXPECT_EQ(env->valueLen, valLen);
+ EXPECT_EQ(env->recLen, nameLen + valLen + 5);
+
+ // Make sure just anything isn't findable
+ EXPECT_EQ(NULL, drv_NVRAM_FindEnv(part, nameOther));
+ EXPECT_EQ(NULL, drv_NVRAM_FindEnv(partOther, name));
+
+ // Check RAWFS, just to be thorough
+ EXPECT_EQ(0, dlist_size(HMX_NVRAM_PARTITION_W_RAWFS));
+ EXPECT_EQ(NULL, drv_NVRAM_FindEnv(HMX_NVRAM_PARTITION_W_RAWFS, name));
+ EXPECT_EQ(0, dlist_size(HMX_NVRAM_PARTITION_W_RAWFS));
+
+ // Make sure we can add more than one
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, nameOther, val, valLen));
+ EXPECT_EQ(2, dlist_size(part));
+ EXPECT_EQ(1, dlist_contains(part, name));
+ EXPECT_EQ(1, dlist_contains(part, nameOther));
+}
+
+TEST_P(HnvramVariableTest, TestLoadByAddress) {
+ int size;
+ if (part == HMX_NVRAM_PARTITION_RO) {
+ size = NVRAM_RO_SIZE;
+ } else {
+ size = NVRAM_RW_SIZE;
+ }
+
+ // Nothing to load
+ EXPECT_EQ(DRV_OK, drv_NVRAM_LoadByAddress(part, offset, size));
+ EXPECT_EQ(0, dlist_size(part));
+
+ // Corrupt Hnvram start bit
+ char rhb[255];
+ raw_hnvram_bytes(rhb);
+ rhb[0] = '\xAE';
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Write(offset, (unsigned char*)rhb, recLen));
+ EXPECT_EQ(DRV_ERR_EVENT_INITIALIZATION,
+ drv_NVRAM_LoadByAddress(part, offset, size));
+
+ // corrupt record length sizes
+ raw_hnvram_bytes(rhb);
+ rhb[1] = '\xFF';
+ rhb[2] = '\xFF';
+ rhb[3] = '\xFF';
+ rhb[4] = '\xFF';
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Write(offset, (unsigned char*)rhb, recLen));
+ EXPECT_EQ(DRV_ERR_EVENT_INITIALIZATION,
+ drv_NVRAM_LoadByAddress(part, offset, size));
+
+ raw_hnvram_bytes(rhb);
+ rhb[4] = '\0';
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Write(offset, (unsigned char*)rhb, recLen));
+ EXPECT_EQ(DRV_ERR_EVENT_INITIALIZATION,
+ drv_NVRAM_LoadByAddress(part, offset, size));
+
+ // Proper load
+ raw_hnvram_bytes(rhb);
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Write(offset, (unsigned char*)rhb, recLen));
+ EXPECT_EQ(DRV_OK, drv_NVRAM_LoadByAddress(part, offset, size));
+ EXPECT_EQ(1, dlist_size(part));
+ EXPECT_EQ(1, dlist_contains(part, name));
+
+ // Fail cleanly with no partition
+ hnvramFileName = (const char*)"/oops";
+ EXPECT_EQ(DRV_ERR_EXTERNAL_ERROR,
+ drv_NVRAM_LoadByAddress(part, offset, size));
+}
+
+TEST_P(HnvramVariableTest, TestSave) {
+ unsigned char valueLarge[hnvramFileSize + 10];
+ // Variable doesn't fit in partition (fake the value length)
+ EXPECT_EQ(DRV_OK,
+ drv_NVRAM_SetEnv(part, name, valueLarge, sizeof(valueLarge) - 10));
+ EXPECT_EQ(DRV_ERR_OUTOFMEMORY, drv_NVRAM_Save(part));
+ EXPECT_EQ(DRV_OK, drv_NVRAM_Delete(part, name));
+
+ // file should still be empty if dlist has nothing to save
+ EXPECT_EQ(DRV_OK, drv_NVRAM_Save(part));
+ EXPECT_EQ(0, dlist_size(part));
+ EXPECT_TRUE(hnvram_empty());
+
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+ EXPECT_EQ(DRV_OK, drv_NVRAM_Save(part));
+
+ // Raw read back partition and try to match
+ unsigned char read[255];
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(offset, read, totalLen));
+
+ char rhb[255];
+ raw_hnvram_bytes(rhb);
+ EXPECT_EQ(0, memcmp((char*)read, rhb, totalLen));
+
+ // Writes to RW should have also saved to RWB partition, other should be 0s
+ if (part == HMX_NVRAM_PARTITION_RW) {
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(NVRAM_RWB_OFFSET, read, totalLen));
+ EXPECT_EQ(0, memcmp((char*)read, rhb, totalLen));
+ } else {
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(NVRAM_RWB_OFFSET, read, 7));
+ EXPECT_EQ(0, memcmp((char*)read, "\0\0\0\0\0\0\0", 7));
+ }
+
+ // Should be null byte after var to indicate no more variables
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(offset + totalLen, read, 1));
+ EXPECT_EQ(0, memcmp((char*)read, "\0", 1));
+}
+
+TEST_P(HnvramVariableTest, TestHMXWrite) {
+ unsigned char read[255];
+
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_Write(part, name, 0, val, valLen));
+
+ // Write should have inserted into dlist
+ EXPECT_EQ(1, dlist_size(part));
+ EXPECT_EQ(1, dlist_contains(part, name));
+
+ // And saved bytes to file
+ EXPECT_FALSE(hnvram_empty());
+ EXPECT_EQ(0, HMX_UPGRADE_NVRAM_Read(offset, read, totalLen));
+
+ char rhb[255];
+ raw_hnvram_bytes(rhb);
+ EXPECT_EQ(0, memcmp((char*)read, rhb, totalLen));
+}
+
+TEST_P(HnvramVariableTest, TestHMXRead) {
+ unsigned char read[255];
+ unsigned int readLen;
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_Read(part, NULL, 0, NULL, 0, NULL));
+
+ // Should fail to find variable
+ EXPECT_EQ(DRV_ERR_INVALID_PARAMETER,
+ HMX_NVRAM_Read(part, name, 0, read, sizeof(read), NULL));
+
+ // Add val to dlist and make sure Read gets them correct
+ EXPECT_EQ(DRV_OK, drv_NVRAM_SetEnv(part, name, val, valLen));
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_Read(part, name, 0,
+ read, sizeof(read), &readLen));
+ EXPECT_EQ(readLen, valLen);
+ EXPECT_EQ(0, memcmp((char*)read, (char*)val, valLen));
+}
+
+TEST_P(HnvramVariableTest, TestRemove) {
+ // Nothing to delete
+ EXPECT_EQ(DRV_ERR, HMX_NVRAM_Remove(part, name));
+
+ // Write to file and make sure its removed
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_Write(part, name, 0, val, valLen));
+
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_Remove(part, name));
+ EXPECT_EQ(0, dlist_size(part));
+ // Remove operation doesn't 0 entire partition, only needs to clear start byte
+ // If LoadbyAddr doesn't add anything to dlist, partition effectively empty
+ int size;
+ if (part == HMX_NVRAM_PARTITION_RO) {
+ size = NVRAM_RO_SIZE;
+ } else {
+ size = NVRAM_RW_SIZE;
+ }
+ EXPECT_EQ(DRV_OK, drv_NVRAM_LoadByAddress(part, offset, size));
+ EXPECT_EQ(0, dlist_size(part));
+}
+
+INSTANTIATE_TEST_CASE_P(TryBothFields, HnvramFieldTest,
+ ::testing::ValuesIn(field_tuples));
+
+INSTANTIATE_TEST_CASE_P(TryAllPartitions, HnvramVariableTest,
+ ::testing::ValuesIn(var_tuples));
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::AddGlobalTestEnvironment(new HnvramEnvironment);
+ return RUN_ALL_TESTS();
+}