From 79897c6655433cca7b78c25677e82b8a9be0a7b3 Mon Sep 17 00:00:00 2001 From: Aaron Germuth Date: Wed, 5 Oct 2016 17:07:51 -0700 Subject: [PATCH] hnvram: Added option to choose target file + tests $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 --- hnvram/Makefile | 14 +- hnvram/hnvram_integration_test.cc | 205 ++++++++++++++++++++++++++++++ hnvram/hnvram_main.c | 41 +++--- hnvram/hnvram_test.cc | 2 +- 4 files changed, 240 insertions(+), 22 deletions(-) create mode 100644 hnvram/hnvram_integration_test.cc diff --git a/hnvram/Makefile b/hnvram/Makefile index 2790f4d..badf27a 100644 --- a/hnvram/Makefile +++ b/hnvram/Makefile @@ -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 @@ -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 @@ -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 diff --git a/hnvram/hnvram_integration_test.cc b/hnvram/hnvram_integration_test.cc new file mode 100644 index 0000000..b7ceda1 --- /dev/null +++ b/hnvram/hnvram_integration_test.cc @@ -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 +#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 { + 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(); +} diff --git a/hnvram/hnvram_main.c b/hnvram/hnvram_main.c index a406caa..4ba0cde 100644 --- a/hnvram/hnvram_main.c +++ b/hnvram/hnvram_main.c @@ -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 @@ -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, @@ -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); @@ -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]; @@ -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; } @@ -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); } @@ -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); } diff --git a/hnvram/hnvram_test.cc b/hnvram/hnvram_test.cc index 643a436..dbc05a1 100644 --- a/hnvram/hnvram_test.cc +++ b/hnvram/hnvram_test.cc @@ -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; }