Search in sources :

Example 1 with SkipContent

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");
    }
}
Also used : IndexMatcher(com.axway.ats.common.dbaccess.snapshot.IndexMatcher) SkipRows(com.axway.ats.action.dbaccess.snapshot.rules.SkipRows) SkipContent(com.axway.ats.action.dbaccess.snapshot.rules.SkipContent) ArrayList(java.util.ArrayList) TableDescription(com.axway.ats.common.dbaccess.snapshot.TableDescription) DatabaseSnapshotException(com.axway.ats.common.dbaccess.snapshot.DatabaseSnapshotException) DatabaseEqualityState(com.axway.ats.common.dbaccess.snapshot.equality.DatabaseEqualityState) DatabaseSnapshotException(com.axway.ats.common.dbaccess.snapshot.DatabaseSnapshotException) SkipColumns(com.axway.ats.action.dbaccess.snapshot.rules.SkipColumns) PublicAtsApi(com.axway.ats.common.PublicAtsApi)

Example 2 with SkipContent

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;
}
Also used : HashMap(java.util.HashMap) SkipContent(com.axway.ats.action.dbaccess.snapshot.rules.SkipContent)

Example 3 with SkipContent

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();
}
Also used : SkipContent(com.axway.ats.action.dbaccess.snapshot.rules.SkipContent) TableDescription(com.axway.ats.common.dbaccess.snapshot.TableDescription) SkipColumns(com.axway.ats.action.dbaccess.snapshot.rules.SkipColumns)

Example 4 with SkipContent

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;
}
Also used : SkipIndexAttributes(com.axway.ats.action.dbaccess.snapshot.rules.SkipIndexAttributes) SkipRows(com.axway.ats.action.dbaccess.snapshot.rules.SkipRows) Element(org.w3c.dom.Element) SkipContent(com.axway.ats.action.dbaccess.snapshot.rules.SkipContent) Document(org.w3c.dom.Document) File(java.io.File) DatabaseSnapshotException(com.axway.ats.common.dbaccess.snapshot.DatabaseSnapshotException) DatabaseSnapshotException(com.axway.ats.common.dbaccess.snapshot.DatabaseSnapshotException) SkipColumns(com.axway.ats.action.dbaccess.snapshot.rules.SkipColumns)

Example 5 with SkipContent

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;
}
Also used : SkipIndexAttributes(com.axway.ats.action.dbaccess.snapshot.rules.SkipIndexAttributes) SkipRows(com.axway.ats.action.dbaccess.snapshot.rules.SkipRows) XMLSerializer(org.apache.xml.serialize.XMLSerializer) Element(org.w3c.dom.Element) SkipContent(com.axway.ats.action.dbaccess.snapshot.rules.SkipContent) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) OutputFormat(org.apache.xml.serialize.OutputFormat) Document(org.w3c.dom.Document) TableDescription(com.axway.ats.common.dbaccess.snapshot.TableDescription) DatabaseSnapshotException(com.axway.ats.common.dbaccess.snapshot.DatabaseSnapshotException) FileOutputStream(java.io.FileOutputStream) File(java.io.File) DatabaseSnapshotException(com.axway.ats.common.dbaccess.snapshot.DatabaseSnapshotException) SkipColumns(com.axway.ats.action.dbaccess.snapshot.rules.SkipColumns)

Aggregations

SkipContent (com.axway.ats.action.dbaccess.snapshot.rules.SkipContent)5 SkipColumns (com.axway.ats.action.dbaccess.snapshot.rules.SkipColumns)4 SkipRows (com.axway.ats.action.dbaccess.snapshot.rules.SkipRows)3 DatabaseSnapshotException (com.axway.ats.common.dbaccess.snapshot.DatabaseSnapshotException)3 TableDescription (com.axway.ats.common.dbaccess.snapshot.TableDescription)3 SkipIndexAttributes (com.axway.ats.action.dbaccess.snapshot.rules.SkipIndexAttributes)2 File (java.io.File)2 Document (org.w3c.dom.Document)2 Element (org.w3c.dom.Element)2 PublicAtsApi (com.axway.ats.common.PublicAtsApi)1 IndexMatcher (com.axway.ats.common.dbaccess.snapshot.IndexMatcher)1 DatabaseEqualityState (com.axway.ats.common.dbaccess.snapshot.equality.DatabaseEqualityState)1 FileOutputStream (java.io.FileOutputStream)1 OutputStream (java.io.OutputStream)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 OutputFormat (org.apache.xml.serialize.OutputFormat)1 XMLSerializer (org.apache.xml.serialize.XMLSerializer)1