Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[full-ci] [tests-only] [E2E] full text search tests added #9238

Merged
merged 4 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 50 additions & 24 deletions .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FEDERATED = 2
NOTIFICATIONS = 3

ALPINE_GIT = "alpine/git:latest"
APACHE_TIKA = "apache/tika:2.8.0.0"
DEEPDIVER_DOCKER_ORACLE_XE_11G = "deepdiver/docker-oracle-xe-11g:latest"
DRONE_CLI_ALPINE = "drone/cli:alpine"
MINIO_MC = "minio/mc:RELEASE.2021-10-07T04-19-58Z"
Expand Down Expand Up @@ -1198,7 +1199,8 @@ def e2eTests(ctx):
# oCIS specific steps
steps += setupServerConfigureWeb(params["logLevel"]) + \
restoreOcisCache() + \
ocisService() + \
tikaService() + \
ocisService("e2e-tests") + \
getSkeletonFiles()

steps += [{
Expand Down Expand Up @@ -1336,7 +1338,7 @@ def acceptance(ctx):

if (params["runningOnOCIS"]):
# Services and steps required for running tests with oCIS
steps += restoreOcisCache() + ocisService() + getSkeletonFiles()
steps += restoreOcisCache() + ocisService("acceptance-tests") + getSkeletonFiles()
grgprarup marked this conversation as resolved.
Show resolved Hide resolved

else:
# Services and steps required for running tests with oc10
Expand Down Expand Up @@ -2160,33 +2162,40 @@ def idpService():
}],
}]

def ocisService():
def ocisService(type):
grgprarup marked this conversation as resolved.
Show resolved Hide resolved
environment = {
"IDM_ADMIN_PASSWORD": "admin", # override the random admin password from `ocis init`
"IDP_IDENTIFIER_REGISTRATION_CONF": "%s" % dir["ocisIdentifierRegistrationConfig"],
"OCIS_INSECURE": "true",
"OCIS_LOG_LEVEL": "error",
"OCIS_URL": "https://ocis:9200",
"LDAP_GROUP_SUBSTRING_FILTER_TYPE": "any",
"LDAP_USER_SUBSTRING_FILTER_TYPE": "any",
"PROXY_ENABLE_BASIC_AUTH": True,
"STORAGE_HOME_DRIVER": "ocis",
"STORAGE_METADATA_DRIVER_OCIS_ROOT": "/srv/app/tmp/ocis/storage/metadata",
"STORAGE_SHARING_USER_JSON_FILE": "/srv/app/tmp/ocis/shares.json",
"STORAGE_USERS_DRIVER": "ocis",
"STORAGE_USERS_DRIVER_LOCAL_ROOT": "/srv/app/tmp/ocis/local/root",
"STORAGE_USERS_DRIVER_OCIS_ROOT": "/srv/app/tmp/ocis/storage/users",
"STORAGE_USERS_DRIVER_OWNCLOUD_DATADIR": "%s" % dir["ocisRevaDataRoot"],
"WEB_ASSET_PATH": "%s/dist" % dir["web"],
"WEB_UI_CONFIG": "%s" % dir["ocisConfig"],
"FRONTEND_SEARCH_MIN_LENGTH": "2",
"FRONTEND_OCS_ENABLE_DENIALS": True,
}

if type == "e2e-tests":
environment["FRONTEND_FULL_TEXT_SEARCH_ENABLED"] = True
environment["SEARCH_EXTRACTOR_TYPE"] = "tika"
environment["SEARCH_EXTRACTOR_TIKA_TIKA_URL"] = "http://tika:9998"

