diff --git a/.drone.star b/.drone.star index 64f7da67ef..2d70540775 100644 --- a/.drone.star +++ b/.drone.star @@ -101,8 +101,28 @@ config = { "earlyFail": True, }, "localApiTests": { - "skip": False, - "earlyFail": True, + "basic": { + "suites": [ + "apiAccountsHashDifficulty", + "apiArchiver", + "apiContract", + "apiGraph", + "apiSpaces", + "apiSpacesShares", + ], + "skip": False, + "earlyFail": True, + }, + "apiCors": { + "suites": [ + "apiCors", + ], + "skip": False, + "earlyFail": True, + "extraServerEnvironment": { + "OCIS_CORS_ALLOW_ORIGINS": "https://aphno.badal", + }, + }, }, "apiTests": { "numberOfParts": 10, @@ -349,15 +369,8 @@ def testPipelines(ctx): pipelines.append(cs3ApiTests(ctx, "ocis", "default")) if "skip" not in config["wopiValidatorTests"] or not config["wopiValidatorTests"]["skip"]: pipelines.append(wopiValidatorTests(ctx, "ocis", "default")) - if "skip" not in config["localApiTests"] or not config["localApiTests"]["skip"]: - pipelines += [ - localApiTests(ctx, "ocis", "apiAccountsHashDifficulty"), - localApiTests(ctx, "ocis", "apiSpaces"), - localApiTests(ctx, "ocis", "apiSpacesShares"), - localApiTests(ctx, "ocis", "apiContract"), - localApiTests(ctx, "ocis", "apiArchiver"), - localApiTests(ctx, "ocis", "apiGraph"), - ] + + pipelines += localApiTestPipeline(ctx) if "skip" not in config["apiTests"] or not config["apiTests"]["skip"]: pipelines += apiTests(ctx) @@ -670,58 +683,84 @@ def codestyle(ctx): return pipelines -def localApiTests(ctx, storage, suite, accounts_hash_difficulty = 4): - early_fail = config["localApiTests"]["earlyFail"] if "earlyFail" in config["localApiTests"] else False +def localApiTestPipeline(ctx): + pipelines = [] - return { - "kind": "pipeline", - "type": "docker", - "name": "localApiTests-%s-%s" % (suite, storage), - "platform": { - "os": "linux", - "arch": "amd64", - }, - "steps": skipIfUnchanged(ctx, "acceptance-tests") + - restoreBuildArtifactCache(ctx, "ocis-binary-amd64", "ocis/bin") + - ocisServer(storage, accounts_hash_difficulty) + - restoreBuildArtifactCache(ctx, "testrunner", dirs["core"]) + - [ - { - "name": "localApiTests-%s-%s" % (suite, storage), - "image": OC_CI_PHP % DEFAULT_PHP_VERSION, - "environment": { - "TEST_WITH_GRAPH_API": "true", - "PATH_TO_OCIS": dirs["base"], - "PATH_TO_CORE": "%s/%s" % (dirs["base"], dirs["core"]), - "TEST_SERVER_URL": "https://ocis-server:9200", - "OCIS_REVA_DATA_ROOT": "%s" % (dirs["ocisRevaDataRoot"] if storage == "owncloud" else ""), - "OCIS_SKELETON_STRATEGY": "%s" % ("copy" if storage == "owncloud" else "upload"), - "TEST_OCIS": "true", - "SEND_SCENARIO_LINE_REFERENCES": "true", - "STORAGE_DRIVER": storage, - "BEHAT_SUITE": suite, - "BEHAT_FILTER_TAGS": "~@skip&&~@skipOnGraph&&~@skipOnOcis-%s-Storage" % ("OC" if storage == "owncloud" else "OCIS"), - "EXPECTED_FAILURES_FILE": "%s/tests/acceptance/expected-failures-localAPI-on-%s-storage.md" % (dirs["base"], storage.upper()), - "UPLOAD_DELETE_WAIT_TIME": "1" if storage == "owncloud" else 0, - }, - "commands": [ - "pwd", - "ls -la", - "make test-acceptance-api", - ], - }, - ] + failEarly(ctx, early_fail), - "services": redisForOCStorage(storage), - "depends_on": getPipelineNames([buildOcisBinaryForTesting(ctx)]) + - getPipelineNames(cacheCoreReposForTesting(ctx)), - "trigger": { - "ref": [ - "refs/heads/master", - "refs/pull/**", - ], - }, + defaults = { + "suites": {}, + "skip": False, + "earlyFail": False, + "extraEnvironment": {}, + "extraServerEnvironment": {}, + "storages": ["ocis"], + "accounts_hash_difficulty": 4, } + if "localApiTests" in config: + for name, matrix in config["localApiTests"].items(): + if "skip" not in matrix or not matrix["skip"]: + params = {} + for item in defaults: + params[item] = matrix[item] if item in matrix else defaults[item] + for suite in params["suites"]: + early_fail = params["earlyFail"] if "earlyFail" in params else False + for storage in params["storages"]: + pipeline = { + "kind": "pipeline", + "type": "docker", + "name": "localApiTests-%s-%s" % (suite, storage), + "platform": { + "os": "linux", + "arch": "amd64", + }, + "steps": skipIfUnchanged(ctx, "acceptance-tests") + + restoreBuildArtifactCache(ctx, "ocis-binary-amd64", "ocis/bin") + + ocisServer(storage, params["accounts_hash_difficulty"], extra_server_environment = params["extraServerEnvironment"]) + + restoreBuildArtifactCache(ctx, "testrunner", dirs["core"]) + + localApiTests(suite, storage, params["extraEnvironment"]) + + failEarly(ctx, early_fail), + "services": redisForOCStorage(storage), + "depends_on": getPipelineNames([buildOcisBinaryForTesting(ctx)]) + + getPipelineNames(cacheCoreReposForTesting(ctx)), + "trigger": { + "ref": [ + "refs/heads/master", + "refs/pull/**", + ], + }, + } + pipelines.append(pipeline) + return pipelines + +def localApiTests(suite, storage, extra_environment = {}): + environment = { + "TEST_WITH_GRAPH_API": "true", + "PATH_TO_OCIS": dirs["base"], + "PATH_TO_CORE": "%s/%s" % (dirs["base"], dirs["core"]), + "TEST_SERVER_URL": "https://ocis-server:9200", + "OCIS_REVA_DATA_ROOT": "%s" % (dirs["ocisRevaDataRoot"] if storage == "owncloud" else ""), + "OCIS_SKELETON_STRATEGY": "%s" % ("copy" if storage == "owncloud" else "upload"), + "TEST_OCIS": "true", + "SEND_SCENARIO_LINE_REFERENCES": "true", + "STORAGE_DRIVER": storage, + "BEHAT_SUITE": suite, + "BEHAT_FILTER_TAGS": "~@skip&&~@skipOnGraph&&~@skipOnOcis-%s-Storage" % ("OC" if storage == "owncloud" else "OCIS"), + "EXPECTED_FAILURES_FILE": "%s/tests/acceptance/expected-failures-localAPI-on-%s-storage.md" % (dirs["base"], storage.upper()), + "UPLOAD_DELETE_WAIT_TIME": "1" if storage == "owncloud" else 0, + } + + for item in extra_environment: + environment[item] = extra_environment[item] + + return [{ + "name": "localApiTests-%s-%s" % (suite, storage), + "image": OC_CI_PHP % DEFAULT_PHP_VERSION, + "environment": environment, + "commands": [ + "make test-acceptance-api", + ], + }] + def cs3ApiTests(ctx, storage, accounts_hash_difficulty = 4): early_fail = config["cs3ApiTests"]["earlyFail"] if "earlyFail" in config["cs3ApiTests"] else False @@ -1981,7 +2020,7 @@ def notify(): }, } -def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on = [], deploy_type = ""): +def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on = [], deploy_type = "", extra_server_environment = {}): if deploy_type == "": user = "0:0" environment = { @@ -2114,6 +2153,9 @@ def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on = if (accounts_hash_difficulty != "default"): environment["ACCOUNTS_HASH_DIFFICULTY"] = accounts_hash_difficulty + for item in extra_server_environment: + environment[item] = extra_server_environment[item] + return [ { "name": "ocis-server", diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml index 01c570a28b..6527404c11 100644 --- a/tests/acceptance/config/behat.yml +++ b/tests/acceptance/config/behat.yml @@ -136,5 +136,20 @@ default: - TUSContext: - SpacesTUSContext: + apiCors: + paths: + - '%paths.base%/../features/apiCors' + context: *common_ldap_suite_context + contexts: + - SpacesContext: + - FeatureContext: *common_feature_context_params + - OccContext: + - WebDavPropertiesContext: + - FavoritesContext: + - ChecksumContext: + - FilesVersionsContext: + - OCSContext: + - TrashbinContext: + extensions: Cjm\Behat\StepThroughExtension: ~ diff --git a/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md b/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md index e27ee42f4e..b611ea8c9a 100644 --- a/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md +++ b/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md @@ -68,3 +68,13 @@ The expected failures in this file are from features in the owncloud/ocis repo. - [apiGraph/editGroup.feature:23](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/editGroup.feature#L23) - [apiGraph/editGroup.feature:24](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/editGroup.feature#L24) - [apiGraph/editGroup.feature:25](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/editGroup.feature#L25) + +#### [CORS headers are not identical with oC10 headers](https://github.com/owncloud/ocis/issues/5195) +- [apiCors/cors.feature:25](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiCors/cors.feature#L25) +- [apiCors/cors.feature:26](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiCors/cors.feature#L26) +- [apiCors/cors.feature:27](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiCors/cors.feature#L27) +- [apiCors/cors.feature:28](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiCors/cors.feature#L28) + +#### [Requests with invalid credentials do not return CORS headers](https://github.com/owncloud/ocis/issues/5194) +- [apiCors/cors.feature:67](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiCors/cors.feature#L67) +- [apiCors/cors.feature:68](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiCors/cors.feature#L68) diff --git a/tests/acceptance/features/apiCors/cors.feature b/tests/acceptance/features/apiCors/cors.feature new file mode 100644 index 0000000000..1764e2a28f --- /dev/null +++ b/tests/acceptance/features/apiCors/cors.feature @@ -0,0 +1,68 @@ +# NOTE: for running this feature locally, you need to run oCIS with the following env var: +# CORS_ALLOWED_ORIGINS=https://aphno.badal +@api @skipOnOcV10 +Feature: CORS headers + + Background: + Given user "Alice" has been created with default attributes and without skeleton files + + + Scenario Outline: CORS headers should be returned when setting CORS domain sending Origin header + Given using OCS API version "" + When user "Alice" sends HTTP method "GET" to OCS API endpoint "" with headers + | header | value | + | Origin | https://aphno.badal | + Then the OCS status code should be "" + And the HTTP status code should be "" + And the following headers should be set + | header | value | + | Access-Control-Allow-Headers | OC-Checksum,OC-Total-Length,OCS-APIREQUEST,X-OC-Mtime,OC-RequestAppPassword,Accept,Authorization,Brief,Content-Length,Content-Range,Content-Type,Date,Depth,Destination,Host,If,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Location,Lock-Token,Overwrite,Prefer,Range,Schedule-Reply,Timeout,User-Agent,X-Expected-Entity-Length,Accept-Language,Access-Control-Request-Method,Access-Control-Allow-Origin,Cache-Control,ETag,OC-Autorename,OC-CalDav-Import,OC-Chunked,OC-Etag,OC-FileId,OC-LazyOps,OC-Total-File-Length,Origin,X-Request-ID,X-Requested-With | + | Access-Control-Expose-Headers | Content-Location,DAV,ETag,Link,Lock-Token,OC-ETag,OC-Checksum,OC-FileId,OC-JobStatus-Location,OC-RequestAppPassword,Vary,Webdav-Location,X-Sabre-Status | + | Access-Control-Allow-Origin | https://aphno.badal | + | Access-Control-Allow-Methods | GET,OPTIONS,POST,PUT,DELETE,MKCOL,PROPFIND,PATCH,PROPPATCH,REPORT | + Examples: + | ocs_api_version | endpoint | ocs-code | http-code | + | 1 | /config | 100 | 200 | + | 2 | /config | 200 | 200 | + | 1 | /apps/files_sharing/api/v1/shares | 100 | 200 | + | 2 | /apps/files_sharing/api/v1/shares | 200 | 200 | + + + Scenario Outline: CORS headers should not be returned when CORS domain does not match Origin header + Given using OCS API version "" + When user "Alice" sends HTTP method "GET" to OCS API endpoint "" with headers + | header | value | + | Origin | https://mero.badal | + Then the OCS status code should be "" + And the HTTP status code should be "" + And the following headers should not be set + | header | + | Access-Control-Allow-Headers | + | Access-Control-Expose-Headers | + | Access-Control-Allow-Origin | + | Access-Control-Allow-Methods | + Examples: + | ocs_api_version | endpoint | ocs-code | http-code | + | 1 | /config | 100 | 200 | + | 2 | /config | 200 | 200 | + | 1 | /apps/files_sharing/api/v1/shares | 100 | 200 | + | 2 | /apps/files_sharing/api/v1/shares | 200 | 200 | + + + Scenario Outline: CORS headers should be returned when an invalid password is used + Given using OCS API version "" + When user "Alice" sends HTTP method "GET" to OCS API endpoint "" with headers using password "invalid" + | header | value | + | Origin | https://aphno.badal | + Then the OCS status code should be "997" + And the HTTP status code should be "401" + And the following headers should be set + | header | value | + | Access-Control-Allow-Headers | OC-Checksum,OC-Total-Length,OCS-APIREQUEST,X-OC-Mtime,OC-RequestAppPassword,Accept,Authorization,Brief,Content-Length,Content-Range,Content-Type,Date,Depth,Destination,Host,If,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Location,Lock-Token,Overwrite,Prefer,Range,Schedule-Reply,Timeout,User-Agent,X-Expected-Entity-Length,Accept-Language,Access-Control-Request-Method,Access-Control-Allow-Origin,Cache-Control,ETag,OC-Autorename,OC-CalDav-Import,OC-Chunked,OC-Etag,OC-FileId,OC-LazyOps,OC-Total-File-Length,Origin,X-Request-ID,X-Requested-With | + | Access-Control-Expose-Headers | Content-Location,DAV,ETag,Link,Lock-Token,OC-ETag,OC-Checksum,OC-FileId,OC-JobStatus-Location,OC-RequestAppPassword,Vary,Webdav-Location,X-Sabre-Status | + | Access-Control-Allow-Origin | https://aphno.badal | + | Access-Control-Allow-Methods | GET,OPTIONS,POST,PUT,DELETE,MKCOL,PROPFIND,PATCH,PROPPATCH,REPORT | + Examples: + | ocs_api_version | endpoint | + | 1 | /apps/files_sharing/api/v1/shares | + | 2 | /apps/files_sharing/api/v1/shares |