use of com.axway.ats.action.dbaccess.snapshot.rules.SkipContent in project ats-framework by Axway.
the class DatabaseSnapshot method compare.
/**
* Compare both snapshots and throw error if unexpected differences are found.
* Snapshots are compared table by table.
* In the usual case the tables are loaded from database prior to comparing.
* But if a snapshot was saved into a file, then its tables are loaded from the file, not from the database.
*
* @param that the snapshot to compare to
* @param compareOptions - (optional) additional options that change the comparison. by default is null, so the compare is as-is (e.g. if there is an error, the comparison fails)
* @throws DatabaseSnapshotException
*/
@PublicAtsApi
public void compare(DatabaseSnapshot that, CompareOptions compareOptions) throws DatabaseSnapshotException {
try {
if (that == null) {
throw new DatabaseSnapshotException("Snapshot to compare is null");
}
if (this.name.equals(that.name)) {
throw new DatabaseSnapshotException("You are trying to compare snapshots with same name: " + this.name);
}
if (this.metadataTimestamp == -1) {
throw new DatabaseSnapshotException("You are trying to compare snapshots but [" + this.name + "] snapshot is still not created");
}
if (that.metadataTimestamp == -1) {
throw new DatabaseSnapshotException("You are trying to compare snapshots but [" + that.name + "] snapshot is still not created");
}
if (log.isDebugEnabled()) {
log.debug("Comparing snapshots [" + this.name + "] taken on " + DatabaseSnapshotUtils.dateToString(this.metadataTimestamp) + " and [" + that.name + "] taken on " + DatabaseSnapshotUtils.dateToString(that.metadataTimestamp));
}
this.equality = new DatabaseEqualityState(this.name, that.name);
// make copies of the table info, as we will remove from these lists,
// but we do not want to remove from the original table info lists
List<TableDescription> thisTables = new ArrayList<TableDescription>(this.tables);
List<TableDescription> thatTables = new ArrayList<TableDescription>(that.tables);
// Merge all skip rules from both snapshot instances,
// so it is not needed to add same skip rules in both snapshot instances.
// merge all columns to be skipped(per table)
Map<String, SkipColumns> skipColumns = mergeSkipColumns(that.skipColumnsPerTable);
// merge all content to be skipper(per table)
Map<String, SkipContent> skipContent = mergeSkipContent(that.skipContentPerTable);
// merge all rows to be skipped(per table)
Map<String, SkipRows> skipRows = mergeSkipRows(that.skipRowsPerTable);
Set<String> tablesToSkip = getAllTablesToSkip(skipColumns);
// We can use just one index name matcher
IndexMatcher actualIndexNameMatcher = mergeIndexMatchers(that.indexMatcher);
compareTables(this.name, thisTables, that.name, thatTables, that.dbProvider, tablesToSkip, skipColumns, skipContent, skipRows, actualIndexNameMatcher, that.backupXmlFile, equality);
if (compareOptions != null) {
try {
// handle expected differences
handleExpectedMissingRows(compareOptions, equality);
} catch (Exception e) {
log.error("Error occured while handling missing rows", e);
}
}
if (equality.hasDifferences()) {
// there are some unexpected differences
throw new DatabaseSnapshotException(equality);
} else {
log.info("Successful verification");
}
} finally {
// close the database connections
disconnect(this.dbProvider, "after comparing database snapshots");
disconnect(that.dbProvider, "after comparing database snapshots");
}
}
use of com.axway.ats.action.dbaccess.snapshot.rules.SkipContent in project ats-framework by Axway.
the class DatabaseSnapshot method mergeSkipContent.
/**
* Merge skip table content rules from both snapshots into a single list.
*
* @param thatSkipContentPerTable list with table names
* @return
*/
private Map<String, SkipContent> mergeSkipContent(Map<String, SkipContent> thatSkipContentPerTable) {
// we will return a new instance containing all rules
Map<String, SkipContent> allSkipContentPerTable = new HashMap<>();
// first add all rules for this instance
for (String table : this.skipContentPerTable.keySet()) {
allSkipContentPerTable.put(table, this.skipContentPerTable.get(table));
}
// then add all rules for the other instance
for (String table : thatSkipContentPerTable.keySet()) {
SkipContent allSkipContent = allSkipContentPerTable.get(table);
SkipContent thatSkipContent = thatSkipContentPerTable.get(table);
if (allSkipContent != null) {
// there is already a rule for this table
// we have to merge both rules
allSkipContent.setRememberNumberOfRows(thatSkipContent.isRememberNumberOfRows());
} else {
// no current rule for this table, now we add one
allSkipContentPerTable.put(table, thatSkipContent);
}
}
return allSkipContentPerTable;
}
use of com.axway.ats.action.dbaccess.snapshot.rules.SkipContent in project ats-framework by Axway.
the class DatabaseSnapshot method compareTables.
/**
* Compares all tables between two snapshots
*
* @param thisSnapshotName
* @param thisTables
* @param thatSnapshotName
* @param thatTables
* @param thatDbProvider
* @param tablesToSkip
* @param skipColumns
* @param skipContent
* @param skipRows
* @param indexNameMatcher
* @param thatBackupXmlFile
* @param equality
*/
private void compareTables(String thisSnapshotName, List<TableDescription> thisTables, String thatSnapshotName, List<TableDescription> thatTables, DbProvider thatDbProvider, Set<String> tablesToSkip, Map<String, SkipColumns> skipColumns, Map<String, SkipContent> skipContent, Map<String, SkipRows> skipRows, IndexMatcher indexNameMatcher, Document thatBackupXmlFile, DatabaseEqualityState equality) {
// make a list of tables present in both snapshots
List<String> commonTables = getCommonTables(thisSnapshotName, thisTables, thatSnapshotName, thatTables, tablesToSkip);
for (String tableName : commonTables) {
// get tables to compare
TableDescription thisTable = null;
TableDescription thatTable = null;
for (TableDescription table : thisTables) {
if (table.getName().equalsIgnoreCase(tableName)) {
thisTable = table;
break;
}
}
for (TableDescription table : thatTables) {
if (table.getName().equalsIgnoreCase(tableName)) {
thatTable = table;
break;
}
}
SkipColumns skipColumnsPerTable = skipColumns.get(thisTable.getName());
if (skipColumnsPerTable != null && skipColumnsPerTable.isSkipWholeTable()) {
// if table is not of interest - skip it
continue;
}
List<String> thisValuesList = null;
List<String> thatValuesList = null;
int thisNumberOfRows = -1;
int thatNumberOfRows = -1;
SkipContent skipContentForThisTable = skipContent.get(tableName.toLowerCase());
if (skipContentForThisTable != null) {
if (skipContentForThisTable.isRememberNumberOfRows()) {
// we do not compare the content of the tables,
// but we still compare the number of rows
thisNumberOfRows = loadTableLength(thisSnapshotName, thisTable, this.dbProvider, this.backupXmlFile);
thatNumberOfRows = loadTableLength(thatSnapshotName, thatTable, thatDbProvider, thatBackupXmlFile);
}
// else -> we completely do not compare the content of the tables
} else {
// we want to compare the content of the tables,
// so load the table content
thisValuesList = loadTableData(thisSnapshotName, thisTable, skipColumns, skipRows, this.dbProvider, this.backupXmlFile);
thatValuesList = loadTableData(thatSnapshotName, thatTable, skipColumns, skipRows, thatDbProvider, thatBackupXmlFile);
}
// do the actual comparison
thisTable.compare(thatTable, thisValuesList, thatValuesList, thisNumberOfRows, thatNumberOfRows, indexNameMatcher, equality);
}
thisTables.clear();
}
use of com.axway.ats.action.dbaccess.snapshot.rules.SkipContent in project ats-framework by Axway.
the class DatabaseSnapshotBackupUtils method loadFromFile.
/**
* Load a snapshot from a file
*
* @param newSnapshotName the name of the new snapshot
* @param snapshot the snapshot instance to fill with new data
* @param sourceFile the backup file name
* @return the XML document
*/
public Document loadFromFile(String newSnapshotName, DatabaseSnapshot snapshot, String sourceFile) {
log.info("Load database snapshot from file " + sourceFile + " - START");
// first clean up the current instance, in case some snapshot was taken before
snapshot.tables.clear();
Document doc;
try {
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(sourceFile));
doc.getDocumentElement().normalize();
} catch (Exception e) {
throw new DatabaseSnapshotException("Error reading database snapshot backup file " + sourceFile, e);
}
Element databaseNode = doc.getDocumentElement();
if (!DatabaseSnapshotUtils.NODE_DB_SNAPSHOT.equals(databaseNode.getNodeName())) {
throw new DatabaseSnapshotException("Bad backup file. Root node name is expeced to be '" + DatabaseSnapshotUtils.NODE_DB_SNAPSHOT + "', but it is '" + databaseNode.getNodeName() + "'");
}
if (StringUtils.isNullOrEmpty(newSnapshotName)) {
snapshot.name = databaseNode.getAttribute(DatabaseSnapshotUtils.ATTR_SNAPSHOT_NAME);
} else {
// user wants to change the snapshot name
snapshot.name = newSnapshotName;
}
// the timestamps
snapshot.metadataTimestamp = DatabaseSnapshotUtils.stringToDate(databaseNode.getAttribute(DatabaseSnapshotUtils.ATTR_METADATA_TIME));
snapshot.contentTimestamp = DatabaseSnapshotUtils.stringToDate(databaseNode.getAttribute(DatabaseSnapshotUtils.ATTR_CONTENT_TIME));
// the tables
List<Element> tableNodes = DatabaseSnapshotUtils.getChildrenByTagName(databaseNode, DatabaseSnapshotUtils.NODE_TABLE);
for (Element tableNode : tableNodes) {
snapshot.tables.add(TableDescription.fromXmlNode(snapshot.name, tableNode));
}
// any skip table content rules
snapshot.skipContentPerTable.clear();
List<Element> skipContentNodes = DatabaseSnapshotUtils.getChildrenByTagName(databaseNode, DatabaseSnapshotUtils.NODE_SKIP_CONTENT);
for (Element skipContentNode : skipContentNodes) {
SkipContent skipContent = SkipContent.fromXmlNode(skipContentNode);
snapshot.skipContentPerTable.put(skipContent.getTable().toLowerCase(), skipContent);
}
// any skip table column rules
snapshot.skipColumnsPerTable.clear();
List<Element> skipColumnNodes = DatabaseSnapshotUtils.getChildrenByTagName(databaseNode, DatabaseSnapshotUtils.NODE_SKIP_COLUMNS);
for (Element skipColumnNode : skipColumnNodes) {
SkipColumns skipColumns = SkipColumns.fromXmlNode(skipColumnNode);
snapshot.skipColumnsPerTable.put(skipColumns.getTable().toLowerCase(), skipColumns);
}
// any skip index attribute rules
snapshot.skipIndexAttributesPerTable.clear();
List<Element> skipIndexAttributesNodes = DatabaseSnapshotUtils.getChildrenByTagName(databaseNode, DatabaseSnapshotUtils.NODE_SKIP_INDEX_ATTRIBUTES);
for (Element skipIndexAttributesNode : skipIndexAttributesNodes) {
SkipIndexAttributes skipIndexAttributes = SkipIndexAttributes.fromXmlNode(skipIndexAttributesNode);
snapshot.skipIndexAttributesPerTable.put(skipIndexAttributes.getTable().toLowerCase(), skipIndexAttributes);
}
// any skip table row rules
snapshot.skipRowsPerTable.clear();
List<Element> skipRowNodes = DatabaseSnapshotUtils.getChildrenByTagName(databaseNode, DatabaseSnapshotUtils.NODE_SKIP_ROWS);
for (Element skipRowNode : skipRowNodes) {
SkipRows skipRows = SkipRows.fromXmlNode(skipRowNode);
snapshot.skipRowsPerTable.put(skipRows.getTable().toLowerCase(), skipRows);
}
log.info("Load database snapshot from file " + sourceFile + " - END");
return doc;
}
use of com.axway.ats.action.dbaccess.snapshot.rules.SkipContent in project ats-framework by Axway.
the class DatabaseSnapshotBackupUtils method saveToFile.
/**
* Save a snapshot into a file
* @param snapshot the snapshot to save
* @param backupFile the backup file name
* @return the XML document
*/
public Document saveToFile(DatabaseSnapshot snapshot, String backupFile) {
log.info("Save database snapshot into file " + backupFile + " - START");
// create the directory if does not exist
File dirPath = new File(IoUtils.getFilePath(backupFile));
if (!dirPath.exists()) {
dirPath.mkdirs();
}
Document doc;
try {
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
} catch (Exception e) {
throw new DatabaseSnapshotException("Error creating DOM parser for " + backupFile, e);
}
// TODO - add DTD or schema for manual creation and easy validation
Element dbNode = doc.createElement(DatabaseSnapshotUtils.NODE_DB_SNAPSHOT);
dbNode.setAttribute(DatabaseSnapshotUtils.ATTR_SNAPSHOT_NAME, snapshot.name);
// the timestamp comes when user takes a snapshot from database
dbNode.setAttribute(DatabaseSnapshotUtils.ATTR_METADATA_TIME, DatabaseSnapshotUtils.dateToString(snapshot.metadataTimestamp));
// the timestamp now
snapshot.contentTimestamp = System.currentTimeMillis();
dbNode.setAttribute(DatabaseSnapshotUtils.ATTR_CONTENT_TIME, DatabaseSnapshotUtils.dateToString(snapshot.contentTimestamp));
doc.appendChild(dbNode);
// append all table data
for (TableDescription tableDescription : snapshot.tables) {
Element tableNode = doc.createElement(DatabaseSnapshotUtils.NODE_TABLE);
// append table meta data
dbNode.appendChild(tableNode);
tableDescription.toXmlNode(doc, tableNode);
// check if table content is to be skipped
SkipContent skipTableContentOption = snapshot.skipContentPerTable.get(tableDescription.getName().toLowerCase());
if (skipTableContentOption != null) {
// we skip the table content
if (skipTableContentOption.isRememberNumberOfRows()) {
// ... but we want to persist the number of rows
int numberRows = snapshot.loadTableLength(snapshot.name, tableDescription, null, null);
tableNode.setAttribute(DatabaseSnapshotUtils.ATTR_TABLE_NUMBER_ROWS, String.valueOf(numberRows));
}
continue;
}
// append table content
List<String> valuesList = snapshot.loadTableData(snapshot.name, tableDescription, snapshot.skipColumnsPerTable, snapshot.skipRowsPerTable, null, null);
for (String values : valuesList) {
Element rowNode = doc.createElement(DatabaseSnapshotUtils.NODE_ROW);
rowNode.setTextContent(StringUtils.escapeNonPrintableAsciiCharacters(values));
tableNode.appendChild(rowNode);
}
}
// append any skip table content rules
for (SkipContent skipContent : snapshot.skipContentPerTable.values()) {
skipContent.toXmlNode(doc, dbNode);
}
// append any skip table column rules
for (SkipColumns skipColumns : snapshot.skipColumnsPerTable.values()) {
skipColumns.toXmlNode(doc, dbNode);
}
// append any skip index attribute rules
for (SkipIndexAttributes skipIndexAttributes : snapshot.skipIndexAttributesPerTable.values()) {
skipIndexAttributes.toXmlNode(doc, dbNode);
}
// append any skip table row rules
for (SkipRows skipRows : snapshot.skipRowsPerTable.values()) {
skipRows.toXmlNode(doc, dbNode);
}
// save the XML file
OutputStream fos = null;
try {
OutputFormat format = new OutputFormat(doc);
format.setIndenting(true);
format.setIndent(4);
format.setLineWidth(1000);
fos = new FileOutputStream(new File(backupFile));
XMLSerializer serializer = new XMLSerializer(fos, format);
serializer.serialize(doc);
} catch (Exception e) {
throw new DatabaseSnapshotException("Error saving " + backupFile, e);
} finally {
IoUtils.closeStream(fos, "Error closing IO stream to file used for database snapshot backup " + backupFile);
}
log.info("Save database snapshot into file " + backupFile + " - END");
return doc;
}
Aggregations