return [
{
"name": "ocis",
"image": OC_CI_GOLANG,
"detach": True,
"environment": {
"IDM_ADMIN_PASSWORD": "admin", # override the random admin password from `ocis init`
"IDP_IDENTIFIER_REGISTRATION_CONF": "%s" % dir["ocisIdentifierRegistrationConfig"],
"OCIS_INSECURE": "true",
"OCIS_LOG_LEVEL": "error",
"OCIS_URL": "https://ocis:9200",
"LDAP_GROUP_SUBSTRING_FILTER_TYPE": "any",
"LDAP_USER_SUBSTRING_FILTER_TYPE": "any",
"PROXY_ENABLE_BASIC_AUTH": True,
"STORAGE_HOME_DRIVER": "ocis",
"STORAGE_METADATA_DRIVER_OCIS_ROOT": "/srv/app/tmp/ocis/storage/metadata",
"STORAGE_SHARING_USER_JSON_FILE": "/srv/app/tmp/ocis/shares.json",
"STORAGE_USERS_DRIVER": "ocis",
"STORAGE_USERS_DRIVER_LOCAL_ROOT": "/srv/app/tmp/ocis/local/root",
"STORAGE_USERS_DRIVER_OCIS_ROOT": "/srv/app/tmp/ocis/storage/users",
"STORAGE_USERS_DRIVER_OWNCLOUD_DATADIR": "%s" % dir["ocisRevaDataRoot"],
"WEB_ASSET_PATH": "%s/dist" % dir["web"],
"WEB_UI_CONFIG": "%s" % dir["ocisConfig"],
"FRONTEND_SEARCH_MIN_LENGTH": "2",
"FRONTEND_OCS_ENABLE_DENIALS": True,
},
"environment": environment,
"commands": [
"cd %s" % dir["ocis"],
"mkdir -p %s" % dir["ocisRevaDataRoot"],
Expand Down Expand Up @@ -3175,3 +3184,20 @@ def publishTracingResult(ctx, suite):
],
},
}]

def tikaService():
return [
{
"name": "tika",
"type": "docker",
"image": APACHE_TIKA,
"detach": True,
},
{
"name": "wait-for-tika-service",
"image": OC_CI_WAIT_FOR,
"commands": [
"wait-for -it tika:9998 -t 300",
],
},
]
20 changes: 20 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
#FRONTEND
FRONTEND_SEARCH_MIN_LENGTH: "2"
FRONTEND_OCS_ENABLE_DENIALS: "true"
FRONTEND_FULL_TEXT_SEARCH_ENABLED: "true"

# IDM
IDM_CREATE_DEMO_USERS: "${DEMO_USERS:-true}"
Expand Down Expand Up @@ -56,6 +57,10 @@ services:

# CORS
OCIS_CORS_ALLOW_ORIGINS: "https://host.docker.internal:9201"

# TIKA
SEARCH_EXTRACTOR_TYPE: "tika"
SEARCH_EXTRACTOR_TIKA_TIKA_URL: "http://host.docker.internal:9998"
volumes:
- ./dev/docker/ocis.entrypoint.sh:/usr/bin/entrypoint
- ./dev/docker/ocis.idp.config.yaml:/etc/ocis/idp.yaml
Expand All @@ -73,6 +78,7 @@ services:
traefik.http.routers.ocis.middlewares: cors
depends_on:
- traefik
- tika-service

oc10:
build:
Expand Down Expand Up @@ -231,6 +237,20 @@ services:
- "./dev/docker/traefik/configs:/configs"
- "/var/run/docker.sock:/var/run/docker.sock:ro"

tika-service:
image: dadarek/wait-for-dependencies
container_name: web_tika_service
depends_on:
- tika
command: tika:9998

tika:
image: apache/tika:2.8.0.0
container_name: web_tika
ports:
- 9998:9998
restart: always
grgprarup marked this conversation as resolved.
Show resolved Hide resolved

volumes:
uploads:
uppy_companion_datadir:
Expand Down
93 changes: 93 additions & 0 deletions tests/e2e/cucumber/features/smoke/fullTextSearch.ocis.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
Feature: Search
As a user
I want to do full text search
So that I can find the files with the content I am looking for

