diff options
38 files changed, 2143 insertions, 122 deletions
diff --git a/.gitignore b/.gitignore index 348bcfd17..63ec65cb3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,8 @@ blackDuckHubProjectName.txt blackDuckHubProjectVersionName.txt vid-parent_bdio.jsonld *.iml -.idea/
\ No newline at end of file +.idea/ +target/ +vid-app-common/node/ +vid-app-common/package-lock.json +vid-webpack-master/package-lock.json
\ No newline at end of file diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/available-models-tree/available-models-tree.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/available-models-tree/available-models-tree.component.ts index 8790afa56..7e9b374d6 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/available-models-tree/available-models-tree.component.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/available-models-tree/available-models-tree.component.ts @@ -129,7 +129,7 @@ export class AvailableModelsTreeComponent { selectNode(node: ITreeNode): void { node.expand(); - this._sharedTreeService.setSelectedVNF(null); + this._sharedTreeService.setSelectedNF(null); this.highlightInstances.emit(node.data.modelUniqueId); if (FeatureFlagsService.getFlagState(Features.FLAG_1906_COMPONENT_INFO, this.store)) { const serviceHierarchy = this._store.getState().service.serviceHierarchy[this.serviceModelId]; @@ -179,8 +179,8 @@ export class AvailableModelsTreeComponent { positionOfNextInstance = this._defaultDataGeneratorService.calculatePositionOfVfmodule(this.serviceModelId); } } - if (this._sharedTreeService.selectedVNF) { - this.store.dispatch(createVFModuleInstance(vfModule, node.data.name, this.serviceModelId, positionOfNextInstance, this._sharedTreeService.selectedVNF)); + if (this._sharedTreeService.selectedNF) { + this.store.dispatch(createVFModuleInstance(vfModule, node.data.name, this.serviceModelId, positionOfNextInstance, this._sharedTreeService.selectedNF)); DrawingBoardTreeService.triggerCheckIsDirty.next(this.serviceModelId); } else if (this._availableModelsTreeService.getOptionalVNFs(this.serviceModelId, node.parent.data.modelUniqueId).length === 1) { let existVnf = this._store.getState().service.serviceInstance[this.serviceModelId].vnfs; diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts index 7526970d3..6998d6ad5 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts @@ -231,7 +231,7 @@ export class DrawingBoardTreeComponent implements OnInit, AfterViewInit { public selectNode(node: ITreeNode): void { node.expand(); - this._sharedTreeService.setSelectedVNF(node); + this._sharedTreeService.setSelectedNF(node); this.highlightNode.emit(node.data.modelUniqueId); if (FeatureFlagsService.getFlagState(Features.FLAG_1906_COMPONENT_INFO, this.store)) { const serviceHierarchy = this._store.getState().service.serviceHierarchy[this.serviceModelId]; diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts index ce1af451c..b01c79613 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts @@ -215,7 +215,7 @@ export class NetworkModelInfo implements ILevelNodeInfo { let storeKey: string = node.data.networkStoreKey; this._store.dispatch(removeInstance(node.data.networkStoreKey, serviceModelId, storeKey, node)); this._store.dispatch(changeInstanceCounter(node.data.modelUniqueId, serviceModelId, -1, node)); - this._sharedTreeService.selectedVNF = null; + this._sharedTreeService.selectedNF = null; }, visible: (node) => node.data.parentType !== 'VRF' && this._sharedTreeService.shouldShowRemoveAndEdit(node), enable: (node) => node.data.parentType !== 'VRF' && this._sharedTreeService.shouldShowRemoveAndEdit(node), diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.extended.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.extended.spec.ts new file mode 100644 index 000000000..7e7a6fc1d --- /dev/null +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.extended.spec.ts @@ -0,0 +1,597 @@ +import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing"; +import {getTestBed, TestBed} from "@angular/core/testing"; +import {MockNgRedux, NgReduxTestingModule} from "@angular-redux/store/testing"; +import {PnfModelInfoExtended} from "./pnf.model.info.extended"; +import {DynamicInputsService} from "../../dynamicInputs.service"; +import {SharedTreeService} from "../../shared.tree.service"; +import {NgRedux} from "@angular-redux/store"; +import {AppState} from "../../../../../shared/store/reducers"; +import {DefaultDataGeneratorService} from "../../../../../shared/services/defaultDataServiceGenerator/default.data.generator.service"; +import {DialogService} from "ng2-bootstrap-modal"; +import {DuplicateService} from "../../../duplicate/duplicate.service"; +import {IframeService} from "../../../../../shared/utils/iframe.service"; +import {ComponentInfoService} from "../../../component-info/component-info.service"; +import {AaiService} from "../../../../../shared/services/aaiService/aai.service"; +import {HttpClient, HttpHandler} from "@angular/common/http"; +import {FeatureFlagsService} from "../../../../../shared/services/featureFlag/feature-flags.service"; +import {PnfPopupService} from "../../../../../shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service"; +import {DrawingBoardModes} from "../../../drawing-board.modes"; +import {ServiceInstanceActions} from "../../../../../shared/models/serviceInstanceActions"; +import {PNFModel} from "../../../../../shared/models/pnfModel"; +import {AvailableNodeIcons} from "../../../available-models-tree/available-models-tree.service"; + +class MockFeatureFlagsService extends FeatureFlagsService { + getAllFlags(): { [p: string]: boolean } { + return {}; + } +} + +class NodeBuilder { + static getPnfNode() { + return this.getPnfNodeWithAction(ServiceInstanceActions.None); + } + + static getPnfNodeWithAction(action: ServiceInstanceActions) { + return { + data: { + "action": action, + "pnfStoreKey": "PNF_KEY", + "children": null, + "name": "pnfName", + "modelUniqueId": "modelCustomizationId", + "menuActions": { + "delete": "", + "undoDelete": "" + } + }, + children: null, + type: 'PNF' + }; + } +} + +describe('Pnf Model Info Extended', () => { + let injector; + let _dynamicInputsService: DynamicInputsService; + let _sharedTreeService: SharedTreeService; + let _dialogService: DialogService; + let _pnfPopupService: PnfPopupService; + let _duplicateService: DuplicateService; + let _iframeService: IframeService; + let _featureFlagsService: FeatureFlagsService; + let _store: NgRedux<AppState>; + let pnfModelExtended: PnfModelInfoExtended; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, NgReduxTestingModule], + providers: [ + MockNgRedux, + DynamicInputsService, + DialogService, + PnfPopupService, + DefaultDataGeneratorService, + SharedTreeService, + DuplicateService, + AaiService, + HttpClient, + HttpHandler, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, + ComponentInfoService, + IframeService] + }).compileComponents(); + + injector = getTestBed(); + _sharedTreeService = injector.get(SharedTreeService); + _store = injector.get(NgRedux); + _featureFlagsService = injector.get(FeatureFlagsService); + + pnfModelExtended = new PnfModelInfoExtended( + _store, + _sharedTreeService, + _dialogService, + _pnfPopupService, + _iframeService, + _duplicateService, + null, + _dynamicInputsService); + }); + + test('pnfModelExtended should be defined', () => { + expect(pnfModelExtended).toBeDefined(); + }); + + test('getMenuAction: edit should not be visible when mode is null and actions is "None"', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: {} + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['edit']).toBeDefined(); + expect(menuActions['edit'].visible(node)).toBeFalsy(); + expect(menuActions['edit'].enable(node)).toBeFalsy(); + }); + + test('getMenuAction: edit should be visible when mode is null and action is "Create"', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: {} + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.Create); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['edit']).toBeDefined(); + expect(menuActions['edit'].visible(node)).toBeTruthy(); + expect(menuActions['edit'].enable(node)).toBeTruthy(); + }); + + test('getMenuAction: edit should be visible when mode is "RETRY" and action is "Create"', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.RETRY + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.Create); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['edit']).toBeDefined(); + expect(menuActions['edit'].visible(node)).toBeFalsy(); + expect(menuActions['edit'].enable(node)).toBeFalsy(); + }); + + test('getMenuAction: showAuditInfo should be visible when mode is "RETRY"', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.RETRY + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.Create); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['showAuditInfo']).toBeDefined(); + expect(menuActions['showAuditInfo'].visible(node)).toBeTruthy(); + expect(menuActions['showAuditInfo'].enable(node)).toBeTruthy(); + }); + + test('getMenuAction: showAuditInfo should not be visible when mode is not "RETRY" and action is "CREATE"', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.EDIT + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.Create); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['showAuditInfo']).toBeDefined(); + expect(menuActions['showAuditInfo'].visible(node)).toBeFalsy(); + expect(menuActions['showAuditInfo'].enable(node)).toBeFalsy(); + }); + + test('getMenuAction: remove should dispatch 2 actions with proper data', () => { + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + spyOn(_store, 'dispatch'); + menuActions['remove'].method(node, serviceModelId); + + expect(_store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "REMOVE_INSTANCE", + storeKey: "PNF_KEY" + })); + expect(_store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "CHANGE_INSTANCE_COUNTER", + changeBy: -1 + })); + }); + + test('getMenuAction: remove should not dispatch actions when node has children', () => { + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + node.data.children = [ + {"not": "empty"} + ]; + + spyOn(_store, 'dispatch'); + menuActions['remove'].method(node, serviceModelId); + + expect(_store.dispatch).not.toHaveBeenCalledWith(jasmine.objectContaining({ + type: "REMOVE_INSTANCE", + storeKey: "PNF_KEY" + })); + expect(_store.dispatch).not.toHaveBeenCalledWith(jasmine.objectContaining({ + type: "CHANGE_INSTANCE_COUNTER", + changeBy: -1 + })); + }); + + test('getMenuAction: delete should dispatch delete action', () => { + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + spyOn(_store, 'dispatch'); + menuActions['delete'].method(node, serviceModelId); + + expect(_store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "DELETE_PNF_INSTANCE", + storeKey: "PNF_KEY" + })); + }); + + test('getMenuAction: delete should show modal when node has children', () => { + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + node.data.children = [ + {"not": "empty"} + ]; + + spyOn(_sharedTreeService, 'shouldShowDeleteInstanceWithChildrenModal'); + menuActions['delete'].method(node, serviceModelId); + + expect(_sharedTreeService.shouldShowDeleteInstanceWithChildrenModal).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "PNF" + }), jasmine.anything(), jasmine.anything()); + }); + + test('getMenuAction: delete should not be visible when service isMacro', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.EDIT + }, + service: { + serviceInstance: { + "d6557200-ecf2-4641-8094-5393ae3aae60": { + isALaCarte: false + } + } + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['delete']).toBeDefined(); + expect(menuActions['delete'].visible(node)).toBeFalsy(); + expect(menuActions['delete'].enable(node)).toBeFalsy(); + }); + + test('getMenuAction: delete should not be visible when service is aLaCarte and Action is Create', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.EDIT + }, + service: { + serviceInstance: { + "d6557200-ecf2-4641-8094-5393ae3aae60": { + isALaCarte: true + } + } + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.Create); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['delete']).toBeDefined(); + expect(menuActions['delete'].visible(node)).toBeFalsy(); + expect(menuActions['delete'].enable(node)).toBeFalsy(); + }); + + test('getMenuAction: delete should be visible when service is aLaCarte and Action is None', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.EDIT + }, + service: { + serviceInstance: { + "d6557200-ecf2-4641-8094-5393ae3aae60": { + isALaCarte: true + } + } + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['delete']).toBeDefined(); + expect(menuActions['delete'].visible(node)).toBeTruthy(); + expect(menuActions['delete'].enable(node)).toBeTruthy(); + }); + + test('getMenuAction: undo delete should dispatch undo delete action when no children', () => { + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + spyOn(_store, 'dispatch'); + menuActions['undoDelete'].method(node, serviceModelId); + + expect(_store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "UNDO_DELETE_PNF_INSTANCE", + storeKey: "PNF_KEY" + })); + }); + + test('getMenuAction: undo delete should iterate over children when they exist', () => { + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None); + node.data.children = [ + {"not": "empty"} + ]; + node.children = node.data.children; + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + spyOn(_store, 'dispatch'); + menuActions['undoDelete'].method(node, serviceModelId); + + expect(_store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "UNDO_DELETE_PNF_INSTANCE", + storeKey: "PNF_KEY" + })); + }); + + test('getMenuAction: undo delete should not be visible when action is Create or Delete', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.EDIT + }, + service: { + serviceInstance: { + "d6557200-ecf2-4641-8094-5393ae3aae60": {} + } + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.Create); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['undoDelete']).toBeDefined(); + expect(menuActions['undoDelete'].visible(node)).toBeFalsy(); + expect(menuActions['undoDelete'].enable(node)).toBeFalsy(); + }); + + test('getMenuAction: undo delete should be visible when action is contains "*_Delete"', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.EDIT + }, + service: { + serviceInstance: { + "d6557200-ecf2-4641-8094-5393ae3aae60": { + action: ServiceInstanceActions.None + } + } + } + }); + + let node = NodeBuilder.getPnfNodeWithAction(ServiceInstanceActions.None_Delete); + let serviceModelId = "d6557200-ecf2-4641-8094-5393ae3aae60"; + let menuActions = pnfModelExtended.getMenuAction(<any>node, serviceModelId); + + expect(menuActions['undoDelete']).toBeDefined(); + expect(menuActions['undoDelete'].visible(node)).toBeTruthy(); + expect(menuActions['undoDelete'].enable(node, serviceModelId)).toBeTruthy(); + }); + + test('getModel should return PNF model', () => { + expect(pnfModelExtended.getModel({})).toBeInstanceOf(PNFModel); + }); + + test('getNextLevelObject should return null as there are no childs expected in PNF for now', () => { + expect(pnfModelExtended.getNextLevelObject()).toBeNull(); + }); + + test('getNodeCount should return counter of 0 when existingPNFCounterMap doesnt exist', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: {}, + service: { + serviceInstance: { + 'd6557200-ecf2-4641-8094-5393ae3aae60': {} + } + } + }); + + let serviceId: string = 'd6557200-ecf2-4641-8094-5393ae3aae60'; + let node = NodeBuilder.getPnfNode(); + let result = pnfModelExtended.getNodeCount(<any>node, serviceId); + jest.spyOn(_sharedTreeService, 'getExistingInstancesWithDeleteMode').mockReturnValue(0); + + expect(result).toEqual(0); + }); + + test('getNodeCount should return counter of 1 when one node exists and no nodes in delete mode', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: {}, + service: { + serviceInstance: { + 'd6557200-ecf2-4641-8094-5393ae3aae60': { + 'existingPNFCounterMap': { + 'modelCustomizationId': 1 + } + } + } + } + }); + + let serviceId: string = 'd6557200-ecf2-4641-8094-5393ae3aae60'; + let node = NodeBuilder.getPnfNode(); + let result = pnfModelExtended.getNodeCount(<any>node, serviceId); + jest.spyOn(_sharedTreeService, 'getExistingInstancesWithDeleteMode').mockReturnValue(0); + + expect(result).toEqual(1); + }); + + test('getNodeCount should return counter of 2 when three nodes exist and one node is in delete mode', () => { + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: {}, + service: { + serviceInstance: { + 'd6557200-ecf2-4641-8094-5393ae3aae60': { + 'existingPNFCounterMap': { + 'modelCustomizationId': 3 + } + } + } + } + }); + + jest.spyOn(_sharedTreeService, 'getExistingInstancesWithDeleteMode').mockReturnValue(1); + let serviceId: string = 'd6557200-ecf2-4641-8094-5393ae3aae60'; + let node = NodeBuilder.getPnfNode(); + let result = pnfModelExtended.getNodeCount(<any>node, serviceId); + + expect(result).toEqual(2); + }); + + test('getTooltip should return "PNF"', () => { + expect(pnfModelExtended.getTooltip()).toEqual('PNF'); + }); + + test('getType should return "PNF"', () => { + expect(pnfModelExtended.getType()).toEqual('PNF'); + }); + + test('isEcompGeneratedNaming should return true if isEcompGeneratedNaming is "true" ', () => { + let isEcompGeneratedNaming: boolean = pnfModelExtended.isEcompGeneratedNaming(<any>{ + properties: { + ecomp_generated_naming: 'true' + } + }); + expect(isEcompGeneratedNaming).toBeTruthy(); + }); + + test('isEcompGeneratedNaming should return false if isEcompGeneratedNaming is not defined', () => { + let isEcompGeneratedNaming: boolean = pnfModelExtended.isEcompGeneratedNaming({ + properties: {} + }); + expect(isEcompGeneratedNaming).toBeFalsy(); + }); + + test('showNodeIcons should return false if reached limit of instances', () => { + let serviceId: string = 'servicedId'; + let node = NodeBuilder.getPnfNode(); + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: {}, + service: { + serviceHierarchy: { + 'servicedId': { + 'pnfs': { + modelCustomizationId: "modelCustomizationId", + 'modelInfo': { + modelCustomizationId: "modelCustomizationId" + }, + 'pnfName': { + 'properties': { + 'max_instances': 1 + } + } + } + } + }, + serviceInstance: { + 'servicedId': { + 'existingPNFCounterMap': { + 'modelCustomizationId': 1 + }, + 'pnfs': { + 'pnfName': {} + } + } + } + } + }); + + let result = pnfModelExtended.showNodeIcons(<any>node, serviceId); + expect(result).toEqual(new AvailableNodeIcons(false, true)); + }); + + test('showNodeIcons should return true if limit of instances is not reached', () => { + let serviceId: string = 'servicedId'; + let node = NodeBuilder.getPnfNode(); + jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ + global: { + drawingBoardStatus: DrawingBoardModes.EDIT + }, + service: { + serviceHierarchy: { + 'servicedId': { + 'pnfs': { + modelCustomizationId: "modelCustomizationId", + 'modelInfo': { + modelCustomizationId: "modelCustomizationId" + }, + 'pnfName': { + 'properties': { + 'max_instances': 2 + } + } + } + } + }, + serviceInstance: { + 'servicedId': { + 'existingPNFCounterMap': { + 'modelCustomizationId': 1 + }, + 'pnfs': { + 'pnfName': {} + } + } + } + } + }); + + let result = pnfModelExtended.showNodeIcons(<any>node, serviceId); + expect(result).toEqual(new AvailableNodeIcons(true, false)); + }); + + test('hasMissingData returns true instanceName is empty and ecompNameGenerating is off ', () => { + let instance = { + instanceName: "", + platformName: "platformName" + } + + let result = pnfModelExtended.hasMissingData(instance, [], false); + + expect(result).toBeTruthy(); + }); + + test('hasMissingData returns true when at least one required field is empty ', () => { + let instance = { + platformName: "" + } + + let result = pnfModelExtended.hasMissingData(instance, [], true); + + expect(result).toBeTruthy(); + }); + + test('hasMissingData returns false when there is no missing data', () => { + let instance = { + platformName: "platformName" + } + + let result = pnfModelExtended.hasMissingData(instance, [], true); + + expect(result).toBeFalsy(); + }); + +}); diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.extended.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.extended.ts index e2e31e904..3c3f09b5d 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.extended.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.extended.ts @@ -3,7 +3,6 @@ import {ComponentInfoType} from "../../../component-info/component-info-model"; import {ModelInformationItem} from "../../../../../shared/components/model-information/model-information.component"; import {ITreeNode} from "angular-tree-component/dist/defs/api"; import {AvailableNodeIcons} from "../../../available-models-tree/available-models-tree.service"; - import {PNFModel} from "../../../../../shared/models/pnfModel"; import {SharedTreeService} from "../../shared.tree.service"; import * as _ from "lodash"; @@ -17,19 +16,35 @@ import { import {DialogService} from "ng2-bootstrap-modal"; import {PnfPopupService} from "../../../../../shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service"; import {PnfTreeNode} from "../../../../../shared/models/pnfTreeNode"; +import {changeInstanceCounter, removeInstance} from "../../../../../shared/storeUtil/utils/general/general.actions"; +import {MessageBoxData} from "../../../../../shared/components/messageBox/messageBox.data"; +import {MessageBoxService} from "../../../../../shared/components/messageBox/messageBox.service"; +import {IframeService} from "../../../../../shared/utils/iframe.service"; +import {DuplicateService} from "../../../duplicate/duplicate.service"; +import {ModalService} from "../../../../../shared/components/customModal/services/modal.service"; +import { + deleteActionPnfInstance, + undoDeleteActionPnfInstance, + updatePnfPosition +} from "../../../../../shared/storeUtil/utils/pnf/pnf.actions"; +import {DynamicInputsService} from "../../dynamicInputs.service"; +import {InputType} from "../../../../../shared/models/inputTypes"; - -export class PnfModelInfoExtended implements ILevelNodeInfo{ +export class PnfModelInfoExtended implements ILevelNodeInfo { constructor( private _store: NgRedux<AppState>, private _sharedTreeService: SharedTreeService, private _dialogService: DialogService, - private _pnfPopupService: PnfPopupService - ){} + private _pnfPopupService: PnfPopupService, + private _iframeService: IframeService, + private _duplicateService: DuplicateService, + private modalService: ModalService, + private _dynamicInputsService: DynamicInputsService + ) {} name: string = 'pnfs'; - type: string ='PNF'; + type: string = 'PNF'; typeName: string = 'PNF'; childNames: string[]; componentInfoType = ComponentInfoType.PNF; @@ -60,15 +75,109 @@ export class PnfModelInfoExtended implements ILevelNodeInfo{ return _.uniq(_.flatten(result)); } - getMenuAction(node: ITreeNode, serviceModelId: string): { [methodName: string]: { method: Function; visible: Function; enable: Function } } { - return {}; + getMenuAction(node: ITreeNode, serviceModelId: string): { [methodName: string]: { method: Function, visible: Function, enable: Function } } { + return <any>{ + edit: { + method: (node, serviceModelId) => { + this._iframeService.addClassOpenModal('content'); + this._dialogService.addDialog(GenericFormPopupComponent, { + type: PopupType.PNF, + uuidData: <any>{ + serviceId: serviceModelId, + modelName: node.data.modelName, + pnfStoreKey: node.data.pnfStoreKey, + modelId: node.data.modelId, + type: node.data.type, + popupService: this._pnfPopupService + }, + node: node, + isUpdateMode: true + }); + }, + visible: (node) => this._sharedTreeService.shouldShowRemoveAndEdit(node), + enable: (node) => this._sharedTreeService.shouldShowRemoveAndEdit(node), + }, + showAuditInfo: { + method: (node, serviceModelId) => { + const instance = this._store.getState().service.serviceInstance[serviceModelId].pnfs[node.data.pnfStoreKey]; + this._sharedTreeService.openAuditInfoModal(node, serviceModelId, instance, 'PNF', this); + }, + visible: (node) => this._sharedTreeService.shouldShowAuditInfo(node), + enable: (node) => this._sharedTreeService.shouldShowAuditInfo(node) + }, + remove: { + method: (node, serviceModelId) => { + if ((!_.isNil(node.data.children) && node.data.children.length === 0) || _.isNil(node.data.children)) { + let storeKey: string = node.data.pnfStoreKey; + this._store.dispatch(removeInstance(node.data.pnfStoreKey, serviceModelId, storeKey, node)); + this._store.dispatch(changeInstanceCounter(node.data.modelUniqueId, serviceModelId, -1, node)); + this._sharedTreeService.selectedNF = null; + } else { + let messageBoxData: MessageBoxData = new MessageBoxData( + "Remove PNF", // modal title + "You are about to remove this PNF from this service. Are you sure you want to remove it?", + <any>"warning", + <any>"md", + [ + { + text: "Remove PNF", + size: "large", + callback: this.removePnf.bind(this, node, serviceModelId), + closeModal: true + }, + {text: "Don’t Remove", size: "medium", closeModal: true} + ]); + + MessageBoxService.openModal.next(messageBoxData); + } + }, + visible: (node) => this._sharedTreeService.shouldShowRemoveAndEdit(node), + enable: (node) => this._sharedTreeService.shouldShowRemoveAndEdit(node), + }, + delete: { + method: (node, serviceModelId) => { + if ((!_.isNil(node.data.children) && node.data.children.length === 0) || _.isNil(node.data.children)) { + this._store.dispatch(deleteActionPnfInstance(node.data.pnfStoreKey, serviceModelId)); + } else { + this._sharedTreeService.shouldShowDeleteInstanceWithChildrenModal(node, serviceModelId, (node, serviceModelId) => { + this._sharedTreeService.removeDeleteAllChild(node, serviceModelId, (node, serviceModelId) => { + this._store.dispatch(deleteActionPnfInstance(node.data.pnfStoreKey, serviceModelId)); + }); + }); + } + }, + visible: (node) => this._sharedTreeService.shouldShowDelete(node, serviceModelId), + enable: (node) => this._sharedTreeService.shouldShowDelete(node, serviceModelId) + }, + undoDelete: { + method: (node, serviceModelId) => { + if ((!_.isNil(node.data.children) && node.data.children.length === 0) || _.isNil(node.data.children)) { + this._store.dispatch(undoDeleteActionPnfInstance(node.data.pnfStoreKey, serviceModelId)); + } else { + this._sharedTreeService.undoDeleteAllChild(node, serviceModelId, (node, serviceModelId) => { + this._store.dispatch(undoDeleteActionPnfInstance(node.data.pnfStoreKey, serviceModelId)); + }); + } + }, + visible: (node) => this._sharedTreeService.shouldShowUndoDelete(node), + enable: (node, serviceModelId) => this._sharedTreeService.shouldShowUndoDelete(node) && !this._sharedTreeService.isServiceOnDeleteMode(serviceModelId) + } + } + } + + removePnf(this, node, serviceModelId) { + this._store.dispatch(removeInstance(node.data.modelName, serviceModelId, node.data.pnfStoreKey, node)); + this._store.dispatch(changeInstanceCounter(node.data.modelUniqueId, serviceModelId, -1, node)); + this._sharedTreeService.selectedNF = null; } getModel = (instanceModel: any): PNFModel => { return new PNFModel(instanceModel); }; - getNextLevelObject(): any { return null; } + getNextLevelObject(): any { + return null; + } getNodeCount(node: ITreeNode, serviceModelId: string): number { let map = null; @@ -90,17 +199,20 @@ export class PnfModelInfoExtended implements ILevelNodeInfo{ getTooltip = (): string => 'PNF'; - getType = (): string => 'PNF'; - hasMissingData(instance, dynamicInputs: any, isEcompGeneratedNaming: boolean): boolean { - return false; + return this._sharedTreeService.hasMissingData(instance, dynamicInputs, isEcompGeneratedNaming, [InputType.PLATFORM]); } - isEcompGeneratedNaming(currentModel): boolean { - return false; - } + /*********************************************************** + * return if user should provide instance name or not. + * @param currentModel - current Model object + ************************************************************/ + isEcompGeneratedNaming = (currentModel): boolean => { + const ecompGeneratedNaming = currentModel.properties.ecomp_generated_naming; + return ecompGeneratedNaming === "true"; + }; onClickAdd(node, serviceModelId: string): void { this._dialogService.addDialog(GenericFormPopupComponent, { @@ -130,9 +242,12 @@ export class PnfModelInfoExtended implements ILevelNodeInfo{ return new AvailableNodeIcons(showAddIcon, isReachedLimit) } - updateDynamicInputsDataFromModel = (currentModel): any => []; + updateDynamicInputsDataFromModel = (currentModel): any => { + let displayInputs = _.isNil(currentModel) ? [] : currentModel.inputs; + return _.isEmpty(displayInputs) ? [] : this._dynamicInputsService.getArbitraryInputs(displayInputs); + }; updatePosition(that, node, instanceId): void { + that.store.dispatch(updatePnfPosition(node, instanceId, node.vnfStoreKey)); } - } diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.spec.ts index 8675d36f2..150069db4 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/pnf/pnf.model.info.spec.ts @@ -12,9 +12,7 @@ import {IframeService} from "../../../../../shared/utils/iframe.service"; import {HttpClientTestingModule} from "@angular/common/http/testing"; import {MockNgRedux, NgReduxTestingModule} from "@angular-redux/store/testing"; import {HttpClient, HttpHandler} from "@angular/common/http"; -import {CollectionResourceModel} from "../../../../../shared/models/collectionResourceModel"; import {ComponentInfoType} from "../../../component-info/component-info-model"; -import {VNFModel} from "../../../../../shared/models/vnfModel"; import {PNFModel} from "../../../../../shared/models/pnfModel"; diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts index 42ee238d0..dd6bb5027 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts @@ -197,7 +197,7 @@ describe('VFModule Model Info', () => { name : 'vnfName' } }; - _sharedTreeService.setSelectedVNF({ + _sharedTreeService.setSelectedNF({ data : { id : 'vfModuleId', name : 'VfModuleName' @@ -250,7 +250,7 @@ describe('VFModule Model Info', () => { } } }; - jest.spyOn(_sharedTreeService, 'getSelectedVNF').mockReturnValue('vnfName'); + jest.spyOn(_sharedTreeService, 'getSelectedNF').mockReturnValue('vnfName'); jest.spyOn(_sharedTreeService, 'modelUniqueId').mockReturnValue('vnfCustomizationId'); jest.spyOn(vfModuleModel, 'getOptionalVNFs').mockReturnValue([{vnfStoreKey: 'vnfName'}]); jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ @@ -535,7 +535,7 @@ describe('VFModule Model Info', () => { } } }); - jest.spyOn(_sharedTreeService, 'getSelectedVNF').mockReturnValue('vnfName_1'); + jest.spyOn(_sharedTreeService, 'getSelectedNF').mockReturnValue('vnfName_1'); let node = { data : { @@ -557,7 +557,7 @@ describe('VFModule Model Info', () => { test('onClickAdd should open message box if no vnfStoreKey', ()=>{ - jest.spyOn(_sharedTreeService, 'getSelectedVNF').mockReturnValue(null); + jest.spyOn(_sharedTreeService, 'getSelectedNF').mockReturnValue(null); jest.spyOn(vfModuleModel, 'getDefaultVNF').mockReturnValue(null); jest.spyOn(MessageBoxService.openModal, 'next'); vfModuleModel.onClickAdd(<any>{}, 'serviceId'); diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts index 72b3c398e..a6d4e98bd 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts @@ -146,7 +146,7 @@ export class VFModuleModelInfo implements ILevelNodeInfo { * @param serviceModelId - current service id ************************************************************/ onClickAdd(node: ITreeNode, serviceModelId: string): void { - const vnfStoreKey = this._sharedTreeService.getSelectedVNF() || this.getDefaultVNF(node.parent, serviceModelId); + const vnfStoreKey = this._sharedTreeService.getSelectedNF() || this.getDefaultVNF(node.parent, serviceModelId); if (vnfStoreKey) { this._dialogService.addDialog(GenericFormPopupComponent, { type: PopupType.VF_MODULE, @@ -191,7 +191,7 @@ export class VFModuleModelInfo implements ILevelNodeInfo { const vnfs = this._store.getState().service.serviceInstance[serviceModelId].vnfs; let count: number = 0; if (!_.isNil(this._store.getState().service.serviceInstance) && !_.isNil(this._store.getState().service.serviceInstance[serviceModelId])) { - const selectedVNF: string = this._sharedTreeService.getSelectedVNF(); + const selectedVNF: string = this._sharedTreeService.getSelectedNF(); if (selectedVNF) { count += this.countNumberOfVFModule(vnfs[selectedVNF], node); }else { @@ -235,7 +235,7 @@ export class VFModuleModelInfo implements ILevelNodeInfo { * @param serviceModelId - service id ************************************************************/ showNodeIcons(node: ITreeNode, serviceModelId: string): AvailableNodeIcons { - const selectedVNF: string = this._sharedTreeService.getSelectedVNF(); + const selectedVNF: string = this._sharedTreeService.getSelectedNF(); if (selectedVNF) { return this.showVFModuleOnSelectedVNF(node, selectedVNF, serviceModelId); } else { diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts index d391f4a48..56a53916d 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts @@ -235,7 +235,7 @@ export class VnfModelInfo implements ILevelNodeInfo { let storeKey: string = node.data.vnfStoreKey; this._store.dispatch(removeInstance(node.data.vnfStoreKey, serviceModelId, storeKey, node)); this._store.dispatch(changeInstanceCounter(node.data.modelUniqueId, serviceModelId, -1, node)); - this._sharedTreeService.selectedVNF = null; + this._sharedTreeService.selectedNF = null; } else { let messageBoxData: MessageBoxData = new MessageBoxData( "Remove VNF", // modal title @@ -306,7 +306,7 @@ export class VnfModelInfo implements ILevelNodeInfo { removeVnf(this, node, serviceModelId) { this._store.dispatch(removeInstance(node.data.modelName, serviceModelId, node.data.vnfStoreKey, node)); this._store.dispatch(changeInstanceCounter(node.data.modelUniqueId, serviceModelId, -1, node)); - this._sharedTreeService.selectedVNF = null; + this._sharedTreeService.selectedNF = null; } /*********************************************************** diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnfGrouping/vnfGrouping.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnfGrouping/vnfGrouping.model.info.ts index 2787c6174..64b35a56e 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnfGrouping/vnfGrouping.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnfGrouping/vnfGrouping.model.info.ts @@ -170,7 +170,7 @@ export class VnfGroupingModelInfo implements ILevelNodeInfo { let storeKey: string = node.data.vnfGroupStoreKey; this._store.dispatch(removeInstance(node.data.vnfGroupStoreKey, serviceModelId, storeKey, node)); this._store.dispatch(changeInstanceCounter(node.data.modelUniqueId, serviceModelId, -1, node)); - this._sharedTreeService.selectedVNF = null; + this._sharedTreeService.selectedNF = null; } else { let messageBoxData: MessageBoxData = new MessageBoxData( "Remove VNFGroup", // modal title @@ -386,7 +386,7 @@ export class VnfGroupingModelInfo implements ILevelNodeInfo { removeGroup(this, node, serviceModelId) { this._store.dispatch(removeInstance(node.data.modelName, serviceModelId, node.data.vnfGroupStoreKey, node)); this._store.dispatch(changeInstanceCounter(node.data.modelUniqueId, serviceModelId, -1, node)); - this._sharedTreeService.selectedVNF = null; + this._sharedTreeService.selectedNF = null; } updatePosition(that, node, instanceId): void { diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrfModal/vpnStep/vpn.step.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrfModal/vpnStep/vpn.step.service.ts index 5523cf1ff..c706f24a2 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrfModal/vpnStep/vpn.step.service.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrfModal/vpnStep/vpn.step.service.ts @@ -22,7 +22,7 @@ import { clearAssociateVRFMemberInstance, createVrfInstance } from "../../../../../../../shared/storeUtil/utils/vrf/vrf.actions"; -import {calculateNextUniqueModelName} from "../../../../../../../shared/storeUtil/utils/vnf/vnf.reducers"; +import {calculateNextUniqueModelName} from "../../../../../../../shared/storeUtil/utils/reducersHelper"; @Injectable() export class VpnStepService { diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.spec.ts index 32b8d6bac..25d52b400 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.spec.ts @@ -37,6 +37,7 @@ import {SharedControllersService} from "../../../../shared/components/genericFor import {ModalService} from "../../../../shared/components/customModal/services/modal.service"; import {CreateDynamicComponentService} from "../../../../shared/components/customModal/services/create-dynamic-component.service"; import {PnfPopupService} from "../../../../shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service"; +import {PnfControlGenerator} from "../../../../shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator"; class MockAppStore<T> { getState() { @@ -86,6 +87,7 @@ describe('Model Tree Generator service', () => { DialogService, FeatureFlagsService, VnfControlGenerator, + PnfControlGenerator, AaiService, DialogService, ErrorMsgService, diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.ts index cabf80664..ca54f5fc8 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToInstanceTree/objectToInstanceTree.service.ts @@ -37,7 +37,7 @@ export class ObjectToInstanceTreeService { this.numberOfElements = 0; let _this = this; const serviceModelId:string = serviceInstance.modelInfo.modelVersionId; - const firstLevelOptions: ILevelNodeInfo[] = _this._objectToTreeService.getFirstLevelOptions(serviceInstance.isAlaCarte); + const firstLevelOptions: ILevelNodeInfo[] = _this._objectToTreeService.getFirstLevelOptions(serviceInstance.isALaCarte); for (let option of firstLevelOptions) { _.forOwn(serviceInstance[option.name], function (instance, modelName) { nodes.push(_this.getNodeInstance(modelName, null, instance, serviceHierarchy, option, serviceModelId)); diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.spec.ts index 8d4dbc4bb..64fdae1c0 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.spec.ts @@ -40,6 +40,7 @@ import {SharedControllersService} from "../../../../shared/components/genericFor import {ModalService} from "../../../../shared/components/customModal/services/modal.service"; import {CreateDynamicComponentService} from "../../../../shared/components/customModal/services/create-dynamic-component.service"; import {PnfPopupService} from "../../../../shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service"; +import {PnfControlGenerator} from "../../../../shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator"; class MockAppStore<T> { getState() { @@ -110,6 +111,7 @@ describe('Model Tree Generator service', () => { DialogService, FeatureFlagsService, VnfControlGenerator, + PnfControlGenerator, AaiService, DialogService, DuplicateService, diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts index 67a962e8a..a1a66596e 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts @@ -60,7 +60,7 @@ export class ObjectToTreeService { if (FeatureFlagsService.getFlagState(Features.FLAG_EXTENDED_MACRO_PNF_CONFIG, this._store) === true && isALaCarte === false) { return [new VnfModelInfo(this._dynamicInputsService, this._sharedTreeService, this._defaultDataGeneratorService, this._dialogService, this._vnfPopupService, this._vfModulePopupService, this._vfModuleUpgradePopupService, this._duplicateService, this._modalService, this._iframeService, this._componentInfoService, this._featureFlagsService, this._store) , new NetworkModelInfo(this._dynamicInputsService, this._sharedTreeService, this._dialogService, this._networkPopupService, this._duplicateService, this._modalService, this._iframeService, this._featureFlagsService, this._store), - new PnfModelInfoExtended(this._store, this._sharedTreeService, this._dialogService, this._pnfPopupService), + new PnfModelInfoExtended(this._store, this._sharedTreeService, this._dialogService, this._pnfPopupService, this._iframeService, this._duplicateService, this._modalService, this._dynamicInputsService), new VrfModelInfo(this._store, this._sharedTreeService, this._dialogService, this._iframeService, this._featureFlagsService, this._networkStepService, this._vpnStepService), new CollectionResourceModelInfo(this._store, this._sharedTreeService), new ConfigurationModelInfo(this._dynamicInputsService, this._sharedTreeService), diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.spec.ts index c82850eb8..ef11d6a4c 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.spec.ts @@ -45,6 +45,7 @@ import {SharedControllersService} from "../../../shared/components/genericForm/f import {ModalService} from "../../../shared/components/customModal/services/modal.service"; import {CreateDynamicComponentService} from "../../../shared/components/customModal/services/create-dynamic-component.service"; import { PnfPopupService } from "../../../shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service"; +import { PnfControlGenerator } from "../../../shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator"; class MockAppStore<T> { getState() { @@ -110,6 +111,7 @@ describe('Shared Tree Service', () => { DialogService, FeatureFlagsService, VnfControlGenerator, + PnfControlGenerator, AaiService, DialogService, GenericFormService, diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts index 0ba90c20a..26776d05d 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts @@ -28,19 +28,21 @@ export class SharedTreeService { * @param dynamicInputs - from the instance * @param isEcompGeneratedNaming ************************************************************/ - selectedVNF: string = null; + selectedNF: string = null; - - getSelectedVNF(): string { - return this.selectedVNF; + getSelectedNF(): string { + return this.selectedNF; } - setSelectedVNF(node): void { + setSelectedNF(node): void { if (_.isNil(node) || node.data.type !== 'VF') { - this.selectedVNF = null; - } else { - this.selectedVNF = node.data.vnfStoreKey; + this.selectedNF = null; + } else if (node.data.type === 'VF'){ + this.selectedNF = node.data.vnfStoreKey; + } else if (node.data.type === 'PNF'){ + this.selectedNF = node.data.pnfStoreKey; } + } /** diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator.spec.ts new file mode 100644 index 000000000..e510eaad2 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator.spec.ts @@ -0,0 +1,175 @@ +import {getTestBed, TestBed} from '@angular/core/testing'; +import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; +import {NgRedux} from '@angular-redux/store'; +import {FormControlNames} from "../service.control.generator"; +import {ControlGeneratorUtil} from "../control.generator.util.service"; +import {AaiService} from "../../../../services/aaiService/aai.service"; +import {GenericFormService} from "../../generic-form.service"; +import {FormBuilder} from "@angular/forms"; +import {FormControlModel} from "../../../../models/formControlModels/formControl.model"; +import {LogService} from "../../../../utils/log/log.service"; +import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flags.service"; +import {SharedControllersService} from "../sharedControlles/shared.controllers.service"; +import {PnfControlGenerator} from "./pnf.control.generator"; +import {MockNgRedux} from "@angular-redux/store/testing"; + +class MockFeatureFlagsService { +} + +class MockAppStore<T> { + getState() { + return { + global: { + flags: { + "FLAG_NETWORK_TO_ASYNC_INSTANTIATION": false, + "FLAG_SHOW_ASSIGNMENTS": true, + "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, + "FLAG_SHOW_VERIFY_SERVICE": false, + "FLAG_SERVICE_MODEL_CACHE": true, + "FLAG_ADD_MSO_TESTAPI_FIELD": true + } + }, + service: { + serviceHierarchy: { + 'serviceId': { + 'pnfs': { + 'pnfName': {} + } + } + }, + serviceInstance: { + 'serviceId': { + 'pnfs': { + 'pnfName': {} + } + } + } + } + } + } +} + +describe('PNF Control Generator', () => { + let injector; + let service: PnfControlGenerator; + let httpMock: HttpTestingController; + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + MockNgRedux, + PnfControlGenerator, + GenericFormService, + ControlGeneratorUtil, + SharedControllersService, + AaiService, + FormBuilder, + LogService, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, + {provide: NgRedux, useClass: MockAppStore}] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + service = injector.get(PnfControlGenerator); + httpMock = injector.get(HttpTestingController); + + })().then(done).catch(done.fail)); + + test('getMacroFormControls check for mandatory controls', () => { + const serviceId = "serviceId"; + const pnfName = "pnfName"; + const pnfStoreKey = "pnfStoreKey"; + const mandatoryControls: string[] = [ + FormControlNames.INSTANCE_NAME, + FormControlNames.PRODUCT_FAMILY_ID + ]; + + const controls: FormControlModel[] = service.getMacroFormControls(serviceId, pnfStoreKey, pnfName, []); + + for (let i = 0; i < mandatoryControls.length; i++) { + let requiredExist = controls.find(ctrl => ctrl.controlName === mandatoryControls[i]).validations.find(item => item.validatorName === 'required'); + expect(requiredExist).toBeDefined(); + } + }); + + test('should provide empty array on getMacroFormControls when serviceId, pnfName and pnfStoreKey equals to null', () => { + let pnfStoreKey = null; + const serviceId = null; + const pnfName: string = null; + + const controls: FormControlModel[] = service.getMacroFormControls(serviceId, pnfStoreKey, pnfName, []); + + expect(controls).toEqual([]); + }); + + test('getAlacartFormControls check for mandatory controls', () => { + const serviceId = "serviceId"; + const pnfName = "pnfName"; + const pnfStoreKey = "pnfStoreKey"; + const mandatoryControls: string[] = [ + FormControlNames.INSTANCE_NAME, + 'platformName', + 'lineOfBusiness', + 'rollbackOnFailure' + ]; + + const controls: FormControlModel[] = service.getAlaCarteFormControls(serviceId, pnfStoreKey, pnfName, []); + + for (let i = 0; i < mandatoryControls.length; i++) { + let requiredExist = controls.find(ctrl => ctrl.controlName === mandatoryControls[i]).validations.find(item => item.validatorName === 'required'); + expect(requiredExist).toBeDefined(); + } + }); + + test('should provide empty array on getAlaCarteFormControls when serviceId, pnfName and pnfStoreKey equals to null', () => { + let pnfStoreKey = null; + const serviceId = null; + const pnfName: string = null; + + const result: FormControlModel[] = service.getAlaCarteFormControls(serviceId, pnfStoreKey, pnfName, []); + + expect(result).toEqual([]); + }); + + + test('getMacroFormControls should return the correct order of controls', () => { + const serviceId = "serviceId"; + const pnfName = "pnfName"; + const pnfStoreKey = "pnfStoreKey"; + const controls: FormControlModel[] = service.getMacroFormControls(serviceId, pnfStoreKey, pnfName, []); + + const controlsOrderNames = [ + FormControlNames.INSTANCE_NAME, + FormControlNames.PRODUCT_FAMILY_ID, + 'platformName', + 'lineOfBusiness']; + + expect(controls.length).toEqual(4); + for (let i = 0; i < controls.length; i++) { + expect(controls[i].controlName).toEqual(controlsOrderNames[i]); + } + }); + + test('getAlacarteFormControls should return the correct order of controls', () => { + const serviceId = "serviceId"; + const pnfName = "pnfName"; + const pnfStoreKey = "pnfStoreKey"; + const controls: FormControlModel[] = service.getAlaCarteFormControls(serviceId, pnfStoreKey, pnfName, []); + + const controlsOrderNames = [ + FormControlNames.INSTANCE_NAME, + FormControlNames.PRODUCT_FAMILY_ID, + 'platformName', + 'lineOfBusiness', + 'rollbackOnFailure' + ]; + + expect(controls.length).toEqual(5); + for (let i = 0; i < controls.length; i++) { + expect(controls[i].controlName).toEqual(controlsOrderNames[i]); + } + }); +}); + diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator.ts new file mode 100644 index 000000000..7e3381701 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator.ts @@ -0,0 +1,87 @@ +import {Injectable} from "@angular/core"; +import {GenericFormService} from "../../generic-form.service"; +import {AaiService} from "../../../../services/aaiService/aai.service"; +import {NgRedux} from "@angular-redux/store"; +import {HttpClient} from "@angular/common/http"; +import {ControlGeneratorUtil} from "../control.generator.util.service"; +import {FormControlModel} from "../../../../models/formControlModels/formControl.model"; +import {LogService} from "../../../../utils/log/log.service"; +import {PNFModel} from "../../../../models/pnfModel"; +import {AppState} from "../../../../store/reducers"; +import * as _ from 'lodash'; +import {SharedControllersService} from "../sharedControlles/shared.controllers.service"; + +@Injectable() +export class PnfControlGenerator { + aaiService: AaiService; + constructor(private genericFormService: GenericFormService, + private _basicControlGenerator: ControlGeneratorUtil, + private _sharedControllersService : SharedControllersService, + private store: NgRedux<AppState>, + private http: HttpClient, + private _aaiService: AaiService, + private _logService: LogService) { + this.aaiService = _aaiService; + } + + getPnfInstance = (serviceId: string, pnfStoreKey: string): any => { + let pnfInstance = null; + if (this.store.getState().service.serviceInstance[serviceId] && _.has(this.store.getState().service.serviceInstance[serviceId].pnfs, pnfStoreKey)) { + pnfInstance = Object.assign({}, this.store.getState().service.serviceInstance[serviceId].pnfs[pnfStoreKey]); + } + return pnfInstance; + }; + + getMacroFormControls(serviceId: string, pnfStoreKey: string, pnfName: string, dynamicInputs?: any[]): FormControlModel[] { + pnfStoreKey = _.isNil(pnfStoreKey) ? pnfName : pnfStoreKey; + + if (_.isNil(serviceId) || _.isNil(pnfStoreKey) || _.isNil(pnfName)) { + this._logService.error('should provide serviceId, pnfName, pnfStoreKey', serviceId); + return []; + } + const pnfInstance = this._basicControlGenerator.retrieveInstanceIfUpdateMode(this.store,this.getPnfInstance(serviceId, pnfStoreKey)); + const pnfModel = new PNFModel(this.store.getState().service.serviceHierarchy[serviceId].pnfs[pnfName]); + let result: FormControlModel[] = []; + const flags = this.store.getState().global.flags; + + if (!_.isNil(pnfModel)) { + const isPlatformMultiSelected = flags['FLAG_2002_PNF_PLATFORM_MULTI_SELECT']; + const isLobMultiSelected = flags['FLAG_2006_PNF_LOB_MULTI_SELECT']; + + result.push(this.getInstanceName(pnfInstance, serviceId, pnfName, pnfModel.isEcompGeneratedNaming)); + result.push(this._sharedControllersService.getProductFamilyControl(pnfInstance, result, true)); + result.push(this._sharedControllersService.getPlatformMultiselectControl(pnfInstance, result, isPlatformMultiSelected)); + result.push(this._sharedControllersService.getLobMultiselectControl(pnfInstance, isLobMultiSelected)); + } + return result; + } + + getAlaCarteFormControls(serviceId: string, pnfStoreKey: string, pnfName: string, dynamicInputs?: any[]): FormControlModel[] { + pnfStoreKey = _.isNil(pnfStoreKey) ? pnfName : pnfStoreKey; + if (_.isNil(serviceId) || _.isNil(pnfStoreKey) || _.isNil(pnfName)) { + this._logService.error('should provide serviceId, pnfName, pnfStoreKey', serviceId); + return []; + } + + let result: FormControlModel[] = []; + const pnfInstance = this._basicControlGenerator.retrieveInstanceIfUpdateMode(this.store,this.getPnfInstance(serviceId, pnfStoreKey)); + const pnfModel = new PNFModel(this.store.getState().service.serviceHierarchy[serviceId].pnfs[pnfName]); + const flags = this.store.getState().global.flags; + + if (!_.isNil(pnfModel)) { + const isPlatformMultiSelected = flags['FLAG_2002_VNF_PLATFORM_MULTI_SELECT']; + const isLobMultiSelected = flags['FLAG_2006_VNF_LOB_MULTI_SELECT']; + result.push(this.getInstanceName(pnfInstance, serviceId, pnfName, pnfModel.isEcompGeneratedNaming)); + result.push(this._sharedControllersService.getProductFamilyControl(pnfInstance, result, true)); + result.push(this._sharedControllersService.getPlatformMultiselectControl(pnfInstance, result, isPlatformMultiSelected)); + result.push(this._sharedControllersService.getLobMultiselectControl(pnfInstance,isLobMultiSelected)); + result.push(this._sharedControllersService.getRollbackOnFailureControl(pnfInstance)); + } + return result; + } + + getInstanceName(instance : any, serviceId : string, pnfName : string, isEcompGeneratedNaming: boolean): FormControlModel { + const pnfModel : PNFModel = this.store.getState().service.serviceHierarchy[serviceId].pnfs[pnfName]; + return this._sharedControllersService.getInstanceNameController(instance, serviceId, isEcompGeneratedNaming, pnfModel); + } +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service.spec.ts new file mode 100644 index 000000000..bae5aee61 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service.spec.ts @@ -0,0 +1,351 @@ +import {DefaultDataGeneratorService} from "../../../../services/defaultDataServiceGenerator/default.data.generator.service"; +import {NgRedux} from "@angular-redux/store"; +import {IframeService} from "../../../../utils/iframe.service"; +import {VfModulePopupService} from "../vfModule/vfModule.popup.service"; +import {FormBuilder} from "@angular/forms"; +import {GenericFormService} from "../../../genericForm/generic-form.service"; +import {BasicPopupService} from "../basic.popup.service"; +import {AaiService} from "../../../../services/aaiService/aai.service"; +import {LogService} from "../../../../utils/log/log.service"; +import {HttpClient} from "@angular/common/http"; +import {ControlGeneratorUtil} from "../../../genericForm/formControlsServices/control.generator.util.service"; +import {PnfControlGenerator} from "../../../genericForm/formControlsServices/pnfGenerator/pnf.control.generator"; +import {UUIDData} from "../../generic-form-popup.component"; +import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flags.service"; +import {getTestBed, TestBed} from "@angular/core/testing"; +import {VfModuleUpgradePopupService} from "../vfModuleUpgrade/vfModule.upgrade.popuop.service"; +import {SharedControllersService} from "../../../genericForm/formControlsServices/sharedControlles/shared.controllers.service"; +import {PnfPopupService} from "../pnf/pnf.popup.service"; +import {AppState} from "../../../../store/reducers"; + +class MockAppStore<T> { +} + +class MockReduxStore<T> { + dispatch() {} + getState() { + return { + "global": { + "flags": { + "FLAG_NETWORK_TO_ASYNC_INSTANTIATION": false, + "FLAG_SHOW_ASSIGNMENTS": true, + "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, + "FLAG_SHOW_VERIFY_SERVICE": false, + "FLAG_SERVICE_MODEL_CACHE": true, + "FLAG_ADD_MSO_TESTAPI_FIELD": true + } + }, + "service": { + "serviceHierarchy": { + "serviceId": { + "service": { + "uuid": "6e59c5de-f052-46fa-aa7e-2fca9d674c44", + "invariantUuid": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "name": "action-data", + "version": "1.0", + "toscaModelURL": null, + "category": "Emanuel", + "serviceType": "", + "serviceRole": "", + "description": "action-data", + "serviceEcompNaming": "false", + "instantiationType": "Macro", + "vidNotions": { + "instantiationType": "Macro" + }, + }, + "globalSubscriberId": "subscriberId", + "pnfs": { + "pnfInstanceV1": { + "name": "pnfName", + "pnfStoreKey": "pnfInstanceV1", + "version": "1.0", + "description": "PNF description", + "uuid": "0903e1c0-8e03-4936-b5c2-260653b96413", + "invariantUuid": "00beb8f9-6d39-452f-816d-c709b9cbb87d" + }, + "pnfInstanceV2": { + "name": "pnfName2", + "pnfStoreKey": "pnfInstanceV2" + } + }, + "modelInfo": { + "modelInvariantId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "modelVersionId": "6b528779-44a3-4472-bdff-9cd15ec93450", + "modelName": "action-data", + "modelVersion": "1.0", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450" + }, + "instanceName": "InstanceName", + "owningEntityId": "d61e6f2d-12fa-4cc2-91df-7c244011d6fc", + "productFamilyId": "17cc1042-527b-11e6-beb8-9e71128cae77", + "lcpCloudRegionId": "AAIAIC25", + "tenantId": "092eb9e8e4b7412e8787dd091bc58e86", + "aicZoneId": "JAG1", + "projectName": null, + "rollbackOnFailure": "true", + "aicZoneName": "YUDFJULP-JAG1", + "owningEntityName": "WayneHolland", + "testApi": "GR_API", + "tenantName": "USP-SIP-IC-24335-T-01", + "bulkSize": 1, + "isALaCarte": false, + "name": "action-data", + "version": "1.0", + "description": "", + "category": "", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450", + "invariantUuid": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "serviceType": "", + "serviceRole": "", + "isMultiStepDesign": false + } + }, + "serviceInstance": { + "serviceId": { + "globalSubscriberId": "subscriberId", + "pnfs": { + "pnfInstanceV1": { + "name": "pnfName", + "pnfStoreKey": "pnfInstanceV1" + }, + "pnfInstanceV2": { + "name": "pnfName2", + "pnfStoreKey": "pnfInstanceV2" + } + }, + "modelInfo": { + "modelInvariantId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "modelVersionId": "6b528779-44a3-4472-bdff-9cd15ec93450", + "modelName": "action-data", + "modelVersion": "1.0", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450" + }, + "instanceName": "InstanceName", + "owningEntityId": "d61e6f2d-12fa-4cc2-91df-7c244011d6fc", + "productFamilyId": "17cc1042-527b-11e6-beb8-9e71128cae77", + "lcpCloudRegionId": "AAIAIC25", + "tenantId": "092eb9e8e4b7412e8787dd091bc58e86", + "aicZoneId": "JAG1", + "projectName": null, + "rollbackOnFailure": "true", + "aicZoneName": "YUDFJULP-JAG1", + "owningEntityName": "WayneHolland", + "testApi": "GR_API", + "tenantName": "USP-SIP-IC-24335-T-01", + "bulkSize": 1, + "isALaCarte": false, + "name": "action-data", + "version": "1.0", + "description": "", + "category": "", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450", + "invariantUuid": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "serviceType": "", + "serviceRole": "", + "isMultiStepDesign": false + } + }, + "subscribers": [ + { + "id": "someSubscriberId", + "name": "someSubscriberName", + "isPermitted": true + }, + { + "id": "subscriberId", + "name": "subscriberName", + "isPermitted": true + }, + { + "id": "subscriberId2", + "name": "subscriberName2", + "isPermitted": true + } + ] + } + } + } +} + +class MockFeatureFlagsService { +} + +describe('pnf new popup service', () => { + let injector; + let service: PnfPopupService; + let store: NgRedux<AppState>; + + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + providers: [ + PnfPopupService, + DefaultDataGeneratorService, + GenericFormService, + FormBuilder, + IframeService, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, + AaiService, + LogService, + BasicPopupService, + VfModulePopupService, + VfModuleUpgradePopupService, + ControlGeneratorUtil, + SharedControllersService, + PnfControlGenerator, + {provide: NgRedux, useClass: MockReduxStore}, + {provide: HttpClient, useClass: MockAppStore}, + ] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + store = injector.get(NgRedux); + service = injector.get(PnfPopupService); + + })().then(done).catch(done.fail)); + + test('getGenericFormPopupDetails returns the FormPopupDetails object', () => { + const serviceId: string = 'serviceId'; + const pnfModelName: string = 'pnfInstanceV2'; + const pnfStoreKey: string = 'pnfInstanceV2'; + let uuidData: UUIDData = <any>{ + serviceId: "serviceId", + modelName: "pnfInstanceV2", + pnfStoreKey: "pnfInstanceV2" + }; + + const formPopupDetailsObject = service.getGenericFormPopupDetails(serviceId, pnfModelName, pnfStoreKey, null, uuidData, true); + + expect(formPopupDetailsObject).toBeDefined(); + } + ); + + test('getInstance with empty storekey should be created', () => { + const serviceId: string = 'serviceId'; + const pnfModelName: string = 'pnfInstanceV1'; + + const newInstance = service.getInstance(serviceId, pnfModelName, null); + + expect(newInstance).toBeDefined(); + expect(newInstance.pnfStoreKey).toBeNull(); + }); + + test('getInstance with not empty storekey should return existing instance with the same model name as store key', () => { + const serviceId: string = 'serviceId'; + const pnfModelName: string = 'pnfInstanceV1'; + const pnfStoreKey: string = 'pnfInstanceV2'; + + const newInstance = service.getInstance(serviceId, pnfModelName, pnfStoreKey); + + expect(newInstance).toBeDefined(); + expect(newInstance.pnfStoreKey).toEqual('pnfInstanceV2'); + }); + + test('getModelInformation pnf should update modelInformations', () => { + const serviceId: string = 'serviceId'; + const pnfModelName: string = 'pnfInstanceV1'; + + service.getModelInformation(serviceId, pnfModelName); + + expect(service.modelInformations.length).toEqual(14); + + expect(service.modelInformations[0].label).toEqual("Subscriber Name"); + expect(service.modelInformations[0].values).toEqual(['subscriberName']); + + expect(service.modelInformations[1].label).toEqual("Service Name"); + expect(service.modelInformations[1].values).toEqual(['action-data']); + + expect(service.modelInformations[2].label).toEqual("Service Instance Name"); + expect(service.modelInformations[2].values).toEqual(['InstanceName']); + + expect(service.modelInformations[3].label).toEqual("Model Name"); + expect(service.modelInformations[3].values).toEqual(['pnfName']); + + expect(service.modelInformations[4].label).toEqual("Model version"); + expect(service.modelInformations[4].values).toEqual(['1.0']); + + expect(service.modelInformations[5].label).toEqual("Description"); + expect(service.modelInformations[5].values).toEqual(['PNF description']); + + expect(service.modelInformations[6].label).toEqual("Category"); + expect(service.modelInformations[6].values).toEqual([undefined]); + + expect(service.modelInformations[7].label).toEqual("Sub Category"); + expect(service.modelInformations[7].values).toEqual([undefined]); + + expect(service.modelInformations[8].label).toEqual("UUID"); + expect(service.modelInformations[8].values).toEqual(['0903e1c0-8e03-4936-b5c2-260653b96413']); + + expect(service.modelInformations[9].label).toEqual("Invariant UUID"); + expect(service.modelInformations[9].values).toEqual(['00beb8f9-6d39-452f-816d-c709b9cbb87d']); + + expect(service.modelInformations[10].label).toEqual("Service type"); + expect(service.modelInformations[10].values).toEqual(['']); + + expect(service.modelInformations[11].label).toEqual("Service role"); + expect(service.modelInformations[11].values).toEqual(['']); + + expect(service.modelInformations[12].label).toEqual("Minimum to instantiate"); + expect(service.modelInformations[12].values).toEqual(['0']); + + expect(service.modelInformations[13].label).toEqual("Maximum to instantiate"); + expect(service.modelInformations[13].values).toEqual(['1']); + }); + + test('getSubLeftTitle new pnf popup should return service model name', () => { + service.uuidData = { + serviceId: 'serviceId', + modelName: 'pnfInstanceV1' + }; + expect(service.getSubLeftTitle()).toBe("PNF MODEL: pnfName"); + }); + + test('storePNF should dispatch createPNFInstance action when isUpdateMode is false', () => { + let mockedPopupService = getMockedPopupService(false); + + spyOn(store, 'dispatch'); + service.storePNF(mockedPopupService, {}); + + expect(store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "CREATE_PNF_INSTANCE", + })); + }); + + test('storePNF should dispatch updatePNFInstance action when isUpdateMode is true', () => { + let mockedPopupService = getMockedPopupService(true); + + spyOn(mockedPopupService._store, 'dispatch'); + service.storePNF(mockedPopupService, {}); + + expect(mockedPopupService._store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "UPDATE_PNF_INSTANCE", + })); + }); + + function getMockedPopupService(isUpdateMode: boolean) { + return <any>{ + model: {}, + isUpdateMode: isUpdateMode, + _store: { + dispatch: () => { + } + }, + uuidData: { + serviceId: "serviceId" + } + }; + } + + test('getTitle pnf should return the correct title for edit and create mode', () => { + expect(service.getTitle(false)).toBe('Set a new PNF'); + expect(service.getTitle(true)).toBe('Edit PNF instance'); + }); + + test('extractSubscriberNameBySubscriberId should extract proper subscriber by id', () => { + expect(service.extractSubscriberNameBySubscriberId("subscriberId", store)) + .toBe('subscriberName'); + }); + +}); diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service.ts index c4f1b2eea..70fcc16db 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/pnf/pnf.popup.service.ts @@ -7,6 +7,7 @@ import {ModelInformationItem} from "../../../model-information/model-information import {ServiceModel} from "../../../../models/serviceModel"; import {Subject} from "rxjs/Subject"; import {ControlGeneratorUtil} from "../../../genericForm/formControlsServices/control.generator.util.service"; +import {PnfControlGenerator} from "../../../genericForm/formControlsServices/pnfGenerator/pnf.control.generator"; import {IframeService} from "../../../../utils/iframe.service"; import {DefaultDataGeneratorService} from "../../../../services/defaultDataServiceGenerator/default.data.generator.service"; import {AaiService} from "../../../../services/aaiService/aai.service"; @@ -16,14 +17,17 @@ import {AppState} from "../../../../store/reducers"; import {Subscriber} from "../../../../models/subscriber"; import {Constants} from "../../../../utils/constants"; import {PnfInstance} from "../../../../models/pnfInstance"; +import {ModelInfo} from "../../../../models/modelInfo"; +import {changeInstanceCounter} from "../../../../storeUtil/utils/general/general.actions"; +import {createPNFInstance, updatePNFInstance} from "../../../../storeUtil/utils/pnf/pnf.actions"; import * as _ from 'lodash'; @Injectable() -export class PnfPopupService implements GenericPopupInterface{ +export class PnfPopupService implements GenericPopupInterface { dynamicInputs: any; instance: any; - model:any; - serviceModel:ServiceModel; + model: any; + serviceModel: ServiceModel; modelInformations: ModelInformationItem[] = []; uuidData: Object; closeDialogEvent: Subject<any> = new Subject<any>(); @@ -31,6 +35,7 @@ export class PnfPopupService implements GenericPopupInterface{ constructor( private _basicControlGenerator: ControlGeneratorUtil, + private _pnfControlGenerator: PnfControlGenerator, private _iframeService: IframeService, private _defaultDataGeneratorService: DefaultDataGeneratorService, private _aaiService: AaiService, @@ -53,17 +58,25 @@ export class PnfPopupService implements GenericPopupInterface{ this.getControls(serviceId, modelName, pnfStoreKey), this._basicPopupService.getDynamicInputs(serviceId, modelName, pnfStoreKey, 'pnfs'), this.modelInformations, - (that, form: FormGroup) => {that.onSubmit(that, form);}, - (that: any, form: FormGroup) => {that.onCancel(that, form); } - ) + (that, form: FormGroup) => { + that.onSubmit(that, form); + }, + (that: any, form: FormGroup) => { + that.onCancel(that, form); + } + ) } - getControls(serviceId: string, modelName: string, pnfStoreKey: string){ - return []; + getControls(serviceId: string, modelName: string, pnfStoreKey: string) { + if (this._store.getState().service.serviceHierarchy[serviceId].service.vidNotions.instantiationType === 'Macro') { + return this._pnfControlGenerator.getMacroFormControls(serviceId, pnfStoreKey, modelName); + } else { + return this._pnfControlGenerator.getAlaCarteFormControls(serviceId, pnfStoreKey, modelName); + } } getInstance(serviceId: string, modelName: string, pnfStoreKey: string): any { - if(_.isNil(pnfStoreKey)){ + if (_.isNil(pnfStoreKey)) { return new PnfInstance(); } return this._store.getState().service.serviceInstance[serviceId].pnfs[pnfStoreKey]; @@ -89,7 +102,7 @@ export class PnfPopupService implements GenericPopupInterface{ new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole]), new ModelInformationItem("Minimum to instantiate", "min", [!_.isNil(this.model.min) ? this.model.min.toString() : '0'], "", false), this._basicPopupService.createMaximumToInstantiateModelInformationItem(this.model) - ]; + ]; }) } @@ -101,10 +114,20 @@ export class PnfPopupService implements GenericPopupInterface{ return "PNF Instance Details"; } - storePNF = (that, formValues: any): void => {}; + storePNF = (that, formValues: any): void => { + formValues.modelInfo = new ModelInfo(that.model); + formValues.uuid = formValues.modelInfo.uuid; + formValues.isMissingData = false; + if (!that.isUpdateMode) { + that._store.dispatch(changeInstanceCounter(formValues.modelInfo.modelUniqueId, that.uuidData.serviceId, 1, <any>{data: {type: 'PNF'}})); + this._store.dispatch(createPNFInstance(formValues, that.uuidData['modelName'], that.uuidData['serviceId'], that.uuidData['modelName'])); + } else { + that._store.dispatch(updatePNFInstance(formValues, that.uuidData.modelName, that.uuidData.serviceId, that.uuidData.pnfStoreKey)) + } + }; getTitle(isUpdateMode: boolean): string { - return isUpdateMode ? "Edit PNF instance": "Set a new PNF" ; + return isUpdateMode ? "Edit PNF instance" : "Set a new PNF"; } onCancel(that, form): void { @@ -116,7 +139,7 @@ export class PnfPopupService implements GenericPopupInterface{ onSubmit(that, form: FormGroup, ...args): void { form.value['instanceParams'] = form.value['instanceParams'] && [form.value['instanceParams']]; that.storePNF(that, form.value); - window.parent.postMessage( { + window.parent.postMessage({ eventId: 'submitIframe', data: { serviceModelId: that.uuidData.serviceId diff --git a/vid-webpack-master/src/app/shared/models/pnfInstance.ts b/vid-webpack-master/src/app/shared/models/pnfInstance.ts index ba3679646..ff855bc8c 100644 --- a/vid-webpack-master/src/app/shared/models/pnfInstance.ts +++ b/vid-webpack-master/src/app/shared/models/pnfInstance.ts @@ -5,6 +5,7 @@ export class PnfInstance extends Level1Instance { pnfStoreKey : string; statusMessage?: string; + position: number; constructor() { super(); diff --git a/vid-webpack-master/src/app/shared/models/pnfModel.ts b/vid-webpack-master/src/app/shared/models/pnfModel.ts index 14e6588d2..8f9e0d1de 100644 --- a/vid-webpack-master/src/app/shared/models/pnfModel.ts +++ b/vid-webpack-master/src/app/shared/models/pnfModel.ts @@ -3,6 +3,8 @@ import { Level1ModelProperties, Level1ModelResponseInterface } from "./nodeModel"; +import {VNFModelResponseInterface} from "./vnfModel"; +import {Utils} from "../utils/utils"; @@ -18,10 +20,11 @@ export class PNFModel extends Level1Model{ roles: string[] = []; properties: PnfProperties; - constructor(pnfJson?: PNFModelResponseInterface) { + constructor(pnfJson?: PNFModelResponseInterface, flags?: { [key: string]: boolean }) { super(pnfJson); if (pnfJson && pnfJson.properties) { this.properties = pnfJson.properties; + this.max = Utils.getMaxFirstLevel(this.properties, flags); } } diff --git a/vid-webpack-master/src/app/shared/models/serviceInstance.ts b/vid-webpack-master/src/app/shared/models/serviceInstance.ts index 1f111d14b..67b8806a8 100644 --- a/vid-webpack-master/src/app/shared/models/serviceInstance.ts +++ b/vid-webpack-master/src/app/shared/models/serviceInstance.ts @@ -23,8 +23,8 @@ export class ServiceInstance extends NodeInstance{ latestAvailableVersion: Number; pause: boolean; bulkSize: number; - pnfs: { [pnf_module_model_name: string]: PnfInstance; }; vnfs: { [vnf_module_model_name: string]: VnfInstance; }; + pnfs: { [pnf_module_model_name: string]: PnfInstance; }; vrfs: { [vrf_model_name: string]: VrfInstance; }; vnfGroups : {[vnf_module_model_name: string]: VnfGroupInstance; }; networks: { [vnf_module_model_name: string]: NetworkInstance; }; @@ -36,8 +36,8 @@ export class ServiceInstance extends NodeInstance{ validationCounter: number; existingNames: {[key: string] : any}; modelInavariantId?: string; - existingPNFCounterMap : { [pnf_module_model_name: string]: number; }; existingVNFCounterMap : { [vnf_module_model_name: string]: number; }; + existingPNFCounterMap : { [pnf_module_model_name: string]: number; }; existingVRFCounterMap : { [vrf_module_model_name: string]: number; }; existingVnfGroupCounterMap : { [vnf_group_module_model_name: string]: number; }; existingNetworksCounterMap : { [network_module_model_name: string]: number; }; diff --git a/vid-webpack-master/src/app/shared/services/aaiService/aai.service.spec.ts b/vid-webpack-master/src/app/shared/services/aaiService/aai.service.spec.ts index f563cbc75..ad934cf79 100644 --- a/vid-webpack-master/src/app/shared/services/aaiService/aai.service.spec.ts +++ b/vid-webpack-master/src/app/shared/services/aaiService/aai.service.spec.ts @@ -22,7 +22,7 @@ describe("AaiService", () => { let httpMock: HttpTestingController; let aaiService: AaiService; let mockFeatureFlagsService: FeatureFlagsService = mock(FeatureFlagsService); - let store : NgRedux<AppState>; + let store: NgRedux<AppState>; beforeAll(done => (async () => { TestBed.configureTestingModule({ @@ -42,8 +42,6 @@ describe("AaiService", () => { })().then(done).catch(done.fail)); - - describe('#resolve tests', () => { test('aai service resolve should return the right object', () => { let serviceInstance = new ServiceInstance(); @@ -173,8 +171,37 @@ describe("AaiService", () => { }); }); + describe('#Pnf modelCustomizationName initialization tests', () => { + + test('initializePnfModelCustomizationName should not reinitialize modelCustomizationName when it exists', () => { + let serviceHierarchy = { + "pnfs": { + "pnfInstance": { + "modelCustomizationName": "existingName" + } + } + } + + aaiService.initializePnfModelCustomizationName(serviceHierarchy); + + expect(serviceHierarchy.pnfs["pnfInstance"].modelCustomizationName).toBe("existingName"); + }); + + test('initializePnfModelCustomizationName should initialize modelCustomizationName when it doesnt exist', () => { + let serviceHierarchy = { + "pnfs": { + "pnfInstance": {} + } + } + + aaiService.initializePnfModelCustomizationName(serviceHierarchy); + + expect((serviceHierarchy.pnfs["pnfInstance"] as any).modelCustomizationName).toBe("pnfInstance"); + }); + }); + function getTopology() { - return { + return { "vnfs": { "2017-388_PASQUALE-vPE 0": { "vfModules": {}, @@ -398,7 +425,7 @@ describe("AaiService", () => { } } - function getMockActiveNetworks(){ + function getMockActiveNetworks() { return [ { networkInstanceName: "networkInstanceName", diff --git a/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts b/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts index adb7017be..2829a8981 100644 --- a/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts +++ b/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts @@ -58,6 +58,7 @@ export class AaiService { getServiceModelById = (serviceModelId: string): Observable<any> => { if (_.has(this.store.getState().service.serviceHierarchy, serviceModelId)) { + this.initializePnfModelCustomizationName(this.store.getState().service.serviceHierarchy[serviceModelId]); return of(<any> JSON.parse(JSON.stringify(this.store.getState().service.serviceHierarchy[serviceModelId]))); } let pathQuery: string = Constants.Path.SERVICES_PATH + serviceModelId; @@ -321,6 +322,15 @@ export class AaiService { return result; } + initializePnfModelCustomizationName(serviceHierarchy) : void { + let pnfs = serviceHierarchy.pnfs; + for (let pnf in pnfs) { + if (!pnfs[pnf].modelCustomizationName){ + pnfs[pnf].modelCustomizationName = pnf; + } + } + } + loadMockMembers(): any { return [ { diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts index 56f49e75c..4abffabcb 100644 --- a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts +++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts @@ -4,25 +4,176 @@ import {NgRedux} from '@angular-redux/store'; import {DefaultDataGeneratorService} from './default.data.generator.service'; import {ServiceNodeTypes} from "../../models/ServiceNodeTypes"; import {VNFModel} from "../../models/vnfModel"; +import {AppState} from "../../store/reducers"; -class MockAppStore<T> {} +class MockAppStore<T> { + dispatch() { + + } + + getState() { + return { + "global": { + "flags": { + "FLAG_NETWORK_TO_ASYNC_INSTANTIATION": false, + "FLAG_SHOW_ASSIGNMENTS": true, + "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, + "FLAG_SHOW_VERIFY_SERVICE": false, + "FLAG_SERVICE_MODEL_CACHE": true, + "FLAG_ADD_MSO_TESTAPI_FIELD": true + } + }, + "service": { + "serviceHierarchy": { + "serviceId": { + "service": { + "uuid": "6e59c5de-f052-46fa-aa7e-2fca9d674c44", + "invariantUuid": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "name": "action-data", + "version": "1.0", + "toscaModelURL": null, + "category": "Emanuel", + "serviceType": "", + "serviceRole": "", + "description": "action-data", + "serviceEcompNaming": "false", + "instantiationType": "Macro", + "vidNotions": { + "instantiationType": "Macro" + }, + }, + "globalSubscriberId": "subscriberId", + "pnfs": { + "pnfInstanceV1": { + "name": "pnfName", + "pnfStoreKey": "pnfInstanceV1", + "version": "1.0", + "description": "PNF description", + "uuid": "0903e1c0-8e03-4936-b5c2-260653b96413", + "invariantUuid": "00beb8f9-6d39-452f-816d-c709b9cbb87d", + "properties": { + "min_instances": "1", + "ecomp_generated_naming": "true" + } + } + }, + "modelInfo": { + "modelInvariantId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "modelVersionId": "6b528779-44a3-4472-bdff-9cd15ec93450", + "modelName": "action-data", + "modelVersion": "1.0", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450" + }, + "instanceName": "InstanceName", + "owningEntityId": "d61e6f2d-12fa-4cc2-91df-7c244011d6fc", + "productFamilyId": "17cc1042-527b-11e6-beb8-9e71128cae77", + "lcpCloudRegionId": "AAIAIC25", + "tenantId": "092eb9e8e4b7412e8787dd091bc58e86", + "aicZoneId": "JAG1", + "projectName": null, + "rollbackOnFailure": "true", + "aicZoneName": "YUDFJULP-JAG1", + "owningEntityName": "WayneHolland", + "testApi": "GR_API", + "tenantName": "USP-SIP-IC-24335-T-01", + "bulkSize": 1, + "isALaCarte": false, + "name": "action-data", + "version": "1.0", + "description": "", + "category": "", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450", + "invariantUuid": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "serviceType": "", + "serviceRole": "", + "isMultiStepDesign": false + } + }, + "serviceInstance": { + "serviceId": { + "globalSubscriberId": "subscriberId", + "pnfs": { + "pnfInstanceV1": { + "name": "pnfName", + "pnfStoreKey": "pnfInstanceV1" + }, + "pnfInstanceV2": { + "name": "pnfName2", + "pnfStoreKey": "pnfInstanceV2" + } + }, + "modelInfo": { + "modelInvariantId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "modelVersionId": "6b528779-44a3-4472-bdff-9cd15ec93450", + "modelName": "action-data", + "modelVersion": "1.0", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450" + }, + "instanceName": "InstanceName", + "owningEntityId": "d61e6f2d-12fa-4cc2-91df-7c244011d6fc", + "productFamilyId": "17cc1042-527b-11e6-beb8-9e71128cae77", + "lcpCloudRegionId": "AAIAIC25", + "tenantId": "092eb9e8e4b7412e8787dd091bc58e86", + "aicZoneId": "JAG1", + "projectName": null, + "rollbackOnFailure": "true", + "aicZoneName": "YUDFJULP-JAG1", + "owningEntityName": "WayneHolland", + "testApi": "GR_API", + "tenantName": "USP-SIP-IC-24335-T-01", + "bulkSize": 1, + "isALaCarte": false, + "name": "action-data", + "version": "1.0", + "description": "", + "category": "", + "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450", + "invariantUuid": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "serviceType": "", + "serviceRole": "", + "isMultiStepDesign": false + } + }, + "subscribers": [ + { + "id": "someSubscriberId", + "name": "someSubscriberName", + "isPermitted": true + }, + { + "id": "subscriberId", + "name": "subscriberName", + "isPermitted": true + }, + { + "id": "subscriberId2", + "name": "subscriberName2", + "isPermitted": true + } + ] + } + } + } +} describe('Default Data Generator Service', () => { let injector; let service: DefaultDataGeneratorService; + let store: NgRedux<AppState>; let httpMock: HttpTestingController; beforeAll(done => (async () => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], - providers: [DefaultDataGeneratorService, - {provide: NgRedux, useClass: MockAppStore}] + providers: [DefaultDataGeneratorService, + {provide: NgRedux, useClass: MockAppStore}] }); await TestBed.compileComponents(); injector = getTestBed(); service = injector.get(DefaultDataGeneratorService); httpMock = injector.get(HttpTestingController); + store = injector.get(NgRedux); })().then(done).catch(done.fail)); test('generateVFModule aLaCarte vf module object should missed data', () => { @@ -124,7 +275,7 @@ describe('Default Data Generator Service', () => { "modelVersion": "1" }, volumeGroupName: "", - isMissingData : false, + isMissingData: false, trackById: Math.random().toString() }, vfModuleModel, vnfModuleUUID, false, [], ""); expect(newVfModule.name).toEqual('<Automatically Assigned>'); @@ -147,7 +298,7 @@ describe('Default Data Generator Service', () => { "modelVersion": "1" }, volumeGroupName: "", - isMissingData : false, + isMissingData: false, trackById: Math.random().toString() }, vfModuleModel, vnfModuleUUID, true, [], ""); expect(newVfModule.name).toEqual('<Automatically Assigned>'); @@ -159,7 +310,7 @@ describe('Default Data Generator Service', () => { test('createNewVnfTreeNode with isEcompGeneratedNaming instance name not filled - missing data true', () => { const vnfModel = generateServiceHierarchy().vnfs['VF_vGeraldine 0']; const newVnf = service.createNewTreeNode({ - uuid : '', + uuid: '', instanceName: "", productFamilyId: "productFamilyId", lcpCloudRegionId: "lcpCloudRegionId", @@ -168,7 +319,7 @@ describe('Default Data Generator Service', () => { platformName: "platformName", lineOfBusiness: "lineOfBusiness", rollbackOnFailure: "rollbackOnFailure", - originalName : null, + originalName: null, vfModules: {}, modelInfo: { "modelCustomizationName": "VF_vGeraldine 0", @@ -182,7 +333,7 @@ describe('Default Data Generator Service', () => { isMissingData: false, trackById: Math.random().toString(), vnfStoreKey: "abc" - }, new VNFModel(vnfModel),'VF_vGeraldine 0', 'vnfs'); + }, new VNFModel(vnfModel), 'VF_vGeraldine 0', 'vnfs'); expect(newVnf.name).toEqual('VF_vGeraldine 0'); expect(newVnf.missingData).toEqual(true); }); @@ -190,7 +341,7 @@ describe('Default Data Generator Service', () => { test('createNewVnfTreeNode with isEcompGeneratedNaming instance name filled - missing data false', () => { const vnfModel = generateServiceHierarchy().vnfs['VF_vGeraldine 0']; const newVnf = service.createNewTreeNode({ - uuid : '', + uuid: '', instanceName: "instanceName", productFamilyId: "productFamilyId", lcpCloudRegionId: "lcpCloudRegionId", @@ -199,7 +350,7 @@ describe('Default Data Generator Service', () => { platformName: "platformName", lineOfBusiness: "lineOfBusiness", rollbackOnFailure: "rollbackOnFailure", - originalName : null, + originalName: null, vfModules: {}, modelInfo: { "modelCustomizationName": "VF_vGeraldine 0", @@ -213,12 +364,73 @@ describe('Default Data Generator Service', () => { isMissingData: false, trackById: Math.random().toString(), vnfStoreKey: "abc" - }, vnfModel,'VF_vGeraldine 0', 'vnfs'); + }, vnfModel, 'VF_vGeraldine 0', 'vnfs'); expect(newVnf.name).toEqual("instanceName"); expect(newVnf.missingData).toEqual(false); }); }); + describe('#updatePnfsOnFirstSet tests', () => { + + test('updatePnfsOnFirstSet should call createPNFInstanceReduxIfNotExist when pnfs exists and extended pnf flag is on', () => { + jest.spyOn(service, 'isExtendedMacroPnfConfigOn').mockReturnValue(true); + spyOn(service, 'createPNFInstanceReduxIfNotExist'); + + service.updatePnfsOnFirstSet("serviceId", {}) + + expect(service.createPNFInstanceReduxIfNotExist).toHaveBeenCalled(); + }); + + test('updatePnfsOnFirstSet should not call createPNFInstanceReduxIfNotExist when pnfs exists and extended pnf flag is off', () => { + jest.spyOn(service, 'isExtendedMacroPnfConfigOn').mockReturnValue(false); + spyOn(service, 'createPNFInstanceReduxIfNotExist'); + + service.updatePnfsOnFirstSet("serviceId", {}) + + expect(service.createPNFInstanceReduxIfNotExist).not.toHaveBeenCalled(); + }); + + test('updatePnfsOnFirstSet should not call createPNFInstanceReduxIfNotExist when min_instances == 0 and extended pnf flag is on', () => { + jest.spyOn(service, 'isExtendedMacroPnfConfigOn').mockReturnValue(true); + jest.spyOn(service, 'isMinInstancesGreaterThanZero').mockReturnValue(false); + spyOn(service, 'createPNFInstanceReduxIfNotExist'); + + service.updatePnfsOnFirstSet("serviceId", {}) + + expect(service.createPNFInstanceReduxIfNotExist).not.toHaveBeenCalled(); + }); + + test('createPNFInstanceReduxIfNotExist should dispatch proper actions when pnf doesnt exist', () => { + let pnfData = { + modelInfo: { + modelCustomizationName: "pnfName" + } + }; + spyOn(store, 'dispatch'); + + service.createPNFInstanceReduxIfNotExist("serviceId", pnfData); + + expect(store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "CREATE_PNF_INSTANCE", + })); + expect(store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ + type: "CHANGE_INSTANCE_COUNTER", + })); + }); + + test('createPNFInstanceReduxIfNotExist should not dispatch anything when pnf exists', () => { + let pnfData = { + modelInfo: { + modelCustomizationName: "pnfInstanceV1" + } + }; + spyOn(store, 'dispatch'); + + service.createPNFInstanceReduxIfNotExist("serviceId", pnfData); + + expect(store.dispatch).not.toHaveBeenCalled(); + }); + }); }); diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts index e00b259a0..1bf698463 100644 --- a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts +++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts @@ -1,6 +1,5 @@ import {Injectable} from '@angular/core'; import * as _ from 'lodash'; - import {NgRedux} from '@angular-redux/store'; import {AppState} from '../../store/reducers'; import {VnfTreeNode} from "../../models/vnfTreeNode"; @@ -21,12 +20,15 @@ import {VnfGroupTreeNode} from "../../models/vnfGroupTreeNode"; import {ModelInfo} from "../../models/modelInfo"; import {ServiceInstanceActions} from "../../models/serviceInstanceActions"; import Parameter = Constants.Parameter; +import {createPNFInstance} from "../../storeUtil/utils/pnf/pnf.actions"; +import {FeatureFlagsService, Features} from "../featureFlag/feature-flags.service"; @Injectable() export class DefaultDataGeneratorService { static controlsFieldsStatus = {}; public requiredFields = { VF: [InputType.LCP_REGION, InputType.TENANT, InputType.PLATFORM], + PNF: [InputType.PLATFORM], Network: [InputType.LCP_REGION, InputType.TENANT, InputType.PLATFORM], VL: [InputType.LCP_REGION, InputType.TENANT, InputType.PLATFORM], VFmodule: [], @@ -65,11 +67,10 @@ export class DefaultDataGeneratorService { break; } if (Utils.hasContents(inputs[key][Parameter.CONSTRAINTS]) - && ( inputs[key][Parameter.CONSTRAINTS].length > 0 )) { + && (inputs[key][Parameter.CONSTRAINTS].length > 0)) { let constraintsArray = inputs[key][Parameter.CONSTRAINTS]; this.addConstraintParameters(parameterList, constraintsArray, key, inputs, parameter); - } - else { + } else { parameterList.push(parameter); } @@ -97,8 +98,8 @@ export class DefaultDataGeneratorService { name: constraintsArray[i][Parameter.VALID_VALUES][j], isDefault: false }; - if ((Utils.hasContents(inputs[key][Parameter.DEFAULT]) ) - && (inputs[key][Parameter.DEFAULT] === constraintsArray[i][Parameter.VALID_VALUES][j] )) { + if ((Utils.hasContents(inputs[key][Parameter.DEFAULT])) + && (inputs[key][Parameter.DEFAULT] === constraintsArray[i][Parameter.VALID_VALUES][j])) { option = { name: constraintsArray[i][Parameter.VALID_VALUES][j], isDefault: true @@ -180,14 +181,13 @@ export class DefaultDataGeneratorService { return _.isEmpty(displayInputs) ? [] : this.getArbitraryInputs(displayInputs); } - updateNetworksOnFirstSet(serviceId: string, formServiceValues: any){ + updateNetworksOnFirstSet(serviceId: string, formServiceValues: any) { const serviceHierarchy = this.store.getState().service.serviceHierarchy[serviceId]; if (serviceHierarchy && !_.isEmpty(serviceHierarchy.networks)) { for (let networkUUID in serviceHierarchy.networks) { const isEcompGeneratedNaming = this.getIsEcompGeneratedNaming(serviceHierarchy.networks[networkUUID]); let min_vnf_instances_greater_than_0 = serviceHierarchy.networks[networkUUID].properties['min_instances'] && serviceHierarchy.networks[networkUUID].properties['min_instances'] > 0; - if(min_vnf_instances_greater_than_0) - { + if (min_vnf_instances_greater_than_0) { this.createNetworkInstanceReduxIfNotExist( serviceId, this.generateNetworkData(serviceHierarchy, networkUUID, formServiceValues, isEcompGeneratedNaming) @@ -197,14 +197,13 @@ export class DefaultDataGeneratorService { } } - updateVnfGroupsOnFirstSet(serviceId: string, formServiceValues: any){ + updateVnfGroupsOnFirstSet(serviceId: string, formServiceValues: any) { const serviceHierarchy = this.store.getState().service.serviceHierarchy[serviceId]; if (serviceHierarchy && !_.isEmpty(serviceHierarchy.vnfGroups)) { for (let vnfGroupUUID in serviceHierarchy.vnfGroups) { const isEcompGeneratedNaming = this.getIsEcompGeneratedNaming(serviceHierarchy.vnfGroups[vnfGroupUUID]); let min_vnf_group_instances_greater_than_0 = serviceHierarchy.vnfGroups[vnfGroupUUID].properties['min_instances'] && serviceHierarchy.vnfGroups[vnfGroupUUID].properties['min_instances'] > 0; - if(min_vnf_group_instances_greater_than_0) - { + if (min_vnf_group_instances_greater_than_0) { this.createVnfGroupInstanceReduxIfNotExist( serviceId, this.generateVnfGroupData(serviceHierarchy, vnfGroupUUID, formServiceValues, isEcompGeneratedNaming) @@ -214,9 +213,38 @@ export class DefaultDataGeneratorService { } } + updatePnfsOnFirstSet(serviceId: string, formServiceValues: any) { + const serviceHierarchy = this.store.getState().service.serviceHierarchy[serviceId]; + if (serviceHierarchy && !_.isEmpty(serviceHierarchy.pnfs)) { + for (let pnfUUID in serviceHierarchy.pnfs) { + if (this.isMinInstancesGreaterThanZero(serviceHierarchy, pnfUUID) && this.isExtendedMacroPnfConfigOn()) { + this.createPNFInstanceReduxIfNotExist( + serviceId, + this.generatePNFData( + serviceHierarchy, + pnfUUID, + formServiceValues, + this.getIsEcompGeneratedNaming(serviceHierarchy.pnfs[pnfUUID]) + ) + ); + } + } + } + } + + isExtendedMacroPnfConfigOn(): boolean { + return FeatureFlagsService.getFlagState(Features.FLAG_EXTENDED_MACRO_PNF_CONFIG, this.store) + } + + isMinInstancesGreaterThanZero(serviceHierarchy, pnfUUID): boolean { + return serviceHierarchy.pnfs[pnfUUID].properties['min_instances'] + && serviceHierarchy.pnfs[pnfUUID].properties['min_instances'] > 0; + } + updateReduxOnFirstSet(serviceId: string, formServiceValues: any): void { this.updateNetworksOnFirstSet(serviceId, formServiceValues); this.updateVnfGroupsOnFirstSet(serviceId, formServiceValues); + this.updatePnfsOnFirstSet(serviceId, formServiceValues); const serviceHierarchy = this.store.getState().service.serviceHierarchy[serviceId]; if (serviceHierarchy && !_.isEmpty(serviceHierarchy.vnfs)) { for (let vnfUUID in serviceHierarchy.vnfs) { @@ -245,8 +273,7 @@ export class DefaultDataGeneratorService { } let min_vnf_instances_greater_than_0 = serviceHierarchy.vnfs[vnfUUID].properties['min_instances'] && serviceHierarchy.vnfs[vnfUUID].properties['min_instances'] > 0; - if(min_vnf_instances_greater_than_0) - { + if (min_vnf_instances_greater_than_0) { this.createVNFInstanceReduxIfNotExist( serviceId, this.generateVNFData(serviceHierarchy, vnfUUID, formServiceValues, isEcompGeneratedNaming) @@ -256,7 +283,6 @@ export class DefaultDataGeneratorService { } } - private getIsEcompGeneratedNaming(vnfJson) { const ecompGeneratedNaming = vnfJson.properties.ecomp_generated_naming; return ecompGeneratedNaming === "true"; @@ -269,6 +295,13 @@ export class DefaultDataGeneratorService { } } + createPNFInstanceReduxIfNotExist(serviceId: string, pnfData: any): void { + if(!this.store.getState().service.serviceInstance[serviceId].pnfs[pnfData.modelInfo.modelCustomizationName]){ + this.store.dispatch(createPNFInstance(pnfData, pnfData.modelInfo.modelCustomizationName, serviceId)); + this.store.dispatch(changeInstanceCounter(pnfData.modelInfo.modelUniqueId, serviceId, 1, <any> {data : {type : 'PNF'}})); + } + } + createNetworkInstanceReduxIfNotExist(serviceId: string, networkData: any): void { if(!this.store.getState().service.serviceInstance[serviceId].vnfs[networkData.modelInfo.modelCustomizationName]){ this.store.dispatch(createNetworkInstance(networkData, networkData.modelInfo.modelCustomizationName, serviceId)); @@ -378,6 +411,29 @@ export class DefaultDataGeneratorService { } } + generatePNFData(serviceHierarchy: any, pnfName: string, formValues: any, isEcompGeneratedNaming) { + return { + 'uuid' : serviceHierarchy.pnfs[pnfName].uuid, + 'isMissingData' :this.setIsMissingData(ServiceNodeTypes.PNF, [], isEcompGeneratedNaming), + 'productFamilyId': formValues.productFamilyId, + 'lcpCloudRegionId': null, + 'tenantId': null, + 'lineOfBusiness': null, + 'platformName': null, + 'modelInfo': { + 'modelType': 'PNF', + 'modelInvariantId': serviceHierarchy.pnfs[pnfName].invariantUuid, + 'modelVersionId': serviceHierarchy.pnfs[pnfName].uuid, + 'modelName': serviceHierarchy.pnfs[pnfName].name, + 'modelVersion': serviceHierarchy.pnfs[pnfName].version, + 'modelCustomizationId': serviceHierarchy.pnfs[pnfName].customizationUuid, + 'modelCustomizationName': serviceHierarchy.pnfs[pnfName].modelCustomizationName, + 'modelUniqueId' : serviceHierarchy.pnfs[pnfName].customizationUuid || serviceHierarchy.pnfs[pnfName].uuid, + }, + 'trackById': DefaultDataGeneratorService.createRandomTrackById(), + } + } + generateNetworkData(serviceHierarchy: any, networkName: string, formValues: any, isEcompGeneratedNaming) { return { 'uuid' : serviceHierarchy.network[networkName].uuid, diff --git a/vid-webpack-master/src/app/shared/shared.module.ts b/vid-webpack-master/src/app/shared/shared.module.ts index f228389aa..e4238e079 100644 --- a/vid-webpack-master/src/app/shared/shared.module.ts +++ b/vid-webpack-master/src/app/shared/shared.module.ts @@ -99,6 +99,9 @@ import {MessageModal} from "./components/messageModal/message-modal.service"; import {SpaceToUnderscorePipe} from "./pipes/spaceToUnderscore/space-to-underscore.pipe"; import {ResizableModule} from 'angular-resizable-element'; import {PnfPopupService} from "./components/genericFormPopup/genericFormServices/pnf/pnf.popup.service"; +import {PnfControlGenerator} from "./components/genericForm/formControlsServices/pnfGenerator/pnf.control.generator"; + + @NgModule({ imports: [ @@ -235,6 +238,7 @@ import {PnfPopupService} from "./components/genericFormPopup/genericFormServices ServiceControlGenerator, ServicePopupService, VnfControlGenerator, + PnfControlGenerator, VfModuleControlGenerator, ControlGeneratorUtil, SharedControllersService, diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts index a135563eb..faf4aae4e 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts @@ -26,6 +26,8 @@ import {CrActions} from "./cr/cr.actions"; import {crReducer} from "./cr/cr.reducer"; import {NcfActions} from "./ncf/ncf.actions"; import {ncfReducer} from "./ncf/ncf.reducer"; +import {PNFActions} from "./pnf/pnf.actions"; +import {pnfReducer} from "./pnf/pnf.reducers"; export let initialState: ServiceState = { serviceHierarchy: {}, @@ -64,6 +66,8 @@ export const MainReducer = function (state: ServiceState = initialState, action: return vfModuleReducer(state, action); }else if (Object.values(VNFActions).includes(action.type)){ return vnfReducer(state, action); + }else if (Object.values(PNFActions).includes(action.type)){ + return pnfReducer(state, action); }else if (Object.values(VnfGroupActions).includes(action.type)){ return vnfGroupReducer(state, action); }else if(Object.values(RelatedVnfActions).includes(action.type)){ diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/network/network.reducers.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/network/network.reducers.ts index a8154e856..9c4421317 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/network/network.reducers.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/network/network.reducers.ts @@ -8,7 +8,7 @@ import { UpdateNetworkInstanceAction } from "./network.actions"; import {ServiceInstance} from "../../../models/serviceInstance"; -import {calculateNextUniqueModelName} from "../vnf/vnf.reducers"; +import {calculateNextUniqueModelName} from "../reducersHelper"; import {ServiceState} from "../main.reducer"; import {ServiceInstanceActions} from "../../../models/serviceInstanceActions"; import {deleteFirstLevel, updateServiceValidationCounter} from "../reducersHelper"; diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.actions.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.actions.ts new file mode 100644 index 000000000..82ab59fb5 --- /dev/null +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.actions.ts @@ -0,0 +1,88 @@ +import {Action, ActionCreator} from "redux"; +import {PnfInstance} from "../../../models/pnfInstance"; +import {ActionOnFirstLevel} from "../firstLevel/firstLevel.actions"; + +export enum PNFActions { + CREATE_PNF_INSTANCE = "CREATE_PNF_INSTANCE", + UPDATE_PNF_INSTANCE = "UPDATE_PNF_INSTANCE", + REMOVE_PNF_INSTANCE = "REMOVE_PNF_INSTANCE", + DELETE_ACTION_PNF_INSTANCE = "DELETE_PNF_INSTANCE", + UNDO_DELETE_ACTION_PNF_INSTANCE = "UNDO_DELETE_PNF_INSTANCE", + UPDATE_PNF_POSITION = "UPDATE_PNF_POISTION" +} + +export enum PNFMethods{ + UPGRADE = "upgrade", + UNDO_UPGRADE = "undoUpgrade" +} + + +export interface CreatePnfInstanceAction extends Action { + pnfInstance?: PnfInstance; + pnfModelName?: string; + serviceUuid?: string; + pnfStoreKey?:string; +} + +export interface UpdatePnfPosition extends Action { + node: any, + instanceId : string, + pnfStoreKey?: string; +} + +export interface UpdatePnfInstanceAction extends Action { + pnfInstance?: PnfInstance; + pnfModelName?: string; + serviceUuid?: string; + pnfStoreKey?:string; +} + +export interface RemovePnfInstanceAction extends Action { + pnfStoreKey: string; + serviceId?: string; +} + +export const createPNFInstance: ActionCreator<CreatePnfInstanceAction> = (pnfInstance, pnfModelName, serviceUuid, pnfStoreKey) => ({ + type: PNFActions.CREATE_PNF_INSTANCE, + pnfInstance: pnfInstance, + pnfModelName: pnfModelName, + serviceUuid: serviceUuid, + pnfStoreKey : pnfStoreKey +}); + + +export const updatePNFInstance: ActionCreator<UpdatePnfInstanceAction> = (pnfInstance, pnfModelName, serviceUuid, pnfStoreKey) => ({ + type: PNFActions.UPDATE_PNF_INSTANCE, + pnfInstance: pnfInstance, + pnfModelName: pnfModelName, + serviceUuid: serviceUuid, + pnfStoreKey : pnfStoreKey +}); + + +export const deleteActionPnfInstance: ActionCreator<ActionOnFirstLevel> = (pnfStoreKey, serviceId) => ({ + type: PNFActions.DELETE_ACTION_PNF_INSTANCE, + firstLevelName: 'pnfs', + storeKey: pnfStoreKey, + serviceId: serviceId +}); + +export const undoDeleteActionPnfInstance: ActionCreator<ActionOnFirstLevel> = (pnfStoreKey, serviceId) => ({ + type: PNFActions.UNDO_DELETE_ACTION_PNF_INSTANCE, + firstLevelName: 'pnfs', + storeKey: pnfStoreKey, + serviceId: serviceId +}); + +export const removePnfInstance: ActionCreator<RemovePnfInstanceAction> = (pnfStoreKey, serviceId) => ({ + type: PNFActions.REMOVE_PNF_INSTANCE, + pnfStoreKey: pnfStoreKey, + serviceId: serviceId +}); + +export const updatePnfPosition: ActionCreator<UpdatePnfPosition> = (node, instanceId, pnfStoreKey) => ({ + type: PNFActions.UPDATE_PNF_POSITION, + node: node, + instanceId: instanceId, + pnfStoreKey : pnfStoreKey +}); diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.reducers.spec.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.reducers.spec.ts new file mode 100644 index 000000000..b92495773 --- /dev/null +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.reducers.spec.ts @@ -0,0 +1,172 @@ +import { + CreatePnfInstanceAction, + RemovePnfInstanceAction, + UpdatePnfPosition, + UpdatePnfInstanceAction, + PNFActions +} from "./pnf.actions"; +import {pnfReducer} from "./pnf.reducers"; +import {ServiceInstanceActions} from "../../../models/serviceInstanceActions"; +import {ActionOnFirstLevel} from "../firstLevel/firstLevel.actions"; +import {PnfInstance} from "../../../models/pnfInstance"; + +describe('pnfReducer', () => { + + test('#CREATE_PNF_INSTANCE', () => { + let pnfInstance: PnfInstance = new PnfInstance(); + pnfInstance.isMissingData = false; + pnfInstance.instanceName = 'instanceName'; + let pnfState = pnfReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + pnfs: {} + } + } + }, + <CreatePnfInstanceAction>{ + type: PNFActions.CREATE_PNF_INSTANCE, + pnfInstance: pnfInstance, + pnfStoreKey: null, + pnfModelName: 'pnfModelName', + serviceUuid: 'serviceModelId' + }).serviceInstance['serviceModelId'].pnfs['pnfModelName']; + + expect(pnfState).toBeDefined(); + expect(pnfState.isMissingData).toBeFalsy(); + }); + + test('#UPDATE_PNF_INSTANCE_NAME', () => { + let newInstanceName: string = "newInstanceName" + let pnfInstance: PnfInstance = new PnfInstance(); + pnfInstance.isMissingData = false; + pnfInstance.instanceName = newInstanceName; + + let pnfState = pnfReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + pnfs: { + "pnfStoreKey": { + instanceName: 'oldInstanceName' + } + }, + existingNames: { + 'oldinstancename': {} + } + } + } + }, + <UpdatePnfInstanceAction>{ + type: PNFActions.UPDATE_PNF_INSTANCE, + pnfInstance: pnfInstance, + pnfStoreKey: 'pnfStoreKey', + pnfModelName: 'pnfModelName', + serviceUuid: 'serviceModelId' + }).serviceInstance['serviceModelId']; + + expect(pnfState).toBeDefined(); + expect(pnfState.pnfs['pnfStoreKey'].instanceName).toEqual(newInstanceName); + expect(newInstanceName.toLowerCase() in pnfState.existingNames).toBeTruthy(); + }); + + test('#DELETE_ACTION_PNF_INSTANCE', () => { + let pnfState = pnfReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + pnfs: { + 'pnfStoreKey': { + isMissingData: true, + action: 'None' + } + } + } + } + }, + <ActionOnFirstLevel>{ + type: PNFActions.DELETE_ACTION_PNF_INSTANCE, + firstLevelName: 'pnfs', + storeKey: 'pnfStoreKey', + serviceId: 'serviceModelId' + }).serviceInstance['serviceModelId'].pnfs['pnfStoreKey']; + + expect(pnfState).toBeDefined(); + expect(pnfState.action).toEqual(ServiceInstanceActions.None_Delete); + }); + + test('#UNDO_DELETE_ACTION_PNF_INSTANCE', () => { + let pnfState = pnfReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + pnfs: { + 'pnfStoreKey': { + isMissingData: true, + action: 'Update_Delete' + } + } + } + } + }, + <ActionOnFirstLevel>{ + type: PNFActions.UNDO_DELETE_ACTION_PNF_INSTANCE, + storeKey: 'pnfStoreKey', + firstLevelName: 'pnfs', + serviceId: 'serviceModelId' + }).serviceInstance['serviceModelId'].pnfs['pnfStoreKey']; + + expect(pnfState).toBeDefined(); + expect(pnfState.action).toEqual(ServiceInstanceActions.Update); + }); + + test('#REMOVE_PNF_INSTANCE', () => { + let pnfs = pnfReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + pnfs: { + 'pnfStoreKey': { + isMissingData: true, + action: 'Update_Delete' + }, + 'pnfStoreKey_1': { + isMissingData: true, + action: 'Update_Delete' + } + } + } + } + }, + <RemovePnfInstanceAction>{ + type: PNFActions.REMOVE_PNF_INSTANCE, + pnfStoreKey: 'pnfStoreKey', + serviceId: 'serviceModelId' + }).serviceInstance['serviceModelId'].pnfs; + + expect(pnfs).toBeDefined(); + expect(pnfs['pnfStoreKey']).toBeUndefined(); + expect(pnfs['pnfStoreKey_1']).toBeDefined(); + }); + + test('#UPDATE_PNF_POSITION', () => { + let pnfInstance: PnfInstance = new PnfInstance(); + pnfInstance.isMissingData = false; + pnfInstance.instanceName = 'instanceName'; + let pnfState = pnfReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + pnfs: { + "pnfStoreKey": {} + } + } + } + }, + <UpdatePnfPosition>{ + type: PNFActions.UPDATE_PNF_POSITION, + node: <any>{ + position: 2 + }, + pnfStoreKey: 'pnfStoreKey', + instanceId: 'serviceModelId' + }).serviceInstance['serviceModelId'].pnfs['pnfStoreKey']; + + expect(pnfState).toBeDefined(); + expect(pnfState.position).toEqual(2); + }); +}); diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.reducers.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.reducers.ts new file mode 100644 index 000000000..aeeae4d4e --- /dev/null +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/pnf/pnf.reducers.ts @@ -0,0 +1,87 @@ +import {Action} from "redux"; +import {PnfInstance} from "../../../models/pnfInstance"; +import { + CreatePnfInstanceAction, + RemovePnfInstanceAction, + UpdatePnfInstanceAction, UpdatePnfPosition, + PNFActions +} from "./pnf.actions"; +import * as _ from "lodash"; +import {ServiceState} from "../main.reducer"; +import {ServiceInstanceActions} from "../../../models/serviceInstanceActions"; +import {deleteFirstLevel, updateServiceValidationCounter, calculateNextUniqueModelName, updateUniqueNames} from "../reducersHelper"; +import {ActionOnFirstLevel} from "../firstLevel/firstLevel.actions"; + +export function pnfReducer(state: ServiceState, action: Action): ServiceState { + switch (action.type) { + case PNFActions.CREATE_PNF_INSTANCE: { + const updatePnfInstanceAction = <CreatePnfInstanceAction>action; + const serviceUuid = updatePnfInstanceAction.serviceUuid; + let pnfModelName = updatePnfInstanceAction.pnfModelName; + let newState = _.cloneDeep(state); + + updatePnfInstanceAction.pnfInstance.originalName = pnfModelName; + updatePnfInstanceAction.pnfModelName = calculateNextUniqueModelName(pnfModelName, serviceUuid, newState, 'pnfs'); + + let pnfInstance: PnfInstance = newState.serviceInstance[serviceUuid].pnfs[pnfModelName]; + pnfInstance = new PnfInstance(); + updatePnfInstanceAction.pnfInstance.pnfStoreKey = updatePnfInstanceAction.pnfModelName; + updatePnfInstanceAction.pnfInstance.originalName = pnfModelName; + pnfInstance.originalName = updatePnfInstanceAction.pnfInstance.originalName; + pnfInstance.pnfStoreKey = updatePnfInstanceAction.pnfInstance.pnfStoreKey; + updateServiceValidationCounter(newState, pnfInstance['isMissingData'], updatePnfInstanceAction.pnfInstance['isMissingData'], serviceUuid); + + newState.serviceInstance[serviceUuid].pnfs[updatePnfInstanceAction.pnfModelName] = Object.assign(pnfInstance, updatePnfInstanceAction.pnfInstance); + return newState; + } + + case PNFActions.UPDATE_PNF_INSTANCE: { + const updatePnfInstanceAction = <UpdatePnfInstanceAction>action; + const serviceUuid = updatePnfInstanceAction.serviceUuid; + let pnfStoreKey = updatePnfInstanceAction.pnfStoreKey; + + let newState = _.cloneDeep(state); + let pnfInstance: PnfInstance = newState.serviceInstance[serviceUuid].pnfs[pnfStoreKey]; + let oldInstanceName = pnfInstance ? pnfInstance.instanceName : null; + updateUniqueNames(oldInstanceName, updatePnfInstanceAction.pnfInstance.instanceName, newState.serviceInstance[serviceUuid]); + + pnfInstance = pnfInstance || new PnfInstance(); + updateServiceValidationCounter(newState, pnfInstance['isMissingData'], updatePnfInstanceAction.pnfInstance['isMissingData'], serviceUuid); + + newState.serviceInstance[serviceUuid].pnfs[pnfStoreKey] = Object.assign(pnfInstance, updatePnfInstanceAction.pnfInstance); + return newState; + } + + case PNFActions.DELETE_ACTION_PNF_INSTANCE : { + return deleteFirstLevel(state, <ActionOnFirstLevel>action,true); + } + + case PNFActions.UNDO_DELETE_ACTION_PNF_INSTANCE : { + let newState = _.cloneDeep(state); + let pnf = newState.serviceInstance[(<ActionOnFirstLevel>action).serviceId].pnfs[(<ActionOnFirstLevel>action).storeKey]; + let oldState = pnf.action; + newState.serviceInstance[(<ActionOnFirstLevel>action).serviceId].pnfs[(<ActionOnFirstLevel>action).storeKey].action = (oldState.split('_')[0]) as ServiceInstanceActions; + updateServiceValidationCounter(newState, pnf['isMissingData'], false, (<ActionOnFirstLevel>action).serviceId); + return newState; + } + + case PNFActions.REMOVE_PNF_INSTANCE : { + let newState = _.cloneDeep(state); + let pnfInstance = newState.serviceInstance[(<RemovePnfInstanceAction>action).serviceId].pnfs[(<RemovePnfInstanceAction>action).pnfStoreKey]; + updateServiceValidationCounter(newState, pnfInstance['isMissingData'], false, (<RemovePnfInstanceAction>action).serviceId); + delete newState.serviceInstance[(<RemovePnfInstanceAction>action).serviceId].pnfs[(<RemovePnfInstanceAction>action).pnfStoreKey]; + return newState; + } + + case PNFActions.UPDATE_PNF_POSITION : { + let newState = _.cloneDeep(state); + newState.serviceInstance[(<UpdatePnfPosition>action).instanceId] + .pnfs[(<UpdatePnfPosition>action).pnfStoreKey] + .position = (<UpdatePnfPosition>action).node.position; + return newState; + } + } +} + + + diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/reducersHelper.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/reducersHelper.ts index c192ece48..0291a3b5c 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/reducersHelper.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/reducersHelper.ts @@ -2,6 +2,7 @@ import * as _ from "lodash"; import {ActionOnFirstLevel} from "./firstLevel/firstLevel.actions"; import {ServiceInstanceActions} from "../../models/serviceInstanceActions"; import {ServiceState} from "./main.reducer"; +import {ServiceInstance} from "../../models/serviceInstance"; export function deleteFirstLevel(state: ServiceState, action: ActionOnFirstLevel,shouldUpdateServiceValidationCounter: boolean){ let newState = _.cloneDeep(state); @@ -28,3 +29,26 @@ function resetUpgradeStatus(newState: any, serviceUuid: string){ newState.serviceInstance[serviceUuid].upgradedVFMSonsCounter = 0; newState.serviceInstance[serviceUuid].isUpgraded = false; } + +export const updateUniqueNames = (oldName: string, newName: string, serviceInstance: ServiceInstance): void => { + let existingNames = serviceInstance.existingNames; + if (!_.isNil(oldName) && oldName.toLowerCase() in existingNames) { + delete existingNames[oldName.toLowerCase()]; + } + if (!_.isNil(newName)) { + existingNames[newName.toLowerCase()] = ""; + } +}; + + +export const calculateNextUniqueModelName = (nfModelName: string, serviceId: string, state: any, levelName: string): string => { + let counter: number = null; + while (true) { + let pattern = !_.isNil(counter) ? ("_" + counter) : ""; + if (!_.isNil(state.serviceInstance[serviceId][levelName][nfModelName + pattern])) { + counter = counter ? (counter + 1) : 1; + } else { + return nfModelName + pattern; + } + } +}; diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/vnf/vnf.reducers.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/vnf/vnf.reducers.ts index c5cd88aa7..b5bcec955 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/vnf/vnf.reducers.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/vnf/vnf.reducers.ts @@ -7,10 +7,9 @@ import { VNFActions } from "./vnf.actions"; import * as _ from "lodash"; -import {ServiceInstance} from "../../../models/serviceInstance"; import {ServiceState} from "../main.reducer"; import {ServiceInstanceActions} from "../../../models/serviceInstanceActions"; -import {deleteFirstLevel, updateServiceValidationCounter} from "../reducersHelper"; +import {deleteFirstLevel, updateServiceValidationCounter, calculateNextUniqueModelName, updateUniqueNames} from "../reducersHelper"; import {ActionOnFirstLevel} from "../firstLevel/firstLevel.actions"; export function vnfReducer(state: ServiceState, action: Action): ServiceState { @@ -126,27 +125,3 @@ export function vnfReducer(state: ServiceState, action: Action): ServiceState { } } - - -const updateUniqueNames = (oldName: string, newName: string, serviceInstance: ServiceInstance): void => { - let existingNames = serviceInstance.existingNames; - if (!_.isNil(oldName) && oldName.toLowerCase() in existingNames) { - delete existingNames[oldName.toLowerCase()]; - } - if (!_.isNil(newName)) { - existingNames[newName.toLowerCase()] = ""; - } -}; - - -export const calculateNextUniqueModelName = (vnfModelName: string, serviceId: string, state: any, levelName: string): string => { - let counter: number = null; - while (true) { - let pattern = !_.isNil(counter) ? ("_" + counter) : ""; - if (!_.isNil(state.serviceInstance[serviceId][levelName][vnfModelName + pattern])) { - counter = counter ? (counter + 1) : 1; - } else { - return vnfModelName + pattern; - } - } -}; diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/vrf/vrf.reducer.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/vrf/vrf.reducer.ts index f3d81209e..33992ddfe 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/vrf/vrf.reducer.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/vrf/vrf.reducer.ts @@ -7,7 +7,7 @@ import { CreateVRFInstanceAction, DeleteActionVrfInstanceAction, UndoDeleteActionVrfInstanceAction, VrfActions } from "./vrf.actions"; -import {calculateNextUniqueModelName} from "../vnf/vnf.reducers"; +import {calculateNextUniqueModelName} from "../reducersHelper"; import {ServiceInstanceActions} from "../../../models/serviceInstanceActions"; export function vrfReducer(state: ServiceState, action: Action): ServiceState { |