Skip to content

Commit

Permalink
Merge pull request #114 from Cdayz/fix/issue-#101
Browse files Browse the repository at this point in the history
Allow passing variables to dbQuery and dbResponse
  • Loading branch information
Nikita Tomchik authored Dec 9, 2021
2 parents 79e1574 + fffd9e9 commit 9ba268a
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 6 deletions.
26 changes: 26 additions & 0 deletions README-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ responseHeaders:
- headers
- request
- response
- dbQuery
- dbResponse
- body для моков
- headers для моков
- requestConstraints для моков
Expand All @@ -235,12 +237,17 @@ responseHeaders:
"message": "{{ $mockParam }}"
}
statusCode: 200
dbQuery: >
SELECT id, name FROM testing_tools WHERE id={{ $sqlQueryParam }}
dbResponse:
- '{"id": {{ $sqlResultParam }}, "name": "gonkey"}'
```

Присваивать значения переменным можно следующими способами:

- в описании самого теста
- из результатов предыдущего запроса
- из результата текущего запроса
- в переменных окружения или в env-файле

Приоритеты источников соответствуют порядку перечисления.
Expand Down Expand Up @@ -294,6 +301,25 @@ responseHeaders:

Глубина вложенности может быть любая.

##### Из результата текущего запроса

Пример:

```yaml
- name: Get info with database
method: GET
path: "/info/1"
variables_to_set:
200:
golang_id: query_result.0.0
response:
200: '{"result_id": "1", "query_result": [[ {{ $golang_id }} , "golang"], [2, "gonkey"]]}'
dbQuery: >
SELECT id, name FROM testing_tools WHERE id={{ $golang_id }}
dbResponse:
- '{"id": {{ $golang_id}}, "name": "golang"}'
```

##### В переменных окружения или в env-файле

Gonkey автоматически проверяет наличие указанной переменной среди переменных окружения (в таком же регистре) и берет значение оттуда, в случае наличия.
Expand Down
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ You can use variables in the description of the test, the following fields are s
- headers
- request
- response
- dbQuery
- dbResponse
- mocks body
- mocks headers
- mocks requestConstraints
Expand All @@ -238,12 +240,17 @@ Example:
"message": "{{ $mockParam }}"
}
statusCode: 200
dbQuery: >
SELECT id, name FROM testing_tools WHERE id={{ $sqlQueryParam }}
dbResponse:
- '{"id": {{ $sqlResultParam }}, "name": "gonkey"}'
```

You can assign values to variables in the following ways (priorities are from top to bottom):

- in the description of the test
- from the response of the previous test
- from the response of currently running test
- from environment variables or from env-file

#### More detailed about assignment methods
Expand Down Expand Up @@ -295,6 +302,26 @@ You can access nested fields like this:

Any nesting levels are supported.

##### From the response of currently running test

Example:

```yaml
- name: Get info with database
method: GET
path: "/info/1"
variables_to_set:
200:
golang_id: query_result.0.0
response:
200: '{"result_id": "1", "query_result": [[ {{ $golang_id }} , "golang"], [2, "gonkey"]]}'
dbQuery: >
SELECT id, name FROM testing_tools WHERE id={{ $golang_id }}
dbResponse:
- '{"id": {{ $golang_id}}, "name": "golang"}'
```


##### From environment variables or from env-file

Gonkey automatically checks if variable exists in the environment variables (case-sensitive) and loads a value from there, if it exists.
Expand Down
13 changes: 13 additions & 0 deletions examples/with-db-example/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.PHONY: setup
setup:
@docker-compose -f docker-compose.yaml up --build -d
@curl http://localhost:5000/info/10

.PHONY: teardown
teardown:
@docker-compose -f docker-compose.yaml down -v --remove-orphans

.PHONY: test
test: setup
gonkey -db_dsn "postgresql://testing_user:testing_password@localhost:5432/testing_db?sslmode=disable" -debug -host http://localhost:5000 -tests ./cases/
make teardown
21 changes: 21 additions & 0 deletions examples/with-db-example/cases/database-with-vars.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
- name: Get random number
method: GET
path: /randint/
response:
200: '{ "num": {"generated": "$matchRegexp(\\d)" } }'
variables_to_set:
200:
info_id: num.generated

- name: Get info with database
method: GET
path: "/info/{{ $info_id }}"
variables_to_set:
200:
golang_id: query_result.0.0
response:
200: '{"result_id": "{{ $info_id }}", "query_result": [[ {{ $golang_id }}, "golang"], [2, "gonkey"]]}'
dbQuery: >
SELECT id, name FROM testing WHERE id={{ $golang_id }}
dbResponse:
- '{"id": {{ $golang_id }}, "name": "golang"}'
38 changes: 38 additions & 0 deletions examples/with-db-example/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version: '3'

services:
postgres:
image: postgres:10.3
command: postgres -c 'max_connections=100'
volumes:
- postgres-db:/var/lib/postgresql/data
environment:
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_DB=testing_db
- POSTGRES_USER=testing_user
- POSTGRES_PASSWORD=testing_password
ports:
- 5432:5432
healthcheck:
test: "pg_isready -U postgres"

svc:
build:
context: .
dockerfile: server.dockerfile
command: python /app/server.py
ports:
- 5000:5000
environment:
- APP_POSTGRES_HOST=postgres
- APP_POSTGRES_PORT=5432
- APP_POSTGRES_USER=testing_user
- APP_POSTGRES_PASS=testing_password
- APP_POSTGRES_DB=testing_db
depends_on:
postgres:
condition: service_healthy