Scenario: search for content of file
Given "Admin" creates following users using API
| id |
| Alice |
| Brian |
And "Admin" assigns following roles to the users using API
| id | role |
| Brian | Space Admin |
And "Alice" logs in
And "Alice" uploads the following local file into personal space using API
| localFile | to |
| filesForUpload/textfile.txt | fileToShare.txt |
ScharfViktor marked this conversation as resolved.
Show resolved Hide resolved
And "Alice" opens the "files" app
And "Alice" adds the following tags for the following resources using the sidebar panel
| resource | tags |
| fileToShare.txt | alice tag |
And "Alice" shares the following resource using API
| resource | recipient | type | role |
| fileToShare.txt | Brian | user | Can edit |
And "Alice" logs out
And "Brian" logs in
And "Brian" accepts the following share using API
| name |
| fileToShare.txt |
And "Brian" creates the following folder in personal space using API
| name |
| testFolder |
And "Brian" uploads the following local file into personal space using API
| localFile | to |
| filesForUpload/textfile.txt | textfile.txt |
| filesForUpload/textfile.txt | fileWithTag.txt |
| filesForUpload/textfile.txt | withTag.txt |
| filesForUpload/textfile.txt | testFolder/innerTextfile.txt |
And "Brian" creates the following project spaces using API
| name | id |
| FullTextSearch | fulltextsearch.1 |
And "Brian" creates the following folder in space "FullTextSearch" using API
| name |
| spaceFolder |
And "Brian" creates the following file in space "FullTextSearch" using API
| name | content |
| spaceFolder/spaceTextfile.txt | This is test file. Cheers |
And "Brian" opens the "files" app
And "Brian" adds the following tags for the following resources using the sidebar panel
| resource | tags |
| fileWithTag.txt | tag 1 |
| withTag.txt | tag 1 |

When "Brian" searches "" using the global search bar
Then "Brian" should see the message "Search for files" on the webUI

When "Brian" selects tag "alice tag" from the search result filter chip
Then following resources should be displayed in the files list for user "Brian"
| resource |
| fileToShare.txt |

When "Brian" clears tag filter
And "Brian" selects tag "tag 1" from the search result filter chip
Then following resources should be displayed in the files list for user "Brian"
| resource |
| fileWithTag.txt |
| withTag.txt |

When "Brian" searches "file" using the global search bar
Then following resources should be displayed in the files list for user "Brian"
| resource |
| fileWithTag.txt |

When "Brian" clears tag filter
Then following resources should be displayed in the files list for user "Brian"
| resource |
| textfile.txt |
| fileWithTag.txt |
| testFolder/innerTextfile.txt |
| fileToShare.txt |
| spaceFolder/spaceTextfile.txt |

When "Brian" enables the option to search in file content
And "Brian" searches "Cheers" using the global search bar
Then following resources should be displayed in the files list for user "Brian"
| resource |
| textfile.txt |
| testFolder/innerTextfile.txt |
| fileToShare.txt |
| fileWithTag.txt |
| withTag.txt |
| spaceFolder/spaceTextfile.txt |
And "Brian" logs out
47 changes: 47 additions & 0 deletions tests/e2e/cucumber/steps/ui/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { When, Then } from '@cucumber/cucumber'
import { World } from '../../environment'
import { objects } from '../../../support'
import { expect } from '@playwright/test'

When(
'{string} searches {string} using the global search bar',
async function (this: World, stepUser: string, keyword: string): Promise<void> {
const { page } = this.actorsEnvironment.getActor({ key: stepUser })
const searchObject = new objects.applicationFiles.Search({ page })
await searchObject.fullTextSearch({ keyword })
}
)

Then(
'{string} should see the message {string} on the webUI',
async function (this: World, stepUser: string, message: string): Promise<void> {
const { page } = this.actorsEnvironment.getActor({ key: stepUser })
const searchObject = new objects.applicationFiles.Search({ page })
const actualMessage = await searchObject.getSearchResultMessage()
expect(actualMessage).toBe(message)
}
)

When(
'{string} selects tag {string} from the search result filter chip',
async function (this: World, stepUser: string, tag: string): Promise<void> {
const { page } = this.actorsEnvironment.getActor({ key: stepUser })
const searchObject = new objects.applicationFiles.Search({ page })
await searchObject.selectTagFilter({ tag })
}
)

