diff --git a/.circleci/config.yml b/.circleci/config.yml index 463712d..6448fcc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,11 @@ -version: 2 +version: 2.1 +parameters: + run_performancetesting: + default: false + type: boolean + run_basedeployment: + default: true + type: boolean defaults: &defaults docker: - image: circleci/python:2.7-stretch-browsers @@ -37,7 +44,17 @@ builddeploy_steps: &builddeploy_steps ./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-${APPNAME}-deployvar source buildenvvar ./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -s ${LOGICAL_ENV}-global-appvar,${LOGICAL_ENV}-${APPNAME}-appvar -i ${APPNAME} - + #testing code changes + if [[ true ]]; then + ./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-qa-v1-appvar + source buildenvvar + curl --request POST \ + --url https://circleci.com/api/v2/project/github/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pipeline \ + --header "Circle-Token: ${QA_USER_TOKEN}" \ + --header 'content-type: application/json' \ + --data '{"branch":"'"$CIRCLE_BRANCH"'","parameters":{"run_basedeployment": false, run_performancetesting":true}}' + fi + jobs: # Build & Deploy against development backend "build-dev": @@ -56,9 +73,48 @@ jobs: APPNAME: "member-api-v5" steps: *builddeploy_steps + "Performance-Testing": + docker: + # specify the version you desire here + - image: circleci/openjdk:8-jdk + + # Specify service dependencies here if necessary + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + # - image: circleci/postgres:9.4 + + working_directory: ~/repo + + environment: + # Customize the JVM maximum heap limit + MAVEN_OPTS: -Xmx3200m + + steps: + - checkout + + # Download and cache dependencies + - restore_cache: + keys: + - v1-dependencies-{{ checksum "pom.xml" }} + # fallback to using the latest cache if no exact match is found + - v1-dependencies- + + - run: mvn dependency:go-offline + + - save_cache: + paths: + - ~/.m2 + key: v1-dependencies-{{ checksum "pom.xml" }} + + - run: mvn verify + + - store_artifacts: + path: target/jmeter/reports + workflows: version: 2 build: + when: << pipeline.parameters.run_basedeployment >> jobs: # Development builds are executed on "develop" branch only. - "build-dev": @@ -74,4 +130,21 @@ workflows: context : org-global filters: branches: - only: master \ No newline at end of file + only: master + + Performance Testing: + when: << pipeline.parameters.run_performancetesting >> + jobs: + # Performance Test is executed on "feature/performance" branch only. + - Hold [Performance-Testing]: + type: approval + - Performance-Testing: + context : org-global + requires: + - Hold [Performance-Testing] + filters: + branches: + only: + - develop + - feature/performance + - performance \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..20c76a1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,230 @@ + + 4.0.0 + com.ubikingenierie.ubikloadpack + jmeter-maven-plugin-demo + 0.0.1-SNAPSHOT + + UTF-8 + 2.9.0 + Member API.jmx + + + + commons-codec + commons-codec + 1.11 + + + org.slf4j + slf4j-api + 1.7.25 + + + org.apache.jmeter + ApacheJMeter_core + 5.1 + + + + + + + + + + standalone + + true + + + + + com.lazerycode.jmeter + jmeter-maven-plugin + ${jmeter-maven-plugin.version} + + true + 60 + true + + ${project.version} + 7 + 30 + + + kg.apc:jmeter-plugins-casutg:2.8 + + + com.ubikingenierie.ubikloadpack:jmeter-maven-plugin-demo:${project.version} + + + org.slf4j:slf4j-nop + avalon-framework:* + org.apache.tika:* + excalibur-datasource:excalibur-datasource + excalibur-instrument:excalibur-instrument + excalibur-logger:excalibur-logger + excalibur-pool:* + org.beanshell:bsh:jar:2.0b5 + + + + -XX:MaxMetaspaceSize=512m + -Xmx2048m + -Xms2048m + + + + ${jmeterScript} + + ./test/jmeter + + + + jmeter-tests + verify + + jmeter + results + + + + + + + + + worker + + + + org.codehaus.groovy.maven + gmaven-plugin + 1.0 + + + generate-resources + + execute + + + + project.properties["hostname"] = InetAddress.getLocalHost().getHostName() + + + + + + + com.lazerycode.jmeter + jmeter-maven-plugin + ${jmeter-maven-plugin.version} + + + true + + + kg.apc:jmeter-plugins-casutg:2.8 + + + com.ubikingenierie.ubikloadpack:jmeter-maven-plugin-demo:${project.version} + + + org.slf4j:slf4j-nop + avalon-framework:* + org.apache.tika:* + excalibur-datasource:excalibur-datasource + excalibur-instrument:excalibur-instrument + excalibur-logger:excalibur-logger + excalibur-pool:* + org.beanshell:bsh:jar:2.0b5 + + + + -XX:MaxMetaspaceSize=512m + -Xmx2048m + -Xms2048m + + + ${hostname} + 3010 + + + + start-jmeter-server + + remote-server + + verify + + false + + + + + + + + + controller + + + + com.lazerycode.jmeter + jmeter-maven-plugin + ${jmeter-maven-plugin.version} + + + true + + + ${project.version} + 7 + 30 + + true + + kg.apc:jmeter-plugins-casutg:2.8 + + + com.ubikingenierie.ubikloadpack:jmeter-maven-plugin-demo:${project.version} + + + org.slf4j:slf4j-nop + avalon-framework:* + org.apache.tika:* + excalibur-datasource:excalibur-datasource + excalibur-instrument:excalibur-instrument + excalibur-logger:excalibur-logger + excalibur-pool:* + org.beanshell:bsh:jar:2.0b5 + + + + -XX:MaxMetaspaceSize=512m + -Xmx2048m + -Xms2048m + + + + ${serverList} + true + + + + + performance-test + + jmeter + results + + verify + + + + + + + + \ No newline at end of file diff --git a/test/jmeter/JsonSample.groovy b/test/jmeter/JsonSample.groovy new file mode 100644 index 0000000..23c935c --- /dev/null +++ b/test/jmeter/JsonSample.groovy @@ -0,0 +1,52 @@ +import groovy.json.JsonSlurper +import groovy.json.JsonOutput +import org.apache.jmeter.services.FileServer +import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.ConcurrentHashMap + +class JsonSampleHolder { + static samples = + MapWithDefault.newInstance( + new ConcurrentHashMap(), { String f -> new JsonSample(f) } + ) + + static def next(file) { + return samples.get(file).next() + } +} + +class JsonSample { + def data = null + def ite = null + + JsonSample(file) { + if(data == null) { + def inputPath = FileServer.getFileServer().getBaseDir() + file + File inputFile = new File(inputPath) + def slurper = new JsonSlurper() + data = new ConcurrentLinkedQueue(slurper.parse(inputFile)) + ite = data.iterator() + } + } + synchronized def next() { + if(!ite.hasNext()) { + ite = data.iterator() + } + return ite.next() + } +} + + +Thread thread = Thread.currentThread(); +Long threadNum = thread.getId(); +def value = JsonSampleHolder.next(args[0]) +def json = JsonOutput.toJson(value) +log.info(threadNum + " : " + value) +vars.putObject(args[1], value) +vars.put(args[1] + "_json", json) + +if(binding.hasVariable('SampleResult')) { + SampleResult.setContentType("application/json") + SampleResult.setResponseCodeOK() + SampleResult.setResponseData(json, "utf-8") +} diff --git a/test/jmeter/Member API.jmx b/test/jmeter/Member API.jmx new file mode 100644 index 0000000..9557389 --- /dev/null +++ b/test/jmeter/Member API.jmx @@ -0,0 +1,6053 @@ + + + + + Check the Performance of the Member API + false + true + false + + + + basedir + ${__groovy(import org.apache.jmeter.services.FileServer; FileServer.getFileServer().getBaseDir();)}${__groovy(File.separator)} + = + + + + + + + + continue + + false + 1 + + 1 + 1 + false + + + false + + + + + + true + ${basedir}/JsonSample.groovy + /data/credentials.json credentials + + groovy + + + + true + + + def data = vars.getObject("credentials") +data.entrySet().each { + vars.put(it.getKey(), String.valueOf(it.getValue())) +} + + groovy + + + + + + + adminusername + ${__groovy(System.getenv("ADMIN_USERNAME"))} + = + + + adminpassword + ${__groovy(System.getenv("ADMIN_PASSWORD"))} + = + + + m2m_all_client_id + ${__groovy(System.getenv("M2M_ALL_CLIENT_ID"))} + = + + + m2m_all_client_secret + ${__groovy(System.getenv("M2M_ALL_CLIENT_SECRET"))} + = + + + + + + + + + + + false + ${adminusername} + = + true + username + + + false + ${adminpassword} + = + true + password + + + false + JFDo7HMkf0q2CkVFHojy3zHWafziprhT + = + true + client_id + + + false + false + = + true + sso + + + false + openid profile offline_access + = + true + scope + + + false + token + = + true + response_type + + + false + TC-User-Database + = + true + connection + + + false + password + = + true + grant_type + + + false + Browser + = + true + device + + + + topcoder-dev.auth0.com + + https + + /oauth/ro + POST + true + false + true + false + + + + + + + Get the {refresh_token} + refresh_token + refresh_token + + + + + Get the {id_token} + id_token + id_token + + + + + Set the {access_token} globally + ${__setProperty(id_token, ${id_token})}; +${__setProperty(refresh_token, ${refresh_token})}; + + + false + + + + + true + + + + false + { + "param": { + "externalToken": "${__property(id_token)}", + "refreshToken": "${__property(refresh_token)}" + } +} + = + + + + api.topcoder-dev.com + + https + + /v3/authorizations + POST + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(id_token)} + + + cache-control + no-cache + + + Content-Type + application/json + + + + + + adminusertoken + $.result[*].token + + + + + ${__setProperty(adminusertoken, ${adminusertoken})}; + + + false + + + + + + + + + false + https://m2m.topcoder-dev.com/ + = + true + audience + + + false + client_credentials + = + true + grant_type + + + false + application/json + = + true + content-type + + + false + ${m2m_all_client_id} + = + true + client_id + + + false + ${m2m_all_client_secret} + = + true + client_secret + + + + topcoder-dev.auth0.com + + https + + /oauth/token + POST + true + false + true + false + + + + + + + Get the {access_token} + m2m_token + access_token + + + + + Set the {access_token} globally + ${__setProperty(m2m_token, ${m2m_token})}; + + + false + + + + + + continue + + false + 1 + + 1 + 1 + false + + + true + + + + + + server-url + ${__groovy(System.getenv("SERVER_URL") ?: "api.topcoder-dev.com")} + = + + + + + + + + true + ${basedir}/JsonSample.groovy + /data/challenge-data.json challenge + + groovy + + + + true + + + def data = vars.getObject("challenge") +data.entrySet().each { + vars.put(it.getKey(), String.valueOf(it.getValue())) +} + + groovy + + + + + + + + ${server-url} + + https + + /v5/members/health + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + ${JMeterThread.last_sample_ok} + false + true + + + + + + + + + + + ${server-url} + + https + + /v5/members/upbeat + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + ${server-url} + + https + + /v5/members/invalid + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + true + + + + false + { + "email": "atif.siddiqui2@topcoder.com" +} + = + + + + ${server-url} + + https + + /v5/members/upbeat + PUT + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + + + + ${server-url} + + https + + /v5/members/upbeat/verify + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + ${server-url} + + https + + /v5/members/upbeat/verify + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(m2m_token)} + + + content-type + application/json + + + + + + + + + + token + wrong + token + = + false + true + + + + ${URL} + + + + /members/upbeat/verify + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + token + 580dd76c-7b67-4c92-8c32-cf5b90af90c5 + token + = + false + true + + + + ${URL} + + + + /members/upbeat/verify + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_read} + + + + + + + + + + token + 580dd76c-7b67-4c92-8c32-cf5b90af90c5 + token + = + false + true + + + + ${URL} + + + + /members/upbeat/verify + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${invalid_token} + + + + + + + + + + token + 580dd76c-7b67-4c92-8c32-cf5b90af90c5 + token + = + false + true + + + + ${URL} + + + + /members/upbeat/verify + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${expire_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/verify + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + token + 580dd76c-7b67-4c92-8c32-cf5b90af90c5 + token + = + false + true + + + + ${URL} + + + + /members/invalid/verify + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + true + + + + false + { + "tracks": [ + "DESIGN", + "DEVELOP" + ], + "status": "ACTIVE", + "addresses": [ + { + "zip": "560110", + "streetAddr1": "GM INFINITE ECITY TOWN", + "city": "Bangalore", + "stateCode": "Karnataka", + "type": "HOME" + } + ], + "email": "atif.siddiqui2@topcoder.com", + "firstName": "Atif Ali", + "photoURL": "https://topcoder-dev-media.s3.amazonaws.com/member/profile/upbeat-1575621848253.png", + "competitionCountryCode": "IRL", + "description": "What goes around comes around", + "homeCountryCode": "IRL" +} + = + + + + ${server-url} + + https + + /v5/members/upbeat + PUT + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + true + + + + false + { + "userId": 999, + "firstName": "fff", + "lastName": "lll", + "description": "test", + "tracks": ["code", "design"], + "email": "updated11@test.com" +} + = + + + + ${server-url} + + + + /members/testing?verifyUrl=http://test.com/abc + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + + + + + true + + + + false + { + "tracks": [ + "DESIGN", + "DEVELOP" + ], + "status": "ACTIVE", + "addresses": [ + { + "zip": "560110", + "streetAddr1": "GM INFINITE ECITY TOWN", + "city": "Bangalore", + "stateCode": "Karnataka", + "type": "HOME" + } + ], + "email": "atif.siddiqui2@topcoder.com", + "firstName": "Atif Ali", + "photoURL": "https://topcoder-dev-media.s3.amazonaws.com/member/profile/upbeat-1575621848253.png", + "competitionCountryCode": "IRL", + "userId": 40154303, + "description": "What goes around comes around", + "homeCountryCode": "IRL", + "other": "updated11@test.com" +} + = + + + + ${URL} + + + + /members/upbeat?verifyUrl=http://test.com/abc + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + Authorization + Bearer ${m2m_full} + + + + + + + true + + + + false + { + "tracks": [ + "DESIGN", + "DEVELOP" + ], + "status": "ACTIVE", + "addresses": [ + { + "zip": "560110", + "streetAddr1": "GM INFINITE ECITY TOWN", + "city": "Bangalore", + "stateCode": "Karnataka", + "type": "HOME" + } + ], + "email": "invalid", + "firstName": "Atif Ali", + "photoURL": "https://topcoder-dev-media.s3.amazonaws.com/member/profile/upbeat-1575621848253.png", + "competitionCountryCode": "IRL", + "userId": 40154303, + "description": "What goes around comes around", + "homeCountryCode": "IRL", + "other": "updated11@test.com" +} + = + + + + ${URL} + + + + /members/upbeat?verifyUrl=http://test.com/abc + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + Authorization + Bearer ${m2m_full} + + + + + + + true + + + + false + { + "tracks": [ + "DESIGN", + "DEVELOP" + ], + "status": "ACTIVE", + "addresses": [ + { + "zip": "560110", + "streetAddr1": "GM INFINITE ECITY TOWN", + "city": "Bangalore", + "stateCode": "Karnataka", + "type": "HOME" + } + ], + "email": "atif.siddiqui2@topcoder.com", + "firstName": "Atif Ali", + "photoURL": "https://topcoder-dev-media.s3.amazonaws.com/member/profile/upbeat-1575621848253.png", + "competitionCountryCode": "IRL", + "userId": 40154303, + "description": "What goes around comes around", + "homeCountryCode": "IRL" +} + = + + + + ${URL} + + + + /members/upbeat?verifyUrl=invalid + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + Authorization + Bearer ${m2m_full} + + + + + + + true + + + + false + { + "tracks": [ + "DATA_SCIENCE" + ], + "lastName": "L_NAME", + "status": "ACTIVE", + "addresses": [ + { + "streetAddr1": "123 Main Street", + "streetAddr2": "address_2", + "city": "Santa Clause", + "zip": "47579", + "stateCode": "IN", + "type": "HOME" + } + ], + "otherLangName": "NIAL", + "email": "email@domain.com.z", + "firstName": "F_NAME", + "competitionCountryCode": "IND", + "userId": 22650586 +} + = + + + + ${URL} + + + + /members/invalid?verifyUrl=http://test.com/abc + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + Authorization + Bearer ${m2m_full} + + + + + + + true + + + + false + { + "userId": 999, + "firstName": "fff", + "lastName": "lll", + "description": "test", + "tracks": ["code", "design"], + "email": "updated@test.com" +} + = + + + + ${URL} + + + + /members/testing + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_read} + + + + + + + + + + + + + photo + /Users/at397596/Documents/Workspace/Topcoder/member-api-repository/member-api/docs/member_photo.png + = + false + true + + + + ${server-url} + + https + + /v5/members/upbeat/photo + POST + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + ${URL} + + + + /members/upbeat/photo + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + photo + + = + false + true + + + + ${URL} + + + + /members/upbeat/photo + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + photo + + = + false + true + + + + ${URL} + + + + /members/invalid/photo + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + photo + + = + false + true + + + + ${URL} + + + + /members/upbeat/photo + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${user_token} + + + + + + + + + + + + + + + + traitIds + basic_info,education,work,communities,languages,hobby,organization,device,software,service_provider,subscription,personalization,connect_info + traitIds + = + false + true + + + fields + traitId,categoryName,traits,createdAt,updatedAt + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/upbeat/traits + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + traitIds + invalid,basic_info,education,skill,work,communities,languages,hobby,organization,device,software,service_provider,subscription,personalization,connect_info + traitIds + = + false + true + + + fields + traitId,categoryName,traits + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/upbeat/traits + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + traitIds + basic_info,education,skill,work,communities,languages,hobby,organization,device,software,service_provider,subscription,personalization,connect_info + traitIds + = + false + true + + + fields + traitId,categoryName,traits,categoryName + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/upbeat/traits + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + traitIds + basic_info,work,skill + traitIds + = + false + true + + + fields + traitId,categoryName,traits + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/upbeat/traits + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(m2m_token_modify)} + + + content-type + application/json + + + + + + + + + + traitIds + basic_info,work,skill + traitIds + = + false + true + + + fields + traitId,categoryName,traits + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/invalid/traits + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + true + + + + false + [ + { + "categoryName": "Software", + "traitId": "software", + "traits": { + "traitId": "software", + "data": [ + { + "softwareType": "Developer Tools", + "name": "VSCode" + } + ] + } + } +] + = + + + + ${server-url} + + https + + /v5/members/upbeat/traits + POST + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + true + + + + false + [{ + "traitId": "education", + "categoryName": "category", + "traits": { + "data": [1,2] + } +}] + = + + + + ${URL} + + + + /members/upbeat/traits + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + true + + + + false + [] + = + + + + ${URL} + + + + /members/upbeat/traits + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + true + + + + false + [{ + "traitId": "invalid", + "categoryName": "category", + "traits": { + "data": [{ "test": 123 }] + } +}] + = + + + + ${URL} + + + + /members/upbeat/traits + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + true + + + + false + [{ + "traitId": "education", + "categoryName": "category", + "traits": { + "data": [{ "test": 123 }] + } +}] + = + + + + ${URL} + + + + /members/upbeat/traits + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${invalid_token} + + + + + + + true + + + + false + [{ + "traitId": "education", + "categoryName": "category", + "traits": { + "data": [{ "test": 123 }] + } +}] + = + + + + ${URL} + + + + /members/upbeat/traits + POST + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_read} + + + + + + + + + + true + + + + false + [ + { + "categoryName": "Software", + "traitId": "software", + "traits": { + "data": [ + { + "softwareType": "Browser", + "name": "Chrome" + }, + { + "softwareType": "Developer Tools", + "name": "VSCode" + } + ] + } + } +] + = + + + + ${server-url} + + https + + /v5/members/upbeat/traits + PUT + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + true + + + + false + [ + { + "categoryName": "Hobby", + "traitId": "hobby", + "traits": { + "traitId": "hobby", + "data": [ + { + "hobby": "Cricket", + "description": "Batsman" + }, + { + "hobby": "Programming", + "description": "All Stack" + } + ] + } + }, + { + "categoryName": "Software", + "traitId": "software", + "traits": { + "data": [ + { + "softwareType": "Browser", + "name": "Chrome" + }, + { + "softwareType": "Developer Tools", + "name": "VSCode" + }, + { + "softwareType": "Developer Tools", + "name": "Postman" + } + ] + } + } +] + = + + + + ${server-url} + + https + + /v5/members/upbeat/traits + PUT + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + true + + + + false + [ + { + "categoryName": "Software", + "traitId": "", + "traits": { + "data": [ + { + "softwareType": "Browser", + "name": "Chrome" + } + ] + } + } +] + = + + + + ${URL} + + + + /members/upbeat/traits + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_update} + + + Authorization + Bearer ${admin_token} + + + + + + + true + + + + false + [ + { + "categoryName": ["ABC"], + "traitId": "software", + "traits": { + "data": [ + { + "softwareType": "Browser", + "name": "Chrome" + } + ] + } + } +] + = + + + + ${URL} + + + + /members/upbeat/traits + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_update} + + + Authorization + Bearer ${admin_token} + + + + + + + true + + + + false + [ + { + "categoryName": "Connect User Information", + "traitId": "connect_info", + "traits": { + "data": [] + } + } +] + = + + + + ${URL} + + + + /members/upbeat/traits + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_update} + + + Authorization + Bearer ${admin_token} + + + + + + + true + + + + false + [ + { + "categoryName": "Connect User Information", + "traitId": "connect_info", + "traits": { + "data": [] + } + } +] + = + + + + ${URL} + + + + /members/invalid/traits + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_update} + + + Authorization + Bearer ${admin_token} + + + + + + + true + + + + false + [ + { + "categoryName": "Connect User Information", + "traitId": "connect_info", + "traits": { + "data": [] + } + } +] + = + + + + ${URL} + + + + /members/denis/traits + PUT + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_read} + + + + + + + + + + + + + ${server-url} + + https + + /v5/members/upbeat/traits?traitIds=software + DELETE + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + ${server-url} + + https + + /v5/members/upbeat/traits + DELETE + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(m2m_token)} + + + content-type + application/json + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + ${URL} + + + + /members/upbeat/traits + DELETE + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/traits + DELETE + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/traits + DELETE + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/traits + DELETE + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/traits + DELETE + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_read} + + + + + + + + + + + + + + + + ${server-url} + + https + + /v5/members/stats/distribution + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + track + develop + track + = + false + true + + + subTrack + code + subTrack + = + false + true + + + fields + track,subTrack,distribution + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/stats/distribution + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + track + develop + track + = + false + true + + + subTrack + code + subTrack + = + false + true + + + fields + invalid + fields + = + false + true + + + + ${URL} + + + + /members/stats/distribution + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + track + develop + track + = + false + true + + + subTrack + code + subTrack + = + false + true + + + fields + track,track + fields + = + false + true + + + + ${URL} + + + + /members/stats/distribution + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + track + develop + track + = + false + true + + + subTrack + code + subTrack + = + false + true + + + fields + track, ,subTrack + fields + = + false + true + + + + ${URL} + + + + /members/stats/distribution + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + track + develop + track + = + false + true + + + subTrack + other + subTrack + = + false + true + + + fields + track,subTrack,distribution + fields + = + false + true + + + + ${URL} + + + + /members/stats/distribution + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + + + + fields + userId,handle,DATA_SCIENCE,DEVELOP,createdBy + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/standlove/stats/history + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + groupIds + 10,20000000 + groupIds + = + false + true + + + fields + userId,handle,groupId + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/standlove/stats/history + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + groupIds + 10,20000000,20000010 + groupIds + = + false + true + + + fields + userId,handle,groupId + fields + = + false + true + + + + ${URL} + + + + /members/standlove/stats/history + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,,handle,DEVELOP,createdBy + fields + = + false + true + + + + ${URL} + + + + /members/standlove/stats/history + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,invalid + fields + = + false + true + + + + ${URL} + + + + /members/standlove/stats/history + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,userId + fields + = + false + true + + + + ${URL} + + + + /members/standlove/stats/history + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,handle,DEVELOP,createdBy + fields + = + false + true + + + + ${URL} + + + + /members/invalid/stats/history + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + + + + ${server-url} + + https + + /v5/members/upbeat/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + groupIds + 20000000,20000010 + groupIds + = + false + true + + + + ${server-url} + + https + + /v5/members/tonyj/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + groupIds + 10,20000000,20000010 + groupIds + = + false + true + + + fields + userId,handle,wins,groupId,challenges + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/tonyj/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,groupId,handle,wins,DATA_SCIENCE,DEVELOP,DESIGN + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/tonyj/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,,wins,develop,design + fields + = + false + true + + + + ${URL} + + + + /members/tonyj/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,invalid + fields + = + false + true + + + + ${URL} + + + + /members/tonyj/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,userId + fields + = + false + true + + + + ${URL} + + + + /members/tonyj/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,handle,wins,groupId,challenges + fields + = + false + true + + + + ${URL} + + + + /members/invalid/stats + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + + + + fields + userId,handle,handleLower,skills,createdAt,updatedAt,createdBy,updatedBy + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/upbeat/skills + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,handle,,updatedAt,updatedBy + fields + = + false + true + + + + ${URL} + + + + /members/upbeat/skills + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,handle,handle,updatedAt,updatedBy + fields + = + false + true + + + + ${URL} + + + + /members/upbeat/skills + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,handlexxx,updatedAt,updatedBy + fields + = + false + true + + + + ${URL} + + + + /members/upbeat/skills + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + other + userId,handle,,updatedAt,updatedBy + other + = + false + true + + + + ${URL} + + + + /members/upbeat/skills + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,handle,skills,updatedAt,updatedBy + fields + = + false + true + + + + ${URL} + + + + /members/invalid/skills + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + userId,handle,skills,updatedAt,updatedBy + fields + = + false + true + + + + ${URL} + + + + /members/standlove/skills + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + true + + + + false + { + "311": { + "score": 1455 + } +} + = + + + + ${server-url} + + https + + /v5/members/upbeat/skills + PATCH + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + true + + + + false + { + "311": { + "score": 1455 + }, + "382": { + "score": 1656 + } +} + = + + + + ${server-url} + + https + + /v5/members/upbeat/skills + PATCH + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + ${URL} + + + + /members/upbeat/skills + PATCH + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/skills + PATCH + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/skills + PATCH + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + ${URL} + + + + /members/upbeat/skills + PATCH + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_read} + + + + + + + + + + ${URL} + + + + /members/invalid/skills + PATCH + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_full} + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + + + fields + userId,amount,status,createdBy,createdAt + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/denis/financial + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + userId,amount,status,createdBy,createdAt + fields + = + false + true + + + + ${server-url} + + https + + /v5/members/denis/financial + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(m2m_token)} + + + content-type + application/json + + + + + + + + + + fields + userId,invalid,status,createdBy,createdAt + fields + = + false + true + + + + ${URL} + + + + /members/denis/financial + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + fields + userId,,status,createdBy,createdAt + fields + = + false + true + + + + ${URL} + + + + /members/denis/financial + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + fields + userId,status,status,createdBy,createdAt + fields + = + false + true + + + + ${URL} + + + + /members/denis/financial + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + fields + userId,amount,status,createdBy,createdAt + fields + = + false + true + + + + ${URL} + + + + /members/other/financial + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + fields + userId,amount,status,createdBy,createdAt + fields + = + false + true + + + + ${URL} + + + + /members/denis/financial + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${m2m_update} + + + + + + + + + + fields + userId,amount,status,createdBy,createdAt + fields + = + false + true + + + + ${URL} + + + + /members/denis/financial + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + + + + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + + + + + + + + fields + homeCountryCode,handle,tracks,handleLower,firstName,lastName + fields + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + homeCountryCode,createdAt,createdBy,handle,maxRating,photoURL,skills,stats,tracks,updatedAt,updatedBy,userId,wins,handleLower,status,firstName,lastName,description,email + fields + = + false + true + + + query + upbeat* + query + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + homeCountryCode,handle,tracks,handleLower,firstName,lastName + fields + = + false + true + + + query + AFG + query + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + homeCountryCode,handle,tracks,handleLower,firstName,lastName + fields + = + false + true + + + query + "DESIGN" | "DATA_SCIENCE" + query + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + homeCountryCode,handle,tracks,handleLower,firstName,lastName + fields + = + false + true + + + query + +"DESIGN" +"DATA_SCIENCE" + query + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + handle,firstName,lastName + fields + = + false + true + + + query + mess +"F_Name" -test + query + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + handle,firstName,lastName,skills,stats + fields + = + false + true + + + query + upbeat + query + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + fields + handle,firstName,lastName + fields + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + handleLower + mess + handleLower + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + handle + standlove + handle + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + userId + 40154303 + userId + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(adminusertoken)} + + + content-type + application/json + + + + + + + + + + handleLower + upbeat + handleLower + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${server-url} + + https + + /v5/members + GET + true + false + true + false + + + + + + + + + Authorization + Bearer ${__property(m2m_token)} + + + content-type + application/json + + + + + + + + + + fields + userId,,,, + fields + = + false + true + + + handleLower + upbeat + handleLower + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${URL} + + + + /members + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + fields + userIdxxx + fields + = + false + true + + + handleLower + upbeat + handleLower + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${URL} + + + + /members + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + fields + userId,status,status + fields + = + false + true + + + handleLower + upbeat + handleLower + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${URL} + + + + /members + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + page + -1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${URL} + + + + /members + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + page + 1 + page + = + false + true + + + perPage + -10 + perPage + = + false + true + + + + ${URL} + + + + /members + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + other + 123 + other + = + false + true + + + handleLower + upbeat + handleLower + = + false + true + + + status + active + status + = + false + true + + + page + 1 + page + = + false + true + + + perPage + 10 + perPage + = + false + true + + + + ${URL} + + + + /members + GET + true + false + true + false + + + + + + + + + Accept + application/json + + + Content-Type + application/json + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + report.csv + + + + + diff --git a/test/jmeter/README.md b/test/jmeter/README.md new file mode 100644 index 0000000..dab4061 --- /dev/null +++ b/test/jmeter/README.md @@ -0,0 +1,210 @@ +# Topcoder - JMeter Performance Testing Framework - Part 1 + +## Requirements +- [Java VM >= 8](https://www.java.com/en/download/) +- [Apache maven >= ](https://maven.apache.org/download.cgi) +- [Apache jmeter >= 5.4.1](https://jmeter.apache.org/download_jmeter.cgi) + +## Project structure +- env/ + - _Default env vars to test locally_ +- test/jmeter + - data/ + - _Json Datasets_ + - JsonSample.groovy + - _Custom Json sampler in groovy_ + - Resource API.jmx + - _JMeter test plan file_ +- pom.xml + - _Maven configuration file_ +## What is provided in this project? + + +### Sensitive variables +Sensitive informations are now loaded though environments variables. +- User credentials +- M2M credentials +- TopCoder API URL + - This one is not sensitive but loading it through env var instead of csv or json is more convenient. + +Addind new one is as simple as adding new user variable within JMeter. The value of the variable has just to be set to : +```groovy +${__groovy(System.getenv("ENV_VAR_NAME"))} +``` +You can see exemples in the current JMeter test file +- Authentication/Crendentials +- Resource API[DEV]/API Variables + +As these env vars are copied to standard JMeter vars, they can be used anywhere in the test plan with `${var}`. + +## Json datasets +A groovy script `JsonSample.groovy` is provided to load data from Json files. +It has been implemented using [these datasets](https://github.com/topcoder-platform/resources-api/tree/develop/test/postman/testData/resource-role) under `Create Resource Role`of the test plan. + +THe script is fully generic and can be used for any Json file that has an array as the root object (see bellow). + +### Format requirements +The JSon root object must be an array, the content of it is not restricted. +```json +[ + { + "memberHandle": "handle1", + "httpCode": 200 + }, + { + "memberHandle": "handle2", + "httpCode": 200 + } +] +``` + +### Usage +The has to be used as a `JSR223 Sampler` or `JSR223 PreProcessor` with groovy interpreter. + +Here are the required parameters +- File Name: `JsonSample.groovy` (script path relative to test directory) + +- Parameters: json dataset location + destination var, separated by space. + - ie: /data/sample.json myvar + +### Exemples +You can see an exemple of using the parser as a Sample in the `create-resource-role-by-admin` section of the test plan + +An exemple using it as a pre-processor is available with `create-resource-role-by-m2m`, an inline groovy script is then used to remove unneeded fileds from data, but it can also be written as a plain groovy script. See the body of the `Create active, read and write access resource role by M2M`request. +```groovy +${__groovy( + import groovy.json.JsonOutput + JsonOutput.toJson(vars.getObject("resource_role_m2m").findAll {k\,v -> !['httpCode'\, 'message'].contains(k)} ) +)} +``` + +### Behaviour + +Each of the JMeter gets a different value, very similar to the CSV Dataset Behaviour. + +If there is no more data to load, the reading restarts at the beginning. + +Each element of the Json array is stored as Object to the JMeter variable whose is name from the second groovy script parameter (see Parameters above). + +The result is also stored as the `SampleResult` if used as a Sample and can be use by the orginal Jmeter parsers (ie. JsonPath extractor) + +Finally the element json string is stored inside the `varname_json` var. + +The result can alos be processed by any of the JMeter scripting languages, an exemple is provided in the JMeter test plan. + +```groovy +// Extracting simple json object (no children) to vars named with the keys of the json data +def data = vars.getObject("tokens") +data.entrySet().each { + vars.put(it.getKey(), it.getValue()) +} +``` + +## Testing + +## JMeter GUI +Default env file are provided to allow testing the project without executing CI. + +```bash +source env/api.env +source env/credentials.env +source env/m2m.env +jmeter -t "test/jmeter/Resource API.jmx" +``` + +## Testing with maven +```bash +mvn clean verify + +... + +INFO] ------------------------------------------------------- +[INFO] C O N F I G U R I N G J M E T E R +[INFO] ------------------------------------------------------- +[INFO] +[INFO] Building JMeter directory structure... +[INFO] Configuring JMeter artifacts... +[INFO] Populating JMeter directory... +[INFO] Copying extensions to JMeter lib/ext directory /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/lib/ext with downloadExtensionDependencies set to true... +[WARNING] The POM for commons-math3:commons-math3:jar:3.4.1 is missing, no dependency information available +[WARNING] The POM for commons-pool2:commons-pool2:jar:2.3 is missing, no dependency information available +[INFO] Copying JUnit libraries to JMeter junit lib directory /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/lib/junit with downloadLibraryDependencies set to true... +[INFO] Copying test libraries to JMeter lib directory /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/lib with downloadLibraryDependencies set to true... +[WARNING] The POM for xom:xom:jar:1.2.10 is missing, no dependency information available +[INFO] Configuring JMeter properties... +[INFO] Generating JSON Test config... +[INFO] +[INFO] <<< jmeter-maven-plugin:2.9.0:jmeter (jmeter-tests) < :configure @ jmeter-maven-plugin-demo <<< +[INFO] +[INFO] +[INFO] --- jmeter-maven-plugin:2.9.0:jmeter (jmeter-tests) @ jmeter-maven-plugin-demo --- +[INFO] +[INFO] ------------------------------------------------------- +[INFO] P E R F O R M A N C E T E S T S +[INFO] ------------------------------------------------------- +[INFO] +[INFO] Will generate HTML report in /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/reports/Resource API +[INFO] Executing test: Resource API.jmx +[INFO] Arguments for forked JMeter JVM: [java, -Xms512M, -Xmx512M, -XX:MaxMetaspaceSize=512m, -Xmx2048m, -Xms2048m, -Djava.awt.headless=true, -jar, ApacheJMeter-5.1.1.jar, -d, /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter, -e, -j, /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/logs/Resource API.jmx.log, -l, /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/results/20210803-Resource API.csv, -n, -o, /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/reports/Resource API, -t, /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/testFiles/Resource API.jmx, -Dsun.net.http.allowRestrictedHeaders, true] +[INFO] +[INFO] WARNING: An illegal reflective access operation has occurred +[INFO] WARNING: Illegal reflective access by com.thoughtworks.xstream.core.util.Fields (file:/Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/lib/xstream-1.4.11.jar) to field java.util.TreeMap.comparator +[INFO] WARNING: Please consider reporting this to the maintainers of com.thoughtworks.xstream.core.util.Fields +[INFO] WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations +[INFO] WARNING: All illegal access operations will be denied in a future release +[INFO] Warning: Nashorn engine is planned to be removed from a future JDK release +[INFO] Creating summariser +[INFO] Created the tree successfully using /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/testFiles/Resource API.jmx +[INFO] Starting the test @ Tue Aug 03 16:12:31 CEST 2021 (1627999951676) +[INFO] Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445 +[INFO] Warning: Nashorn engine is planned to be removed from a future JDK release +[INFO] summary + 1 in 00:00:03 = 0,3/s Avg: 2915 Min: 2915 Max: 2915 Err: 0 (0,00%) Active: 1 Started: 1 Finished: 0 +[INFO] summary + 22 in 00:00:18 = 1,3/s Avg: 518 Min: 1 Max: 1880 Err: 8 (36,36%) Active: 0 Started: 1 Finished: 1 +[INFO] summary = 23 in 00:00:21 = 1,1/s Avg: 623 Min: 1 Max: 2915 Err: 8 (34,78%) +[INFO] Tidying up ... @ Tue Aug 03 16:12:53 CEST 2021 (1627999973022) +[INFO] ... end of run +[INFO] Completed Test: /Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/testFiles/Resource API.jmx +[INFO] +[INFO] +[INFO] --- jmeter-maven-plugin:2.9.0:results (jmeter-tests) @ jmeter-maven-plugin-demo --- +[INFO] +[INFO] ------------------------------------------------------- +[INFO] S C A N N I N G F O R R E S U L T S +[INFO] ------------------------------------------------------- +[INFO] +[INFO] Will scan results using format: CSV +[INFO] +[INFO] Parsing results file '/Users/gmagniez/Work/topcoder/jmeter/submission/target/jmeter/results/20210803-Resource API.csv' as type: CSV +[INFO] Number of failures in '20210803-Resource API.csv': 8 +[INFO] Number of successes in '20210803-Resource API.csv': 15 +[INFO] +[INFO] ------------------------------------------------------- +[INFO] P E R F O R M A N C E T E S T R E S U L T S +[INFO] ------------------------------------------------------- +[INFO] +[INFO] Result (.csv) files scanned: 1 +[INFO] Successful requests: 15 +[INFO] Failed requests: 8 +[INFO] Failures: 34.782608% (60.0% accepted) +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 33.142 s +[INFO] Finished at: 2021-08-03T16:12:54+02:00 +[INFO] ------------------------------------------------------------------------ +[INFO] Shutdown detected, destroying JMeter process... +[INFO] +``` + +## Integration with CircleCI +Use a classic Maven/Java pipeline : [Language Guide: Java (with Maven)](https://circleci.com/docs/2.0/language-java-maven/) + +Provided required environment variables : [Using Environment Variables](https://circleci.com/docs/2.0/env-vars/) + + +## Errors +All errors reported by JMeter where already present in the provided tests plan, it was not asked to solve them. +- User 2&3 Invalid credentials +- RessourceRole creation + - Provided ids already exists, not modified to avoid creating millions of entries in the ressource-role database. diff --git a/test/jmeter/data/challenge-data.json b/test/jmeter/data/challenge-data.json new file mode 100644 index 0000000..7aafb1b --- /dev/null +++ b/test/jmeter/data/challenge-data.json @@ -0,0 +1,6 @@ +[ + { + "TEST_USER_ID": "40159018", + "GROUP_ID": "041e0be4-7599-402f-989b-b2873b0bed7e" + } + ] \ No newline at end of file