2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-03 15:35:17 +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:
Thomas Markwalder
2015-11-03 10:03:26 -05:00
parent d85076b046
commit 72a9ea19e2
4 changed files with 155 additions and 15 deletions

View File

@@ -404,7 +404,7 @@ public:
/// Otherwise, this function will write the header to the file. /// Otherwise, this function will write the header to the file.
/// In order to write rows to opened file, the @c append function /// In order to write rows to opened file, the @c append function
/// should be called. /// should be called.
void recreate(); virtual void recreate();
/// @brief Sets error message after row validation. /// @brief Sets error message after row validation.
/// ///

View File

@@ -153,6 +153,22 @@ TEST_F(VersionedCSVFileTest, addColumn) {
ASSERT_NO_THROW(csv->recreate()); ASSERT_NO_THROW(csv->recreate());
ASSERT_TRUE(exists()); 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. // Make sure we can't add columns (even unique) when the file is open.
ASSERT_THROW(csv->addColumn("zoo", "3.0", ""), CSVFileError); 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. // Header should pass validation and allow the open to succeed.
ASSERT_NO_THROW(csv->open()); 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. // First row is correct.
CSVRow row; CSVRow row;
ASSERT_TRUE(csv->next(row)); ASSERT_TRUE(csv->next(row));
@@ -223,7 +255,22 @@ TEST_F(VersionedCSVFileTest, upgradeOlderVersions) {
// Header should pass validation and allow the open to succeed // Header should pass validation and allow the open to succeed
ASSERT_NO_THROW(csv->open()); 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. // First row is correct.
ASSERT_TRUE(csv->next(row)); ASSERT_TRUE(csv->next(row));
@@ -243,15 +290,8 @@ TEST_F(VersionedCSVFileTest, upgradeOlderVersions) {
EXPECT_EQ("blue", row.readAt(1)); EXPECT_EQ("blue", row.readAt(1));
EXPECT_EQ("21", row.readAt(2)); EXPECT_EQ("21", row.readAt(2));
ASSERT_EQ(3, csv->getColumnCount());
// Fourth row is correct. // Fourth row is correct.
if (!csv->next(row)) { ASSERT_TRUE(csv->next(row));
std::cout << "row error is : " <<
csv->getReadMsg() << std::endl;
}
EXPECT_EQ("bird", row.readAt(0)); EXPECT_EQ("bird", row.readAt(0));
EXPECT_EQ("yellow", row.readAt(1)); EXPECT_EQ("yellow", row.readAt(1));
EXPECT_EQ("21", row.readAt(2)); EXPECT_EQ("21", row.readAt(2));

View File

@@ -46,23 +46,77 @@ VersionedCSVFile::setMinimumValidColumns(const std::string& column_name) {
} }
size_t size_t
VersionedCSVFile::getMinimumValidColumns() { VersionedCSVFile::getMinimumValidColumns() const {
return (minimum_valid_columns_); return (minimum_valid_columns_);
} }
size_t
VersionedCSVFile::getValidColumnCount() const {
return (valid_column_count_);
}
void void
VersionedCSVFile::open(const bool seek_to_end) { VersionedCSVFile::open(const bool seek_to_end) {
if (getColumnCount() == 0) { if (getColumnCount() == 0) {
isc_throw(VersionedCSVFileError, isc_throw(VersionedCSVFileError,
"no schema has been defined, cannot open file :" "no schema has been defined, cannot open CSV file :"
<< getFilename()); << getFilename());
} }
CSVFile::open(seek_to_end); 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 bool
VersionedCSVFile::next(CSVRow& row) { VersionedCSVFile::next(CSVRow& row) {
// Use base class to physicall read the row, but skip its row
// validation
CSVFile::next(row, true); CSVFile::next(row, true);
if (row == CSVFile::EMPTY_ROW()) { if (row == CSVFile::EMPTY_ROW()) {
return(true); return(true);
@@ -72,10 +126,10 @@ VersionedCSVFile::next(CSVRow& row) {
// defined column count. If not they're the equal. Either way // defined column count. If not they're the equal. Either way
// each data row must have valid_column_count_ values or its // each data row must have valid_column_count_ values or its
// an invalid row. // an invalid row.
if (row.getValuesCount() < valid_column_count_) { if (row.getValuesCount() < getValidColumnCount()) {
std::ostringstream s; std::ostringstream s;
s << "the size of the row '" << row << "' has too few valid columns " 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() << "'"; << getFilename() << "'";
setReadMsg(s.str()); setReadMsg(s.str());
return (false); return (false);

View File

@@ -153,7 +153,16 @@ public:
/// @brief Returns the minimum number of columns which must be present /// @brief Returns the minimum number of columns which must be present
/// for the file to be considered valid. /// 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. /// @brief Opens existing file or creates a new one.
/// ///
@@ -174,6 +183,17 @@ public:
/// CSVFileError when IO operation fails, or header fails to validate. /// CSVFileError when IO operation fails, or header fails to validate.
virtual void open(const bool seek_to_end = false); 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. /// @brief Reads next row from the file file.
/// ///
/// This function will return the @c CSVRow object representing a /// This function will return the @c CSVRow object representing a
@@ -197,6 +217,32 @@ public:
/// failed. /// failed.
bool next(CSVRow& row); 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: protected:
/// @brief Validates the header of a VersionedCSVFile /// @brief Validates the header of a VersionedCSVFile