When('{string} clears tag filter', async function (this: World, stepUser: string): Promise<void> {
const { page } = this.actorsEnvironment.getActor({ key: stepUser })
const searchObject = new objects.applicationFiles.Search({ page })
await searchObject.clearTagFilter()
})

When(
/^"([^"]*)" (enable|disable)s the option to search in file content?$/,
async function (this: World, stepUser: string, enableOrDisable: string): Promise<void> {
const { page } = this.actorsEnvironment.getActor({ key: stepUser })
const searchObject = new objects.applicationFiles.Search({ page })
await searchObject.toggleSearchInFileContent({ enableOrDisable })
}
)
1 change: 1 addition & 0 deletions tests/e2e/support/objects/app-files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { Resource } from './resource'
export { Share } from './share'
export { Spaces } from './spaces'
export { Trashbin } from './trashbin'
export { Search } from './search'
46 changes: 46 additions & 0 deletions tests/e2e/support/objects/app-files/search/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Page } from 'playwright'
import util from 'util'

const globalSearchInputSelector = '.oc-search-input'
const searchResultMessageSelector = '//p[@class="oc-text-muted"]'
const selectTagDropdownSelector =
'//div[contains(@class,"files-search-filter-tags")]//button[contains(@class,"oc-filter-chip-button")]'
const tagFilterChipSelector = '//button[contains(@data-test-value,"%s")]'
const clearTagFilterSelector =
'//div[contains(@class,"files-search-filter-tags")]//button[contains(@class,"oc-filter-chip-clear")]'
const enableSearchInFileContentSelector =
'//div[contains(@class,"files-search-filter-full-text")]//button[contains(@class,"oc-filter-chip-button")]'
const disableSearchInFileContentSelector =
'//div[contains(@class,"files-search-filter-full-text")]//button[contains(@class,"oc-filter-chip-clear")]'

export interface fullTextSearchArgs {
keyword: string
page: Page
}

export const fullTextSearch = async (args: fullTextSearchArgs): Promise<void> => {
grgprarup marked this conversation as resolved.
Show resolved Hide resolved
const { page, keyword } = args
await page.locator(globalSearchInputSelector).fill(keyword)
await page.keyboard.press('Enter')
}

export const getSearchResultMessage = ({ page }): Promise<string> => {
return page.locator(searchResultMessageSelector).innerText()
}

export const selectTagFilter = async ({ tag, page }): Promise<void> => {
await page.locator(selectTagDropdownSelector).click()
await page.locator(util.format(tagFilterChipSelector, tag)).click()
}

export const clearTagFilter = async ({ page }): Promise<void> => {
await page.locator(clearTagFilterSelector).click()
}

export const toggleSearchInFileContent = async ({ enableOrDisable, page }): Promise<void> => {
const selector =
enableOrDisable === 'enable'
? enableSearchInFileContentSelector
: disableSearchInFileContentSelector
await page.locator(selector).click()
}
30 changes: 30 additions & 0 deletions tests/e2e/support/objects/app-files/search/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Page } from 'playwright'
import * as po from '../search/actions'

export class Search {
#page: Page

constructor({ page }: { page: Page }) {
this.#page = page
}

async fullTextSearch(args: Omit<po.fullTextSearchArgs, 'page'>): Promise<void> {
grgprarup marked this conversation as resolved.
Show resolved Hide resolved
await po.fullTextSearch({ ...args, page: this.#page })
}

getSearchResultMessage(): Promise<string> {
return po.getSearchResultMessage({ page: this.#page })
}

async selectTagFilter({ tag: string }): Promise<void> {
await po.selectTagFilter({ tag: string, page: this.#page })
}

async clearTagFilter(): Promise<void> {
await po.clearTagFilter({ page: this.#page })
}

async toggleSearchInFileContent({ enableOrDisable: string }): Promise<void> {
await po.toggleSearchInFileContent({ enableOrDisable: string, page: this.#page })
}
}