diff --git a/.travis.yml b/.travis.yml index 6389f8cea7..512a7be85d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,15 +59,18 @@ jobs: name: Build script: - ./scripts/travis/build/build.sh - - ./scripts/lint.sh - ./scripts/travis/release/release-npm.sh - ./scripts/travis/release/release-docker.sh after_success: - - ./scripts/travis/release/release-docker.sh - ./scripts/ci/utils/artifact-to-s3.sh -a ./dist/demo-shell -o "$S3_DBP_FOLDER/alfresco-demoshell.tar.bz2" - ./scripts/ci/utils/artifact-to-s3.sh -a ./lib/dist -o "$S3_DBP_FOLDER/alfresco-libs.tar.bz2" + - stage: Lint & Build Dist & Release + name: Lint + script: + - ./scripts/lint.sh + - stage: Unit test name: Unit test content script: ./scripts/travis/unit-test/content.sh diff --git a/e2e/content-services/pages/permissions.page.ts b/e2e/content-services/pages/permissions.page.ts index b71886c2e2..204347c7c5 100644 --- a/e2e/content-services/pages/permissions.page.ts +++ b/e2e/content-services/pages/permissions.page.ts @@ -21,7 +21,7 @@ import { BrowserVisibility, BrowserActions } from '@alfresco/adf-testing'; -import { by, element } from 'protractor'; +import { browser, by, element } from 'protractor'; export class PermissionsPage { @@ -43,6 +43,13 @@ export class PermissionsPage { await BrowserActions.click(this.closeButton); } + async changePermission(name: string, role: string): Promise { + await this.addPermissionsDialog.clickRoleDropdownByUserOrGroupName(name); + await this.addPermissionsDialog.selectOption(role); + await browser.sleep(500); + await this.dataTableComponentPage.checkRowIsNotSelected('Authority ID', name); + } + async checkAddPermissionButtonIsDisplayed(): Promise { await BrowserVisibility.waitUntilElementIsVisible(this.addPermissionButton); } diff --git a/e2e/content-services/permissions/permissions-component.e2e.ts b/e2e/content-services/permissions/permissions-component.e2e.ts index 336b792426..5518682e8b 100644 --- a/e2e/content-services/permissions/permissions-component.e2e.ts +++ b/e2e/content-services/permissions/permissions-component.e2e.ts @@ -23,6 +23,8 @@ import { BrowserActions, LoginPage, NotificationHistoryPage, + PermissionActions, + SearchService, StringUtil, UploadActions, UserModel, @@ -34,6 +36,7 @@ import { FolderModel } from '../../models/ACS/folder.model'; import { MetadataViewPage } from '../../core/pages/metadata-view.page'; import { NavigationBarPage } from '../../core/pages/navigation-bar.page'; import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page'; +import { NotificationDemoPage } from '../../core/pages/notification.page'; describe('Permissions Component', () => { @@ -44,6 +47,9 @@ describe('Permissions Component', () => { const navigationBarPage = new NavigationBarPage(); const uploadActions = new UploadActions(apiService); const usersActions = new UsersActions(apiService); + const notificationPage = new NotificationDemoPage(); + const searchService = new SearchService(apiService); + const permissionActions = new PermissionActions(apiService); const contentList = contentServicesPage.getDocumentList(); const viewerPage = new ViewerPage(); @@ -72,6 +78,10 @@ describe('Permissions Component', () => { displayName: StringUtil.generateRandomString() }; + const fileOwnerUser = new UserModel(); + const filePermissionUser = new UserModel(); + + const duplicateUserPermissionMessage = 'One or more of the permissions you have set is already present : authority -> ' + filePermissionUser.email + ' / role -> Contributor'; const roleConsumerFolderModel = new FolderModel({ name: 'roleConsumer' + StringUtil.generateRandomString() }); const roleCoordinatorFolderModel = new FolderModel({ name: 'roleCoordinator' + StringUtil.generateRandomString() }); const roleCollaboratorFolderModel = new FolderModel({ name: 'roleCollaborator' + StringUtil.generateRandomString() }); @@ -79,99 +89,36 @@ describe('Permissions Component', () => { const roleEditorFolderModel = new FolderModel({ name: 'roleEditor' + StringUtil.generateRandomString() }); let roleConsumerFolder, roleCoordinatorFolder, roleContributorFolder, roleCollaboratorFolder, roleEditorFolder; - let folders; - const fileOwnerUser = new UserModel(); - const filePermissionUser = new UserModel(); - - const duplicateUserPermissionMessage = 'One or more of the permissions you have set is already present : authority -> ' + filePermissionUser.email + ' / role -> Contributor'; beforeAll(async () => { await apiService.loginWithProfile('admin'); await usersActions.createUser(fileOwnerUser); await usersActions.createUser(filePermissionUser); await apiService.getInstance().core.groupsApi.createGroup(groupBody); - await apiService.login(fileOwnerUser.email, fileOwnerUser.password); + // to sync user in acs + await searchService.isUserSearchable(filePermissionUser); + + await apiService.login(fileOwnerUser.email, fileOwnerUser.password); roleConsumerFolder = await uploadActions.createFolder(roleConsumerFolderModel.name, '-my-'); roleCoordinatorFolder = await uploadActions.createFolder(roleCoordinatorFolderModel.name, '-my-'); roleContributorFolder = await uploadActions.createFolder(roleContributorFolderModel.name, '-my-'); roleCollaboratorFolder = await uploadActions.createFolder(roleCollaboratorFolderModel.name, '-my-'); roleEditorFolder = await uploadActions.createFolder(roleEditorFolderModel.name, '-my-'); - folders = [roleConsumerFolder, roleContributorFolder, roleCoordinatorFolder, roleCollaboratorFolder, roleEditorFolder]; - - await apiService.getInstance().core.nodesApi.updateNode(roleConsumerFolder.entry.id, - - { - permissions: { - locallySet: [{ - authorityId: filePermissionUser.email, - name: 'Consumer', - accessStatus: 'ALLOWED' - }] - } - }); - - await apiService.getInstance().core.nodesApi.updateNode(roleCollaboratorFolder.entry.id, - { - permissions: { - locallySet: [{ - authorityId: filePermissionUser.email, - name: 'Collaborator', - accessStatus: 'ALLOWED' - }] - } - }); - - await apiService.getInstance().core.nodesApi.updateNode(roleCoordinatorFolder.entry.id, - { - permissions: { - locallySet: [{ - authorityId: filePermissionUser.email, - name: 'Coordinator', - accessStatus: 'ALLOWED' - }] - } - }); - - await apiService.getInstance().core.nodesApi.updateNode(roleContributorFolder.entry.id, - - { - permissions: { - locallySet: [{ - authorityId: filePermissionUser.email, - name: 'Contributor', - accessStatus: 'ALLOWED' - }] - } - }); - - await apiService.getInstance().core.nodesApi.updateNode(roleEditorFolder.entry.id, - - { - permissions: { - locallySet: [{ - authorityId: filePermissionUser.email, - name: 'Editor', - accessStatus: 'ALLOWED' - }] - } - }); - await uploadActions.uploadFile(fileModel.location, 'RoleConsumer' + fileModel.name, roleConsumerFolder.entry.id); await uploadActions.uploadFile(fileModel.location, 'RoleContributor' + fileModel.name, roleContributorFolder.entry.id); await uploadActions.uploadFile(fileModel.location, 'RoleCoordinator' + fileModel.name, roleCoordinatorFolder.entry.id); await uploadActions.uploadFile(fileModel.location, 'RoleCollaborator' + fileModel.name, roleCollaboratorFolder.entry.id); await uploadActions.uploadFile(fileModel.location, 'RoleEditor' + fileModel.name, roleEditorFolder.entry.id); - await browser.sleep(browser.params.testConfig.timeouts.index_search); // wait search index previous file/folder uploaded - }); + await permissionActions.addRoleForUser(filePermissionUser.email, 'Consumer', roleConsumerFolder); + await permissionActions.addRoleForUser(filePermissionUser.email, 'Collaborator', roleCollaboratorFolder); + await permissionActions.addRoleForUser(filePermissionUser.email, 'Coordinator', roleCoordinatorFolder); + await permissionActions.addRoleForUser(filePermissionUser.email, 'Contributor', roleContributorFolder); + await permissionActions.addRoleForUser(filePermissionUser.email, 'Editor', roleEditorFolder); - afterAll(async () => { - await apiService.loginWithProfile('admin'); - for (const folder of folders) { - await uploadActions.deleteFileOrFolder(folder.entry.id); - } + await browser.sleep(browser.params.testConfig.timeouts.index_search); // wait search index previous file/folder uploaded }); describe('Inherit and assigning permissions', () => { @@ -200,19 +147,6 @@ describe('Permissions Component', () => { await navigationBarPage.clickLogoutButton(); }); - it('[C268974] Inherit Permission', async () => { - await permissionsPage.addPermissionsDialog.checkPermissionInheritedButtonIsDisplayed(); - await permissionsPage.addPermissionsDialog.getPermissionInheritedButtonText('Permission Inherited'); - await permissionsPage.addPermissionsDialog.checkPermissionsDatatableIsDisplayed(); - await permissionsPage.addPermissionsDialog.clickPermissionInheritedButton(); - - await permissionsPage.addPermissionsDialog.getPermissionInheritedButtonText('Inherit Permission'); - await permissionsPage.addPermissionsDialog.checkNoPermissionsIsDisplayed(); - await permissionsPage.addPermissionsDialog.clickPermissionInheritedButton(); - await permissionsPage.addPermissionsDialog.getPermissionInheritedButtonText('Permission Inherited'); - await permissionsPage.addPermissionsDialog.checkPermissionsDatatableIsDisplayed(); - }); - it('[C286272] Should be able to see results when searching for a user', async () => { await permissionsPage.checkAddPermissionButtonIsDisplayed(); await permissionsPage.addPermissionsDialog.clickAddPermissionButton(); @@ -262,7 +196,7 @@ describe('Permissions Component', () => { await permissionsPage.addPermissionsDialog.clickAddPermissionButton(); await permissionsPage.addPermissionsDialog.checkAddPermissionDialogIsDisplayed(); await permissionsPage.addPermissionsDialog.checkSearchUserInputIsDisplayed(); - await permissionsPage.addPermissionsDialog.searchUserOrGroup(filePermissionUser.email); + await permissionsPage.addPermissionsDialog.searchUserOrGroup(filePermissionUser.firstName); await permissionsPage.addPermissionsDialog.clickUserOrGroup(filePermissionUser.firstName); await permissionsPage.addPermissionsDialog.checkUserIsAdded(filePermissionUser.email); }); @@ -284,19 +218,17 @@ describe('Permissions Component', () => { await expect(await BrowserActions.getText(roleDropdownOptions.get(3))).toBe('Editor'); await expect(await BrowserActions.getText(roleDropdownOptions.get(4))).toBe('Consumer'); - await permissionsPage.addPermissionsDialog.selectOption('Collaborator'); + await BrowserActions.closeMenuAndDialogs(); + await permissionsPage.changePermission(filePermissionUser.email, 'Collaborator'); await expect(await permissionsPage.addPermissionsDialog.getRoleCellValue(filePermissionUser.email)).toEqual('Collaborator'); - await permissionsPage.addPermissionsDialog.clickRoleDropdownByUserOrGroupName(filePermissionUser.email); - await permissionsPage.addPermissionsDialog.selectOption('Coordinator'); + await permissionsPage.changePermission(filePermissionUser.email, 'Coordinator'); await expect(await permissionsPage.addPermissionsDialog.getRoleCellValue(filePermissionUser.email)).toEqual('Coordinator'); - await permissionsPage.addPermissionsDialog.clickRoleDropdownByUserOrGroupName(filePermissionUser.email); - await permissionsPage.addPermissionsDialog.selectOption('Editor'); + await permissionsPage.changePermission(filePermissionUser.email, 'Editor'); await expect(await permissionsPage.addPermissionsDialog.getRoleCellValue(filePermissionUser.email)).toEqual('Editor'); - await permissionsPage.addPermissionsDialog.clickRoleDropdownByUserOrGroupName(filePermissionUser.email); - await permissionsPage.addPermissionsDialog.selectOption('Consumer'); + await permissionsPage.changePermission(filePermissionUser.email, 'Consumer'); await expect(await permissionsPage.addPermissionsDialog.getRoleCellValue(filePermissionUser.email)).toEqual('Consumer'); }); @@ -305,9 +237,10 @@ describe('Permissions Component', () => { await permissionsPage.addPermissionsDialog.clickAddPermissionButton(); await permissionsPage.addPermissionsDialog.checkAddPermissionDialogIsDisplayed(); await permissionsPage.addPermissionsDialog.checkSearchUserInputIsDisplayed(); - await permissionsPage.addPermissionsDialog.searchUserOrGroup(filePermissionUser.email); + await permissionsPage.addPermissionsDialog.searchUserOrGroup(filePermissionUser.firstName); await permissionsPage.addPermissionsDialog.clickUserOrGroup(filePermissionUser.firstName); + await expect(await notificationPage.getSnackBarMessage()).toEqual(duplicateUserPermissionMessage); await notificationHistoryPage.checkNotifyContains(duplicateUserPermissionMessage); }); @@ -336,8 +269,11 @@ describe('Permissions Component', () => { await BrowserActions.closeMenuAndDialogs(); await contentList.checkActionMenuIsNotDisplayed(); await contentServicesPage.metadataContent('RoleConsumer' + fileModel.name); + await expect(await notificationPage.getSnackBarMessage()).toEqual('You don\'t have access to do this.'); await notificationHistoryPage.checkNotifyContains('You don\'t have access to do this.'); + await browser.sleep(3000); await contentServicesPage.uploadFile(fileLocation); + await expect(await notificationPage.getSnackBarMessage()).toEqual('You don\'t have the create permission to upload the content'); await notificationHistoryPage.checkNotifyContains('You don\'t have the create permission to upload the content'); }); @@ -443,8 +379,9 @@ describe('Permissions Component', () => { await permissionsPage.addPermissionsDialog.checkPermissionInheritedButtonIsDisplayed(); await permissionsPage.checkAddPermissionButtonIsDisplayed(); await permissionsPage.addPermissionsDialog.clickPermissionInheritedButton(); - await notificationHistoryPage.checkNotifyContains('You are not allowed to change permissions'); + await expect(await notificationPage.getSnackBarMessage()).toEqual('You are not allowed to change permissions'); await permissionsPage.addPermissionsDialog.clickAddPermissionButton(); + await expect(await notificationPage.getSnackBarMessage()).toEqual('You are not allowed to change permissions'); await notificationHistoryPage.checkNotifyContains('You are not allowed to change permissions'); }); }); diff --git a/e2e/protractor.excludes.json b/e2e/protractor.excludes.json index 58024bd418..c0765340ae 100644 --- a/e2e/protractor.excludes.json +++ b/e2e/protractor.excludes.json @@ -7,13 +7,6 @@ "C279932": "login problem APS not basic", "C279931": "login problem APS not basic", "C279930": "login problem APS not basic", - "C274691": "ADF-5283 Fix Permission Flaky test", - "C276980": "ADF-5283 Fix Permission Flaky test", - "C276993": "ADF-5283 Fix Permission Flaky test", - "C276996": "ADF-5283 Fix Permission Flaky test", - "C277000": "ADF-5283 Fix Permission Flaky test", - "C277003": "ADF-5283 Fix Permission Flaky test", - "C277004": "ADF-5283 Fix Permission Flaky test", "C299187": "ADF-5285 Failing aspect test due multiple replica", "C311290": "ADF-5293" } diff --git a/lib/testing/src/lib/core/actions/search.service.ts b/lib/testing/src/lib/core/actions/search.service.ts index ff7b16d8f4..9f2302a758 100644 --- a/lib/testing/src/lib/core/actions/search.service.ts +++ b/lib/testing/src/lib/core/actions/search.service.ts @@ -16,68 +16,101 @@ */ import { ApiService } from './api.service'; -import { ResultSetPaging } from '@alfresco/js-api'; +import { ResultSetPaging, SearchApi } from '@alfresco/js-api'; import { Logger } from '../utils/logger'; import { ApiUtil } from './api.util'; +import { UserModel } from '../models/user.model'; export class SearchService { apiService: ApiService; + searchApi: SearchApi; constructor(apiService: ApiService) { this.apiService = apiService; + this.searchApi = new SearchApi(this.apiService.getInstance()); } async isSearchable(name: string): Promise { - const query = this.createSearchQuery(name); + const query = this.createSearchQuery(name); const predicate = (result: ResultSetPaging) => { - return result.list && result.list.entries.length > 0 && !!result.list.entries.find(({ entry }) => entry.name === name); + return !!result?.list?.entries?.find(({ entry }) => entry.name === name); }; + return this.performSearch(query, predicate, 'Failed to search folder'); + } + + async performSearch(query, predicate, errorMessage): Promise { const apiCall = async () => { try { - const path = '/alfresco/api/-default-/public/search/versions/1/search'; - const method = 'POST'; - - const queryParams = {}, - postBody = JSON.parse(query); - - return this.apiService.performECMOperation(path, method, queryParams, postBody); + return this.searchApi.search(query); } catch (error) { - Logger.error('Failed to search folder'); + Logger.error(errorMessage); + return null; } }; return ApiUtil.waitForApi(apiCall, predicate); } - private createSearchQuery(name: string) { - return `{ - "query": { - "query": "${name}*" + async isUserSearchable(user: UserModel): Promise { + const query = this.createUserSearchQuery(user); + + const predicate = (result: ResultSetPaging) => { + return result.list && result.list.entries.length > 0 && !!result.list.entries.find(({ entry }) => entry.properties['cm:email'] === user.email); + }; + + return this.performSearch(query, predicate, 'Failed to search user'); + } + + private createUserSearchQuery(user: UserModel) { + return { + 'query': { + 'query': `email:*${user.email}* OR firstName:*${user.firstName}* OR lastName:*${user.lastName}*` }, - "include": [ - "path", - "allowableOperations", - "properties" + 'include': [ + 'aspectNames', + 'properties' ], - "paging": { - "maxItems": 20, - "skipCount": 0 + 'paging': { + 'maxItems': 1, + 'skipCount': 0 }, - "filterQueries": [ + 'filterQueries': [ { - "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" + 'query': `TYPE:'cm:authority'` + } + ] + }; + } + + private createSearchQuery(name: string) { + return { + 'query': { + 'query': `${name}*` + }, + 'include': [ + 'path', + 'allowableOperations', + 'properties' + ], + 'paging': { + 'maxItems': 20, + 'skipCount': 0 + }, + 'filterQueries': [ + { + 'query': `TYPE:'cm:folder' OR TYPE:'cm:content'` }, { - "query": "NOT cm:creator:System" + 'query': 'NOT cm:creator:System' } ], - "scope": { - "locations": [ - "nodes" + 'scope': { + 'locations': [ + 'nodes' ] } - }`; + }; } } diff --git a/scripts/lint.sh b/scripts/lint.sh index 51eff7ea3f..770752391e 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -8,14 +8,7 @@ if grep "envalfresco" . -R --exclude-dir={node_modules,.history,.idea,scripts,di exit 1 fi -npm run ng -- lint extensions && \ -npm run ng -- lint core && \ -npm run ng -- lint content-services && \ -npm run ng -- lint process-services && \ -npm run ng -- lint process-services-cloud && \ -npm run ng -- lint insights && \ -npm run ng -- lint testing && \ -npm run ng -- lint demoshell && \ +nx affected:lint --parallel --all --maxParallel=9 && \ npm run lint-e2e && \ npm run stylelint && \ npm run spellcheck && \