提交 149c77e9 编写于 作者: P Piotr Bryk

Merge pull request #194 from zreigz/master

Implement current logs form for replica set detail view
......@@ -184,3 +184,12 @@ backendApi.ReplicaSetPodWithContainers;
* }}
*/
backendApi.ReplicaSetPods;
/**
* @typedef {{
* podId: string,
* sinceTime: string,
* logs: !Array<string>
* }}
*/
backendApi.Logs;
......@@ -13,5 +13,8 @@
// To allow comparison to undefined variable, because Google Closure Compiler does not
// understand angular.isDefined correctly.
"angular/definedundefined": 0,
// To disable error 'use factory() instead of service()'.
"angular/no-service-method": 0,
"valid-jsdoc": [0, {}],
}
}
......@@ -23,7 +23,7 @@ limitations under the License.
<h2>
<span>kubernetes</span>
</h2>
<span flex></span>
<div flex ui-view="toolbar"></div>
</div>
</md-toolbar>
<div ng-transclude></div>
......
......@@ -28,3 +28,7 @@ body {
background-color: $body;
height: 100%;
}
a {
text-decoration: inherit;
}
......@@ -21,6 +21,7 @@ import ChromeController from './chrome_controller';
*/
export default function chromeDirective() {
return {
scope: {},
bindToController: true,
controller: ChromeController,
controllerAs: 'ctrl',
......
// 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.
/** Name of the view. Can be used in state config to define toolbar view */
export const toolbarViewName = 'toolbar';
......@@ -19,6 +19,7 @@
import chromeModule from './chrome/chrome_module';
import deployModule from './deploy/deploy_module';
import indexConfig from './index_config';
import logsModule from './logs/logs_module';
import routeConfig from './index_route';
import replicaSetDetailModule from './replicasetdetail/replicasetdetail_module';
import replicaSetListModule from './replicasetlist/replicasetlist_module';
......@@ -36,6 +37,7 @@ export default angular.module(
'ui.router',
chromeModule.name,
deployModule.name,
logsModule.name,
replicaSetDetailModule.name,
replicaSetListModule.name,
zerostateModule.name,
......
<!--
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.
-->
<div layout="row" flex layout-fill>
<md-content layout-padding flex layout-fill
ng-class=ctrl.getStyleClass()>
<div ng-repeat="n in ctrl.logsSet" class="kd-logs-element">
<pre>{{n}}</pre>
</div>
</md-content>
</div>
// 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.
$logs-color-black: #000;
$logs-color-white: #fff;
.kd-logs-text-color-invert {
background-color: $logs-color-black;
color: $logs-color-white;
}
.kd-logs-text-color {
background-color: $logs-color-white;
color: $logs-color-black;
}
.kd-logs-element {
padding: 0;
}
// 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.
/**
* Controller for the logs view.
*
* @final
*/
export class LogsController {
/**
* @param {!backendApi.Logs} podLogs
* @param {!./logs_service.LogColorInversionService} logsColorInversionService
* @ngInject
*/
constructor(podLogs, logsColorInversionService) {
/** @export {!Array<string>} Log set. */
this.logsSet = podLogs.logs;
/** @private {!./logs_service.LogColorInversionService} */
this.logsColorInversionService_ = logsColorInversionService;
/**
* Indicates color state of log area.
* If false: black text is placed on white area. Otherwise colors are inverted.
* @export
* @return {boolean}
*/
this.isTextColorInverted = function() { return this.logsColorInversionService_.getInverted(); };
}
/**
* Return proper style class for logs content.
* @export
* @returns {string}
*/
getStyleClass() {
const logsTextColor = 'kd-logs-text-color';
if (this.isTextColorInverted()) {
return `${logsTextColor}-invert`;
}
return `${logsTextColor}`;
}
}
// 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 stateConfig from './logs_state';
import {LogColorInversionService} from './logs_service';
/**
* Angular module for the logs view.
*
*/
export default angular.module(
'kubernetesDashboard.logs',
[
'ngResource',
'ui.router',
])
.service('logsColorInversionService', LogColorInversionService)
.config(stateConfig);
// 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.
/**
* Service class for logs colors management.
* @final
*/
export class LogColorInversionService {
/**
* @ngInject
*/
constructor() {
/** @private {boolean} */
this.inverted_ = false;
}
/**
* Getter for invertion flag.
* @return {boolean}
*/
getInverted() { return this.inverted_; }
/** Inverts the flag. */
invert() { this.inverted_ = !this.inverted_; }
}
// 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 {LogsController} from './logs_controller';
import LogsToolbarController from './logstoolbar/logstoolbar_controller';
import {toolbarViewName} from '../chrome/chrome_state';
/** Name of the state. Can be used in, e.g., $state.go method. */
export const stateName = 'logs';
/**
* Parameters for this state.
*
* All properties are @exported and in sync with URL param names.
* @final
*/
export class StateParams {
/**
* @param {string} namespace
* @param {string} replicaSet
* @param {string} podId
* @param {string} container
*/
constructor(namespace, replicaSet, podId, container) {
/** @export {string} Namespace of this Replica Set. */
this.namespace = namespace;
/** @export {string} Name of this Replica Set. */
this.replicaSet = replicaSet;
/** @export {string} Id of this Pod. */
this.podId = podId;
/** @export {string} Name of this pod container. */
this.container = container;
}
}
/**
* Configures states for the logs view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
let views = {
'': {
templateUrl: 'logs/logs.html',
controller: LogsController,
controllerAs: 'ctrl',
},
[toolbarViewName]: {
templateUrl: 'logs/logstoolbar/logstoolbar.html',
controller: LogsToolbarController,
controllerAs: 'ctrl',
},
};
$stateProvider.state(stateName, {
url: '/logs/:namespace/:replicaSet/:podId/:container',
resolve: {
'replicaSetPods': resolveReplicaSetPods,
'podLogs': resolvePodLogs,
},
views: views,
});
}
/**
* @param {!StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSetPods($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.ReplicaSetPods>} */
let resource = $resource('/api/replicasets/pods/:namespace/:replicaSet', $stateParams);
return resource.get().$promise;
}
/**
* @param {!StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolvePodLogs($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.Logs>} */
let resource = $resource('/api/logs/:namespace/:podId/:container', $stateParams);
return resource.get().$promise;
}
<!--
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.
-->
<div layout="row" layout-wrap layout-margin layout-align="center center">
<span flex="10"></span>
<div layout="row" layout-wrap layout-margin layout-align="center center">
<span>Logs from pod</span>
<span flex></span>
<md-select aria-label="Logs from pod" ng-model="ctrl.pod"
md-on-close="ctrl.onPodChange(ctrl.pod.name)"
required>
<md-option ng-repeat="item in ctrl.pods" ng-value="item">
{{item.name}}
</md-option>
</md-select>
<span>container</span>
<md-select aria-label="Containers" ng-model="ctrl.container"
md-on-close="ctrl.onContainerChange(ctrl.container.name)"
required>
<md-option ng-repeat="item in ctrl.containers" ng-value="item">
{{item.name}}
</md-option>
</md-select>
</div>
<span flex>Running since {{ctrl.podCreationTime}}</span>
<span flex></span>
<md-button class="kd-icon-button" id="colorText"
ng-click="ctrl.onTextColorChange()">
<md-icon md-font-library="material-icons"
ng-class=ctrl.getStyleClass()>
format_color_text
</md-icon>
</md-button>
</div>
// 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.
$logs-toolbar-color-black: #000;
$logs-toolbar-color-white: #fff;
.kd-logs-color-icon {
background-color: $logs-toolbar-color-black;
color: $logs-toolbar-color-white;
}
.kd-logs-color-icon-invert {
background-color: $logs-toolbar-color-white;
color: $logs-toolbar-color-black;
}
// This override styles to get white-black icon on toolbar
md-toolbar {
md-icon {
&.kd-logs-color-icon-invert {
color: $logs-toolbar-color-black;
}
}
}
// 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.
/**
* Controller for the logs view.
* @final
*/
export default class LogsToolbarController {
/**
* @param {!ui.router.$state} $state
* @param {!backendApi.ReplicaSetPods} replicaSetPods
* @param {!../logs_service.LogColorInversionService} logsColorInversionService
* @ngInject
*/
constructor($state, replicaSetPods, logsColorInversionService) {
/** @private {!ui.router.$state} */
this.state_ = $state;
// TODO(zreigz): should be StateParam but can not be import from logstoolbar_state. Issue 153.
/** @private {!Object.<string, string, string, string>|null} */
this.params = this.state_.params;
/**
* Service to notify logs controller if any changes on toolbar.
* @private {!../logs_service.LogColorInversionService}
*/
this.logsColorInversionService = logsColorInversionService;
/** @export {!Array<!backendApi.ReplicaSetPodWithContainers>} */
this.pods = replicaSetPods.pods || [];
/**
* Currently chosen pod.
* @export {!backendApi.ReplicaSetPodWithContainers|undefined}
*/
this.pod = this.findPodByName_(this.pods, this.params.podId);
/** @export {!Array<!backendApi.PodContainer>} */
this.containers = this.pod.podContainers || [];
/** @export {!backendApi.PodContainer|undefined} */
this.container = this.findContainerByName_(this.containers, this.params.container);
/**
* Pod creation time.
* @export {string}
*/
this.podCreationTime = new Date(Date.parse(this.pod.startTime)).toLocaleString();
/**
* Namespace.
* @private {string}
*/
this.namespace = this.params.namespace;
/**
* Replica Set name.
* @private {string}
*/
this.replicaSetName = this.params.replicaSet;
/**
* Indicates state of log area color.
* If false: black text is placed on white area. Otherwise colors are inverted.
* @export
* @return {boolean}
*/
this.isTextColorInverted = function() { return this.logsColorInversionService.getInverted(); };
}
/**
* Execute a code when a user changes the selected option of a pod element.
* @param {string} podId
* @return {string}
* @export
*/
onPodChange(podId) {
// TODO(zreigz): state name and StateParam can not be import from logstoolbar_state. Issue 153.
return this.state_.transitionTo("logs", {
namespace: this.namespace,
replicaSet: this.replicaSetName,
podId: podId,
container: this.container.name,
});
}
/**
* Execute a code when a user changes the selected option of a container element.
* @param {string} container
* @return {string}
* @export
*/
onContainerChange(container) {
// TODO(zreigz): state name and StateParam can not be import from logstoolbar_state. Issue 153.
return this.state_.transitionTo("logs", {
namespace: this.namespace,
replicaSet: this.replicaSetName,
podId: this.pod.name,
container: container,
});
}
/**
* Return proper style class for icon.
* @export
* @returns {string}
*/
getStyleClass() {
const logsTextColor = 'kd-logs-color-icon';
if (this.isTextColorInverted()) {
return `${logsTextColor}-invert`;
}
return `${logsTextColor}`;
}
/**
* Execute a code when a user changes the selected option for console color.
* @export
*/
onTextColorChange() { this.logsColorInversionService.invert(); }
/**
* Find Pod by name.
* Return object or undefined if can not find a object.
* @param {!Array<!backendApi.ReplicaSetPodWithContainers>} array
* @param {!string} name
* @return {!backendApi.ReplicaSetPodWithContainers|undefined}
* @private
*/
findPodByName_(array, name) { return array.find((element) => element.name === name); }
/**
* Find Container by name.
* Return object or undefined if can not find a object.
* @param {!Array<!backendApi.PodContainer>} array
* @param {!string} name
* @return {!backendApi.PodContainer|undefined}
* @private
*/
findContainerByName_(array, name) { return array.find((element) => element.name === name); }
}
......@@ -27,18 +27,21 @@ limitations under the License.
</md-menu-item>
<md-menu-item ng-repeat="pod in ctrl.replicaSetPodsList" class="kd-menu-logs-md-menu-item">
<div flex class="kd-menu-logs-item">{{pod.name | middleEllipsis:10}}</div>
<div flex="50" class="kd-menu-logs-item">
<a>
<div flex="50" class="kd-menu-logs-item" ng-if="ctrl.podContainerExists(pod)">
<a ng-href="{{::ctrl.getLogsHref(pod.name, pod.podContainers[0].name)}}">
{{pod.startTime}}<i
class="material-icons kd-menu-logs-link-icon">open_in_new</i>
</a>
</div>
<div flex class="kd-menu-logs-item" ng-if="pod.totalRestartCount != 0">
<div flex="50" class="kd-menu-logs-item" ng-if="!ctrl.podContainerExists(pod)">
-
</div>
<div flex class="kd-menu-logs-item" ng-if="ctrl.podContainersRestarted(pod)">
<a>
Logs<i class="material-icons kd-menu-logs-link-icon">open_in_new</i>
</a>
</div>
<div flex class="kd-menu-logs-item" ng-if="pod.totalRestartCount == 0">
<div flex class="kd-menu-logs-item" ng-if="!ctrl.podContainersRestarted(pod)">
-
</div>
</md-menu-item>
......
......@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {StateParams} from 'logs/logs_state';
import {stateName as logsStateName} from 'logs/logs_state';
/**
* Controller for the logs menu view.
*
......@@ -19,11 +22,15 @@
*/
export default class LogsMenuController {
/**
* @param {!ui.router.$state} $state
* @param {!angular.$log} $log
* @param {!angular.$resource} $resource
* @ngInject
*/
constructor($log, $resource) {
constructor($state, $log, $resource) {
/** @private {!ui.router.$state} */
this.state_ = $state;
/** @private {!angular.$resource} */
this.resource_ = $resource;
......@@ -80,4 +87,42 @@ export default class LogsMenuController {
},
(err) => { this.log_.error('Error fetching Replica Set pods: ', err); });
}
/**
* @param {string} podName
* @param {string} containerName
* @return {string}
* @export
*/
getLogsHref(podName, containerName) {
return this.state_.href(
logsStateName,
new StateParams(this.namespace, this.replicaSetName, podName, containerName));
}
/**
* Checks if pod contains at least one container. Return true if yes, otherwise false.
* @param {!backendApi.ReplicaSetPodWithContainers} pod
* @return {boolean}
* @export
*/
podContainerExists(pod) {
if (pod.podContainers[0].name === undefined) {
return false;
}
return true;
}
/**
* Checks if pod containers were restarted. Return true if yes, otherwise false.
* @param {backendApi.ReplicaSetPodWithContainers} pod
* @return {boolean}
* @export
*/
podContainersRestarted(pod) {
if (pod) {
return pod.totalRestartCount > 0;
}
return false;
}
}
// 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 {LogsController} from 'logs/logs_controller';
import LogsModule from 'logs/logs_module';
describe('Logs controller', () => {
/** @type {string} */
const logsTextColorClassName = 'kd-logs-text-color';
/** @type {!LogsController} */
let ctrl;
let podLogs = {
logs: [],
};
beforeEach(() => {
angular.mock.module(LogsModule.name);
angular.mock.inject(
($controller) => { ctrl = $controller(LogsController, {podLogs: podLogs}); });
});
it('should instantiate the controller properly', () => { expect(ctrl).not.toBeUndefined(); });
it('should return style class for logs content', () => {
// expect
expect(ctrl.getStyleClass()).toEqual(`${logsTextColorClassName}`);
});
});
// 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 LogsToolbarController from 'logs/logstoolbar/logstoolbar_controller';
import LogsModule from 'logs/logs_module';
import {StateParams} from 'logs/logs_state';
describe('Logs toolbar controller', () => {
/** @type {string} */
const iconColorClassName = 'kd-logs-color-icon';
/** @type {string} */
const mockNamespace = 'namespace';
/** @type {string} */
const mockReplicaSet = 'replicaSet';
/** @type {string} */
const mockPodId = 'pod2';
/** @type {string} */
const mockContainer = 'con22';
/** @type {!backendApi.PodContainer} */
const expectedContainer = {name: mockContainer};
/** @type {!backendApi.ReplicaSetPodWithContainers} */
const expectedPod = {name: mockPodId, podContainers: [{name: 'con21'}, expectedContainer]};
/** @type {!Array<!backendApi.ReplicaSetPodWithContainers>} */
const replicaSetPods = {
pods: [
{name: 'pod1', podContainers: [{name: 'con1'}]},
expectedPod,
{name: 'pod3', podContainers: [{name: 'con3'}]},
],
};
/** @type {!StateParams} */
const stateParams = new StateParams(mockNamespace, mockReplicaSet, mockPodId, mockContainer);
/**
* Logs menu controller.
* @type {!LogsToolbarController}
*/
let ctrl;
/** @type {!ui.router.$state} */
let state;
beforeEach(() => {
angular.mock.module(LogsModule.name);
angular.mock.inject(($controller, $state) => {
state = $state;
state.params = stateParams;
ctrl = $controller(LogsToolbarController, {replicaSetPods: replicaSetPods}, $state);
});
});
it('should instantiate the controller properly', () => { expect(ctrl).not.toBeUndefined(); });
it('should invert flag isTextColorInverted when onTextColorChange called', () => {
// before
expect(ctrl.isTextColorInverted()).toBeFalsy();
// when
ctrl.onTextColorChange();
// then
expect(ctrl.isTextColorInverted()).toBeTruthy();
});
it('should find objects (pod and container) by name passed in state params', () => {
// given
let resultPod = ctrl.pod;
let resulContainer = ctrl.container;
expect(resultPod).toEqual(expectedPod);
expect(resulContainer).toEqual(expectedContainer);
});
it('should call transitionTo on pod change', () => {
// given
spyOn(state, 'transitionTo');
// when
ctrl.onPodChange("pod3");
// then
expect(state.transitionTo).toHaveBeenCalled();
});
it('should call transitionTo on container change', () => {
// given
spyOn(state, 'transitionTo');
// when
ctrl.onContainerChange("container");
// then
expect(state.transitionTo).toHaveBeenCalled();
});
it('should return style class for icon', () => {
// expect
expect(ctrl.getStyleClass()).toEqual(`${iconColorClassName}`);
});
});
......@@ -22,6 +22,9 @@ describe('Logs menu controller', () => {
*/
let ctrl;
/** @type {!ui.router.$state} */
let state;
/**
* @type {!function()} mdOpenMenu
*/
......@@ -30,7 +33,10 @@ describe('Logs menu controller', () => {
beforeEach(() => {
angular.mock.module(replicaSetListModule.name);
angular.mock.inject(($controller) => { ctrl = $controller(LogsMenuController); });
angular.mock.inject(($controller, $state) => {
state = $state;
ctrl = $controller(LogsMenuController, $state);
});
});
it('should instantiate the controller properly', () => { expect(ctrl).not.toBeUndefined(); });
......@@ -56,4 +62,55 @@ describe('Logs menu controller', () => {
// then
expect(ctrl.replicaSetPodsList).toEqual([]);
});
it('should call href on log click', () => {
// given
spyOn(state, 'href');
// when
ctrl.getLogsHref("podName", "containerName");
// then
expect(state.href).toHaveBeenCalled();
});
it('should return false when pod does not have any container', () => {
// when
let pod = {
"podContainers": [{}],
};
// then
expect(ctrl.podContainerExists(pod)).toBeFalsy();
});
it('should return true when pod has one container', () => {
// when
let pod = {
"podContainers": [
{
"name": "php-redis",
},
],
};
// then
expect(ctrl.podContainerExists(pod)).toBeTruthy();
});
it('should return false when pod containers were not restarted', () => {
// when
let pod = {
"totalRestartCount": 0,
};
// then
expect(ctrl.podContainersRestarted(pod)).toBeFalsy();
});
it('should return true when pod containers were restarted', () => {
// when
let pod = {
"totalRestartCount": 1,
};
// then
expect(ctrl.podContainersRestarted(pod)).toBeTruthy();
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册