volumes:
postgres-db:
4 changes: 4 additions & 0 deletions examples/with-db-example/server.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM python:3.7.9

RUN pip install -U psycopg2-binary --no-cache-dir
COPY server.py /app/server.py
78 changes: 78 additions & 0 deletions examples/with-db-example/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import http.server
import random
import json
import os
import socketserver
from http import HTTPStatus

import psycopg2


class Handler(http.server.SimpleHTTPRequestHandler):

def get_response(self) -> dict:
if self.path.startswith('/info/'):
response = self.get_info()
elif self.path.startswith('/randint/'):
response = self.get_rand_num()
else:
response = {'non-existing': True}

return response

def get_info(self) -> dict:
info_id = self.path.split('/')[-1]
return {
'result_id': info_id,
'query_result': storage.get_sql_result('SELECT id, name FROM testing LIMIT 2'),
}

def get_rand_num(self) -> dict:
return {'num': {'generated': str(random.randint(0, 100))}}

def do_GET(self):
# заголовки ответа
self.send_response(HTTPStatus.OK)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(self.get_response()).encode())


class PostgresStorage:
def __init__(self):
params = {
"host": os.environ['APP_POSTGRES_HOST'],
"port": os.environ['APP_POSTGRES_PORT'],
"user": os.environ['APP_POSTGRES_USER'],
"password": os.environ['APP_POSTGRES_PASS'],
"database": os.environ['APP_POSTGRES_DB'],
}
self.conn = psycopg2.connect(**params)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE, self.conn)
self.conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
self.cursor = self.conn.cursor()

def apply_migrations(self):
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS testing (id SERIAL PRIMARY KEY, name VARCHAR(200) NOT NULL);
""")
self.conn.commit()
self.cursor.executemany(
"INSERT INTO testing (name) VALUES (%(name)s);",
[{'name': 'golang'}, {'name': 'gonkey'}, {'name': 'testing'}],
)
self.conn.commit()

def get_sql_result(self, sql_str):
self.cursor.execute(sql_str)
query_data = list(self.cursor.fetchall())
self.conn.commit()
return query_data


storage = PostgresStorage()
storage.apply_migrations()

if __name__ == '__main__':
service = socketserver.TCPServer(('', 5000), Handler)
service.serve_forever()
2 changes: 2 additions & 0 deletions models/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type TestInterface interface {
SetForm(form *Form)
SetResponses(map[int]string)
SetHeaders(map[string]string)
SetDbQueryString(string)
SetDbResponseJson([]string)

// comparison properties
NeedsCheckingValues() bool
Expand Down
11 changes: 7 additions & 4 deletions runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ func (r *Runner) executeTest(v models.TestInterface, client *http.Client) (*mode
result.Errors = append(result.Errors, errs...)
}

if err := r.setVariablesFromResponse(v, result.ResponseContentType, bodyStr, resp.StatusCode); err != nil {
return nil, err
}

r.config.Variables.Load(v.GetVariables())
v = r.config.Variables.Apply(v)

for _, c := range r.checkers {
errs, err := c.Check(v, &result)
if err != nil {
Expand All @@ -189,10 +196,6 @@ func (r *Runner) executeTest(v models.TestInterface, client *http.Client) (*mode
result.Errors = append(result.Errors, errs...)
}

if err := r.setVariablesFromResponse(v, result.ResponseContentType, bodyStr, resp.StatusCode); err != nil {
return nil, err
}

return &result, nil
}

Expand Down
1 change: 0 additions & 1 deletion runner/runner_upload_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ func testServerUpload(t *testing.T) *httptest.Server {
_, err = w.Write(respData)
require.NoError(t, err)

return
}))
}

Expand Down
10 changes: 9 additions & 1 deletion testloader/yaml_file/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Test struct {
TestDefinition

Filename string

Request string
Responses map[int]string
ResponseHeaders map[int]map[string]string
Expand Down Expand Up @@ -167,3 +167,11 @@ func (t *Test) SetResponses(val map[int]string) {
func (t *Test) SetHeaders(val map[string]string) {
t.HeadersVal = val
}

func (t *Test) SetDbQueryString(query string) {
t.DbQuery = query
}

func (t *Test) SetDbResponseJson(responses []string) {
t.DbResponse = responses
}
16 changes: 16 additions & 0 deletions variables/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func (vs *Variables) Apply(t models.TestInterface) models.TestInterface {
newTest.SetMethod(vs.perform(newTest.GetMethod()))
newTest.SetPath(vs.perform(newTest.Path()))
newTest.SetRequest(vs.perform(newTest.GetRequest()))
newTest.SetDbQueryString(vs.perform(newTest.DbQueryString()))
newTest.SetDbResponseJson(vs.performDbResponses(newTest.DbResponseJson()))

newTest.SetResponses(vs.performResponses(newTest.GetResponses()))
newTest.SetHeaders(vs.performHeaders(newTest.Headers()))
Expand Down Expand Up @@ -159,6 +161,20 @@ func (vs *Variables) performResponses(responses map[int]string) map[int]string {
return res
}

func (vs *Variables) performDbResponses(responses []string) []string {
if responses == nil {
return nil
}

res := make([]string, len(responses))

for idx, v := range responses {
res[idx] = vs.perform(v)
}

return res
}

func (vs *Variables) Add(v *Variable) *Variables {
vs.variables[v.name] = v

Expand Down

0 comments on commit 9ba268a

Please sign in to comment.