Skip to content

Commit

Permalink
hnvram: Added option to choose target file + tests
Browse files Browse the repository at this point in the history
$HNVRAM_LOCATION envvar can now be used to to read/write from a file
instead of a flash device.

Changed some variable declarations to compile on x86 and allow
end-to-end testing on x86.

Depends on go/fibercl/80569

In reference to b/31822982

Change-Id: I1f41cc9c8351b13d240dbc1fe9d91ceed3bced11
  • Loading branch information
germuth committed Oct 27, 2016
1 parent 7f8220b commit 79897c6
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 22 deletions.
14 changes: 9 additions & 5 deletions hnvram/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ PREFIX=/usr
BINDIR=$(DESTDIR)$(PREFIX)/bin

HUMAX_UPGRADE_DIR ?= ../../../humax/misc/libupgrade
CFLAGS += -g -Os -I$(HUMAX_UPGRADE_DIR) $(EXTRACFLAGS)
CFLAGS += -g -Os -I$(HUMAX_UPGRADE_DIR) -I$(HUMAX_UPGRADE_DIR)/test $(EXTRACFLAGS)
LDFLAGS += -L$(HUMAX_UPGRADE_DIR) $(EXTRALDFLAGS)

all: hnvram
Expand All @@ -22,12 +22,16 @@ hnvram: $(SRCS) $(INCS)
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) -lhmxupgrade

unit_test: test
test: hnvram_test
./hnvram_test
test: clean hnvram_unit_test hnvram_integration_test
./hnvram_unit_test
./hnvram_integration_test

hnvram_test: hnvram_test.cc hnvram_main.c $(INCS)
hnvram_unit_test: hnvram_test.cc hnvram_main.c $(INCS)
$(CPP) $(CFLAGS) hnvram_test.cc -o $@ $(LDFLAGS) -lgtest -lpthread

hnvram_integration_test: hnvram_integration_test.cc
$(CPP) $(CFLAGS) hnvram_integration_test.cc -o $@ $(LDFLAGS) -lgtest -lpthread

install:
mkdir -p $(BINDIR)
cp hnvram $(BINDIR)/hnvram_binary
Expand All @@ -36,4 +40,4 @@ install-libs:
@echo "No libs to install."

clean:
rm -f hnvram hnvram_test *.o
rm -f hnvram hnvram_unit_test hnvram_integration_test *.o
205 changes: 205 additions & 0 deletions hnvram/hnvram_integration_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// Copyright 2016 Google Inc. All Rights Reserved.
// Author: germuth@google.com (Aaron Germuth)

// Tests external methods of hnvram_main end-to-end. No stubbing of lower-level
// methods (Black box testing)

#include <stdio.h>
#include "gtest/gtest.h"
#include "hmx_upgrade_nvram.h"

#define TEST_MAIN
#include "hnvram_main.c"
#include "hmx_test_base.cc"
#include "hmx_upgrade_nvram.c"
#include "hmx_upgrade_flash.c"

// Test constants
const char* name = "NEW_VAR";
const char* val = "ABCDEF";
const char* val2 = "ZZZZZZZZZ";
const int valLen = 6;
const int valLen2 = 9;

const char* fieldName = "MAC_ADDR_BT";
const char* fieldVal = "\x01\x02\x03\x04\x05\x06";
const char* fieldValStr = "01:02:03:04:05:06";
const char* fieldVal2 = "12:34:56:78:0a:bc";
const int fieldValLen = 6;

// Test parameters
const HMX_NVRAM_PARTITION_E partitions[] =
{HMX_NVRAM_PARTITION_RO, HMX_NVRAM_PARTITION_RW};
HMX_NVRAM_PARTITION_E part;

class HnvramIntegrationTest : public HnvramTest,
public ::testing::WithParamInterface<HMX_NVRAM_PARTITION_E> {
public:
HnvramIntegrationTest() {}
virtual ~HnvramIntegrationTest() {}

virtual void SetUp() {
part = GetParam();

libupgrade_verbose = 0;
can_add_flag = 0;

HnvramTest::SetUp();

HMX_NVRAM_Init(hnvramFileName);
}

virtual void TearDown() {
part = HMX_NVRAM_PARTITION_UNSPECIFIED;

// clear dlists
drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RO, (unsigned char*)fieldName);
drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RW, (unsigned char*)name);
drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RO, (unsigned char*)name);

HnvramTest::TearDown();
}
};

TEST_P(HnvramIntegrationTest, TestWriteNvramNew) {
// Should fail without can_add
EXPECT_EQ(-1, write_nvram_new(name, val, part));

// Should fail to parse
can_add_flag = 1;
char valLarge[NVRAM_MAX_DATA + 1];
memset(valLarge, 1, sizeof(valLarge));
EXPECT_EQ(-2, write_nvram_new(name, valLarge, part));

// Should fail cleanly with bad partition
HMX_NVRAM_Init("/tmp/");
EXPECT_EQ(-3, write_nvram_new(name, val, part));

// Read back writes
HMX_NVRAM_Init(hnvramFileName);
unsigned char read[255];
unsigned int readLen = 0;
EXPECT_EQ(0, write_nvram_new(name, val, part));
EXPECT_EQ(DRV_OK,
HMX_NVRAM_Read(part, (unsigned char*)name, 0,
read, sizeof(read), &readLen));
EXPECT_EQ(0, memcmp(val, read, valLen));
EXPECT_EQ(valLen, readLen);
}

