Skip to content

Commit

Permalink
Added integration test for "deploy not existing image" user story.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Florek committed Feb 24, 2016
1 parent d1ab426 commit 325f300
Show file tree
Hide file tree
Showing 11 changed files with 355 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ <h4 class="md-title">Delete Replication Controller</h4>
</md-checkbox>
<md-dialog-actions>
<md-button class="md-primary" ng-click="ctrl.cancel()">Cancel</md-button>
<md-button class="md-primary" ng-click="ctrl.remove()">Delete</md-button>
<md-button id="kd-deletereplicationcontroller-delete-button" class="md-primary"
ng-click="ctrl.remove()">
Delete
</md-button>
</md-dialog-actions>
</md-dialog-content>
</md-dialog>
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ <h1 flex="auto" class="md-title kd-replicationcontrollerdetail-app-name">
</md-select>
</md-input-container>
</div>
<table class="kd-replicationcontrollerdetail-table kd-responsive-table" cellspacing="0"
<table id="kd-replicationcontrollerdetail-events-table"
class="kd-replicationcontrollerdetail-table kd-responsive-table"
cellspacing="0"
cellpadding="15" ng-if="ctrl.hasEvents()">
<thead>
<tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
<div flex="auto" layout="row" layout-align="space-between center"
class="kd-replicationcontroller-card-title-row">
<span layout="row" flex="85">
<md-icon class="material-icons md-warn kd-replicationcontroller-card-status-icon"
<md-icon id="kd-replicationcontroller-card-error-icon"
class="material-icons md-warn kd-replicationcontroller-card-status-icon"
ng-if="::ctrl.hasWarnings()">
error
<md-tooltip>One or more pods have errors</md-tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="ctrl.showDeleteDialog()">
<md-button id="kd-replicationcontroller-card-menu-delete-button"
ng-click="ctrl.showDeleteDialog()">
Delete
</md-button>
</md-menu-item>
Expand Down
26 changes: 26 additions & 0 deletions src/test/integration/deploy/deploy_po.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export default class DeployPageObject {
constructor() {
this.deployButtonQuery = by.buttonText('Deploy');
this.deployButton = element(this.deployButtonQuery);

this.appNameFieldQuery = by.model('ctrl.name');
this.appNameField = element(this.appNameFieldQuery);

this.containerImageFieldQuery = by.model('ctrl.containerImage');
this.containerImageField = element(this.containerImageFieldQuery);
}
}
21 changes: 21 additions & 0 deletions src/test/integration/logs/logs_po.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export default class LogsPageObject {
constructor() {
this.logEntriesQuery = by.css('.kd-logs-element');
this.logEntriesTextQuery = by.css('pre');
this.logEntries = element.all(this.logEntriesQuery).all(this.logEntriesTextQuery);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export default class DeleteReplicationControllerDialogObject {
constructor() {
this.deleteAppButtonQuery = by.id('kd-deletereplicationcontroller-delete-button');
this.deleteAppButton = element(this.deleteAppButtonQuery);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export default class ReplicationControllerDetailPageObject {
constructor() {
this.mdTabItemsQuery = by.tagName('md-tab-item');

this.eventsTab = element.all(this.mdTabItemsQuery).get(1);
this.podsTab = element.all(this.mdTabItemsQuery).get(0);

this.eventsTypeFilterQuery = by.model('ctrl.eventType');
this.eventsTypeFilter = element(this.eventsTypeFilterQuery);

this.eventsTypeWarningQuery = by.css('md-option[value="Warning"]');
this.eventsTypeWarning = element(this.eventsTypeWarningQuery);

this.eventsTableQuery = by.id('kd-replicationcontrollerdetail-events-table');
this.eventsTable = element(this.eventsTableQuery);

this.podLogsLinkQuery = by.css('td[kd-responsive-header="Logs"');
this.podLogsLink = element(this.podLogsLinkQuery).element(by.css('a'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export default class ReplicationControllersPageObject {
constructor() {
this.cardMenuButtonQuery = by.css('.kd-replicationcontroller-card-menu-button');
this.cardMenuButton = element(this.cardMenuButtonQuery);

this.deleteAppButtonQuery = by.id('kd-replicationcontroller-card-menu-delete-button');
this.deleteAppButton = element(this.deleteAppButtonQuery);

this.cardErrorIconQuery = by.id('kd-replicationcontroller-card-error-icon');
this.cardErrorIcon = element(this.cardErrorIconQuery);

this.cardErrorsQuery = by.css('.kd-replicationcontroller-card-error');
this.cardErrors = element.all(this.cardErrorsQuery);

this.cardDetailsPageLinkQuery = by.css('.kd-replicationcontroller-card-name');
this.cardDetailsPageLink = element(this.cardDetailsPageLinkQuery);
}
}
206 changes: 206 additions & 0 deletions src/test/integration/stories/deploy_not_existing_img_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import DeployPageObject from '../deploy/deploy_po';
import DeleteReplicationControllerDialogObject from '../replicationcontrollerdetail/deletereplicationcontroller_po';
import LogsPageObject from '../logs/logs_po';
import ReplicationControllersPageObject from '../replicationcontrollerslist/replicationcontrollers_po';
import ReplicationControllerDetailPageObject from '../replicationcontrollerdetail/replicationcontrollerdetail_po';
import ZeroStatePageObject from '../zerostate/zerostate_po';

/**
* This integration test will check complete user story in given order:
* - [Zerostate Page] - go to deploy page
* - [Deploy Page] - provide data for not existing image and click deploy
* - [Replication Controller List Page] - wait for card status error to appear and go to
* details page
* - [Replication Controller Details Page] - Go to events tab, filter by warnings and check
* results
* - [Replication Controller Details Page] - Go to Pods tab and click on Logs link near the
* existing pod
* - [Logs Page] - Check if pod logs show that pod is in pending state.
* - Clean up and delete created resources
*/
describe('Deploy not existing image story', () => {
/** @type {!ZeroStatePageObject} */
let zeroStatePage;

/** @type {!DeployPageObject} */
let deployPage;

/** @type {!ReplicationControllersPageObject} */
let replicationControllersPage;

/** @type {!DeleteReplicationControllerDialogObject} */
let deleteDialog;

/** @type {!ReplicationControllerDetailPageObject} */
let replicationControllerDetailPage;

/** @type {!LogsPageObject} */
let logsPage;

let appName = 'test';
let containerImage = 'test';
let timeout = 10000; // 10s

/**
* Waits for element to be present on the page. It doesn't have to be displayed yet.
* Additional logic can be given in 'isPresentConditionFn' to f.e. refresh page periodically
* until given element appears on the page.
* @param {!Element} elm
* @param {?function(boolean): boolean} isPresentConditionFn
*/
function waitUntilPresent(elm, isPresentConditionFn) {
browser.driver.wait(() => {
if (!isPresentConditionFn) {
return elm.isPresent();
}

return elm.isPresent().then(isPresentConditionFn);
}, timeout);
}

/**
* Logic is the same as for waitUntilPresent function with the exception that it
* waits for the element to be actually displayed on the page.
* @param {!Element} elm
* @param {?function(boolean): boolean} isPresentConditionFn
*/
function waitUntilDisplayed(elm, isPresentConditionFn) {
browser.driver.wait(() => {
if (!isPresentConditionFn) {
return elm.isDisplayed();
}

return elm.isDisplayed().then(isPresentConditionFn);
}, timeout);
}

beforeAll(() => {
// For empty cluster this should actually redirect to zerostate page
browser.get('#/replicationcontrollers');

zeroStatePage = new ZeroStatePageObject();
deployPage = new DeployPageObject();
replicationControllersPage = new ReplicationControllersPageObject();
deleteDialog = new DeleteReplicationControllerDialogObject();
replicationControllerDetailPage = new ReplicationControllerDetailPageObject();
logsPage = new LogsPageObject();
});

it('should go to deploy page', () => {
// when
zeroStatePage.deployButton.click();
browser.driver.sleep(1000);

// then
expect(browser.getCurrentUrl()).toContain('deploy');
});

it('should deploy app and go to replication controllers list page', () => {
// given
deployPage.appNameField.sendKeys(appName);
deployPage.containerImageField.sendKeys(containerImage);

// when
deployPage.deployButton.click();
browser.driver.sleep(1000);

// then
expect(browser.getCurrentUrl()).toContain('replicationcontrollers');
});

it('should wait for card to be in error state', () => {
// when
waitUntilPresent(replicationControllersPage.cardErrorIcon, (result) => {
if (result) {
return true;
}

browser.driver.navigate().refresh();
browser.driver.sleep(1000);
return false;
});

// then
expect(replicationControllersPage.cardErrorIcon.isDisplayed()).toBeTruthy();
replicationControllersPage.cardErrors.then((errors) => { expect(errors.length).not.toBe(0); });
});

it('should go to details page', () => {
// when
replicationControllersPage.cardDetailsPageLink.click();
browser.driver.sleep(3000);

// then
expect(browser.getCurrentUrl()).toContain(`replicationcontrollers/default/${appName}`);
});

it('should switch to events tab and check for errors', () => {
// when
// Switch to events tab
replicationControllerDetailPage.eventsTab.click();
browser.driver.sleep(1000);

// Filter events by warnings
replicationControllerDetailPage.eventsTypeFilter.click().then(() => {
waitUntilPresent(replicationControllerDetailPage.eventsTypeWarning);
replicationControllerDetailPage.eventsTypeWarning.click();
});

// then
waitUntilDisplayed(replicationControllerDetailPage.eventsTable);
expect(replicationControllerDetailPage.eventsTable.isDisplayed()).toBeTruthy();
});

it('should switch to pods tab and go to pod logs page', () => {
// when
// Switch to pods tab
replicationControllerDetailPage.podsTab.click();
browser.driver.sleep(1000);

// Click pod log link
replicationControllerDetailPage.podLogsLink.click();
browser.driver.sleep(5000);

// then
// Logs page is opened in new window so we have to switch browser focus to that window.
browser.getAllWindowHandles().then((handles) => {
let logsWindowHandle = handles[1];
browser.switchTo().window(logsWindowHandle).then(() => {
expect(browser.getCurrentUrl()).toContain(`logs/default/${appName}`);
});
});
});

it('pod logs should show pending state', () => {
logsPage.logEntries.then((logEntries) => {
expect(logEntries.length).toBe(1);
let logEntryText = logEntries[0].getText();
expect(logEntryText).toContain('State: "Pending"');
});
});

// Clean up and delete created resources
afterAll(() => {
browser.get('#/replicationcontrollers');

replicationControllersPage.cardMenuButton.click();
replicationControllersPage.deleteAppButton.click().then(() => {
waitUntilPresent(deleteDialog.deleteAppButton);
deleteDialog.deleteAppButton.click();
});
});
});
Loading

0 comments on commit 325f300

Please sign in to comment.