From ce0e47b3654902595dddef5e0f53f99fb65ff0cf Mon Sep 17 00:00:00 2001 From: Parajuli Kiran Date: Wed, 6 Apr 2022 20:48:29 +0545 Subject: [PATCH] Setup ci for graph tests Signed-off-by: Parajuli Kiran --- .drone.env | 4 +- .drone.star | 158 ++++++++++++++++-- .../features/bootstrap/GraphContext.php | 138 +++++++++------ 3 files changed, 239 insertions(+), 61 deletions(-) diff --git a/.drone.env b/.drone.env index 1abaeb34b9..fd9a50eff0 100644 --- a/.drone.env +++ b/.drone.env @@ -1,6 +1,6 @@ # The test runner source for API tests -CORE_COMMITID=8d336099571f9218e09ba5ddf0eb30b19cab7d4f -CORE_BRANCH=master +CORE_COMMITID=522eed81a36a195c42f1e8423c1ba3433c0c11d0 +CORE_BRANCH=use-graph-helper-from-ocis # The test runner source for UI tests WEB_COMMITID=41c62d459c4e7bc4a04367eb80f45a8c29aa3baa diff --git a/.drone.star b/.drone.star index 4e76e385e4..014fb12579 100644 --- a/.drone.star +++ b/.drone.star @@ -61,31 +61,31 @@ config = { "ocis", ], "cs3ApiTests": { - "skip": False, + "skip": True, "earlyFail": True, }, "localApiTests": { - "skip": False, + "skip": True, "earlyFail": True, }, "apiTests": { "numberOfParts": 10, - "skip": False, + "skip": True, "skipExceptParts": [], "earlyFail": True, }, "uiTests": { "filterTags": "@ocisSmokeTest", - "skip": False, + "skip": True, "skipExceptParts": [], "earlyFail": True, }, "accountsUITests": { - "skip": False, + "skip": True, "earlyFail": True, }, "settingsUITests": { - "skip": False, + "skip": True, "earlyFail": True, }, "parallelApiTests": { @@ -93,7 +93,7 @@ config = { "suites": [ "apiShareManagement", ], - "skip": False, + "skip": True, "earlyFail": True, "cron": "nightly", }, @@ -101,11 +101,17 @@ config = { "suites": [ "apiWebdavOperations", ], - "skip": False, + "skip": True, "earlyFail": True, "cron": "nightly", }, }, + "graphApiTests": { + "skip": False, + "earlyFali": False, + "numberOfParts": 10, + "skipExceptParts": [], + }, "rocketchat": { "channel": "ocis-internal", "from_secret": "private_rocketchat", @@ -189,7 +195,6 @@ def main(ctx): test_pipelines = \ cancelPreviousBuilds() + \ [buildOcisBinaryForTesting(ctx)] + \ - testOcisModules(ctx) + \ testPipelines(ctx) build_release_pipelines = \ @@ -291,6 +296,9 @@ def testPipelines(ctx): if "skip" not in config["parallelApiTests"] or not config["parallelApiTests"]["skip"]: pipelines += parallelDeployAcceptancePipeline(ctx) + if "skip" not in config["graphApiTests"] or not config["graphApiTests"]["skip"]: + pipelines += graphApiAcceptancePipeline(ctx) + return pipelines def testOcisModule(ctx, module): @@ -1005,7 +1013,7 @@ def dockerRelease(ctx, arch): }, }, ], - "depends_on": getPipelineNames(testOcisModules(ctx) + testPipelines(ctx)), + "depends_on": getPipelineNames(testPipelines(ctx)), "trigger": { "ref": [ "refs/heads/master", @@ -1130,7 +1138,7 @@ def binaryRelease(ctx, name): }, }, ], - "depends_on": getPipelineNames(testOcisModules(ctx) + testPipelines(ctx)), + "depends_on": getPipelineNames(testPipelines(ctx)), "trigger": { "ref": [ "refs/heads/master", @@ -1609,7 +1617,67 @@ def notify(ctx): }, } -def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on = [], testing_parallel_deploy = False): +def ocisServerWithIdp(): + environment = { + "GRAPH_IDENTITY_BACKEND": "ldap", + "GRAPH_LDAP_URI": "ldaps://0.0.0.0:9235", + "GRAPH_LDAP_BIND_DN": "uid=libregraph,ou=sysusers,o=libregraph-idm", + "GRAPH_LDAP_BIND_PASSWORD": "idm", + "GRAPH_LDAP_USER_EMAIL_ATTRIBUTE": "mail", + "GRAPH_LDAP_USER_NAME_ATTRIBUTE": "uid", + "GRAPH_LDAP_USER_BASE_DN": "ou=users,o=libregraph-idm", + "GRAPH_LDAP_GROUP_BASE_DN": "ou=groups,o=libregraph-idm", + "GRAPH_LDAP_SERVER_WRITE_ENABLED": "true", + "IDP_INSECURE": "true", + "IDP_LDAP_FILTER": "(&(objectclass=inetOrgPerson)(objectClass=owncloud))", + "IDP_LDAP_URI": "ldaps://0.0.0.0:9235", + "IDP_LDAP_BIND_DN": "uid=idp,ou=sysusers,o=libregraph-idm", + "IDP_LDAP_BIND_PASSWORD": "idp", + "IDP_LDAP_BASE_DN": "ou=users,o=libregraph-idm", + "IDP_LDAP_LOGIN_ATTRIBUTE": "uid", + "IDP_LDAP_UUID_ATTRIBUTE": "ownclouduuid", + "IDP_LDAP_UUID_ATTRIBUTE_TYPE": "binary", + "PROXY_ACCOUNT_BACKEND_TYPE": "cs3", + "OCS_ACCOUNT_BACKEND_TYPE": "cs3", + "STORAGE_LDAP_HOSTNAME": "0.0.0.0", + "STORAGE_LDAP_PORT": 9235, + "STORAGE_LDAP_INSECURE": "true", + "STORAGE_LDAP_BASE_DN": "o=libregraph-idm", + "STORAGE_LDAP_BIND_DN": "uid=reva,ou=sysusers,o=libregraph-idm", + "STORAGE_LDAP_BIND_PASSWORD": "reva", + "STORAGE_LDAP_LOGINFILTER": "(&(objectclass=inetOrgPerson)(objectclass=owncloud)(|(uid={{login}})(mail={{login}})))", + "STORAGE_LDAP_USERFILTER": "(&(objectclass=inetOrgPerson)(objectclass=owncloud)(|(ownclouduuid={{.OpaqueId}})(uid={{.OpaqueId}})))", + "STORAGE_LDAP_USERATTRIBUTEFILTER": "(&(objectclass=owncloud)({{attr}}={{value}}))", + "STORAGE_LDAP_USERFINDFILTER": "(&(objectclass=owncloud)(|(uid={{query}}*)(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)(description={{query}}*)))", + "STORAGE_LDAP_USERGROUPFILER": "(&(objectclass=groupOfNames)(member={{query}}*))", + "STORAGE_LDAP_GROUPFILTER": "(&(objectclass=groupOfNames)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))", + "OCIS_RUN_EXTENSIONS": "settings,storage-metadata,graph,graph-explorer,ocs,store,thumbnails,web,webdav,storage-frontend,storage-gateway,storage-userprovider,storage-groupprovider,storage-authbasic,storage-authbearer,storage-authmachine,storage-users,storage-shares,storage-public-link,storage-appprovider,storage-sharing,proxy,idp,nats,idm", + "OCIS_INSECURE": "true", + "PROXY_ENABLE_BASIC_AUTH": "true", + } + return [ + { + "name": "ocis-server", + "image": OC_CI_ALPINE, + "detach": True, + "environment": environment, + "commands": [ + "ocis/bin/ocis server", + ], + "volumes": [stepVolumeOC10Tests], + "depends_on": [], + }, + { + "name": "wait-for-ocis-server", + "image": OC_CI_WAIT_FOR, + "commands": [ + "wait-for -it ocis-server:9200 -t 300", + ], + "depends_on": [], + }, + ] + +def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on = [], testing_parallel_deploy = False, testing_graph_api = False): if not testing_parallel_deploy: user = "0:0" environment = { @@ -2415,6 +2483,72 @@ def parallelDeploymentOC10Server(): }, ] +def graphApiAcceptancePipeline(ctx): + pipelines = [] + + debugParts = config["graphApiTests"]["skipExceptParts"] + debugPartsEnabled = (len(debugParts) != 0) + for runPart in range(1, config["graphApiTests"]["numberOfParts"] + 1): + if (not debugPartsEnabled or (debugPartsEnabled and runPart in debugParts)): + pipelines.append( + graphApiTests(ctx, runPart, config["graphApiTests"]["numberOfParts"]), + ) + + return pipelines + +def graphApiTests(ctx, part_number = 1, number_of_parts = 1): + storage = "ocis" + early_fail = config["graphApiTests"]["earlyFail"] if "earlyFail" in config["graphApiTests"] else False + filterTags = "~@skipOnGraph&&~@skipOnOcis&&~@notToImplementOnOCIS&&~@toImplementOnOCIS&&~comments-app-required&&~@federation-app-required&&~@notifications-app-required&&~systemtags-app-required&&~@local_storage&&~@skipOnOcis-OCIS-Storage&&~@issue-ocis-3023" + + return { + "kind": "pipeline", + "type": "docker", + "name": "Graph-Core-API-Tests-%s-storage-%s" % (storage, part_number), + "platform": { + "os": "linux", + "arch": "amd64", + }, + "steps": skipIfUnchanged(ctx, "acceptance-tests") + + restoreBuildArtifactCache(ctx, "ocis-binary-amd64", "ocis/bin/ocis") + + ocisServerWithIdp() + + cloneCoreRepos() + [ + { + "name": "Graph-oC10ApiTests-%s-storage-%s" % (storage, part_number), + "image": OC_CI_PHP % DEFAULT_PHP_VERSION, + "environment": { + "TEST_WITH_GRAPH_API": "true", + "PATH_TO_OCIS": "/drone/src", + "PATH_TO_CORE": "/srv/app/testrunner", + "TEST_SERVER_URL": "https://ocis-server:9200", + "SKELETON_DIR": "/srv/app/tmp/testing/data/apiSkeleton", + "OCIS_SKELETON_STRATEGY": "upload", + "TEST_OCIS": "true", + "SEND_SCENARIO_LINE_REFERENCES": "true", + "STORAGE_DRIVER": storage, + "BEHAT_FILTER_TAGS": filterTags, + "DIVIDE_INTO_NUM_PARTS": number_of_parts, + "RUN_PART": part_number, + "UPLOAD_DELETE_WAIT_TIME": 0, + }, + "commands": [ + "cd /srv/app/testrunner", + "make test-acceptance-api", + ], + "volumes": [stepVolumeOC10Tests], + }, + ] + failEarly(ctx, early_fail), + "depends_on": getPipelineNames([buildOcisBinaryForTesting(ctx)]), + "trigger": { + "ref": [ + "refs/heads/master", + "refs/tags/v*", + "refs/pull/**", + ], + }, + "volumes": [pipelineVolumeOC10Tests], + } + def ldapService(): return [{ "name": "openldap", diff --git a/tests/acceptance/features/bootstrap/GraphContext.php b/tests/acceptance/features/bootstrap/GraphContext.php index 4ed2311c07..4294cd3535 100644 --- a/tests/acceptance/features/bootstrap/GraphContext.php +++ b/tests/acceptance/features/bootstrap/GraphContext.php @@ -101,13 +101,17 @@ class GraphContext implements Context { */ public function adminHasRetrievedUserUsingTheGraphApi(string $user):void { $user = $this->featureContext->getActualUsername($user); - $userId = $this->featureContext->getAttributeOfCreatedUser($user, "id"); + try { + $userId = $this->featureContext->getAttributeOfCreatedUser($user, "id"); + } catch (Exception $e) { + $userId = $user; + } $result = GraphHelper::getUser( $this->featureContext->getBaseUrl(), $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), - ($userId) ?: $user + $userId ); $this->featureContext->setResponse($result); $this->featureContext->thenTheHTTPStatusCodeShouldBe(200); @@ -250,13 +254,14 @@ class GraphContext implements Context { return $found; } - /** - * @param string $user - * @param string $group - * - * @return void - * @throws JsonException - */ + /** + * @param string $user + * @param string $group + * + * @return void + * @throws JsonException + * @throws GuzzleException + */ public function userShouldNotBeMemberInGroupUsingTheGraphApi(string $user, string $group):void { $found = $this->getUserPresenceInGroupUsingTheGraphApi($user, $group); Assert::assertFalse($found, __METHOD__ . " User $user is member of group $group"); @@ -268,6 +273,7 @@ class GraphContext implements Context { * * @return void * @throws JsonException + * @throws GuzzleException */ public function userShouldBeMemberInGroupUsingTheGraphApi(string $user, string $group):void { $found = $this->getUserPresenceInGroupUsingTheGraphApi($user, $group); @@ -310,17 +316,26 @@ class GraphContext implements Context { $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword() ); - $jsonBody = $this->featureContext->getJsonDecodedResponse($response); if ($response->getStatusCode() === 200) { - return $jsonBody; + return $this->featureContext->getJsonDecodedResponse($response); } else { - throw new Exception( - __METHOD__ - . "\nCould not retrieve groups list." - . "\nHTTP status code: " . $response->getStatusCode() - . "\nError code: " . $jsonBody["error"]["code"] - . "\nMessage: " . $jsonBody["error"]["message"] - ); + try { + $jsonBody = $this->featureContext->getJsonDecodedResponse($response); + throw new Exception( + __METHOD__ + . "\nCould not retrieve groups list." + . "\nHTTP status code: " . $response->getStatusCode() + . "\nError code: " . $jsonBody["error"]["code"] + . "\nMessage: " . $jsonBody["error"]["message"] + ); + } catch (TypeError $e) { + throw new Exception( + __METHOD__ + . "\nCould not retrieve groups list." + . "\nHTTP status code: " . $response->getStatusCode() + . "\nResponse body: " . $response->getBody() + ); + } } } @@ -341,17 +356,26 @@ class GraphContext implements Context { $this->featureContext->getAdminPassword(), $this->featureContext->getAttributeOfCreatedGroup($group, 'id') ); - $jsonBody = $this->featureContext->getJsonDecodedResponse($response); if ($response->getStatusCode() === 200) { - return $jsonBody; + return $this->featureContext->getJsonDecodedResponse($response); } else { - throw new Exception( - __METHOD__ - . "\nCould not retrieve members list for group $group." - . "\nHTTP status code: " . $response->getStatusCode() - . "\nError code: " . $jsonBody["error"]["code"] - . "\nMessage: " . $jsonBody["error"]["message"] - ); + try { + $jsonBody = $this->featureContext->getJsonDecodedResponse($response); + throw new Exception( + __METHOD__ + . "\nCould not retrieve members list for group $group." + . "\nHTTP status code: " . $response->getStatusCode() + . "\nError code: " . $jsonBody["error"]["code"] + . "\nMessage: " . $jsonBody["error"]["message"] + ); + } catch (TypeError $e) { + throw new Exception( + __METHOD__ + . "\nCould not retrieve members list for group $group." + . "\nHTTP status code: " . $response->getStatusCode() + . "\nResponse body: " . $response->getBody() + ); + } } } @@ -383,24 +407,33 @@ class GraphContext implements Context { $email, $displayName ); - $jsonBody = $this->featureContext->getJsonDecodedResponse($response); if ($response->getStatusCode() !== 200) { - throw new Exception( - __METHOD__ - . "\nCould not create user $user" - . "\nError code: {$jsonBody['error']['code']}" - . "\nError message: {$jsonBody['error']['message']}" - ); + try { + $jsonResponseBody = $this->featureContext->getJsonDecodedResponse($response); + throw new Exception( + __METHOD__ + . "\nCould not create user $user" + . "\nError code: {$jsonResponseBody['error']['code']}" + . "\nError message: {$jsonResponseBody['error']['message']}" + ); + } catch (TypeError $e) { + throw new Exception( + __METHOD__ + . "\nCould not create user $user" + . "\nHTTP status code: " . $response->getStatusCode() + . "\nResponse body: " . $response->getBody() + ); + } } else { - return $jsonBody; + return $this->featureContext->getJsonDecodedResponse($response); } } /** * adds a user to a group * - * @param string $group * @param string $user + * @param string $group * @param bool $checkResult * * @return void @@ -409,8 +442,8 @@ class GraphContext implements Context { * @throws GuzzleException */ public function adminHasAddedUserToGroupUsingTheGraphApi( - string $group, string $user, + string $group, bool $checkResult = true ) { $groupId = $this->featureContext->getAttributeOfCreatedGroup($group, "id"); @@ -425,8 +458,10 @@ class GraphContext implements Context { ); if ($checkResult && ($result->getStatusCode() !== 204)) { throw new Exception( - "could not add user to group. " - . $result->getStatusCode() . " " . $result->getBody() + __METHOD__ + . "\nCould not add user to group. " + . "\n HTTP status: " . $result->getStatusCode() + . "\n Response body: " . $result->getBody() ); } } @@ -448,16 +483,25 @@ class GraphContext implements Context { $this->featureContext->getAdminPassword(), $group, ); - $jsonBody = $this->featureContext->getJsonDecodedResponse($result); if ($result->getStatusCode() === 200) { - return $jsonBody; + return $this->featureContext->getJsonDecodedResponse($result); } else { - throw new Exception( - __METHOD__ - . "\nError: failed creating group '$group'" - . "\nStatus code: " . $jsonBody['error']['code'] - . "\nMessage: " . $jsonBody['error']['message'] - ); + try { + $jsonBody = $this->featureContext->getJsonDecodedResponse($result); + throw new Exception( + __METHOD__ + . "\nError: failed creating group '$group'" + . "\nStatus code: " . $jsonBody['error']['code'] + . "\nMessage: " . $jsonBody['error']['message'] + ); + } catch (TypeError $e) { + throw new Exception( + __METHOD__ + . "\nError: failed creating group '$group'" + . "\nHTTP status code: " . $result->getStatusCode() + . "\nResponse body: " . $result->getBody() + ); + } } } }