TEST_P(HnvramIntegrationTest, TestWriteNvram) {
// Should fail with large val
char valLarge[NVRAM_MAX_DATA + 1];
memset(valLarge, 1, sizeof(valLarge));
EXPECT_EQ(-1, write_nvram(name, valLarge, part));

// Failure to parse
EXPECT_EQ(-2, write_nvram(fieldName, "not-proper-mac-addr", part));

// Variable doesn't already exist
EXPECT_EQ(-3, write_nvram(name, val, part));

// Variable exists in wrong partition
can_add_flag = 1;
EXPECT_EQ(0, write_nvram_new(name, val, part));
EXPECT_EQ(-4, write_nvram(name, val, HMX_NVRAM_PARTITION_W_RAWFS));

// Fail cleanly from lower-level write
HMX_NVRAM_Init("/tmp/");
EXPECT_EQ(-5, write_nvram(name, val, part));
HMX_NVRAM_Init(hnvramFileName);

// Try to specify partition with a field variable
EXPECT_EQ(0, write_nvram_new(fieldName, fieldVal, part));
HMX_NVRAM_Init(hnvramFileName);
EXPECT_EQ(-6, write_nvram(fieldName, fieldVal2, part));

// Failure from lower-level write w/field
HMX_NVRAM_Init("/tmp/");
char out[255];
EXPECT_EQ(-7, write_nvram(fieldName, fieldValStr,
HMX_NVRAM_PARTITION_UNSPECIFIED));
HMX_NVRAM_Init(hnvramFileName);

// Read back val after changing val
EXPECT_EQ(0, write_nvram(name, val2, part));
unsigned char read[255];
unsigned int readLen = 0;
EXPECT_EQ(DRV_OK, HMX_NVRAM_Read(part, (unsigned char*)name, 0,
read, sizeof(read), &readLen));
EXPECT_EQ(0, memcmp(read, val2, readLen));
EXPECT_EQ(readLen, valLen2);
}

TEST_P(HnvramIntegrationTest, TestClearNvram) {
// Delete non-existing variable
HMX_NVRAM_Init(hnvramFileName);
EXPECT_EQ(DRV_OK, clear_nvram(name));

can_add_flag = 1;
EXPECT_EQ(0, write_nvram_new(name, val, part));

// No hnvram partition
HMX_NVRAM_Init("/tmp/");
EXPECT_EQ(DRV_ERR, clear_nvram(name));

// Delete Existing
HMX_NVRAM_Init(hnvramFileName);
EXPECT_EQ(DRV_OK, clear_nvram(name));
}

TEST_P(HnvramIntegrationTest, TestReadNvram) {
char readR[255];
memset(readR, 56, 30);
HMX_NVRAM_PARTITION_E part_used;
EXPECT_TRUE(NULL == read_nvram(fieldName, readR, sizeof(readR), 0, &part_used));

// No variable to find
EXPECT_EQ(NULL, read_nvram(name, readR, sizeof(readR), 0, &part_used));

// Find field
can_add_flag = 1;
EXPECT_EQ(0, write_nvram_new(fieldName, fieldVal, HMX_NVRAM_PARTITION_RO));
EXPECT_FALSE(NULL == read_nvram(fieldName, readR, sizeof(readR), 1, &part_used));
EXPECT_EQ(0, memcmp(readR, fieldValStr, 18));
EXPECT_EQ(part_used, HMX_NVRAM_PARTITION_RO);

// Find variable
EXPECT_EQ(0, write_nvram_new(name, val, part));
EXPECT_FALSE(NULL == read_nvram(name, readR, sizeof(readR), 1, &part_used));
EXPECT_EQ(0, memcmp(readR, val, valLen));
EXPECT_EQ(part_used, part);
}

TEST_P(HnvramIntegrationTest, TestInitNvram) {
char readR[255];
HMX_NVRAM_PARTITION_E part_used;

// Set envvar to bad file
EXPECT_EQ(0, setenv("HNVRAM_LOCATION", "/tmp/", 1));
EXPECT_EQ(DRV_OK, init_nvram());

// Should fail to read
EXPECT_TRUE(NULL == read_nvram(name, readR, sizeof(readR), 1, &part_used));

// Set envvar to proper, empty file
EXPECT_EQ(0, setenv("HNVRAM_LOCATION", hnvramFileName, 1));
EXPECT_EQ(DRV_OK, init_nvram());

// Write and read it back
can_add_flag = 1;
EXPECT_EQ(0, write_nvram_new(name, val, part));

EXPECT_FALSE(NULL == read_nvram(name, readR, sizeof(readR), 1, &part_used));
EXPECT_EQ(0, memcmp(readR, val, valLen));
EXPECT_EQ(part_used, part);
}

