diff --git a/src/css/backup-and-restore.css b/src/css/backup-and-restore.css new file mode 100644 index 000000000..62b6f0159 --- /dev/null +++ b/src/css/backup-and-restore.css @@ -0,0 +1,7 @@ +.backup-and-restore-updater-icon div, .backup-and-restore-updater-icon img { + display: inline-block; +} + +.backup-and-restore table td { + vertical-align: top; +} diff --git a/src/i18n/locale-en.json b/src/i18n/locale-en.json index ff35ca2bb..6eb09feb0 100644 --- a/src/i18n/locale-en.json +++ b/src/i18n/locale-en.json @@ -583,6 +583,20 @@ "view.namespaces.helpInfo": "The Namespaces view provides an overview of all namespaces defined in a GraphDB repository. Namespaces are essentially shorthand notations for IRIs. Here you can add, remove and modify them.", "view.query.and.update.monitoring.title": "Query and Update monitoring", "view.query.and.update.monitoring.helpInfo": "The Queries and Updates monitoring view shows all running queries and updates in a GraphDB repository. A query or update can be terminated by pressing the Abort button.", + "view.monitoring.backup_and_restore.title": "Backup and Restore", + "view.monitoring.backup_and_restore.helpInfo": "The Backup and Restore monitoring view shows running backup or restore operation.", + "view.monitoring.backup_and_restore.id.header": "Id", + "view.monitoring.backup_and_restore.username.header": "Username", + "view.monitoring.backup_and_restore.recovery_operation_type.header": "Recovery operation type", + "view.monitoring.backup_and_restore.affected_repositories.header": "Affected repositories", + "view.monitoring.backup_and_restore.lifetime.header": "Lifetime", + "view.monitoring.backup_and_restore.snapshot_options.header": "Snapshot options", + "view.monitoring.backup_and_restore.node_performing_cluster_backup.header": "Node performing backup", + "view.monitoring.backup_and_restore.CREATE_BACKUP_IN_PROGRESS": "Creating backup", + "view.monitoring.backup_and_restore.RESTORE_BACKUP_IN_PROGRESS": "Restoring backup", + "view.monitoring.backup_and_restore.CREATE_CLOUD_BACKUP_IN_PROGRESS": "Creating cloud backup", + "view.monitoring.backup_and_restore.RESTORE_CLOUD_BACKUP_IN_PROGRESS": "Restoring cloud backup", + "view.monitoring.backup_and_restore.no_running_backup_and_restore": "No running backup or restore.", "view.rdf.rank.title": "RDF Rank", "view.rdf.rank.helpInfo": "RDF Rank is an algorithm that identifies the most important or popular entities in the repository by examining their interconnectedness. The popularity of the entities can be used to order the query results. Use this view to configure the RDF rank, recompute it or check the current state.", "view.repositories.helpInfo": "The Repositories view is used to create, modify and delete repositories and connections to remote GraphDB instances (also known as remote locations).", @@ -639,6 +653,7 @@ "menu.sparql.label": "SPARQL", "menu.monitor.label": "Monitor", "menu.queries.and.updates.label": "Queries and Updates", + "menu.backup_and_restore.label": "Backup and Restore", "menu.enableFtsIndex.label": "Enable full-text search (FTS) index", "menu.ftsIndexes.label": "FTS indexes to build (comma delimited)", "menu.ftsStringLiteralsIndex.label": "FTS index for xsd:string literals", diff --git a/src/i18n/locale-fr.json b/src/i18n/locale-fr.json index eb2c7afe5..a5b4d30aa 100644 --- a/src/i18n/locale-fr.json +++ b/src/i18n/locale-fr.json @@ -584,6 +584,20 @@ "view.namespaces.helpInfo": "La vue Espaces de noms fournit une vue d'ensemble de tous les espaces de noms définis dans un dépôt GraphDB. Les espaces de noms sont essentiellement des notations abrégées pour les IRI. Vous pouvez y ajouter, supprimer et modifier ces espaces.", "view.query.and.update.monitoring.title": "Surveillance des requêtes et des mises à jour", "view.query.and.update.monitoring.helpInfo": "La vue de surveillance des requêtes et des mises à jour montre toutes les requêtes ou mises à jour en cours dans GraphDB. Une requête ou une mise à jour peut être interrompue en appuyant sur le bouton Abandon.", + "view.monitoring.backup_and_restore.title": "Sauvegarde et Restauration", + "view.monitoring.backup_and_restore.helpInfo": "La vue de surveillance de la sauvegarde et de la restauration affiche les opérations de sauvegarde ou de restauration en cours.", + "view.monitoring.backup_and_restore.id.header": "Id", + "view.monitoring.backup_and_restore.username.header": "Nom d'utilisateur", + "view.monitoring.backup_and_restore.recovery_operation_type.header": "Type d'opération de restauration", + "view.monitoring.backup_and_restore.affected_repositories.header": "Dépôts affectés", + "view.monitoring.backup_and_restore.lifetime.header": "Durée de vie", + "view.monitoring.backup_and_restore.snapshot_options.header": "Options de capture instantanée", + "view.monitoring.backup_and_restore.node_performing_cluster_backup.header": "Nœud effectuant la sauvegarde", + "view.monitoring.backup_and_restore.CREATE_BACKUP_IN_PROGRESS": "Création de sauvegarde en cours", + "view.monitoring.backup_and_restore.RESTORE_BACKUP_IN_PROGRESS": "Restauration de sauvegarde en cours", + "view.monitoring.backup_and_restore.CREATE_CLOUD_BACKUP_IN_PROGRESS": "Création de sauvegarde dans le cloud en cours", + "view.monitoring.backup_and_restore.RESTORE_CLOUD_BACKUP_IN_PROGRESS": "Restauration de sauvegarde dans le cloud en cours", + "view.monitoring.backup_and_restore.no_running_backup_and_restore": "Aucune sauvegarde ou restauration en cours.", "view.rdf.rank.title": "Rang RDF", "view.rdf.rank.helpInfo": "RDF Rank est un algorithme qui identifie les entités les plus importantes ou les plus populaires dans le dépôt en examinant leur interconnexion. La popularité des entités peut alors être utilisée pour ordonner les résultats des requêtes. Utilisez cette vue pour configurer le RDF Rank, le recalculer ou vérifier l'état actuel.", "view.repositories.helpInfo": "La vue Dépôts est utilisée pour créer, modifier et supprimer des dépôts et des connexions à des instances GraphDB distantes (également appelées emplacements distants).", @@ -642,6 +656,7 @@ "menu.sparql.label": "SPARQL", "menu.monitor.label": "Surveiller", "menu.queries.and.updates.label": "Requêtes et mises à jour", + "menu.backup_and_restore.label": "Sauvegarde et Restauration", "menu.ftsLanguages.label": "Entrez la langue pour la recherche plein texte", "menu.resources.label": "Système", "menu.setup.label": "Configurer", diff --git a/src/js/angular/backup-and-restore/app.js b/src/js/angular/backup-and-restore/app.js new file mode 100644 index 000000000..e17495e49 --- /dev/null +++ b/src/js/angular/backup-and-restore/app.js @@ -0,0 +1,6 @@ +import 'angular/backup-and-restore/controllers'; +const modules = [ + 'graphdb.framework.monitoring.backupandrestore.controllers' +]; + +angular.module('graphdb.framework.monitoring.backupandrestore', modules); diff --git a/src/js/angular/backup-and-restore/controllers.js b/src/js/angular/backup-and-restore/controllers.js new file mode 100644 index 000000000..8ba699228 --- /dev/null +++ b/src/js/angular/backup-and-restore/controllers.js @@ -0,0 +1,65 @@ +const modules = []; +const UPDATE_BACKUP_AND_RESTORE_INFO_DATA_TIME_INTERVAL = 2000; + +angular + .module('graphdb.framework.monitoring.backupandrestore.controllers', modules) + .controller('BackupAndRestoreCtrl', BackupAndRestoreCtrl); + +BackupAndRestoreCtrl.$inject = ['$scope', '$interval', 'MonitoringRestService']; + +function BackupAndRestoreCtrl($scope, $interval, MonitoringRestService) { + + $scope.loading = false; + $scope.initialized = false; + + /** + * @type {BackupAndRestoreInfo[]} + */ + $scope.backupAndRestoreInfos = undefined; + $scope.hasClusterOperation = false; + let timer = undefined; + + // ========================= + // Public functions + // ========================= + $scope.hasToShowValue = (value) => { + if (typeof value === 'boolean') { + return true; + } + return !!value; + }; + + // ========================= + // Private functions + // ========================= + const loadBackupAndRestoreData = () => { + if ($scope.loading) { + return; + } + $scope.loading = true; + MonitoringRestService.monitorBackup() + .then((backupAndRestoreInfos) => { + $scope.backupAndRestoreInfos = backupAndRestoreInfos; + $scope.initialized = true; + $scope.hasClusterOperation = $scope.backupAndRestoreInfos.some((backupAndRestoreInfo) => backupAndRestoreInfo.nodePerformingClusterBackup); + }) + .finally(() => $scope.loading = false); + }; + + const removeAllListeners = () => { + if (timer) { + $interval.cancel(timer); + } + }; + + // ========================= + // Event handlers + // ========================= + $scope.$on('$destroy', removeAllListeners); + + // ========================= + // Initializes controller. + // ========================= + loadBackupAndRestoreData(); + timer = $interval(() => loadBackupAndRestoreData(), UPDATE_BACKUP_AND_RESTORE_INFO_DATA_TIME_INTERVAL); +} diff --git a/src/js/angular/backup-and-restore/plugin.js b/src/js/angular/backup-and-restore/plugin.js new file mode 100644 index 000000000..db397c976 --- /dev/null +++ b/src/js/angular/backup-and-restore/plugin.js @@ -0,0 +1,23 @@ +PluginRegistry.add('route', { + 'url': '/monitor/backup-and-restore', + 'module': 'graphdb.framework.monitoring.backupandrestore', + 'path': 'backup-and-restore/app', + 'chunk': 'monitor-backup-and-restore', + 'controller': 'BackupAndRestoreCtrl', + 'templateUrl': 'pages/monitor/backup-and-restore.html', + 'title': 'view.monitoring.backup_and_restore.title', + 'helpInfo': 'view.monitoring.backup_and_restore.helpInfo' +}); + +PluginRegistry.add('main.menu', { + 'items': [ + { + label: 'Backup and Restore', + labelKey: 'menu.backup_and_restore.label', + href: 'monitor/backup-and-restore', + order: 2, + parent: 'Monitor', + guideSelector: 'sub-menu-backup-and-restore' + } + ] +}); diff --git a/src/js/angular/models/monitoring/backup-and-restore-info.js b/src/js/angular/models/monitoring/backup-and-restore-info.js new file mode 100644 index 000000000..d88dbdfc9 --- /dev/null +++ b/src/js/angular/models/monitoring/backup-and-restore-info.js @@ -0,0 +1,15 @@ +export class BackupAndRestoreInfo { + constructor() { + this.id = undefined; + this.username = ''; + + /** + * @type {string} - The value must be one of the @{see BackupAndRestoreOperationType} values. + */ + this.operation = ''; + this.affectedRepositories = []; + this.secondsSinceCreated = 0; + this.snapshotOptions = []; + this.nodePerformingClusterBackup = ''; + } +} diff --git a/src/js/angular/models/monitoring/backup-and-restore-operation-type.js b/src/js/angular/models/monitoring/backup-and-restore-operation-type.js new file mode 100644 index 000000000..6be923be6 --- /dev/null +++ b/src/js/angular/models/monitoring/backup-and-restore-operation-type.js @@ -0,0 +1,6 @@ +export const BackupAndRestoreOperationType = { + 'CREATE_BACKUP_IN_PROGRESS': 'CREATE_BACKUP_IN_PROGRESS', + 'RESTORE_BACKUP_IN_PROGRESS': 'RESTORE_BACKUP_IN_PROGRESS', + 'CREATE_CLOUD_BACKUP_IN_PROGRESS': 'CREATE_CLOUD_BACKUP_IN_PROGRESS', + 'RESTORE_CLOUD_BACKUP_IN_PROGRESS': 'RESTORE_CLOUD_BACKUP_IN_PROGRESS' +}; diff --git a/src/js/angular/models/monitoring/snapshot-option-info.js b/src/js/angular/models/monitoring/snapshot-option-info.js new file mode 100644 index 000000000..627bfa5a1 --- /dev/null +++ b/src/js/angular/models/monitoring/snapshot-option-info.js @@ -0,0 +1,11 @@ +export class SnapshotOptionInfo { + constructor() { + this.withRepositoryData = false; + this.withSystemData = false; + this.withClusterData = false; + this.cleanDataDir = false; + this.removeCluster = false; + this.repositories = []; + this.replicationTimeoutMs = 0; + } +} diff --git a/src/js/angular/resources/plugin.js b/src/js/angular/resources/plugin.js index 5052449a5..8f4f25ae3 100644 --- a/src/js/angular/resources/plugin.js +++ b/src/js/angular/resources/plugin.js @@ -26,7 +26,7 @@ PluginRegistry.add('main.menu', { href: 'monitor/system', // Added role requirement here to assert that users cannot see Resources menu item role: 'ROLE_MONITORING', - order: 2, + order: 3, parent: 'Monitor', guideSelector: 'sub-menu-resources' } diff --git a/src/js/angular/rest/mappers/monitor-backup-and-restore-mapper.js b/src/js/angular/rest/mappers/monitor-backup-and-restore-mapper.js new file mode 100644 index 000000000..a5c3412d8 --- /dev/null +++ b/src/js/angular/rest/mappers/monitor-backup-and-restore-mapper.js @@ -0,0 +1,30 @@ +import {BackupAndRestoreInfo} from "../../models/monitoring/backup-and-restore-info"; +import {SnapshotOptionInfo} from "../../models/monitoring/snapshot-option-info"; + +export const mapBackupAndRestoreResponseToModel = (responseData = []) => { + const backupAndRestoreInfos = []; + responseData.forEach((backupAndRestoreResponseData) => { + const backupAndRestoreInfo = new BackupAndRestoreInfo(); + backupAndRestoreInfo.id = backupAndRestoreResponseData.id; + backupAndRestoreInfo.username = backupAndRestoreResponseData.username; + backupAndRestoreInfo.operation = backupAndRestoreResponseData.operation; + backupAndRestoreInfo.affectedRepositories = backupAndRestoreResponseData.affectedRepositories; + backupAndRestoreInfo.secondsSinceCreated = backupAndRestoreResponseData.msSinceCreated / 1000; + backupAndRestoreInfo.snapshotOptions = mapSnapshotOptionsResponseToModel(backupAndRestoreResponseData.snapshotOptions); + backupAndRestoreInfo.nodePerformingClusterBackup = backupAndRestoreResponseData.nodePerformingClusterBackup; + backupAndRestoreInfos.push(backupAndRestoreInfo); + }); + return backupAndRestoreInfos; +}; + +export const mapSnapshotOptionsResponseToModel = ((snapshotOption) => { + const snapshotOptionInfo = new SnapshotOptionInfo(); + snapshotOptionInfo.withRepositoryData = snapshotOption.withRepositoryData; + snapshotOptionInfo.withSystemData = snapshotOption.withSystemData; + snapshotOptionInfo.withClusterData = snapshotOption.withClusterData; + snapshotOptionInfo.cleanDataDir = snapshotOption.cleanDataDir; + snapshotOptionInfo.removeCluster = snapshotOption.removeCluster; + snapshotOptionInfo.repositories = snapshotOption.repositories; + snapshotOptionInfo.replicationTimeoutMs = snapshotOption.replicationTimeoutMs; + return snapshotOptionInfo; +}); diff --git a/src/js/angular/rest/monitoring.rest.service.js b/src/js/angular/rest/monitoring.rest.service.js index 34e4cda99..0ea3ba9ad 100644 --- a/src/js/angular/rest/monitoring.rest.service.js +++ b/src/js/angular/rest/monitoring.rest.service.js @@ -1,3 +1,5 @@ +import {mapBackupAndRestoreResponseToModel} from "./mappers/monitor-backup-and-restore-mapper"; + angular .module('graphdb.framework.rest.monitoring.service', []) .factory('MonitoringRestService', MonitoringRestService); @@ -6,6 +8,7 @@ MonitoringRestService.$inject = ['$http']; const MONITORING_ENDPOINT = 'rest/monitor'; const QUERY_MONITORING_ENDPOINT = `${MONITORING_ENDPOINT}/repository`; +const BACKUP_MONITORING_ENDPOINT = `${MONITORING_ENDPOINT}/backup`; function MonitoringRestService($http) { return { @@ -14,6 +17,7 @@ function MonitoringRestService($http) { monitorCluster, monitorGC, monitorQuery, + monitorBackup, deleteQuery, getQueryCount, checkAutocompleteStatus, @@ -44,6 +48,15 @@ function MonitoringRestService($http) { return $http.get(`${QUERY_MONITORING_ENDPOINT}/${repositoryID}/query/active`); } + /** + * + * @return {Promise} + */ + function monitorBackup() { + return $http.get(BACKUP_MONITORING_ENDPOINT) + .then((response) => mapBackupAndRestoreResponseToModel(response.data)); + } + function deleteQuery(queryId, repositoryID) { return $http.delete(`${QUERY_MONITORING_ENDPOINT}/${repositoryID}/query?query=${encodeURIComponent(queryId)}`); } diff --git a/src/pages/monitor/backup-and-restore.html b/src/pages/monitor/backup-and-restore.html new file mode 100644 index 000000000..53db948ac --- /dev/null +++ b/src/pages/monitor/backup-and-restore.html @@ -0,0 +1,74 @@ +
+ ${messages.app.title} : ${messages.jmx.QueryMonitoringPage.title} + + + +

+ {{title}} + + + + + +

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
{{'view.monitoring.backup_and_restore.id.header' | translate}}{{'view.monitoring.backup_and_restore.username.header' | translate}}{{'view.monitoring.backup_and_restore.recovery_operation_type.header' | translate}} + {{'view.monitoring.backup_and_restore.affected_repositories.header' | translate}} + {{'view.monitoring.backup_and_restore.lifetime.header' | translate}}{{'view.monitoring.backup_and_restore.snapshot_options.header' | translate}} + {{'view.monitoring.backup_and_restore.node_performing_cluster_backup.header' | translate}} +
{{backupAndRestoreInfo.id}}{{backupAndRestoreInfo.username}}{{('view.monitoring.backup_and_restore.' + backupAndRestoreInfo.operation) | translate}} +
+ {{repository}} +
+
{{getHumanReadableSeconds(backupAndRestoreInfo.secondsSinceCreated)}} +
+
+ {{key}} : {{value}} +
+
+
{{backupAndRestoreInfo.nodePerformingClusterBackup}}
+ +
+ {{'view.monitoring.backup_and_restore.no_running_backup_and_restore' | translate}} +
+
+ +
+
+
+
+
diff --git a/test-cypress/fixtures/locale-en.json b/test-cypress/fixtures/locale-en.json index fa69cbabf..1b05a4ef7 100644 --- a/test-cypress/fixtures/locale-en.json +++ b/test-cypress/fixtures/locale-en.json @@ -575,6 +575,20 @@ "view.namespaces.helpInfo": "The Namespaces view provides an overview of all namespaces defined in a GraphDB repository. Namespaces are essentially shorthand notations for IRIs. Here you can add, remove and modify them.", "view.query.and.update.monitoring.title": "Query and Update monitoring", "view.query.and.update.monitoring.helpInfo": "The Queries and Updates monitoring view shows all running queries and updates in a GraphDB repository. A query or update can be terminated by pressing the Abort button.", + "view.monitoring.backup_and_restore.title": "Backup and Restore", + "view.monitoring.backup_and_restore.helpInfo": "The Backup and Restore monitoring view shows running backup or restore operation.", + "view.monitoring.backup_and_restore.id.header": "Id", + "view.monitoring.backup_and_restore.username.header": "Username", + "view.monitoring.backup_and_restore.recovery_operation_type.header": "Recovery operation type", + "view.monitoring.backup_and_restore.affected_repositories.header": "Affected repositories", + "view.monitoring.backup_and_restore.lifetime.header": "Lifetime", + "view.monitoring.backup_and_restore.snapshot_options.header": "Snapshot options", + "view.monitoring.backup_and_restore.node_performing_cluster_backup.header": "Node performing backup", + "view.monitoring.backup_and_restore.CREATE_BACKUP_IN_PROGRESS": "Creating backup", + "view.monitoring.backup_and_restore.RESTORE_BACKUP_IN_PROGRESS": "Restoring backup", + "view.monitoring.backup_and_restore.CREATE_CLOUD_BACKUP_IN_PROGRESS": "Creating cloud backup", + "view.monitoring.backup_and_restore.RESTORE_CLOUD_BACKUP_IN_PROGRESS": "Restoring cloud backup", + "view.monitoring.backup_and_restore.no_running_backup_and_restore": "No running backup or restore.", "view.rdf.rank.title": "RDF Rank", "view.rdf.rank.helpInfo": "RDF Rank is an algorithm that identifies the most important or popular entities in the repository by examining their interconnectedness. The popularity of the entities can be used to order the query results. Use this view to configure the RDF rank, recompute it or check the current state.", "view.repositories.helpInfo": "The Repositories view is used to create, modify and delete repositories and connections to remote GraphDB instances (also known as remote locations).", @@ -631,6 +645,7 @@ "menu.sparql.label": "SPARQL", "menu.monitor.label": "Monitor", "menu.queries.and.updates.label": "Queries and Updates", + "menu.backup_and_restore.label": "Backup and Restore", "menu.enableFtsIndex.label": "Enable full-text search (FTS) index", "menu.ftsIndexes.label": "FTS indexes to build (comma delimited)", "menu.ftsStringLiteralsIndex.label": "FTS index for xsd:string literals", diff --git a/test-cypress/fixtures/monitoring/backup-and-restore.json b/test-cypress/fixtures/monitoring/backup-and-restore.json new file mode 100644 index 000000000..16aef8aff --- /dev/null +++ b/test-cypress/fixtures/monitoring/backup-and-restore.json @@ -0,0 +1,69 @@ +[ + { + "id": "1", + "username": "admin", + "operation": "CREATE_CLOUD_BACKUP", + "affectedRepositories": [ + "1" + ], + "msSinceCreated": 23416, + "snapshotOptions": { + "withRepositoryData": true, + "withSystemData": false, + "withClusterData": false, + "cleanDataDir": true, + "removeCluster": false, + "repositories": null, + "replicationTimeoutMs": null + }, + "nodePerformingClusterBackup": null + }, + { + "id": "2", + "username": "admin", + "operation": "CREATE_CLOUD_BACKUP", + "affectedRepositories": [ + "1", + "test Repository 2" + ], + "msSinceCreated": 3423, + "snapshotOptions": { + "withRepositoryData": true, + "withSystemData": false, + "withClusterData": false, + "cleanDataDir": true, + "removeCluster": false, + "repositories": null, + "replicationTimeoutMs": null + }, + "nodePerformingClusterBackup": "node Performing Cluster Backup" + }, + { + "id": "3", + "username": "admin", + "operation": "CREATE_CLOUD_BACKUP", + "affectedRepositories": [ + "1", + "test Repository 2", + "test Repository 3", + "test Repository 4", + "test Repository 5", + "test Repository 6", + "test Repository 7", + "test Repository 8", + "test Repository 9", + "test Repository 10" + ], + "msSinceCreated": 12334, + "snapshotOptions": { + "withRepositoryData": true, + "withSystemData": false, + "withClusterData": false, + "cleanDataDir": true, + "removeCluster": false, + "repositories": null, + "replicationTimeoutMs": null + }, + "nodePerformingClusterBackup": "node Performing Cluster Backup" + } +] diff --git a/test-cypress/integration/monitor/monitor.backup-and-restore.spec.js b/test-cypress/integration/monitor/monitor.backup-and-restore.spec.js new file mode 100644 index 000000000..900285d83 --- /dev/null +++ b/test-cypress/integration/monitor/monitor.backup-and-restore.spec.js @@ -0,0 +1,21 @@ +import {BackupAndRestoreSteps} from "../../steps/monitoring/backup-and-restore-steps"; +import {BackupAndRestoreStubs} from "../../stubs/backup-and-restore-stubs"; + +describe("Monitoring 'Backup And Restore'", () => { + + beforeEach(() => { + const repositoryId = 'backup-and-restore-' + Date.now(); + cy.createRepository({id: repositoryId}); + cy.presetRepository(repositoryId); + }); + + it('should show running backup or restore operations', () => { + // When visit the "Backup and restore page", + BackupAndRestoreSteps.visit(); + // and there are run backup and restore operations. + BackupAndRestoreStubs.stubBackupAndRestoreResponse(); + + // Then I expect to see information for all run operations. + BackupAndRestoreSteps.getBackupAndRestoreResults().should('have.length', 3); + }); +}); diff --git a/test-cypress/integration/sparql/main.menu.spec.js b/test-cypress/integration/sparql/main.menu.spec.js index 62f802624..56e28b8a6 100644 --- a/test-cypress/integration/sparql/main.menu.spec.js +++ b/test-cypress/integration/sparql/main.menu.spec.js @@ -63,6 +63,11 @@ describe('Main menu tests', function () { visible: false, redirect: '/queries' }, + { + name: 'Backup and Restore', + visible: false, + redirect: '/monitor/backup-and-restore' + }, { name: 'System', visible: false, diff --git a/test-cypress/steps/monitoring/backup-and-restore-steps.js b/test-cypress/steps/monitoring/backup-and-restore-steps.js new file mode 100644 index 000000000..e90ca7642 --- /dev/null +++ b/test-cypress/steps/monitoring/backup-and-restore-steps.js @@ -0,0 +1,14 @@ +export class BackupAndRestoreSteps { + + static visit() { + cy.visit('/monitor/backup-and-restore'); + } + + static getInfoMessageElement() { + return cy.get('.no-running-backup-and-restore-alert'); + } + + static getBackupAndRestoreResults() { + return cy.get('.backup-and-restore table tbody tr'); + } +} diff --git a/test-cypress/stubs/backup-and-restore-stubs.js b/test-cypress/stubs/backup-and-restore-stubs.js new file mode 100644 index 000000000..5a87cf596 --- /dev/null +++ b/test-cypress/stubs/backup-and-restore-stubs.js @@ -0,0 +1,9 @@ +export class BackupAndRestoreStubs { + static stubBackupAndRestoreResponse(withDelay = 0) { + BackupAndRestoreStubs.stubQueryResponse('/rest/monitor/backup', '/monitoring/backup-and-restore.json', 'backup-and-restore-response', withDelay); + } + + static stubQueryResponse(url, fixture, alias, withDelay = 0) { + cy.intercept(url, {fixture, delay: withDelay}).as(alias); + } +}