mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[3601] Added methods to VersionedCSVFile for tracking when updating is needed
src/lib/util/csv_file.h Made recreate() virtual src/lib/util/versioned_csv_file.h src/lib/util/versioned_csv_file.cc Added several methods to VersionedCSVFile: getValidColumnCount() - returns number of valid columns in header recreate() - wraps base class method, ensuring valid column count gets set to number of defined columns for new files needsUpgrading() - returns bool true if file schema is out of date getInputSchemaVersion() - returns schema version found in file getSchemaVersion() - returns current schema version getVersionedColumn() - returns the column definition for a given index src/lib/util/tests/versioned_csv_file_unittest.cc Added checks for new methods to existing tests
This commit is contained in:
@@ -404,7 +404,7 @@ public:
|
||||
/// Otherwise, this function will write the header to the file.
|
||||
/// In order to write rows to opened file, the @c append function
|
||||
/// should be called.
|
||||
void recreate();
|
||||
virtual void recreate();
|
||||
|
||||
/// @brief Sets error message after row validation.
|
||||
///
|
||||
|
@@ -153,6 +153,22 @@ TEST_F(VersionedCSVFileTest, addColumn) {
|
||||
ASSERT_NO_THROW(csv->recreate());
|
||||
ASSERT_TRUE(exists());
|
||||
|
||||
// We should have 3 defined columns
|
||||
EXPECT_EQ(3, csv->getColumnCount());
|
||||
|
||||
// Number valid columns should match defined columns
|
||||
EXPECT_EQ(3, csv->getValidColumnCount());
|
||||
|
||||
// Minium valid columns wasn't set. (Remember it's optional)
|
||||
EXPECT_EQ(0, csv->getMinimumValidColumns());
|
||||
|
||||
// Upgrade flag should be false
|
||||
EXPECT_EQ(false, csv->needsUpgrading());
|
||||
|
||||
// Schema versions for new files should always match
|
||||
EXPECT_EQ("3.0", csv->getInputSchemaVersion());
|
||||
EXPECT_EQ("3.0", csv->getSchemaVersion());
|
||||
|
||||
// Make sure we can't add columns (even unique) when the file is open.
|
||||
ASSERT_THROW(csv->addColumn("zoo", "3.0", ""), CSVFileError);
|
||||
|
||||
@@ -182,6 +198,22 @@ TEST_F(VersionedCSVFileTest, upgradeOlderVersions) {
|
||||
// Header should pass validation and allow the open to succeed.
|
||||
ASSERT_NO_THROW(csv->open());
|
||||
|
||||
// We should have 2 defined columns
|
||||
EXPECT_EQ(2, csv->getColumnCount());
|
||||
|
||||
// We should have found 1 valid column in the header
|
||||
EXPECT_EQ(1, csv->getValidColumnCount());
|
||||
|
||||
// Minium valid columns wasn't set. (Remember it's optional)
|
||||
EXPECT_EQ(0, csv->getMinimumValidColumns());
|
||||
|
||||
// Upgrade flag should be true
|
||||
EXPECT_EQ(true, csv->needsUpgrading());
|
||||
|
||||
// Input schema should be 1.0, while our current schema should be 2.0
|
||||
EXPECT_EQ("1.0", csv->getInputSchemaVersion());
|
||||
EXPECT_EQ("2.0", csv->getSchemaVersion());
|
||||
|
||||
// First row is correct.
|
||||
CSVRow row;
|
||||
ASSERT_TRUE(csv->next(row));
|
||||
@@ -223,7 +255,22 @@ TEST_F(VersionedCSVFileTest, upgradeOlderVersions) {
|
||||
|
||||
// Header should pass validation and allow the open to succeed
|
||||
ASSERT_NO_THROW(csv->open());
|
||||
ASSERT_EQ(3, csv->getColumnCount());
|
||||
|
||||
// We should have 2 defined columns
|
||||
EXPECT_EQ(3, csv->getColumnCount());
|
||||
|
||||
// We should have found 1 valid column in the header
|
||||
EXPECT_EQ(1, csv->getValidColumnCount());
|
||||
|
||||
// Minium valid columns wasn't set. (Remember it's optional)
|
||||
EXPECT_EQ(0, csv->getMinimumValidColumns());
|
||||
|
||||
// Upgrade flag should be true
|
||||
EXPECT_EQ(true, csv->needsUpgrading());
|
||||
|
||||
// Make sure schema versions are accurate
|
||||
EXPECT_EQ("1.0", csv->getInputSchemaVersion());
|
||||
EXPECT_EQ("3.0", csv->getSchemaVersion());
|
||||
|
||||
// First row is correct.
|
||||
ASSERT_TRUE(csv->next(row));
|
||||
@@ -243,15 +290,8 @@ TEST_F(VersionedCSVFileTest, upgradeOlderVersions) {
|
||||
EXPECT_EQ("blue", row.readAt(1));
|
||||
EXPECT_EQ("21", row.readAt(2));
|
||||
|
||||
ASSERT_EQ(3, csv->getColumnCount());
|
||||
|
||||
// Fourth row is correct.
|
||||
if (!csv->next(row)) {
|
||||
std::cout << "row error is : " <<
|
||||
csv->getReadMsg() << std::endl;
|
||||
|
||||
}
|
||||
|
||||
ASSERT_TRUE(csv->next(row));
|
||||
EXPECT_EQ("bird", row.readAt(0));
|
||||
EXPECT_EQ("yellow", row.readAt(1));
|
||||
EXPECT_EQ("21", row.readAt(2));
|
||||
|
@@ -46,23 +46,77 @@ VersionedCSVFile::setMinimumValidColumns(const std::string& column_name) {
|
||||
}
|
||||
|
||||
size_t
|
||||
VersionedCSVFile::getMinimumValidColumns() {
|
||||
VersionedCSVFile::getMinimumValidColumns() const {
|
||||
return (minimum_valid_columns_);
|
||||
}
|
||||
|
||||
size_t
|
||||
VersionedCSVFile::getValidColumnCount() const {
|
||||
return (valid_column_count_);
|
||||
}
|
||||
|
||||
void
|
||||
VersionedCSVFile::open(const bool seek_to_end) {
|
||||
if (getColumnCount() == 0) {
|
||||
isc_throw(VersionedCSVFileError,
|
||||
"no schema has been defined, cannot open file :"
|
||||
"no schema has been defined, cannot open CSV file :"
|
||||
<< getFilename());
|
||||
}
|
||||
|
||||
CSVFile::open(seek_to_end);
|
||||
}
|
||||
|
||||
void
|
||||
VersionedCSVFile::recreate() {
|
||||
if (getColumnCount() == 0) {
|
||||
isc_throw(VersionedCSVFileError,
|
||||
"no schema has been defined, cannot create CSV file :"
|
||||
<< getFilename());
|
||||
}
|
||||
|
||||
CSVFile::recreate();
|
||||
// For new files they always match.
|
||||
valid_column_count_ = getColumnCount();
|
||||
}
|
||||
|
||||
bool
|
||||
VersionedCSVFile::needsUpgrading() const {
|
||||
return (getValidColumnCount() < getColumnCount());
|
||||
}
|
||||
|
||||
std::string
|
||||
VersionedCSVFile::getInputSchemaVersion() const {
|
||||
if (getValidColumnCount() > 0) {
|
||||
return (getVersionedColumn(getValidColumnCount() - 1)->version_);
|
||||
}
|
||||
|
||||
return ("undefined");
|
||||
}
|
||||
|
||||
std::string
|
||||
VersionedCSVFile::getSchemaVersion() const {
|
||||
if (getColumnCount() > 0) {
|
||||
return (getVersionedColumn(getColumnCount() - 1)->version_);
|
||||
}
|
||||
|
||||
return ("undefined");
|
||||
}
|
||||
|
||||
const VersionedColumnPtr&
|
||||
VersionedCSVFile::getVersionedColumn(const size_t index) const {
|
||||
if (index >= getColumnCount()) {
|
||||
isc_throw(isc::OutOfRange, "versioned column index " << index
|
||||
<< " out of range; CSV file : " << getFilename()
|
||||
<< " only has " << getColumnCount() << " columns ");
|
||||
}
|
||||
|
||||
return (columns_[index]);
|
||||
}
|
||||
|
||||
bool
|
||||
VersionedCSVFile::next(CSVRow& row) {
|
||||
// Use base class to physicall read the row, but skip its row
|
||||
// validation
|
||||
CSVFile::next(row, true);
|
||||
if (row == CSVFile::EMPTY_ROW()) {
|
||||
return(true);
|
||||
@@ -72,10 +126,10 @@ VersionedCSVFile::next(CSVRow& row) {
|
||||
// defined column count. If not they're the equal. Either way
|
||||
// each data row must have valid_column_count_ values or its
|
||||
// an invalid row.
|
||||
if (row.getValuesCount() < valid_column_count_) {
|
||||
if (row.getValuesCount() < getValidColumnCount()) {
|
||||
std::ostringstream s;
|
||||
s << "the size of the row '" << row << "' has too few valid columns "
|
||||
<< valid_column_count_ << "' of the CSV file '"
|
||||
<< getValidColumnCount() << "' of the CSV file '"
|
||||
<< getFilename() << "'";
|
||||
setReadMsg(s.str());
|
||||
return (false);
|
||||
|
@@ -153,7 +153,16 @@ public:
|
||||
|
||||
/// @brief Returns the minimum number of columns which must be present
|
||||
/// for the file to be considered valid.
|
||||
size_t getMinimumValidColumns();
|
||||
size_t getMinimumValidColumns() const;
|
||||
|
||||
/// @brief Returns the number of valid columns found in the header
|
||||
/// For newly created files this will always match the number of defined
|
||||
/// columns (i.e. getColumnCount()). For existing files, this will be
|
||||
/// the number of columns in the header that match the defined columnns.
|
||||
/// When this number is less than getColumnCount() it means the input file
|
||||
/// is from an earlier schema. This value is zero until the file has
|
||||
/// been opened.
|
||||
size_t getValidColumnCount() const;
|
||||
|
||||
/// @brief Opens existing file or creates a new one.
|
||||
///
|
||||
@@ -174,6 +183,17 @@ public:
|
||||
/// CSVFileError when IO operation fails, or header fails to validate.
|
||||
virtual void open(const bool seek_to_end = false);
|
||||
|
||||
/// @brief Creates a new CSV file.
|
||||
///
|
||||
/// The file creation will fail if there are no columns specified.
|
||||
/// Otherwise, this function will write the header to the file.
|
||||
/// In order to write rows to opened file, the @c append function
|
||||
/// should be called.
|
||||
///
|
||||
/// @throw VersionedCSVFileError if schema has not been defined
|
||||
/// CSVFileError if an IO operation fails
|
||||
virtual void recreate();
|
||||
|
||||
/// @brief Reads next row from the file file.
|
||||
///
|
||||
/// This function will return the @c CSVRow object representing a
|
||||
@@ -197,6 +217,32 @@ public:
|
||||
/// failed.
|
||||
bool next(CSVRow& row);
|
||||
|
||||
/// @brief Returns the schema version of the physical file
|
||||
///
|
||||
/// @return text version of the schema found or string "undefined" if the
|
||||
/// file has not been opened
|
||||
std::string getInputSchemaVersion() const;
|
||||
|
||||
/// @brief text version of current schema supported by the file's metadata
|
||||
///
|
||||
/// @return text version info assigned to the last column in the list of
|
||||
/// defined column, or the string "undefined" if no columns have been
|
||||
/// defined.
|
||||
std::string getSchemaVersion() const;
|
||||
|
||||
/// @brief Fetch the column descriptor for a given index
|
||||
///
|
||||
/// @param index index within the list of columns of the desired column
|
||||
/// @return a pointer to the VersionedColumn at the given index
|
||||
/// @trow OutOfRange exception if the index is invalid
|
||||
const VersionedColumnPtr& getVersionedColumn(const size_t index) const;
|
||||
|
||||
/// @brief Returns true if the opened file is needs to be upgraded
|
||||
///
|
||||
/// @return true if the file's valid column count is greater than 0 and
|
||||
/// is less than the defined number of columns
|
||||
bool needsUpgrading() const;
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Validates the header of a VersionedCSVFile
|
||||
|
Reference in New Issue
Block a user