Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.x] [Management] Fix importing objects connected to saved searches that contain conflicts (#16004) #16492

Merged
merged 1 commit into from
Feb 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ <h5>
ng-repeat="pattern in indexPatternList | orderBy:['-default','title'] track by pattern.id"
class="sidebar-item"
>
<a href="{{::pattern.url}}" class="euiLink euiLink--primary show">
<a
href="{{::pattern.url}}"
class="euiLink euiLink--primary show"
data-test-subj="indexPatternLink"
>
<div class="{{::pattern.class}}">
<i aria-hidden="true" ng-if="pattern.default" class="fa fa-star"></i>
<span ng-bind="::pattern.title"></span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ uiModules.get('apps/management')
// We want to do the same for saved searches, but we want to keep them separate because they need
// to be applied _first_ because other saved objects can be depedent on those saved searches existing
const conflictedSearchDocs = [];
// It's possbile to have saved objects that link to saved searches which then link to index patterns
// and those could error out, but the error comes as an index pattern not found error. We can't resolve
// those the same as way as normal index pattern not found errors, but when those are fixed, it's very
// likely that these saved objects will work once resaved so keep them around to resave them.
const conflictedSavedObjectsLinkedToSavedSearches = [];

function importDocument(swallowErrors, doc) {
const { service } = find($scope.services, { type: doc._type }) || {};
Expand Down Expand Up @@ -242,7 +247,11 @@ uiModules.get('apps/management')
conflictedSearchDocs.push(doc);
return;
case 'index-pattern':
conflictedIndexPatterns.push({ obj, doc });
if (obj.savedSearchId) {
conflictedSavedObjectsLinkedToSavedSearches.push(obj);
} else {
conflictedIndexPatterns.push({ obj, doc });
}
return;
}
}
Expand Down Expand Up @@ -280,7 +289,11 @@ uiModules.get('apps/management')
return;
}
return obj.hydrateIndexPattern(newIndexId)
.then(() => obj.save({ confirmOverwrite: !overwriteAll }));
.then(() => saveObject(obj));
}

function saveObject(obj) {
return obj.save({ confirmOverwrite: !overwriteAll });
}