INSTANTIATE_TEST_CASE_P(TryAllPartitions, HnvramIntegrationTest,
::testing::ValuesIn(partitions));

int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::AddGlobalTestEnvironment(new HnvramEnvironment);
return RUN_ALL_TESTS();
}
41 changes: 25 additions & 16 deletions hnvram/hnvram_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ void usage(const char* progname) {
printf("\t-n : toggles whether -w can create new variables. Default is off\n");
printf("\t-p [RW|RO] : toggles what partition new writes (-n) used. Default is RW\n");
printf("\t-k VARNAME : delete existing key/value pair from NVRAM.\n");
printf("\t Set environment variable: $HNVRAM_LOCATION to change where read/writes are performed.");
printf("\t By default hnvram uses '/dev/mtd/hnvram'\n");
}

// Format of data in the NVRAM
Expand Down Expand Up @@ -369,7 +371,7 @@ unsigned char* parse_nvram(hnvram_format_e format, const char* input,
return NULL;
}

DRV_Error clear_nvram(char* optarg) {
DRV_Error clear_nvram(const char* optarg) {
DRV_Error err1 = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RW,
(unsigned char*)optarg);
DRV_Error err2 = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RO,
Expand All @@ -387,7 +389,8 @@ DRV_Error clear_nvram(char* optarg) {
}


int write_nvram(char* name, char* value, HMX_NVRAM_PARTITION_E desired_part) {
int write_nvram(const char* name, const char* value,
HMX_NVRAM_PARTITION_E desired_part) {
const hnvram_field_t* field = get_nvram_field(name);
int is_field = (field != NULL);

Expand All @@ -400,8 +403,8 @@ int write_nvram(char* name, char* value, HMX_NVRAM_PARTITION_E desired_part) {

if (strlen(value) > NVRAM_MAX_DATA) {
fprintf(stderr, "Value length %d exceeds maximum data size of %d\n",
strlen(value), NVRAM_MAX_DATA);
return -2;
(int)strlen(value), NVRAM_MAX_DATA);
return -1;
}

unsigned char nvram_value[NVRAM_MAX_DATA];
Expand Down Expand Up @@ -444,18 +447,18 @@ int write_nvram(char* name, char* value, HMX_NVRAM_PARTITION_E desired_part) {
}

// Adds new variable to HNVRAM in desired_partition as STRING
int write_nvram_new(char* name, char* value,
int write_nvram_new(const char* name, const char* value,
HMX_NVRAM_PARTITION_E desired_part) {
if (!can_add_flag) {
fprintf(stderr, "Key not found in NVRAM. Add -n to allow creation %s\n",
name);
return -1;
}

char tmp[NVRAM_MAX_DATA] = {0};
unsigned char nvram_value[NVRAM_MAX_DATA];
unsigned int nvram_len = sizeof(nvram_value);
if (parse_nvram(HNVRAM_STRING, value, nvram_value, &nvram_len) == NULL) {
return -1;
}

if (!can_add_flag) {
fprintf(stderr, "Key not found in NVRAM. Add -n to allow creation %s\n",
name);
return -2;
}

Expand All @@ -472,13 +475,19 @@ int write_nvram_new(char* name, char* value,
return 0;
}

int init_nvram() {
const char* location = secure_getenv("HNVRAM_LOCATION");
return (int)HMX_NVRAM_Init(location);
}

int hnvram_main(int argc, char* const argv[]) {
DRV_Error err;

libupgrade_verbose = 0;

if ((err = HMX_NVRAM_Init()) != DRV_OK) {
fprintf(stderr, "NVRAM Init failed: %d\n", err);
int ret = init_nvram();
if (ret != 0) {
fprintf(stderr, "NVRAM Init failed: %d\n", ret);
exit(1);
}

Expand Down Expand Up @@ -524,13 +533,13 @@ int hnvram_main(int argc, char* const argv[]) {
char* value = equal + 1;

int ret = write_nvram(name, value, desired_part);
if (ret == -3 && can_add_flag) {
// key not found, and we are authorized to add a new one
if (ret == -3) {
// key not found, try to add a new one
ret = write_nvram_new(name, value, desired_part);
}

if (ret != 0) {
fprintf(stderr, "Unable to write %s\n", duparg);
fprintf(stderr, "Err %d: Unable to write %s\n", ret, duparg);
free(duparg);
exit(1);
}
Expand Down
2 changes: 1 addition & 1 deletion hnvram/hnvram_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ DRV_Error HMX_NVRAM_SetField(NVRAM_FIELD_T field, unsigned int offset,
return HMX_NVRAM_SetField_Return;
}

DRV_Error HMX_NVRAM_Init(void) {
DRV_Error HMX_NVRAM_Init(const char* target_mtd) {
return DRV_OK;
}

Expand Down

0 comments on commit 79897c6

Please sign in to comment.