Used for HTTP stress testing of Texera deployments based on jmeter. For now only a simple test plan is included.
-
Need to have jmeter installed first. Open
simple_test/jmx
in jmeter before reading the rest of this doc. -
Need to install extension WebSocket Samplers by Peter Doornbosch first before opening the jmx file.
-
Currently the jmx file is using relative path which should work. If you encounter file not found error for some tests, you might need to replace the file paths used in the jmx plan with the absolute path in your machine.
Thread Group -> CSV Data Set Config -> Filename
http://localhost:8080/api/dataset/create -> Files Upload -> File Path
-
Any disabled http headers/cookie managers can be ignored.
-
Disabled HTTP requests may be used but are not necessary for the testplan to work. (Check port numbers being used before using these, change whenever necessary)
-
Thread Group: (Defines number of threads and other thread related configuration)
- Number of threads: number of users to simulate
- Ramp up period: Number of seconds to initially ramp up to the load(number of users) defined
- Loop count: Number of times each thread should run/repeat.
- Check “Same user on each iteration”. This makes sure that same user is used by the same thread for every iteration. (Each thread maps to one user)
-
CSV Dataset Config: CSV file that defines all the username and password pairs to be used for testing.
- CSV format: user, password
- Variable name: Generate jmeter variable name to store username and password
For all request:
-
Server name: localhost
-
Port: 8080
-
Path: /api/{path}
-
http://localhost:8080/api/auth/register
- Registers the user with given username and password
- Response assertion has a regex matching to make sure accessToken is generated and returned in response.
random_pairs.csv
contains the usernames/passwords for testing. The file can be generated/upsaled by executinggenerate.sh
. It's better to run this script first before executing tests.- If using an existing file for
random_pairs.csv
, it's okay if this test fails because the user is already registered.
-
http://localhost:8080/api/auth/login
- Login user similar to above
- Does response assertion as described above
- JSON extractor:
- Used to extract the accessToken from HTTP response and store it in a jmeter variable for use in further requests
- Name of created variable: name of the jmeter variable to store the access token
- JSON Path expression:
$.accessToken ($ being the json object) - Match No.: 1 (matches and returns the first match we get)
-
http://localhost:8080/api/auth/refresh
- Same as above except the accessToken is sent in the body instead of the user, password
-
http://localhost:8080/api/user/file/uploadUploads a file to the account that is being usedIn HTTP header manager(expand the http request to get this), content type and authorization are defined. (Authorization contains the access token as value defined as follows: Bearer {accessToken}) (All requests following this make use of this token)Check “Use multipart/form data”. (Data is sent in form data)Under “Files upload” tab, enter file path, parameter name(“file” is how it is referenced in form data), MIME type - “text/plain”
-
http://localhost:4200/api/user/file/listSimple get request that returns list of all files stored in a user’s account-
3 JSON extractors are used:-
First extracts file id and stores in variable “fid”-
JSON path expressions: $.[-1].file.fidResponse is a list of files so index -1 gives us the last/most recently added file response object. Access file within this object which contain fid(file id)
Match no.: 1
-
-
Second JSON extractor stores username-
JSON path expressions: $.[-1].ownerEmailSimilar to above, get the last file object using index -1, and get ownerEmail for username
-
-
Third JSON extractor gets filename:-
JSON path expressions: $.[-1].file.nameSame as above
-
-
-
http://localhost:8080/api/dataset/create
- Creates a test dataset named “Test Dataset” with the provided file “Assignment 5.csv”.
- Extracts the dataset id as ${did} from the response JSON.
-
http://localhost:8080/api/workflow/create
- Creates the workflow to be run and tested
- Generate the workflow and download it as a json file
- JSON file will be of following format:
- {“operators”: [{list of operator objects}]}
- Copy the above json object(json_obj) and insert into the request body as follows:
- {“name”: “workflow_name”, “content”: {insert copied json_obj}}
- Make sure to use quotes around the object along with necessary escape characters (refer jmx file for clarity)
- {“name”: “workflow_name”, “content”: {insert copied json_obj}}
-
http://localhost:8080/api/workflow/${wid}/environment
- Retrieves the eid of the created workflow.
-
http://localhost:8080/api/environment/${eid}/dataset/add
- Adds the test dataset to the environment of this workflow.
-
Websocket Connections: Uses a WebSocket request-response Sampler to send a request to the server with the request data and get a singular response.
-
WebSocket Single Read Sampler: Reads messages coming from the server. This sampler is put inside a **Loop controller **which loops and allows this sampler to run a given number of times (loop count defined in the loop controller).
-
Websocket configuration:
-
Server url: ws://localhost:8080/wsapi/workflow-websocket?access-token=${accessToken}
-
The url is defined in the sampler as follows:
-
Protocol: ws
-
Server name/IP: localhost
-
Port: 8080
-
Path: wsapi/workflow-websocket?access-token=${accessToken}
-
-
There are 4 websocket requests sent from the client to the server. These will be defined below. After each request, there is a loop controller with a read sampler as explained above to read multiple responses that would be received by the client after sending the request. (The request response sampler only checks for one response, subsequent responses are ignored unless we use a read sampler).
-
WebSocket request-response Sampler 1
- Request that registers the given workflow using the workflow id
- Request data:
-
{ "type": "RegisterWorkflowIdRequest", "workflowId": "${wid}" }
-
-
WebSocket request-response Sampler 2 3. Initiates a EditingTimeCompilationRequest to send the updated workflow with all the operators, their configuration and how they link to each other. 4. Sample Body(Refer Chrome Network tab to get body for alternate workflow):
{ "type": "EditingTimeCompilationRequest", "operators": [ { "fileEncoding": "US_ASCII", "customDelimiter": ",", "hasHeader": true, "fileName": "${username}/${filename}", "operatorID": "CSVFileScan-operator-68c5b948-6246-47a4-9d70-618d346b8c17", "operatorType": "CSVFileScan", "inputPorts": [], "outputPorts": [ { "portID": "output-0", "displayName": "", "allowMultiInputs": false, "isDynamicPort": false } ] }, { "operatorID": "SimpleSink-operator-838553b8-5873-4d13-a589-9c969479d7c2", "operatorType": "SimpleSink", "inputPorts": [ { "portID": "input-0", "displayName": "", "allowMultiInputs": false, "isDynamicPort": false, "dependencies": [] } ], "outputPorts": [ { "portID": "output-0", "displayName": "", "allowMultiInputs": false, "isDynamicPort": false } ] } ], "links": [ { "fromOpId": "CSVFileScan-operator-68c5b948-6246-47a4-9d70-618d346b8c17", "fromPortId": { "id": 0, "internal": false }, "toOpId": "SimpleSink-operator-838553b8-5873-4d13-a589-9c969479d7c2", "toPortId": { "id": 0, "internal": false } } ], "opsToViewResult": [], "opsToReuseResult": [] }
-
WebSocket request-response Sampler 3 5. Workflow execute request to start workflow execution 6. Sample Body (Refer Chrome Network tab to get body for alternate workflow):
{ "type": "WorkflowExecuteRequest", "executionName": "", "engineVersion": "8b84d50c2", "logicalPlan": { "operators": [ { "fileEncoding": "US_ASCII", "customDelimiter": ",", "hasHeader": true, "fileName": "${username}/${filename}", "operatorID": "CSVFileScan-operator-68c5b948-6246-47a4-9d70-618d346b8c17", "operatorType": "CSVFileScan", "inputPorts": [], "outputPorts": [ { "portID": "output-0", "displayName": "", "allowMultiInputs": false, "isDynamicPort": false } ] }, { "operatorID": "SimpleSink-operator-838553b8-5873-4d13-a589-9c969479d7c2", "operatorType": "SimpleSink", "inputPorts": [ { "portID": "input-0", "displayName": "", "allowMultiInputs": false, "isDynamicPort": false, "dependencies": [] } ], "outputPorts": [ { "portID": "output-0", "displayName": "", "allowMultiInputs": false, "isDynamicPort": false } ] } ], "links": [ { "fromOpId": "CSVFileScan-operator-68c5b948-6246-47a4-9d70-618d346b8c17", "fromPortId": { "id": 0, "internal": false }, "toOpId": "SimpleSink-operator-838553b8-5873-4d13-a589-9c969479d7c2", "toPortId": { "id": 0, "internal": false } } ], "opsToViewResult": [], "opsToReuseResult": [] } }
-
WebSocket request-response Sampler 4 7. Get the final result of the workflow executed. 8. In this case, SimpleSink operator is referred which is “View Results”(Displays results in a tabulated format). Sample Body (Refer Chrome Network tab to get body for alternate workflow):
{ "type": "ResultPaginationRequest", "operatorID": "SimpleSink-operator-838553b8-5873-4d13-a589-9c969479d7c2", "pageIndex": 1, "pageSize": 5 }
-
The request also has a response assertion to check for the accuracy of the response. Response expected for the inputted csv file is as follows:
[{"id":100,"name":"John Smith","city":"Austin","state":"TX","zipcode":78727},{"id":200,"name":"Joe Johnson","city":"Dallas","state":"TX","zipcode":75201},{"id":300,"name":"Bob Jones","city":"Houston","state":"TX","zipcode":77028},{"id":400,"name":"Andy Davis","city":"San Antonio","state":"TX","zipcode":78227},{"id":500,"name":"James Williams","city":"Austin","state":"TX","zipcode":78727}]
As seen above, response is in the form of a list of objects. Each object is a key value pair like a dictionary with key being the column and value being the value of that column for a particular entry. Also, path matching is “$.table” as this list comes in the table parameter of the response object.
-
-
Close the websocket using websocket close.