const docTypes = groupByType(docs);
Expand All @@ -293,6 +306,7 @@ uiModules.get('apps/management')
showChangeIndexModal(
(objs) => {
Promise.map(conflictedIndexPatterns, resolveConflicts.bind(null, objs))
.then(Promise.map(conflictedSavedObjectsLinkedToSavedSearches, saveObject))
.then(resolve)
.catch(reject);
},
Expand Down
124 changes: 64 additions & 60 deletions test/functional/apps/management/_import_objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,117 +5,121 @@ export default function ({ getService, getPageObjects }) {
const retry = getService('retry');
const kibanaServer = getService('kibanaServer');
const esArchiver = getService('esArchiver');
const PageObjects = getPageObjects(['common', 'settings']);
const PageObjects = getPageObjects(['common', 'settings', 'header']);

describe('import objects', function describeIndexTests() {
before(async function () {
beforeEach(async function () {
// delete .kibana index and then wait for Kibana to re-create it
await kibanaServer.uiSettings.replace({});
await PageObjects.settings.navigateTo();
await esArchiver.load('management');
});

after(async function () {
afterEach(async function () {
await esArchiver.unload('management');
});

it('should import saved objects normally', async function () {
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickKibanaSavedObjects();
await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects.json'));
await PageObjects.common.clickConfirmOnModal();
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.settings.clickVisualizationsTab();
const rowCount = await retry.try(async () => {
const rows = await PageObjects.settings.getVisualizationRows();
if (rows.length !== 2) {
throw 'Not loaded yet';
}
return rows.length;
});
expect(rowCount).to.be(2);
});

it('should import conflicts using a confirm modal', async function () {
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickKibanaSavedObjects();
await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects-conflicts.json'));
await PageObjects.common.clickConfirmOnModal();
await PageObjects.settings.setImportIndexFieldOption(2);
await PageObjects.settings.clickChangeIndexConfirmButton();
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.settings.clickVisualizationsTab();
const rowCount = await retry.try(async () => {
const rows = await PageObjects.settings.getVisualizationRows();
if (rows.length !== 2) {
throw 'Not loaded yet';
}
return rows.length;
});
expect(rowCount).to.be(2);
});

// Flaky: https://github.com/elastic/kibana/issues/15913
// it('should allow for overrides', async function () {
// await PageObjects.settings.navigateTo();
// await PageObjects.settings.clickKibanaSavedObjects();
// await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects.json'));
// await PageObjects.common.clickConfirmOnModal();
// await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects.json'));
// await PageObjects.common.clickConfirmOnModal();
// await PageObjects.settings.clickVisualizationsTab();
// const rowCount = await retry.try(async () => {
// const rows = await PageObjects.settings.getVisualizationRows();
// if (rows.length !== 2) {
// throw 'Not loaded yet';
// }
// return rows.length;
// });
// expect(rowCount).to.be(2);
// });

// Flaky: https://github.com/elastic/kibana/issues/15913
// it('should allow for cancelling overrides', async function () {
// await PageObjects.settings.navigateTo();
// await PageObjects.settings.clickKibanaSavedObjects();
// await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects.json'));
// await PageObjects.common.clickConfirmOnModal();
// await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects.json'));
// await PageObjects.common.clickCancelOnModal(true);
// await PageObjects.common.clickConfirmOnModal();
// await PageObjects.settings.clickVisualizationsTab();
// const rowCount = await retry.try(async () => {
// const rows = await PageObjects.settings.getVisualizationRows();
// if (rows.length !== 2) {
// throw 'Not loaded yet';
// }
// return rows.length;
// });
// expect(rowCount).to.be(2);
// });

it('should handle saved searches and objects with saved searches properly', async function () {
await PageObjects.settings.navigateTo();
it('should allow for overrides', async function () {
await PageObjects.settings.clickKibanaSavedObjects();
await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects_with_saved_searches.json'));

// Put in data which already exists
await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects_exists.json'));
// Say we want to be asked
await PageObjects.common.clickCancelOnModal();
// Interact with the conflict modal
await PageObjects.settings.setImportIndexFieldOption(2);
await PageObjects.settings.clickChangeIndexConfirmButton();
// Now confirm we want to override
await PageObjects.common.clickConfirmOnModal();
await PageObjects.header.waitUntilLoadingHasFinished();

await PageObjects.settings.clickVisualizationsTab();
const rowCount = await retry.try(async () => {
const rows = await PageObjects.settings.getVisualizationRows();
return rows.length;
});
expect(rowCount).to.be(1);
});

it('should allow for cancelling overrides', async function () {
await PageObjects.settings.clickKibanaSavedObjects();

// Put in data which already exists
await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects_exists.json'));
// Say we want to be asked
await PageObjects.common.clickCancelOnModal();
// Interact with the conflict modal
await PageObjects.settings.setImportIndexFieldOption(2);
await PageObjects.settings.clickChangeIndexConfirmButton();
// Now cancel the override
await PageObjects.common.clickCancelOnModal();

await PageObjects.settings.clickVisualizationsTab();
const rowCount = await retry.try(async () => {
const rows = await PageObjects.settings.getVisualizationRows();
return rows.length;
});
expect(rowCount).to.be(1);
});

it('should handle saved searches and objects with saved searches properly', async function () {
// First, import the saved search
await PageObjects.settings.clickKibanaSavedObjects();
await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects_saved_search.json'));
await PageObjects.common.clickConfirmOnModal();

// Second, we need to delete the index pattern
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickKibanaIndices();
await PageObjects.settings.clickOnOnlyIndexPattern();
await PageObjects.settings.removeIndexPattern();

// Last, import a saved object connected to the saved search
// This should NOT show the modal
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickKibanaSavedObjects();
await PageObjects.settings.importFile(path.join(__dirname, 'exports', '_import_objects_connected_to_saved_search.json'));
await PageObjects.common.clickConfirmOnModal();
await PageObjects.header.waitUntilLoadingHasFinished();

await PageObjects.settings.clickVisualizationsTab();
const vizRowCount = await retry.try(async () => {
const rows = await PageObjects.settings.getVisualizationRows();
if (rows.length !== 2) {
throw 'Not loaded yet';
}
return rows.length;
});
expect(vizRowCount).to.be(2);
expect(vizRowCount).to.be(1);

await PageObjects.settings.clickSearchesTab();
const searchRowCount = await retry.try(async () => {
const rows = await PageObjects.settings.getVisualizationRows();
if (rows.length !== 1) {
throw 'Not loaded yet';
}
return rows.length;
});
expect(searchRowCount).to.be(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,4 @@
[
{
"_id": "c45e6c50-ba72-11e7-a8f9-ad70f02e633d",
"_type": "search",
"_source": {
"title": "PHP saved search",
"description": "",
"hits": 0,
"columns": [
"_source"
],
"sort": [
"@timestamp",
"desc"
],
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"f0df0960-ae8d-11e7-9c8d-53400275d89a\",\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":\"php\"},\"filter\":[]}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "cbd520f0-ba72-11e7-a8f9-ad70f02e633d",
"_type": "visualization",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[
{
"_id": "Shared-Item-Visualization-AreaChart",
"_type": "visualization",
"_source": {
"title": "Shared-Item Visualization AreaChart",
"visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
"uiStateJSON": "{}",
"description": "AreaChart",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[
{
"_id": "c45e6c50-ba72-11e7-a8f9-ad70f02e633d",
"_type": "search",
"_source": {
"title": "PHP saved search",
"description": "",
"hits": 0,
"columns": [
"_source"
],
"sort": [
"@timestamp",
"desc"
],
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"f1e4c910-a2e6-11e7-bb30-233be9be6a15\",\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":\"php\"},\"filter\":[]}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]
4 changes: 4 additions & 0 deletions test/functional/page_objects/settings_page.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,10 @@ export function SettingsPageProvider({ getService, getPageObjects }) {
return await testSubjects.find('createIndexPatternCreateButton');
}

async clickOnOnlyIndexPattern() {
return await testSubjects.click('indexPatternLink');
}

async removeIndexPattern() {
let alertText;
await retry.try(async () => {
Expand Down