mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
Tests for server with access control, and some more tests (#710)
* 1) Tests for creating permissions 2) Test for constraint_on with GraphQL insert on_conflict * Run tests with access key and webhook * Tests for GraphQL query with quoted columns * Rewrite test-server.sh so that it can be run locally * JWT based tests * Tests with various postgres types * For tests on select queries, run setup only once per class * Tests for v1 count queries * Skip teardown for tests that does not modify data * Workaround for hpc 'parse error when reading .tix file' * Move GeoJson tests to the new structure * Basic tests for v1 queries * Tests for column, table or operator not found error cases on GraphQL queries * Skip test teardown for mutation tests which does not change database state, even when it returns 200.
This commit is contained in:
parent
58582be644
commit
0ffb0478b9
@ -90,34 +90,19 @@ refs:
|
||||
at: /build
|
||||
- *wait_for_postgres
|
||||
- run:
|
||||
name: run the server in background
|
||||
working_directory: ./server
|
||||
name: Run Python tests
|
||||
environment:
|
||||
HASURA_GRAPHQL_DATABASE_URL: postgres://gql_test:@localhost:5432/gql_test
|
||||
EVENT_WEBHOOK_HEADER: MyEnvValue
|
||||
background: true
|
||||
HASURA_GRAPHQL_DATABASE_URL: 'postgres://gql_test:@localhost:5432/gql_test'
|
||||
GRAPHQL_ENGINE: '/build/_server_output/graphql-engine'
|
||||
command: |
|
||||
/build/_server_output/graphql-engine serve
|
||||
apt-get update
|
||||
apt install --yes jq
|
||||
OUTPUT_FOLDER=/build/_server_test_output/$PG_VERSION .circleci/test-server.sh
|
||||
- run:
|
||||
name: create test output dir
|
||||
command: |
|
||||
mkdir -p /build/_server_test_output/$PG_VERSION
|
||||
- *wait_for_hge
|
||||
- run:
|
||||
name: pytest the server
|
||||
working_directory: ./server/tests-py
|
||||
environment:
|
||||
DATABASE_URL: postgres://gql_test:@localhost:5432/gql_test
|
||||
HGE_URL: http://localhost:8080
|
||||
command: |
|
||||
pip3 install -r requirements.txt
|
||||
pytest -vv --hge-url="$HGE_URL" --pg-url="$DATABASE_URL"
|
||||
- run:
|
||||
name: stop the server and generate coverage report
|
||||
name: Generate coverage report
|
||||
working_directory: ./server
|
||||
command: |
|
||||
kill -2 $(ps -e | grep graphql-engine | awk '{print $1}')
|
||||
stack --system-ghc hpc report graphql-engine.tix --destdir /build/_server_test_output/$PG_VERSION
|
||||
stack --system-ghc hpc report /build/_server_test_output/$PG_VERSION/graphql-engine.tix --destdir /build/_server_test_output/$PG_VERSION
|
||||
- store_artifacts:
|
||||
path: /build/_server_test_output
|
||||
destination: server_test
|
||||
|
206
.circleci/test-server.sh
Executable file
206
.circleci/test-server.sh
Executable file
@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
### Functions
|
||||
|
||||
stop_services() {
|
||||
kill -INT $PID
|
||||
kill $WH_PID
|
||||
}
|
||||
|
||||
wait_for_port() {
|
||||
local PORT=$1
|
||||
echo "waiting for $PORT"
|
||||
for _ in $(seq 1 60);
|
||||
do
|
||||
nc -z localhost $PORT && echo "port $PORT is ready" && return
|
||||
echo -n .
|
||||
sleep 1
|
||||
done
|
||||
echo "Failed waiting for $PORT" && exit 1
|
||||
}
|
||||
|
||||
init_jwt() {
|
||||
CUR_DIR="$PWD"
|
||||
mkdir -p "$OUTPUT_FOLDER/ssl"
|
||||
cd "$OUTPUT_FOLDER/ssl"
|
||||
openssl genrsa -out jwt_private.key 2048
|
||||
openssl rsa -pubout -in jwt_private.key -out jwt_public.key
|
||||
cd "$CUR_DIR"
|
||||
}
|
||||
|
||||
init_ssl() {
|
||||
CUR_DIR="$PWD"
|
||||
mkdir -p "$OUTPUT_FOLDER/ssl"
|
||||
cd "$OUTPUT_FOLDER/ssl"
|
||||
CNF_TEMPLATE='[req]
|
||||
req_extensions = v3_req
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
[req_distinguished_name]
|
||||
|
||||
[ v3_req ]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = localhost
|
||||
IP.1 = 127.0.0.1'
|
||||
|
||||
echo "$CNF_TEMPLATE" > webhook-req.cnf
|
||||
|
||||
openssl genrsa -out ca-key.pem 2048
|
||||
openssl req -x509 -new -nodes -key ca-key.pem -days 10 -out ca.pem -subj "/CN=webhook-ca"
|
||||
openssl genrsa -out webhook-key.pem 2048
|
||||
openssl req -new -key webhook-key.pem -out webhook.csr -subj "/CN=hge-webhook" -config webhook-req.cnf
|
||||
openssl x509 -req -in webhook.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out webhook.pem -days 10 -extensions v3_req -extfile webhook-req.cnf
|
||||
|
||||
cp ca.pem /etc/ssl/certs/webhook.crt
|
||||
update-ca-certificates
|
||||
cd "$CUR_DIR"
|
||||
}
|
||||
|
||||
combine_hpc_reports() {
|
||||
(stack --allow-different-user exec -- hpc combine graphql-engine.tix graphql-engine-combined.tix --union > graphql-engine-combined.tix2 && mv graphql-engine-combined.tix2 graphql-engine-combined.tix ) || true
|
||||
rm graphql-engine.tix || true
|
||||
}
|
||||
|
||||
if [ -z "${HASURA_GRAPHQL_DATABASE_URL:-}" ] ; then
|
||||
echo "Env var HASURA_GRAPHQL_DATABASE_URL is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! stack --allow-different-user exec which hpc ; then
|
||||
echo "hpc not found; Install it with 'stack install hpc'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CIRCLECI_FOLDER="${BASH_SOURCE[0]%/*}"
|
||||
cd $CIRCLECI_FOLDER
|
||||
CIRCLECI_FOLDER="$PWD"
|
||||
|
||||
PYTEST_ROOT="$CIRCLECI_FOLDER/../server/tests-py"
|
||||
|
||||
OUTPUT_FOLDER=${OUTPUT_FOLDER:-"$CIRCLECI_FOLDER/test-server-output"}
|
||||
mkdir -p "$OUTPUT_FOLDER"
|
||||
|
||||
cd $PYTEST_ROOT
|
||||
|
||||
if ! stack --allow-different-user exec -- which graphql-engine > /dev/null && [ -z "${GRAPHQL_ENGINE:-}" ] ; then
|
||||
echo "Do 'stack build' before tests, or export the location of executable in the GRAPHQL_ENGINE envirnoment variable"
|
||||
exit 1
|
||||
fi
|
||||
GRAPHQL_ENGINE=${GRAPHQL_ENGINE:-"$(stack --allow-different-user exec -- which graphql-engine)"}
|
||||
if ! [ -x "$GRAPHQL_ENGINE" ] ; then
|
||||
echo "$GRAPHQL_ENGINE is not present or is not an executable"
|
||||
exit 1
|
||||
fi
|
||||
RUN_WEBHOOK_TESTS=true
|
||||
|
||||
echo -e "\nINFO: GraphQL Executable : $GRAPHQL_ENGINE"
|
||||
echo -e "INFO: Logs Folder : $OUTPUT_FOLDER\n"
|
||||
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
mkdir -p "$OUTPUT_FOLDER"
|
||||
|
||||
export EVENT_WEBHOOK_HEADER="MyEnvValue"
|
||||
export HGE_URL="http://localhost:8080"
|
||||
|
||||
PID=""
|
||||
WH_PID=""
|
||||
trap stop_services ERR
|
||||
trap stop_services INT
|
||||
|
||||
echo -e "\n<########## TEST GRAPHQL-ENGINE WITHOUT ACCESS KEYS ###########################################>\n"
|
||||
|
||||
"$GRAPHQL_ENGINE" serve > "$OUTPUT_FOLDER/graphql-engine.log" & PID=$!
|
||||
|
||||
wait_for_port 8080
|
||||
|
||||
pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL"
|
||||
|
||||
kill -INT $PID
|
||||
sleep 4
|
||||
mv graphql-engine.tix graphql-engine-combined.tix
|
||||
|
||||
##########
|
||||
echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ACCESS KEY #####################################>\n"
|
||||
|
||||
export HASURA_GRAPHQL_ACCESS_KEY="HGE$RANDOM$RANDOM"
|
||||
|
||||
"$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" & PID=$!
|
||||
|
||||
wait_for_port 8080
|
||||
|
||||
pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ACCESS_KEY"
|
||||
|
||||
kill -INT $PID
|
||||
sleep 4
|
||||
combine_hpc_reports
|
||||
|
||||
##########
|
||||
echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ACCESS KEY AND JWT #####################################>\n"
|
||||
|
||||
init_jwt
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key }')"
|
||||
|
||||
"$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" & PID=$!
|
||||
|
||||
pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ACCESS_KEY" --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key"
|
||||
|
||||
kill -INT $PID
|
||||
sleep 4
|
||||
combine_hpc_reports
|
||||
|
||||
unset HASURA_GRAPHQL_JWT_SECRET
|
||||
|
||||
##########
|
||||
|
||||
if [ $EUID != 0 ] ; then
|
||||
echo -e "SKIPPING webhook based tests, as \nroot permission is required for running webhook tests (inorder to trust certificate authority)."
|
||||
RUN_WEBHOOK_TESTS=false
|
||||
fi
|
||||
|
||||
if [ "$RUN_WEBHOOK_TESTS" == "true" ] ; then
|
||||
|
||||
echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ACCESS KEY & WEBHOOK #########################>\n"
|
||||
|
||||
export HASURA_GRAPHQL_AUTH_HOOK="https://localhost:9090/"
|
||||
init_ssl
|
||||
|
||||
"$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$!
|
||||
|
||||
python3 webhook.py 9090 "$OUTPUT_FOLDER/ssl/webhook-key.pem" "$OUTPUT_FOLDER/ssl/webhook.pem" > "$OUTPUT_FOLDER/webhook.log" 2>&1 & WH_PID=$!
|
||||
|
||||
wait_for_port 8080
|
||||
|
||||
wait_for_port 9090
|
||||
|
||||
pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ACCESS_KEY" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK"
|
||||
|
||||
rm /etc/ssl/certs/webhook.crt
|
||||
update-ca-certificates
|
||||
|
||||
kill -INT $PID
|
||||
sleep 4
|
||||
combine_hpc_reports
|
||||
|
||||
echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ACCESS KEY & HTTPS INSECURE WEBHOOK ########>\n"
|
||||
|
||||
"$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$!
|
||||
|
||||
wait_for_port 8080
|
||||
|
||||
pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ACCESS_KEY" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" --test-webhook-insecure test_webhook_insecure.py
|
||||
|
||||
kill -INT $PID
|
||||
sleep 4
|
||||
combine_hpc_reports
|
||||
|
||||
kill $WH_PID
|
||||
fi
|
||||
|
||||
mv graphql-engine-combined.tix "$OUTPUT_FOLDER/graphql-engine.tix"
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ npm-debug.log
|
||||
*.temp
|
||||
*.DS_Store
|
||||
.tern-project
|
||||
test-server-output
|
||||
|
6
server/tests-py/.gitignore
vendored
6
server/tests-py/.gitignore
vendored
@ -128,5 +128,9 @@ dmypy.json
|
||||
pyvenv.cfg
|
||||
pip-selfcheck.json
|
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/python
|
||||
|
||||
*.pem
|
||||
ca.srl
|
||||
webhook-req.cnf
|
||||
webhook.csr
|
||||
|
@ -9,17 +9,45 @@ def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--pg-url", metavar="PG_URL", help="url for connecting to Postgres directly", required=True
|
||||
)
|
||||
parser.addoption(
|
||||
"--hge-key", metavar="HGE_KEY", help="access key for graphql-engine", required=False
|
||||
)
|
||||
parser.addoption(
|
||||
"--hge-webhook", metavar="HGE_WEBHOOK", help="url for graphql-engine's access control webhook", required=False
|
||||
)
|
||||
parser.addoption(
|
||||
"--test-webhook-insecure", action="store_true",
|
||||
help="Run Test cases for insecure https webhook"
|
||||
)
|
||||
parser.addoption(
|
||||
"--hge-jwt-key-file", metavar="HGE_JWT_KEY_FILE", help="File containting the private key used to encode jwt tokens using RS512 algorithm", required=False
|
||||
)
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def hge_ctx(request):
|
||||
print ("create hge_ctx")
|
||||
hge_url = request.config.getoption('--hge-url')
|
||||
pg_url = request.config.getoption('--pg-url')
|
||||
hge_key = request.config.getoption('--hge-key')
|
||||
hge_webhook = request.config.getoption('--hge-webhook')
|
||||
webhook_insecure = request.config.getoption('--test-webhook-insecure')
|
||||
hge_jwt_key_file = request.config.getoption('--hge-jwt-key-file')
|
||||
try:
|
||||
hge_ctx = HGECtx(hge_url=hge_url, pg_url=pg_url)
|
||||
hge_ctx = HGECtx(hge_url=hge_url, pg_url=pg_url, hge_key=hge_key, hge_webhook=hge_webhook, hge_jwt_key_file=hge_jwt_key_file, webhook_insecure = webhook_insecure )
|
||||
except HGECtxError as e:
|
||||
pytest.exit(str(e))
|
||||
yield hge_ctx # provide the fixture value
|
||||
print("teardown hge_ctx")
|
||||
hge_ctx.teardown()
|
||||
time.sleep(2)
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def setup_ctrl(request, hge_ctx):
|
||||
"""
|
||||
This fixure is used to store the state of test setup in some test classes.
|
||||
Used primarily when teardown is skipped in some test cases in the class where the test is not expected to change the database state.
|
||||
"""
|
||||
setup_ctrl = { "setupDone" : False }
|
||||
yield setup_ctrl
|
||||
hge_ctx.may_skip_test_teardown = False
|
||||
request.cls().do_teardown(setup_ctrl, hge_ctx)
|
||||
|
@ -53,7 +53,7 @@ class WebhookServer(http.server.HTTPServer):
|
||||
self.socket.bind(self.server_address)
|
||||
|
||||
class HGECtx:
|
||||
def __init__(self, hge_url, pg_url):
|
||||
def __init__(self, hge_url, pg_url, hge_key, hge_webhook, hge_jwt_key_file, webhook_insecure):
|
||||
server_address = ('0.0.0.0', 5592)
|
||||
|
||||
self.resp_queue = queue.Queue(maxsize=1)
|
||||
@ -69,6 +69,15 @@ class HGECtx:
|
||||
|
||||
self.http = requests.Session()
|
||||
self.hge_url = hge_url
|
||||
self.hge_key = hge_key
|
||||
self.hge_webhook = hge_webhook
|
||||
if hge_jwt_key_file is None:
|
||||
self.hge_jwt_key = None
|
||||
else:
|
||||
with open(hge_jwt_key_file) as f:
|
||||
self.hge_jwt_key = f.read()
|
||||
self.webhook_insecure = webhook_insecure
|
||||
self.may_skip_test_teardown = False
|
||||
|
||||
self.ws_url = urlparse(hge_url)
|
||||
self.ws_url = self.ws_url._replace(scheme='ws')
|
||||
@ -78,7 +87,7 @@ class HGECtx:
|
||||
self.wst.daemon = True
|
||||
self.wst.start()
|
||||
|
||||
result = subprocess.run(['../../scripts/get-version.sh'], shell=True, stdout=subprocess.PIPE, check=True)
|
||||
result = subprocess.run(['../../scripts/get-version.sh'], shell=False, stdout=subprocess.PIPE, check=True)
|
||||
self.version = result.stdout.decode('utf-8').strip()
|
||||
try:
|
||||
st_code, resp = self.v1q_f('queries/clear_db.yaml')
|
||||
@ -108,6 +117,7 @@ class HGECtx:
|
||||
def reflect_tables(self):
|
||||
self.meta.reflect(bind=self.engine)
|
||||
|
||||
|
||||
def anyq(self, u, q, h):
|
||||
resp = self.http.post(
|
||||
self.hge_url + u,
|
||||
@ -117,9 +127,13 @@ class HGECtx:
|
||||
return resp.status_code, resp.json()
|
||||
|
||||
def v1q(self, q):
|
||||
h = dict()
|
||||
if self.hge_key is not None:
|
||||
h['X-Hasura-Access-Key'] = self.hge_key
|
||||
resp = self.http.post(
|
||||
self.hge_url + "/v1/query",
|
||||
json=q
|
||||
json=q,
|
||||
headers=h
|
||||
)
|
||||
return resp.status_code, resp.json()
|
||||
|
||||
|
2
server/tests-py/pytest.ini
Normal file
2
server/tests-py/pytest.ini
Normal file
@ -0,0 +1,2 @@
|
||||
[pytest]
|
||||
norecursedirs = queries webhook
|
@ -1,26 +0,0 @@
|
||||
type: bulk
|
||||
args:
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table hge_tests.test_t1(
|
||||
c1 int,
|
||||
c2 text
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: hge_tests
|
||||
name: test_t1
|
||||
- type: create_event_trigger
|
||||
args:
|
||||
name: t1_all
|
||||
table:
|
||||
schema: hge_tests
|
||||
name: test_t1
|
||||
insert:
|
||||
columns: "*"
|
||||
update:
|
||||
columns: "*"
|
||||
delete:
|
||||
columns: "*"
|
||||
webhook: http://127.0.0.1:5592
|
@ -1,9 +0,0 @@
|
||||
type: bulk
|
||||
args:
|
||||
- type: delete_event_trigger
|
||||
args:
|
||||
name: t1_all
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table hge_tests.test_t1
|
@ -76,3 +76,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted articles
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from article;
|
||||
delete from author;
|
||||
SELECT setval('article_id_seq', 1, FALSE);
|
||||
SELECT setval('author_id_seq', 1, FALSE);
|
||||
|
@ -0,0 +1,39 @@
|
||||
#Inserting data into test_types table
|
||||
- description: Inserts Array into an Array column
|
||||
url: /v1alpha1/graphql
|
||||
response:
|
||||
data:
|
||||
insert_test_types:
|
||||
returning:
|
||||
c34_text_array: ["a","b","c"]
|
||||
status: 200
|
||||
query:
|
||||
variables:
|
||||
textArray: ["a","b","c"]
|
||||
query: |
|
||||
mutation insert_test_types
|
||||
($textArray: [String])
|
||||
{
|
||||
insert_test_types(
|
||||
objects: [
|
||||
{
|
||||
c34_text_array: $textArray
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
c34_text_array
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted test_types rows
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from test_types;
|
||||
SELECT setval('test_types_c10_bigserial_seq', 1, FALSE);
|
||||
SELECT setval('test_types_c9_serial_seq', 1, FALSE);
|
||||
SELECT setval('test_types_c8_smallserial_seq', 1, FALSE);
|
@ -0,0 +1,159 @@
|
||||
#Inserting data into test_types table
|
||||
- description: Inserts data into test_types table with various postgres types
|
||||
url: /v1alpha1/graphql
|
||||
response:
|
||||
data:
|
||||
insert_test_types:
|
||||
returning:
|
||||
- c1_smallint: 32767
|
||||
c2_integer: 2147483647
|
||||
c3_bigint: "9223372036854775807"
|
||||
c4_decimal: 123.45
|
||||
c5_numeric: 1.234
|
||||
c6_real: 0.00390625
|
||||
c7_double_precision: 16.0001220703125
|
||||
c8_smallserial: 1
|
||||
c9_serial: 1
|
||||
c10_bigserial: "1"
|
||||
c11_varchar_3: "abc"
|
||||
c12_char_4: "baaz"
|
||||
c13_text: "foo bar baz"
|
||||
c14_timestamp: "2004-10-19T10:23:54"
|
||||
c15_timestamptz: "2015-10-17T14:42:43+00:00"
|
||||
c16_date: '2014-09-14'
|
||||
c17_time: '11:09:23'
|
||||
c18_time_with_zone: '15:22:23+00'
|
||||
c19_interval: '01:03:02'
|
||||
c20_boolean: true
|
||||
c21_point: '(1,2)'
|
||||
c22_line: '{2,3,-1}'
|
||||
c23_lseg: '[(4,2),(3,1)]'
|
||||
c24_box: '(31,12),(14,11)'
|
||||
c25_closed_path: '((0,0),(0,3),(1,0))'
|
||||
c26_open_path: '[(0,0),(0,-1),(-3,0)]'
|
||||
c27_polygon: '((0,0),(0,6),(2,0))'
|
||||
c28_circle: '<(-2,-3),3>'
|
||||
c29_cidr: '192.168.100.128/25'
|
||||
c30_inet: '198.24.10.0'
|
||||
c31_macaddr: '08:00:2b:01:02:03'
|
||||
c32_json:
|
||||
a: b
|
||||
c33_jsonb:
|
||||
c: d
|
||||
c36_uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
|
||||
c39_range_integer: '[123,456)'
|
||||
c40_range_bigint: '[1147483647,2147483647)'
|
||||
c41_range_numeric: '[1.23,4.56]'
|
||||
c42_range_timestamp: '["2010-01-01 14:30:00","2010-01-01 15:30:02")'
|
||||
c43_range_timestamptz: '("2011-02-05 12:03:00+00","2012-03-04 16:40:04+00"]'
|
||||
c44_xml: '<foo>bar</foo>'
|
||||
status: 200
|
||||
query:
|
||||
variables:
|
||||
json:
|
||||
a: b
|
||||
jsonb:
|
||||
c: d
|
||||
query: |
|
||||
mutation insert_test_types
|
||||
( $json: json
|
||||
, $jsonb: jsonb
|
||||
, $compositeComplex: complex
|
||||
) {
|
||||
insert_test_types(
|
||||
objects: [
|
||||
{ c1_smallint: 32767
|
||||
, c2_integer: 2147483647
|
||||
, c3_bigint: "9223372036854775807"
|
||||
, c4_decimal: 123.45
|
||||
, c5_numeric: 1.234
|
||||
, c6_real: 0.00390625
|
||||
, c7_double_precision: 16.0001220703125
|
||||
, c11_varchar_3: "abc"
|
||||
, c12_char_4: "baaz"
|
||||
, c13_text: "foo bar baz"
|
||||
, c14_timestamp: "2004-10-19T10:23:54"
|
||||
, c15_timestamptz: "2015-10-17T14:42:43+00:00"
|
||||
, c16_date: "2014-09-14"
|
||||
, c17_time: "11:09:23"
|
||||
, c18_time_with_zone: "15:22:23+00"
|
||||
, c19_interval: "01:03:02"
|
||||
, c20_boolean: true
|
||||
, c21_point: "(1,2)"
|
||||
, c22_line: "{2,3,-1}"
|
||||
, c23_lseg: "[(4,2),(3,1)]"
|
||||
, c24_box: "(31,12),(14,11)"
|
||||
, c25_closed_path: "((0,0),(0,3),(1,0))"
|
||||
, c26_open_path: "[(0,0),(0,-1),(-3,0)]"
|
||||
, c27_polygon: "((0,0),(0,6),(2,0))"
|
||||
, c28_circle: "<(-2,-3),3>"
|
||||
, c29_cidr: "192.168.100.128/25"
|
||||
, c30_inet: "198.24.10.0"
|
||||
, c31_macaddr: "08:00:2b:01:02:03"
|
||||
, c32_json: $json
|
||||
, c33_jsonb: $jsonb
|
||||
, c36_uuid: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"
|
||||
, c39_range_integer: "[123,456)"
|
||||
, c40_range_bigint: "[1147483647,2147483647)"
|
||||
, c41_range_numeric: "[1.23,4.56]"
|
||||
, c42_range_timestamp: "[\"2010-01-01 14:30:00\",\"2010-01-01 15:30:02\")"
|
||||
, c43_range_timestamptz: "(\"2011-02-05 12:03:00+00\",\"2012-03-04 16:40:04+00\"]"
|
||||
, c44_xml: "<foo>bar</foo>"
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
c1_smallint
|
||||
c2_integer
|
||||
c3_bigint
|
||||
c4_decimal
|
||||
c5_numeric
|
||||
c6_real
|
||||
c7_double_precision
|
||||
c8_smallserial
|
||||
c9_serial
|
||||
c10_bigserial
|
||||
c11_varchar_3
|
||||
c12_char_4
|
||||
c13_text
|
||||
c14_timestamp
|
||||
c15_timestamptz
|
||||
c16_date
|
||||
c17_time
|
||||
c18_time_with_zone
|
||||
c19_interval
|
||||
c20_boolean
|
||||
c21_point
|
||||
c22_line
|
||||
c23_lseg
|
||||
c24_box
|
||||
c25_closed_path
|
||||
c26_open_path
|
||||
c27_polygon
|
||||
c28_circle
|
||||
c29_cidr
|
||||
c30_inet
|
||||
c31_macaddr
|
||||
c32_json
|
||||
c33_jsonb
|
||||
c36_uuid
|
||||
c39_range_integer
|
||||
c40_range_bigint
|
||||
c41_range_numeric
|
||||
c42_range_timestamp
|
||||
c43_range_timestamptz
|
||||
c44_xml
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted rows in test_types table
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from test_types;
|
||||
SELECT setval('test_types_c10_bigserial_seq', 1, FALSE);
|
||||
SELECT setval('test_types_c9_serial_seq', 1, FALSE);
|
||||
SELECT setval('test_types_c8_smallserial_seq', 1, FALSE);
|
@ -1,20 +1,29 @@
|
||||
description: Insert into order table with a null value
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
query:
|
||||
query: |
|
||||
mutation insert_orders{
|
||||
insert_orders(
|
||||
objects: [
|
||||
{
|
||||
placed: "2017-08-19 14:22:11.802755+02",
|
||||
shipped: null
|
||||
- description: Insert into order table with a null value
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
query:
|
||||
query: |
|
||||
mutation insert_orders{
|
||||
insert_orders(
|
||||
objects: [
|
||||
{
|
||||
placed: "2017-08-19 14:22:11.802755+02",
|
||||
shipped: null
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
affected_rows
|
||||
}
|
||||
affected_rows
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted orders
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from orders;
|
||||
SELECT setval('orders_id_seq', 1, FALSE);
|
||||
|
@ -1,24 +1,33 @@
|
||||
description: Inserts person data via GraphQL mutation
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
query:
|
||||
variables:
|
||||
value:
|
||||
name:
|
||||
first: john
|
||||
last: murphy
|
||||
query: |
|
||||
mutation insert_person($value: jsonb) {
|
||||
insert_person(
|
||||
objects: [
|
||||
{
|
||||
details: $value
|
||||
- description: Inserts person data via GraphQL mutation
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
query:
|
||||
variables:
|
||||
value:
|
||||
name:
|
||||
first: john
|
||||
last: murphy
|
||||
query: |
|
||||
mutation insert_person($value: jsonb) {
|
||||
insert_person(
|
||||
objects: [
|
||||
{
|
||||
details: $value
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
details
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
details
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted persons
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from person;
|
||||
SELECT setval('person_id_seq', 1, FALSE);
|
||||
|
@ -1,27 +1,36 @@
|
||||
description: Inserts persons data via GraphQL mutation
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
query:
|
||||
variables:
|
||||
value:
|
||||
- name:
|
||||
first: thelonious
|
||||
last: jaha
|
||||
- name:
|
||||
first: clarke
|
||||
last: griffin
|
||||
query: |
|
||||
mutation insert_person($value: jsonb) {
|
||||
insert_person(
|
||||
objects: [
|
||||
{
|
||||
details: $value
|
||||
- description: Inserts persons data via GraphQL mutation
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
query:
|
||||
variables:
|
||||
value:
|
||||
- name:
|
||||
first: thelonious
|
||||
last: jaha
|
||||
- name:
|
||||
first: clarke
|
||||
last: griffin
|
||||
query: |
|
||||
mutation insert_person($value: jsonb) {
|
||||
insert_person(
|
||||
objects: [
|
||||
{
|
||||
details: $value
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
details
|
||||
}
|
||||
]
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
details
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted persons
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from person;
|
||||
SELECT setval('person_id_seq', 1, FALSE);
|
||||
|
@ -77,3 +77,80 @@ args:
|
||||
table: article
|
||||
column: author_id
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TYPE complex AS (
|
||||
r double precision,
|
||||
i double precision
|
||||
);
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TYPE inventory_item AS (
|
||||
name text,
|
||||
supplier_id integer,
|
||||
price numeric
|
||||
);
|
||||
|
||||
#Test table with different types
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table test_types (
|
||||
c1_smallint smallint,
|
||||
c2_integer integer,
|
||||
c3_bigint bigint,
|
||||
c4_decimal decimal (5, 2),
|
||||
c5_numeric numeric (4, 3),
|
||||
c6_real real,
|
||||
c7_double_precision double precision,
|
||||
c8_smallserial smallserial primary key,
|
||||
c9_serial serial,
|
||||
c10_bigserial bigserial,
|
||||
c11_varchar_3 varchar(3),
|
||||
c12_char_4 char(4),
|
||||
c13_text text,
|
||||
c14_timestamp timestamp,
|
||||
c15_timestamptz timestamptz,
|
||||
c16_date date,
|
||||
c17_time time,
|
||||
c18_time_with_zone time with time zone,
|
||||
c19_interval interval,
|
||||
c20_boolean boolean,
|
||||
c21_point point,
|
||||
c22_line line,
|
||||
c23_lseg lseg,
|
||||
c24_box box,
|
||||
c25_closed_path path,
|
||||
c26_open_path path,
|
||||
c27_polygon polygon,
|
||||
c28_circle circle,
|
||||
c29_cidr cidr,
|
||||
c30_inet inet,
|
||||
c31_macaddr macaddr,
|
||||
c32_json json,
|
||||
c33_jsonb jsonb,
|
||||
c34_text_array text[],
|
||||
c35_integer_2d_array integer[][],
|
||||
c36_uuid uuid,
|
||||
c37_composite_type_complex complex,
|
||||
c38_composite_type_inventory inventory_item,
|
||||
c39_range_integer int4range,
|
||||
c40_range_bigint int8range,
|
||||
c41_range_numeric numrange,
|
||||
c42_range_timestamp tsrange,
|
||||
c43_range_timestamptz tstzrange,
|
||||
c44_xml xml
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: test_types
|
||||
|
||||
#Set timezone
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
SET TIME ZONE 'UTC';
|
||||
|
@ -12,15 +12,33 @@ args:
|
||||
args:
|
||||
sql: |
|
||||
drop table person
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table orders
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table author
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table test_types
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop type complex
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop type inventory_item
|
||||
|
@ -1,36 +1,44 @@
|
||||
description: Insert area as a polygon
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_area:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Foo
|
||||
area: &area
|
||||
coordinates: &coords
|
||||
-
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
- [43.75049, 11.03207]
|
||||
type: Polygon
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
areas:
|
||||
- name: Foo
|
||||
area: *area
|
||||
query: |
|
||||
mutation insertArea($areas: [area_insert_input!]!) {
|
||||
insert_area(objects: $areas) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
area
|
||||
- description: Insert area as a polygon
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_area:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Foo
|
||||
area: &area
|
||||
coordinates: &coords
|
||||
-
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
- [43.75049, 11.03207]
|
||||
type: Polygon
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
areas:
|
||||
- name: Foo
|
||||
area: *area
|
||||
query: |
|
||||
mutation insertArea($areas: [area_insert_input!]!) {
|
||||
insert_area(objects: $areas) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
area
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted area
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from area
|
||||
|
@ -1,44 +1,52 @@
|
||||
description: Insert the path for a curved road
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_compounds:
|
||||
returning:
|
||||
- description: Insert the path for a road
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_compounds:
|
||||
returning:
|
||||
- user_id: 1
|
||||
name: foo
|
||||
areas: &areas
|
||||
type: MultiPolygon
|
||||
coordinates:
|
||||
- - - [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.90009, 11.03308]
|
||||
- [43.75049, 11.03207]
|
||||
- - [43.75049, 11.03207]
|
||||
- [41.60009, 21.03208]
|
||||
- [41.70009, 21.03308]
|
||||
- [43.75049, 11.03207]
|
||||
- - - [23.75049, 31.03207]
|
||||
- [23.80009, 31.03208]
|
||||
- [23.80009, 31.03308]
|
||||
- [23.75049, 31.03207]
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
compounds:
|
||||
- user_id: 1
|
||||
name: foo
|
||||
areas: &areas
|
||||
type: MultiPolygon
|
||||
coordinates:
|
||||
- - - [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.90009, 11.03308]
|
||||
- [43.75049, 11.03207]
|
||||
- - [43.75049, 11.03207]
|
||||
- [41.60009, 21.03208]
|
||||
- [41.70009, 21.03308]
|
||||
- [43.75049, 11.03207]
|
||||
- - - [23.75049, 31.03207]
|
||||
- [23.80009, 31.03208]
|
||||
- [23.80009, 31.03308]
|
||||
- [23.75049, 31.03207]
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
compounds:
|
||||
- user_id: 1
|
||||
name: foo
|
||||
areas: *areas
|
||||
query: |
|
||||
mutation insertCompounds($compounds: [compounds_insert_input!]!) {
|
||||
insert_compounds(objects: $compounds) {
|
||||
returning{
|
||||
user_id
|
||||
name
|
||||
areas
|
||||
areas: *areas
|
||||
query: |
|
||||
mutation insertCompounds($compounds: [compounds_insert_input!]!) {
|
||||
insert_compounds(objects: $compounds) {
|
||||
returning{
|
||||
user_id
|
||||
name
|
||||
areas
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted compounds
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from compounds
|
||||
|
@ -1,29 +1,37 @@
|
||||
description: Insert location of drone as geojson point
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_drone_3d_location:
|
||||
returning:
|
||||
- description: Insert location of drone as geojson point
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_drone_3d_location:
|
||||
returning:
|
||||
- drone_id: 1
|
||||
location: &loc
|
||||
coordinates: [43.75049, 11.03207, 1.234]
|
||||
type: Point
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
location:
|
||||
- drone_id: 1
|
||||
location: &loc
|
||||
coordinates: [43.75049, 11.03207, 1.234]
|
||||
type: Point
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
location:
|
||||
- drone_id: 1
|
||||
location: *loc
|
||||
query: |
|
||||
mutation insertDroneLoc($location: [drone_3d_location_insert_input!]!) {
|
||||
insert_drone_3d_location(objects: $location) {
|
||||
returning{
|
||||
drone_id
|
||||
location
|
||||
location: *loc
|
||||
query: |
|
||||
mutation insertDroneLoc($location: [drone_3d_location_insert_input!]!) {
|
||||
insert_drone_3d_location(objects: $location) {
|
||||
returning{
|
||||
drone_id
|
||||
location
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted drone location
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from drone_3d_location
|
||||
|
@ -1,71 +1,79 @@
|
||||
description: Insert a geometry collection
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_geometry_collection:
|
||||
returning:
|
||||
- id: 1
|
||||
geometries: &geometry
|
||||
type: GeometryCollection
|
||||
geometries:
|
||||
- type: Point
|
||||
coordinates: [43.75049, 11.03207]
|
||||
|
||||
- type: MultiPoint
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.80009, 11.03308]
|
||||
|
||||
- type: LineString
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
|
||||
- type: MultiLineString
|
||||
coordinates:
|
||||
- - [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- - [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
|
||||
- type: Polygon
|
||||
coordinates: &coords
|
||||
- - [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
- description: Insert a geometry collection
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_geometry_collection:
|
||||
returning:
|
||||
- id: 1
|
||||
geometries: &geometry
|
||||
type: GeometryCollection
|
||||
geometries:
|
||||
- type: Point
|
||||
coordinates: [43.75049, 11.03207]
|
||||
|
||||
- type: MultiPoint
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
|
||||
- type: MultiPolygon
|
||||
coordinates:
|
||||
- - - [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.90009, 11.03308]
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.80009, 11.03308]
|
||||
|
||||
- type: LineString
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
|
||||
- type: MultiLineString
|
||||
coordinates:
|
||||
- - [43.75049, 11.03207]
|
||||
- [41.60009, 21.03208]
|
||||
- [41.70009, 21.03308]
|
||||
- [43.80009, 11.03208]
|
||||
- - [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
|
||||
- type: Polygon
|
||||
coordinates: &coords
|
||||
- - [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
- [43.75049, 11.03207]
|
||||
- - - [23.75049, 31.03207]
|
||||
- [23.80009, 31.03208]
|
||||
- [23.80009, 31.03308]
|
||||
- [23.75049, 31.03207]
|
||||
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
geometries:
|
||||
- geometries: *geometry
|
||||
query: |
|
||||
mutation insertGeometries($geometries: [geometry_collection_insert_input!]!) {
|
||||
insert_geometry_collection(objects: $geometries) {
|
||||
returning{
|
||||
id
|
||||
geometries
|
||||
|
||||
- type: MultiPolygon
|
||||
coordinates:
|
||||
- - - [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.90009, 11.03308]
|
||||
- [43.75049, 11.03207]
|
||||
- - [43.75049, 11.03207]
|
||||
- [41.60009, 21.03208]
|
||||
- [41.70009, 21.03308]
|
||||
- [43.75049, 11.03207]
|
||||
- - - [23.75049, 31.03207]
|
||||
- [23.80009, 31.03208]
|
||||
- [23.80009, 31.03308]
|
||||
- [23.75049, 31.03207]
|
||||
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
geometries:
|
||||
- geometries: *geometry
|
||||
query: |
|
||||
mutation insertGeometries($geometries: [geometry_collection_insert_input!]!) {
|
||||
insert_geometry_collection(objects: $geometries) {
|
||||
returning{
|
||||
id
|
||||
geometries
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted geometry collection
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
DELETE from geometry_collection
|
||||
|
@ -1,44 +1,52 @@
|
||||
description: Insert landmarks
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_landmark:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Baz
|
||||
- description: Insert landmarks
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_landmark:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Baz
|
||||
type: river
|
||||
location: &loc1
|
||||
coordinates: [43.75049, 11.03207]
|
||||
type: Point
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
- id: 2
|
||||
name: Foo Bar
|
||||
type: park
|
||||
location: &loc2
|
||||
coordinates: [43.76417, 11.25869]
|
||||
type: Point
|
||||
crs: *crs
|
||||
query:
|
||||
variables:
|
||||
landmarks:
|
||||
- name: Baz
|
||||
type: river
|
||||
location: &loc1
|
||||
coordinates: [43.75049, 11.03207]
|
||||
type: Point
|
||||
crs: &crs
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
- id: 2
|
||||
name: Foo Bar
|
||||
location: *loc1
|
||||
- name: Foo Bar
|
||||
type: park
|
||||
location: &loc2
|
||||
coordinates: [43.76417, 11.25869]
|
||||
type: Point
|
||||
crs: *crs
|
||||
query:
|
||||
variables:
|
||||
landmarks:
|
||||
- name: Baz
|
||||
type: river
|
||||
location: *loc1
|
||||
- name: Foo Bar
|
||||
type: park
|
||||
location: *loc2
|
||||
query: |
|
||||
mutation insertLandmark($landmarks: [landmark_insert_input!]!) {
|
||||
insert_landmark(objects: $landmarks) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
location
|
||||
type
|
||||
location: *loc2
|
||||
query: |
|
||||
mutation insertLandmark($landmarks: [landmark_insert_input!]!) {
|
||||
insert_landmark(objects: $landmarks) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
location
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted landmarks
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from landmark
|
||||
|
@ -1,33 +1,41 @@
|
||||
description: Insert a straight road as a geojson LineString
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_road:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Foo
|
||||
path: &path
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
type: LineString
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
roads:
|
||||
- name: Foo
|
||||
path: *path
|
||||
query: |
|
||||
mutation insertRoad($roads: [road_insert_input!]!) {
|
||||
insert_road(objects: $roads) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
path
|
||||
- description: Insert a straight road as a geojson LineString
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_road:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Foo
|
||||
path: &path
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
type: LineString
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
roads:
|
||||
- name: Foo
|
||||
path: *path
|
||||
query: |
|
||||
mutation insertRoad($roads: [road_insert_input!]!) {
|
||||
insert_road(objects: $roads) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted road
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from road
|
||||
|
@ -1,37 +1,45 @@
|
||||
description: Insert a route as a geojson MultiLineString
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_route:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Foo
|
||||
route: &route
|
||||
coordinates:
|
||||
-
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
-
|
||||
- [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
type: MultiLineString
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
routes:
|
||||
- name: Foo
|
||||
route: *route
|
||||
query: |
|
||||
mutation insertRoute($routes: [route_insert_input!]!) {
|
||||
insert_route(objects: $routes) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
route
|
||||
- description: Insert a route as a geojson MultiLineString
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_route:
|
||||
returning:
|
||||
- id: 1
|
||||
name: Foo
|
||||
route: &route
|
||||
coordinates:
|
||||
-
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
-
|
||||
- [43.80009, 11.03208]
|
||||
- [42.60009, 10.13248]
|
||||
type: MultiLineString
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
routes:
|
||||
- name: Foo
|
||||
route: *route
|
||||
query: |
|
||||
mutation insertRoute($routes: [route_insert_input!]!) {
|
||||
insert_route(objects: $routes) {
|
||||
returning{
|
||||
id
|
||||
name
|
||||
route
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted route
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from route
|
||||
|
@ -1,31 +1,39 @@
|
||||
description: Insert the path for a curved road
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_service_locations:
|
||||
returning:
|
||||
- id: 1
|
||||
locations: &locs
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.80009, 11.03308]
|
||||
type: MultiPoint
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
locations:
|
||||
- locations: *locs
|
||||
query: |
|
||||
mutation insertServLoc($locations: [service_locations_insert_input!]!) {
|
||||
insert_service_locations(objects: $locations) {
|
||||
returning{
|
||||
id
|
||||
locations
|
||||
- description: Insert the path for a curved road
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_service_locations:
|
||||
returning:
|
||||
- id: 1
|
||||
locations: &locs
|
||||
coordinates:
|
||||
- [43.75049, 11.03207]
|
||||
- [43.80009, 11.03208]
|
||||
- [43.80009, 11.03308]
|
||||
type: MultiPoint
|
||||
crs:
|
||||
type: name
|
||||
properties:
|
||||
name: 'urn:ogc:def:crs:EPSG::4326'
|
||||
query:
|
||||
variables:
|
||||
locations:
|
||||
- locations: *locs
|
||||
query: |
|
||||
mutation insertServLoc($locations: [service_locations_insert_input!]!) {
|
||||
insert_service_locations(objects: $locations) {
|
||||
returning{
|
||||
id
|
||||
locations
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Delete the inserted service locations
|
||||
url: /v1/query
|
||||
status: 200
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
delete from service_locations
|
||||
|
@ -0,0 +1,26 @@
|
||||
description: Upserts article data via GraphQL mutation as User role
|
||||
url: /v1alpha1/graphql
|
||||
status: 400
|
||||
header:
|
||||
X-Hasura-Role: user
|
||||
X-Hasura-User-Id: 1
|
||||
query:
|
||||
query: |
|
||||
mutation insert_article {
|
||||
insert_article (
|
||||
objects: [
|
||||
{
|
||||
content: "Updated Article 1 content",
|
||||
id: 1
|
||||
}
|
||||
],
|
||||
on_conflict: {
|
||||
constraint_on: id
|
||||
}
|
||||
) {
|
||||
returning {
|
||||
title
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
description: Nested select on article
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
article:
|
||||
- id: 1
|
||||
title: Article 1
|
||||
content: Sample article content 1
|
||||
author:
|
||||
id: 1
|
||||
name: Author 1
|
||||
- id: 2
|
||||
title: Article 2
|
||||
content: Sample article content 2
|
||||
author:
|
||||
id: 1
|
||||
name: Author 1
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
article (where: {author: {name: {_eq: "Author 1"}}} ) {
|
||||
id
|
||||
title
|
||||
content
|
||||
author {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
description: Simple GraphQL object query on author querying a column which does not exist
|
||||
url: /v1alpha1/graphql
|
||||
status: 400
|
||||
response:
|
||||
errors:
|
||||
- path: $.selectionSet.author.selectionSet.notPresentCol
|
||||
error: |-
|
||||
field "notPresentCol" not found in type: 'author'
|
||||
code: validation-failed
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
author {
|
||||
id
|
||||
name
|
||||
notPresentCol
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
description: Simple GraphQL object query on author
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
author:
|
||||
- name: Author 1
|
||||
id: 1
|
||||
createdAt: '2017-09-21T09:39:44+00:00'
|
||||
- name: Author 2
|
||||
id: 2
|
||||
createdAt: '2017-09-21T09:50:44+00:00'
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
author {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
description: Select query on table which is not tracked
|
||||
url: /v1alpha1/graphql
|
||||
status: 400
|
||||
response:
|
||||
errors:
|
||||
- path: $.selectionSet.random
|
||||
error: |-
|
||||
field "random" not found in type: 'query_root'
|
||||
code: validation-failed
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
random {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
description: GraphQL query to test different data types of Postgres
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
test_types:
|
||||
- c1_smallint: 32767
|
||||
c2_integer: 2147483647
|
||||
c3_bigint: '9223372036854775807'
|
||||
c4_decimal: 123.45
|
||||
c5_numeric: 1.234
|
||||
c6_real: 0.00390625
|
||||
c7_double_precision: 16.0001220703125
|
||||
c8_smallserial: 1
|
||||
c9_serial: 1
|
||||
c10_bigserial: '1'
|
||||
c11_varchar_3: 'abc'
|
||||
c12_char_4: 'baaz'
|
||||
c13_text: 'foo bar baz'
|
||||
c14_timestamp: '2004-10-19T10:23:54'
|
||||
c15_timestamptz: '2015-10-17T14:42:43+00:00'
|
||||
c16_date: '2014-09-14'
|
||||
c17_time: '11:09:23'
|
||||
c18_time_with_zone: '15:22:23+00'
|
||||
c19_interval: '01:03:02'
|
||||
c20_boolean: true
|
||||
c21_point: '(1,2)'
|
||||
c22_line: '{2,3,-1}'
|
||||
c23_lseg: '[(4,2),(3,1)]'
|
||||
c24_box: '(31,12),(14,11)'
|
||||
c25_closed_path: '((0,0),(0,3),(1,0))'
|
||||
c26_open_path: '[(0,0),(0,-1),(-3,0)]'
|
||||
c27_polygon: '((0,0),(0,6),(2,0))'
|
||||
c28_circle: '<(-2,-3),3>'
|
||||
c29_cidr: '192.168.100.128/25'
|
||||
c30_inet: '198.24.10.0'
|
||||
c31_macaddr: '08:00:2b:01:02:03'
|
||||
c32_json:
|
||||
a: b
|
||||
c33_jsonb:
|
||||
c: d
|
||||
c34_text_array: ["a","b","c"]
|
||||
c35_integer_2d_array:
|
||||
- [4,5,6]
|
||||
- [7,8,9]
|
||||
c36_uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
|
||||
c37_composite_type_complex:
|
||||
r: 1.23
|
||||
i: -3.456
|
||||
c38_composite_type_inventory:
|
||||
name: fuzzy dice
|
||||
supplier_id: 42
|
||||
price: 1.99
|
||||
c39_range_integer: '[123,456)'
|
||||
c40_range_bigint: '[1147483647,2147483647)'
|
||||
c41_range_numeric: '[1.23,4.56]'
|
||||
c42_range_timestamp: '["2010-01-01 14:30:00","2010-01-01 15:30:02")'
|
||||
c43_range_timestamptz: '("2011-02-05 12:03:00+00","2012-03-04 16:40:04+00"]'
|
||||
c44_xml: '<foo>bar</foo>'
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
test_types {
|
||||
c1_smallint
|
||||
c2_integer
|
||||
c3_bigint
|
||||
c4_decimal
|
||||
c5_numeric
|
||||
c6_real
|
||||
c7_double_precision
|
||||
c8_smallserial
|
||||
c9_serial
|
||||
c10_bigserial
|
||||
c11_varchar_3
|
||||
c12_char_4
|
||||
c13_text
|
||||
c14_timestamp
|
||||
c15_timestamptz
|
||||
c16_date
|
||||
c17_time
|
||||
c18_time_with_zone
|
||||
c19_interval
|
||||
c20_boolean
|
||||
c21_point
|
||||
c22_line
|
||||
c23_lseg
|
||||
c24_box
|
||||
c25_closed_path
|
||||
c26_open_path
|
||||
c27_polygon
|
||||
c28_circle
|
||||
c29_cidr
|
||||
c30_inet
|
||||
c31_macaddr
|
||||
c32_json
|
||||
c33_jsonb
|
||||
c34_text_array
|
||||
c35_integer_2d_array
|
||||
c36_uuid
|
||||
c37_composite_type_complex
|
||||
c38_composite_type_inventory
|
||||
c39_range_integer
|
||||
c40_range_bigint
|
||||
c41_range_numeric
|
||||
c42_range_timestamp
|
||||
c43_range_timestamptz
|
||||
c44_xml
|
||||
}
|
||||
}
|
@ -1,13 +1,87 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TYPE complex AS (
|
||||
r double precision,
|
||||
i double precision
|
||||
);
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TYPE inventory_item AS (
|
||||
name text,
|
||||
supplier_id integer,
|
||||
price numeric
|
||||
);
|
||||
|
||||
#Test table with different types
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table test_types (
|
||||
c1_smallint smallint,
|
||||
c2_integer integer,
|
||||
c3_bigint bigint,
|
||||
c4_decimal decimal (5, 2),
|
||||
c5_numeric numeric (4, 3),
|
||||
c6_real real,
|
||||
c7_double_precision double precision,
|
||||
c8_smallserial smallserial,
|
||||
c9_serial serial,
|
||||
c10_bigserial bigserial,
|
||||
c11_varchar_3 varchar(3),
|
||||
c12_char_4 char(4),
|
||||
c13_text text,
|
||||
c14_timestamp timestamp,
|
||||
c15_timestamptz timestamptz,
|
||||
c16_date date,
|
||||
c17_time time,
|
||||
c18_time_with_zone time with time zone,
|
||||
c19_interval interval,
|
||||
c20_boolean boolean,
|
||||
c21_point point,
|
||||
c22_line line,
|
||||
c23_lseg lseg,
|
||||
c24_box box,
|
||||
c25_closed_path path,
|
||||
c26_open_path path,
|
||||
c27_polygon polygon,
|
||||
c28_circle circle,
|
||||
c29_cidr cidr,
|
||||
c30_inet inet,
|
||||
c31_macaddr macaddr,
|
||||
c32_json json,
|
||||
c33_jsonb jsonb,
|
||||
c34_text_array text[],
|
||||
c35_integer_2d_array integer[][],
|
||||
c36_uuid uuid,
|
||||
c37_composite_type_complex complex,
|
||||
c38_composite_type_inventory inventory_item,
|
||||
c39_range_integer int4range,
|
||||
c40_range_bigint int8range,
|
||||
c41_range_numeric numrange,
|
||||
c42_range_timestamp tsrange,
|
||||
c43_range_timestamptz tstzrange,
|
||||
c44_xml xml
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: test_types
|
||||
|
||||
|
||||
#Author table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique
|
||||
id serial primary key,
|
||||
name text unique,
|
||||
"createdAt" timestamptz
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
@ -51,15 +125,105 @@ args:
|
||||
table: article
|
||||
column: author_id
|
||||
|
||||
#Insert values
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
insert into test_types
|
||||
( c1_smallint
|
||||
, c2_integer
|
||||
, c3_bigint
|
||||
, c4_decimal
|
||||
, c5_numeric
|
||||
, c6_real
|
||||
, c7_double_precision
|
||||
, c11_varchar_3
|
||||
, c12_char_4
|
||||
, c13_text
|
||||
, c14_timestamp
|
||||
, c15_timestamptz
|
||||
, c16_date
|
||||
, c17_time
|
||||
, c18_time_with_zone
|
||||
, c19_interval
|
||||
, c20_boolean
|
||||
, c21_point
|
||||
, c22_line
|
||||
, c23_lseg
|
||||
, c24_box
|
||||
, c25_closed_path
|
||||
, c26_open_path
|
||||
, c27_polygon
|
||||
, c28_circle
|
||||
, c29_cidr
|
||||
, c30_inet
|
||||
, c31_macaddr
|
||||
, c32_json
|
||||
, c33_jsonb
|
||||
, c34_text_array
|
||||
, c35_integer_2d_array
|
||||
, c36_uuid
|
||||
, c37_composite_type_complex
|
||||
, c38_composite_type_inventory
|
||||
, c39_range_integer
|
||||
, c40_range_bigint
|
||||
, c41_range_numeric
|
||||
, c42_range_timestamp
|
||||
, c43_range_timestamptz
|
||||
, c44_xml
|
||||
)
|
||||
values
|
||||
( 32767 -- c1_smallint
|
||||
, 2147483647 -- c2_integer
|
||||
, 9223372036854775807 -- c3_bigint
|
||||
, 123.45 -- c4_decimal
|
||||
, 1.234 -- c5_numeric
|
||||
, 0.00390625 -- c6_real
|
||||
, 16.0001220703125 -- c7_double_precision
|
||||
, 'abc' -- c11_varchar_3
|
||||
, 'baaz' -- c12_char_4
|
||||
, 'foo bar baz' -- c13_text
|
||||
, '2004-10-19T10:23:54' -- c14_timestamp
|
||||
, '2015-10-17T14:42:43+00:00' -- c15_timestamptz
|
||||
, '2014-09-14' -- c16_date
|
||||
, '11:09:23' -- c17_time
|
||||
, '15:22:23+00' -- c18_time_with_zone
|
||||
, '01:03:02' -- c19_interval
|
||||
, true -- c20_boolean
|
||||
, '(1,2)' -- c21_point
|
||||
, '{2,3,-1}' -- c22_line
|
||||
, '[(4,2),(3,1)]' -- c23_line
|
||||
, '((31,12),(14,11))' -- c24_box
|
||||
, '((0,0),(0,3),(1,0))' -- c25_closed_path
|
||||
, '[(0,0),(0,-1),(-3,0)]' -- c26_open_path
|
||||
, '((0,0),(0,6),(2,0))' -- c27_polygon
|
||||
, '<(-2,-3),3>' -- c28_circle
|
||||
, '192.168.100.128/25' -- c29_cidr
|
||||
, '198.24.10.0' -- c30_inet
|
||||
, '08:00:2b:01:02:03' -- c31_macaddr
|
||||
, '{ "a" : "b" }' -- c32_json
|
||||
, '{ "c" : "d" }' -- c33_jsonb
|
||||
, '{"a","b","c"}' -- c34_text_array
|
||||
, '{{4,5,6},{7,8,9}}' -- c35_integer_2d_array
|
||||
, 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' -- c36_uuid
|
||||
, '(1.23,-3.456)' -- c37_composite_type_complexa
|
||||
, '("fuzzy dice",42,1.99)' -- c38_composite_type_inventory
|
||||
, '[123,456)' -- c39_range_integer
|
||||
, '[1147483647, 2147483647)' -- c40_range_bigint
|
||||
, '[1.23, 4.56]' -- c41_range_numeric
|
||||
, '[2010-01-01 14:30:00, 2010-01-01 15:30:02)' -- c42_range_timestamp
|
||||
, '(2011-02-05T12:03:00+00:00, 2012-03-04T16:40:04+00:00]' -- c43_range_timestamptz
|
||||
, '<foo>bar</foo>' -- c44_xml
|
||||
)
|
||||
|
||||
#Insert values
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
insert into author (name)
|
||||
insert into author (name, "createdAt")
|
||||
values
|
||||
('Author 1'),
|
||||
('Author 2')
|
||||
('Author 1', '2017-09-21T09:39:44Z'),
|
||||
('Author 2', '2017-09-21T09:50:44Z')
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
@ -106,3 +270,9 @@ args:
|
||||
number: '123456789'
|
||||
- name: User 2
|
||||
number: '123456780'
|
||||
|
||||
#Set timezone
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
SET TIME ZONE 'UTC';
|
||||
|
@ -1,5 +1,11 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table test_types
|
||||
|
||||
#Drop relationship first
|
||||
- type: drop_relationship
|
||||
args:
|
||||
@ -22,3 +28,13 @@ args:
|
||||
args:
|
||||
sql: |
|
||||
drop table "user"
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop type complex
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop type inventory_item
|
||||
|
@ -0,0 +1,23 @@
|
||||
description: Select author and their articles
|
||||
url: /v1alpha1/graphql
|
||||
status: 400
|
||||
response:
|
||||
errors:
|
||||
- path: $.selectionSet.author.args.where.name._ne
|
||||
error: |-
|
||||
field "_ne" not found in type: 'text_comparison_exp'
|
||||
code: validation-failed
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
author (where: {name: {_ne: "Author 1"}}) {
|
||||
id
|
||||
name
|
||||
articles {
|
||||
id
|
||||
title
|
||||
content
|
||||
is_published
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
description: Select author and their articles
|
||||
url: /v1alpha1/graphql
|
||||
status: 400
|
||||
response:
|
||||
errors:
|
||||
- path: $.selectionSet.author.args.where.id._unexpected
|
||||
error: |-
|
||||
field "_unexpected" not found in type: 'integer_comparison_exp'
|
||||
code: validation-failed
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
author (
|
||||
where: {id: {_unexpected: 2}}
|
||||
) {
|
||||
id
|
||||
name
|
||||
articles{
|
||||
id
|
||||
title
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 400
|
||||
response:
|
||||
path: $
|
||||
error: When parsing Hasura.Server.Query.RQLQuery expected Object but got String.
|
||||
code: parse-failed
|
||||
query: |
|
||||
type: count
|
||||
args: |
|
||||
table: author
|
11
server/tests-py/queries/v1/basic/query_string_input_err.yaml
Normal file
11
server/tests-py/queries/v1/basic/query_string_input_err.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 400
|
||||
response:
|
||||
path: $
|
||||
error: When parsing Hasura.Server.Query.RQLQuery expected Object but got String.
|
||||
code: parse-failed
|
||||
query: |
|
||||
type: count
|
||||
args:
|
||||
table: author
|
@ -0,0 +1,7 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 400
|
||||
query:
|
||||
type: random
|
||||
args:
|
||||
foo: bar
|
94
server/tests-py/queries/v1/basic/setup.yaml
Normal file
94
server/tests-py/queries/v1/basic/setup.yaml
Normal file
@ -0,0 +1,94 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
#Author table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique,
|
||||
is_registered boolean
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
#Article table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TABLE article (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
author_id INTEGER REFERENCES author(id),
|
||||
is_published BOOLEAN,
|
||||
published_on TIMESTAMP
|
||||
)
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: article
|
||||
#Object relationship
|
||||
- type: create_object_relationship
|
||||
args:
|
||||
table: article
|
||||
name: author
|
||||
using:
|
||||
foreign_key_constraint_on: author_id
|
||||
|
||||
#Insert values
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
insert into author (name, is_registered)
|
||||
values
|
||||
('Author 1', false),
|
||||
('Author 2', true),
|
||||
('Author 3', true),
|
||||
('Author 4', false)
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
insert into article (title, content, author_id, is_published)
|
||||
values
|
||||
(
|
||||
'Article 1',
|
||||
'Sample article content 1',
|
||||
1,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 2',
|
||||
'Sample article content 2',
|
||||
1,
|
||||
true
|
||||
),
|
||||
(
|
||||
'Article 3',
|
||||
'Sample article content 3',
|
||||
2,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 4',
|
||||
'Sample article content 4',
|
||||
3,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 5',
|
||||
'Sample article content 5',
|
||||
3,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 6',
|
||||
'Sample article content 6',
|
||||
3,
|
||||
true
|
||||
)
|
||||
|
10
server/tests-py/queries/v1/basic/teardown.yaml
Normal file
10
server/tests-py/queries/v1/basic/teardown.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
type: bulk
|
||||
args:
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table author
|
@ -0,0 +1,12 @@
|
||||
description: Count articles of registered authors
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
count: 2
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
where:
|
||||
author:
|
||||
is_registered: false
|
@ -0,0 +1,12 @@
|
||||
description: Count articles of registered authors
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
count: 4
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
where:
|
||||
author:
|
||||
is_registered: true
|
@ -0,0 +1,9 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
count: 4
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: author
|
@ -0,0 +1,13 @@
|
||||
description: Count number of authors with atleast one published article
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
count: 2
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
distinct:
|
||||
- author_id
|
||||
where:
|
||||
is_published: true
|
@ -0,0 +1,13 @@
|
||||
description: Count number of authors with atleast one published article
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
count: 3
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
distinct:
|
||||
- author_id
|
||||
where:
|
||||
is_published: false
|
@ -0,0 +1,15 @@
|
||||
description: Count number of authors with atleast one published article
|
||||
url: /v1/query
|
||||
status: 400
|
||||
response:
|
||||
path: $.args.distinct[0]
|
||||
error: ! 'no such column exists : "author_name"'
|
||||
code: permission-denied
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
distinct:
|
||||
- author_name
|
||||
where:
|
||||
is_published: true
|
@ -0,0 +1,11 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
count: 2
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
where:
|
||||
is_published: true
|
@ -0,0 +1,11 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
count: 4
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
where:
|
||||
is_published: false
|
94
server/tests-py/queries/v1/count/basic/setup.yaml
Normal file
94
server/tests-py/queries/v1/count/basic/setup.yaml
Normal file
@ -0,0 +1,94 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
#Author table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique,
|
||||
is_registered boolean
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
#Article table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TABLE article (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
author_id INTEGER REFERENCES author(id),
|
||||
is_published BOOLEAN,
|
||||
published_on TIMESTAMP
|
||||
)
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: article
|
||||
#Object relationship
|
||||
- type: create_object_relationship
|
||||
args:
|
||||
table: article
|
||||
name: author
|
||||
using:
|
||||
foreign_key_constraint_on: author_id
|
||||
|
||||
#Insert values
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
insert into author (name, is_registered)
|
||||
values
|
||||
('Author 1', false),
|
||||
('Author 2', true),
|
||||
('Author 3', true),
|
||||
('Author 4', false)
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
insert into article (title, content, author_id, is_published)
|
||||
values
|
||||
(
|
||||
'Article 1',
|
||||
'Sample article content 1',
|
||||
1,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 2',
|
||||
'Sample article content 2',
|
||||
1,
|
||||
true
|
||||
),
|
||||
(
|
||||
'Article 3',
|
||||
'Sample article content 3',
|
||||
2,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 4',
|
||||
'Sample article content 4',
|
||||
3,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 5',
|
||||
'Sample article content 5',
|
||||
3,
|
||||
false
|
||||
),
|
||||
(
|
||||
'Article 6',
|
||||
'Sample article content 6',
|
||||
3,
|
||||
true
|
||||
)
|
||||
|
10
server/tests-py/queries/v1/count/basic/teardown.yaml
Normal file
10
server/tests-py/queries/v1/count/basic/teardown.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
type: bulk
|
||||
args:
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table author
|
@ -0,0 +1,16 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 400
|
||||
headers:
|
||||
X-Hasura-Role: contractor
|
||||
response:
|
||||
path: $.args
|
||||
error: select on "article" for role "contractor" is not allowed. ; "count" is only
|
||||
allowed if the role has "select" permissions on the table
|
||||
code: permission-denied
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
where:
|
||||
is_published: false
|
@ -0,0 +1,14 @@
|
||||
description: Count number of authors
|
||||
url: /v1/query
|
||||
status: 200
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
X-Hasura-User-Id: '3'
|
||||
response:
|
||||
count: 3
|
||||
query:
|
||||
type: count
|
||||
args:
|
||||
table: article
|
||||
where:
|
||||
is_published: false
|
185
server/tests-py/queries/v1/count/permissions/setup.yaml
Normal file
185
server/tests-py/queries/v1/count/permissions/setup.yaml
Normal file
@ -0,0 +1,185 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
#Author table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique,
|
||||
is_registered boolean not null default false,
|
||||
remarks_internal text
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
#Article table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TABLE article (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
author_id INTEGER NOT NULL REFERENCES author(id),
|
||||
is_published BOOLEAN NOT NULL default FALSE,
|
||||
published_on TIMESTAMP
|
||||
)
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: article
|
||||
|
||||
#Object relationship
|
||||
- type: create_object_relationship
|
||||
args:
|
||||
name: author
|
||||
table: article
|
||||
using:
|
||||
foreign_key_constraint_on: author_id
|
||||
|
||||
#Array relationship
|
||||
- type: create_array_relationship
|
||||
args:
|
||||
table: author
|
||||
name: articles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
table: article
|
||||
column: author_id
|
||||
|
||||
#Article select permission for user
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: article
|
||||
role: user
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
- content
|
||||
- is_published
|
||||
filter:
|
||||
$or:
|
||||
- author_id: X-HASURA-USER-ID
|
||||
- is_published: true
|
||||
|
||||
#Article select permission for anonymous (only published articles)
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: article
|
||||
role: anonymous
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
- content
|
||||
- is_published
|
||||
filter:
|
||||
is_published: true
|
||||
|
||||
#Article insert permission for user
|
||||
- type: create_insert_permission
|
||||
args:
|
||||
table: article
|
||||
role: user
|
||||
permission:
|
||||
check:
|
||||
author_id: X-Hasura-User-Id
|
||||
|
||||
#Author select permission for user
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: author
|
||||
role: user
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- name
|
||||
- is_registered
|
||||
filter:
|
||||
_or:
|
||||
- id: X-HASURA-USER-ID
|
||||
- articles:
|
||||
is_published:
|
||||
_eq: true
|
||||
|
||||
#Author select permission for anonymous users
|
||||
#Only authors with atleast one article will be shown
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: author
|
||||
role: anonymous
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- name
|
||||
filter:
|
||||
articles:
|
||||
is_published:
|
||||
_eq: true
|
||||
|
||||
#Author insert permission for user
|
||||
- type: create_insert_permission
|
||||
args:
|
||||
table: author
|
||||
role: user
|
||||
permission:
|
||||
check:
|
||||
id: X-HASURA-USER-ID
|
||||
allow_upsert: true
|
||||
|
||||
#Insert Author values
|
||||
- type: insert
|
||||
args:
|
||||
table: author
|
||||
objects:
|
||||
- name: Author 1
|
||||
remarks_internal: remark 1
|
||||
- name: Author 2
|
||||
remarks_internal: remark 2
|
||||
- name: Author 3
|
||||
remarks_internal: remark 3
|
||||
|
||||
#Insert Article values
|
||||
- type: insert
|
||||
args:
|
||||
table: article
|
||||
objects:
|
||||
- title: Article 1
|
||||
content: Sample article content 1
|
||||
author_id: 1
|
||||
is_published: false
|
||||
|
||||
- title: Article 2
|
||||
content: Sample article content 2
|
||||
author_id: 1
|
||||
is_published: true
|
||||
|
||||
- title: Article 3
|
||||
content: Sample article content 3
|
||||
author_id: 2
|
||||
is_published: true
|
||||
|
||||
- title: Article 4
|
||||
content: Sample article content 4
|
||||
author_id: 3
|
||||
is_published: false
|
||||
|
||||
- title: Article 5
|
||||
content: Sample article content 5
|
||||
author_id: 3
|
||||
is_published: true
|
||||
|
||||
- title: Article 6
|
||||
content: Sample article content 6
|
||||
author_id: 3
|
||||
is_published: false
|
||||
|
||||
- title: Article 7
|
||||
content: Sample article content 7
|
||||
author_id: 3
|
||||
is_published: false
|
14
server/tests-py/queries/v1/count/permissions/teardown.yaml
Normal file
14
server/tests-py/queries/v1/count/permissions/teardown.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article
|
||||
cascade: true
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table author
|
||||
cascade: true
|
@ -0,0 +1,17 @@
|
||||
description: Create permission with admin as role (error)
|
||||
url: /v1/query
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: >-
|
||||
'select' permission on "author" for role "admin" already exists
|
||||
code: already-exists
|
||||
query:
|
||||
type: create_select_permission
|
||||
args:
|
||||
table: author
|
||||
role: admin
|
||||
permission:
|
||||
columns: '*'
|
||||
filter:
|
||||
id: X-Hasura-User-Id
|
@ -0,0 +1,26 @@
|
||||
- description: Create permission with user as role
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
message: success
|
||||
query:
|
||||
type: create_select_permission
|
||||
args:
|
||||
table: author
|
||||
role: user
|
||||
permission:
|
||||
columns: '*'
|
||||
filter:
|
||||
id: X-Hasura-User-Id
|
||||
|
||||
- description: Drop select permission
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
message: success
|
||||
query:
|
||||
type: drop_select_permission
|
||||
args:
|
||||
table: author
|
||||
role: user
|
||||
|
30
server/tests-py/queries/v1/permissions/setup.yaml
Normal file
30
server/tests-py/queries/v1/permissions/setup.yaml
Normal file
@ -0,0 +1,30 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
#Author table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique,
|
||||
remarks text
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
#Article table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TABLE article (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
author_id INTEGER REFERENCES author(id),
|
||||
is_published BOOLEAN,
|
||||
published_on TIMESTAMP
|
||||
)
|
||||
|
13
server/tests-py/queries/v1/permissions/teardown.yaml
Normal file
13
server/tests-py/queries/v1/permissions/teardown.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table author
|
||||
|
@ -0,0 +1,35 @@
|
||||
description: Nested select on article
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
- id: 1
|
||||
title: Article 1
|
||||
content: Sample article content 1
|
||||
author_info:
|
||||
id: 1
|
||||
name: Author 1
|
||||
- id: 2
|
||||
title: Article 2
|
||||
content: Sample article content 2
|
||||
author_info:
|
||||
id: 1
|
||||
name: Author 1
|
||||
- id: 3
|
||||
title: Article 3
|
||||
content: Sample article content 3
|
||||
author_info:
|
||||
id: 2
|
||||
name: Author 2
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
table: article
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
- content
|
||||
- name: author
|
||||
alias: author_info
|
||||
columns:
|
||||
- id
|
||||
- name
|
@ -0,0 +1,14 @@
|
||||
url: /v1/query
|
||||
status: 400
|
||||
response:
|
||||
code: not-exists
|
||||
error: table "foobar" does not exist
|
||||
path: $.args.table
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
table: foobar
|
||||
columns:
|
||||
- id
|
||||
- name
|
||||
- user
|
@ -4,3 +4,6 @@ pytest
|
||||
requests
|
||||
pyyaml
|
||||
websocket-client
|
||||
pyjwt >= 1.5.3
|
||||
jsondiff
|
||||
cryptography
|
||||
|
45
server/tests-py/super_classes.py
Normal file
45
server/tests-py/super_classes.py
Normal file
@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class DefaultTestQueries(ABC):
|
||||
|
||||
def do_setup(self, setup_ctrl, hge_ctx):
|
||||
if not setup_ctrl['setupDone']:
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir() + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
setup_ctrl['setupDone'] = True
|
||||
|
||||
def do_teardown(self, setup_ctrl, hge_ctx):
|
||||
if setup_ctrl['setupDone'] and not hge_ctx.may_skip_test_teardown:
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir() + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
setup_ctrl['setupDone'] = False
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, setup_ctrl, hge_ctx):
|
||||
self.do_setup(setup_ctrl, hge_ctx)
|
||||
yield
|
||||
self.do_teardown(setup_ctrl, hge_ctx);
|
||||
|
||||
@abstractmethod
|
||||
def dir(self):
|
||||
pass
|
||||
|
||||
|
||||
class DefaultTestSelectQueries(ABC):
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def transact(self, request, hge_ctx):
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir() + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir() + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def ensure_transact(self, transact):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def dir(self):
|
||||
pass
|
@ -1,40 +1,34 @@
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from validate import check_query_f
|
||||
from validate import check_query_f, check_query
|
||||
from super_classes import DefaultTestSelectQueries
|
||||
|
||||
class TestGraphqlIntrospection:
|
||||
class TestGraphqlIntrospection(DefaultTestSelectQueries):
|
||||
|
||||
def test_introspection(self, hge_ctx):
|
||||
with open(self.dir + "/introspection.yaml") as c:
|
||||
conf = yaml.load(c)
|
||||
code, resp = hge_ctx.anyq( conf['url'], conf['query'], {})
|
||||
assert code == 200
|
||||
hasArticle = False
|
||||
hasArticleAuthorFKRel = False
|
||||
hasArticleAuthorManualRel = False
|
||||
for t in resp['data']['__schema']['types']:
|
||||
if t['name'] == 'article':
|
||||
hasArticle = True
|
||||
for fld in t['fields']:
|
||||
if fld['name'] == 'author_obj_rel_manual':
|
||||
hasArticleAuthorManualRel = True
|
||||
assert fld['type']['kind'] == 'OBJECT'
|
||||
elif fld['name'] == 'author_obj_rel_fk':
|
||||
hasArticleAuthorFKRel = True
|
||||
assert fld['type']['kind'] == 'NON_NULL'
|
||||
assert hasArticle
|
||||
assert hasArticleAuthorFKRel
|
||||
assert hasArticleAuthorManualRel
|
||||
with open(self.dir() + "/introspection.yaml") as c:
|
||||
conf = yaml.load(c)
|
||||
code, resp = check_query(hge_ctx, conf)
|
||||
assert code == 200, resp
|
||||
hasArticle = False
|
||||
hasArticleAuthorFKRel = False
|
||||
hasArticleAuthorManualRel = False
|
||||
for t in resp['data']['__schema']['types']:
|
||||
if t['name'] == 'article':
|
||||
hasArticle = True
|
||||
for fld in t['fields']:
|
||||
if fld['name'] == 'author_obj_rel_manual':
|
||||
hasArticleAuthorManualRel = True
|
||||
assert fld['type']['kind'] == 'OBJECT'
|
||||
elif fld['name'] == 'author_obj_rel_fk':
|
||||
hasArticleAuthorFKRel = True
|
||||
assert fld['type']['kind'] == 'NON_NULL'
|
||||
assert hasArticle
|
||||
assert hasArticleAuthorFKRel
|
||||
assert hasArticleAuthorManualRel
|
||||
|
||||
def test_introspection_user(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/introspection_user_role.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/introspection_user_role.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_introspection"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_introspection"
|
||||
|
@ -1,372 +1,340 @@
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from validate import check_query_f
|
||||
from super_classes import DefaultTestQueries
|
||||
|
||||
class TestGraphQLInsert(object):
|
||||
|
||||
class TestGraphQLInsert(DefaultTestQueries):
|
||||
|
||||
def test_inserts_author_article(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_article.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_inserts_various_postgres_types(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_various_postgres_types.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
@pytest.mark.xfail(reason="Refer https://github.com/hasura/graphql-engine/issues/348")
|
||||
def test_insert_into_array_col_with_array_input(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_into_array_col_with_array_input.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_using_variable(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_jsonb_variable.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_jsonb_variable.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_using_array_variable(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_jsonb_variable_array.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_jsonb_variable_array.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_null_col_value(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/order_col_shipped_null.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/order_col_shipped_null.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/insert/basic"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/insert/basic"
|
||||
|
||||
|
||||
class TestGraphqlInsertOnConflict(object):
|
||||
class TestGraphqlInsertOnConflict(DefaultTestQueries):
|
||||
|
||||
def test_on_conflict_update(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_update.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_update.yaml")
|
||||
|
||||
def test_on_conflict_no_action_specified(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_no_action_specified.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_no_action_specified.yaml")
|
||||
|
||||
def test_on_conflict_ignore(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_ignore_constraint.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_ignore_constraint.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_on_conflict_update_empty_cols(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_empty_update_columns.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_empty_update_columns.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_err_missing_article_constraint(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_error_missing_article_constraint.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_error_missing_article_constraint.yaml")
|
||||
|
||||
def test_err_unexpected_action(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_unexpected_on_conflict_action.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_unexpected_on_conflict_action.yaml")
|
||||
|
||||
def test_err_unexpected_constraint(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_unexpected_on_conflict_constraint_error.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_unexpected_on_conflict_constraint_error.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/insert/onconflict"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/insert/onconflict"
|
||||
|
||||
|
||||
|
||||
class TestGraphqlInsertPermission(object):
|
||||
class TestGraphqlInsertPermission(DefaultTestQueries):
|
||||
|
||||
def test_user_role_on_conflict_update(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_user_role.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_user_role.yaml")
|
||||
|
||||
def test_user_role_on_conflict_constraint_on_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_constraint_on_user_role_error.yaml")
|
||||
|
||||
@pytest.mark.xfail(reason="Refer https://github.com/hasura/graphql-engine/issues/563")
|
||||
def test_user_role_on_conflict_ignore(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_on_conflict_ignore_user_role.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_on_conflict_ignore_user_role.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_user_on_conflict_err_no_action_specified(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_article_on_conflict_err_no_action_specified.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_article_on_conflict_err_no_action_specified.yaml")
|
||||
|
||||
def test_user_err_missing_article_constraint(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_article_on_conflict_error_missing_article_constraint.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_article_on_conflict_error_missing_article_constraint.yaml")
|
||||
|
||||
def test_user_err_unexpected_action(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_article_error_unexpected_on_conflict_action.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_article_error_unexpected_on_conflict_action.yaml")
|
||||
|
||||
def test_user_err_unexpected_constraint(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_article_unexpected_on_conflict_constraint_error.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_article_unexpected_on_conflict_constraint_error.yaml")
|
||||
|
||||
def test_role_has_no_permissions_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/address_permission_error.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/address_permission_error.yaml")
|
||||
|
||||
def test_author_user_role_insert_check_perm_success(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_user_role_insert_check_perm_success.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_user_role_insert_check_perm_success.yaml")
|
||||
|
||||
def test_user_role_insert_check_is_registered_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_user_role_insert_check_is_registered_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_user_role_insert_check_is_registered_fail.yaml")
|
||||
|
||||
def test_user_role_insert_check_user_id_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_user_role_insert_check_user_id_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_user_role_insert_check_user_id_fail.yaml")
|
||||
|
||||
def test_student_role_insert_check_bio_success(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_student_role_insert_check_bio_success.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_student_role_insert_check_bio_success.yaml")
|
||||
|
||||
def test_student_role_insert_check_bio_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_student_role_insert_check_bio_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_student_role_insert_check_bio_fail.yaml")
|
||||
|
||||
def test_company_user_role_insert(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/company_user_role.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/company_user_role.yaml")
|
||||
|
||||
def test_company_user_role_insert_on_conflict(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/company_user_role_on_conflict.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/company_user_role_on_conflict.yaml")
|
||||
|
||||
def test_resident_user_role_insert(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/resident_user.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/resident_user.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/insert/permissions"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/insert/permissions"
|
||||
|
||||
|
||||
class TestGraphqlInsertConstraints(object):
|
||||
class TestGraphqlInsertConstraints(DefaultTestQueries):
|
||||
|
||||
def test_address_not_null_constraint_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/address_not_null_constraint_error.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/address_not_null_constraint_error.yaml")
|
||||
|
||||
def test_insert_unique_constraint_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_unique_constraint_error.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_unique_constraint_error.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/insert/constraints"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/insert/constraints"
|
||||
|
||||
|
||||
class TestGraphqlInsertGeoJson():
|
||||
class TestGraphqlInsertGeoJson(DefaultTestQueries):
|
||||
|
||||
def test_insert_point_landmark(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_landmark.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_landmark.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_3d_point_drone_loc(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_drone_3d_location.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_drone_3d_location.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_landmark_single_position_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_landmark_single_position_err.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_landmark_single_position_err.yaml")
|
||||
|
||||
def test_insert_line_string_road(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_road.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_road.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_road_single_point_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_road_single_point_err.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_road_single_point_err.yaml")
|
||||
|
||||
def test_insert_multi_point_service_locations(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_service_locations.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_service_locations.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_multi_line_string_route(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_route.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_route.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_polygon(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_area.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_area.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_linear_ring_less_than_4_points_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_area_less_than_4_points_err.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_area_less_than_4_points_err.yaml")
|
||||
|
||||
def test_insert_linear_ring_last_point_not_equal_to_first_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_linear_ring_last_point_not_equal_to_first_err.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_linear_ring_last_point_not_equal_to_first_err.yaml")
|
||||
|
||||
def test_insert_multi_polygon_compounds(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_compounds.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_compounds.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_geometry_collection(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_geometry_collection.yaml")
|
||||
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_geometry_collection.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_insert_unexpected_geometry_type_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_geometry_unexpected_type_err.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_geometry_unexpected_type_err.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/insert/geojson"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/insert/geojson"
|
||||
|
||||
|
||||
class TestGraphqlNestedInserts(object):
|
||||
class TestGraphqlNestedInserts(DefaultTestQueries):
|
||||
|
||||
def test_author_with_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_with_articles.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_with_articles.yaml")
|
||||
|
||||
def test_author_with_articles_author_id_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_with_articles_author_id_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_with_articles_author_id_fail.yaml")
|
||||
|
||||
def test_articles_with_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/articles_with_author.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/articles_with_author.yaml")
|
||||
|
||||
def test_articles_with_author_author_id_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/articles_with_author_author_id_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/articles_with_author_author_id_fail.yaml")
|
||||
|
||||
def test_author_upsert_articles_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_upsert_articles_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_upsert_articles_fail.yaml")
|
||||
|
||||
def test_articles_author_upsert_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/articles_author_upsert_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/articles_author_upsert_fail.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/insert/nested"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/insert/nested"
|
||||
|
||||
class TestGraphqlInsertViews(object):
|
||||
|
||||
class TestGraphqlInsertViews(DefaultTestQueries):
|
||||
|
||||
def test_insert_view_author_simple(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_view_author_simple.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_view_author_simple.yaml")
|
||||
|
||||
def test_insert_view_author_complex_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/insert_view_author_complex_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/insert_view_author_complex_fail.yaml")
|
||||
|
||||
def test_nested_insert_article_author_simple_view(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/nested_insert_article_author_simple_view.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/nested_insert_article_author_simple_view.yaml")
|
||||
|
||||
def test_nested_insert_article_author_complex_view_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/nested_insert_article_author_complex_view_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/nested_insert_article_author_complex_view_fail.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/insert/views"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/insert/views"
|
||||
|
||||
class TestGraphqlUpdateBasic:
|
||||
|
||||
class TestGraphqlUpdateBasic(DefaultTestQueries):
|
||||
|
||||
def test_set_author_name(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_set_name.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_set_name.yaml")
|
||||
|
||||
def test_set_person_details(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_set_details.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_set_details.yaml")
|
||||
|
||||
def test_person_id_inc(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_inc.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_inc.yaml")
|
||||
|
||||
def test_no_operator_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_error_no_operator.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_error_no_operator.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/update/basic"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/update/basic"
|
||||
|
||||
|
||||
class TestGraphqlUpdateJsonB:
|
||||
class TestGraphqlUpdateJsonB(DefaultTestQueries):
|
||||
|
||||
def test_jsonb_append_object(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_append_object.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_append_object.yaml")
|
||||
|
||||
def test_jsonb_append_array(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_append_array.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_append_array.yaml")
|
||||
|
||||
def test_jsonb_prepend_array(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_prepend_array.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_prepend_array.yaml")
|
||||
|
||||
def test_jsonb_delete_at_path(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_delete_at_path.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_delete_at_path.yaml")
|
||||
|
||||
def test_jsonb_delete_array_element(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_delete_array_element.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_delete_array_element.yaml")
|
||||
|
||||
def test_jsonb_delete_key(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_delete_key.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_delete_key.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/update/jsonb"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/update/jsonb"
|
||||
|
||||
|
||||
class TestGraphqlUpdatePermissions:
|
||||
class TestGraphqlUpdatePermissions(DefaultTestQueries):
|
||||
|
||||
def test_user_can_update_unpublished_article(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_can_update_unpublished_article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_can_update_unpublished_article.yaml")
|
||||
|
||||
def test_user_cannot_update_published_version_col(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_cannot_update_published_article_version.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_cannot_update_published_article_version.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_user_cannot_update_another_users_article(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_cannot_update_another_users_article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_cannot_update_another_users_article.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_user_cannot_update_id_col(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_cannot_update_id_col_article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_cannot_update_id_col_article.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/update/permissions"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/update/permissions"
|
||||
|
||||
|
||||
class TestGraphqlDeleteBasic:
|
||||
class TestGraphqlDeleteBasic(DefaultTestQueries):
|
||||
|
||||
def test_article_delete(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article.yaml")
|
||||
|
||||
def test_article_delete_returning(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_returning.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_returning.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/delete/basic"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/delete/basic"
|
||||
|
||||
|
||||
class TestGraphqlDeleteConstraints:
|
||||
class TestGraphqlDeleteConstraints(DefaultTestQueries):
|
||||
|
||||
def test_author_delete_foreign_key_violation(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_foreign_key_violation.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_foreign_key_violation.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/delete/constraints"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/delete/constraints"
|
||||
|
||||
|
||||
class TestGraphqlDeletePermissions:
|
||||
class TestGraphqlDeletePermissions(DefaultTestQueries):
|
||||
|
||||
def test_author_can_delete_his_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_can_delete_his_articles.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_can_delete_his_articles.yaml")
|
||||
|
||||
def test_author_cannot_delete_other_users_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_cannot_delete_other_users_articles.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_cannot_delete_other_users_articles.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_resident_delete_without_select_perm_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/resident_delete_without_select_perm_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/resident_delete_without_select_perm_fail.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/graphql_mutation/delete/permissions"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/graphql_mutation/delete/permissions"
|
||||
|
@ -1,277 +1,255 @@
|
||||
import pytest
|
||||
import yaml
|
||||
from validate import check_query_f
|
||||
from super_classes import DefaultTestSelectQueries
|
||||
|
||||
class TestGraphQLQueryBasic:
|
||||
|
||||
class TestGraphQLQueryBasic(DefaultTestSelectQueries):
|
||||
|
||||
def test_select_query_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_author.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author.yaml')
|
||||
|
||||
def test_select_various_postgres_types(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_test_types.yaml')
|
||||
|
||||
def test_select_query_author_quoted_col(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author_col_quoted.yaml')
|
||||
|
||||
def test_select_query_author_pk(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_author_by_pkey.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author_by_pkey.yaml')
|
||||
|
||||
def test_select_query_where(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_author_where.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author_where.yaml')
|
||||
|
||||
def test_nested_select_query_article_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/nested_select_query_article_author.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_query_article_author.yaml')
|
||||
|
||||
def test_nested_select_query_deep(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/nested_select_query_deep.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_query_deep.yaml')
|
||||
|
||||
def test_nested_select_query_where(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/nested_select_where_query_author_article.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_where_query_author_article.yaml')
|
||||
|
||||
def test_nested_select_query_where_on_relationship(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_query_article_author_where_on_relationship.yaml')
|
||||
|
||||
def test_select_query_user(self, hge_ctx):
|
||||
check_query_f(hge_ctx, "queries/graphql_query/basic/select_query_user.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/select_query_user.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/basic'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
def test_select_query_non_tracked_table(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/select_query_non_tracked_table_err.yaml")
|
||||
|
||||
class TestGraphQLQueryAgg:
|
||||
def test_select_query_col_not_present_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/select_query_author_col_not_present_err.yaml")
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/basic'
|
||||
|
||||
|
||||
class TestGraphQLQueryAgg(DefaultTestSelectQueries):
|
||||
|
||||
def test_article_agg_count_sum_avg_max_min_with_aliases(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/article_agg_count_sum_avg_max_min_with_aliases.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/article_agg_count_sum_avg_max_min_with_aliases.yaml')
|
||||
|
||||
def test_article_agg_where(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/article_agg_where.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/article_agg_where.yaml')
|
||||
|
||||
def test_author_agg_with_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/author_agg_with_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/author_agg_with_articles.yaml')
|
||||
|
||||
def test_author_agg_with_articles_where(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/author_agg_with_articles_where.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/author_agg_with_articles_where.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/aggregations'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/aggregations'
|
||||
|
||||
class TestGraphQLQueryAggPerm:
|
||||
|
||||
class TestGraphQLQueryAggPerm(DefaultTestSelectQueries):
|
||||
|
||||
def test_author_agg_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/author_agg_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/author_agg_articles.yaml')
|
||||
|
||||
def test_article_agg_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/article_agg_fail.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/article_agg_fail.yaml')
|
||||
|
||||
def test_author_articles_agg_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/author_articles_agg_fail.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/author_articles_agg_fail.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/agg_perm'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/agg_perm'
|
||||
|
||||
class TestGraphQLQueryLimits:
|
||||
|
||||
class TestGraphQLQueryLimits(DefaultTestSelectQueries):
|
||||
|
||||
def test_limit_1(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_limit_1.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_limit_1.yaml')
|
||||
|
||||
def test_limit_2(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_limit_2.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_limit_2.yaml')
|
||||
|
||||
def test_err_str_limit_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_string_limit_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_string_limit_error.yaml')
|
||||
|
||||
def test_err_neg_limit_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_neg_limit_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_neg_limit_error.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/limits'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/limits'
|
||||
|
||||
class TestGraphQLQueryOffsets:
|
||||
|
||||
class TestGraphQLQueryOffsets(DefaultTestSelectQueries):
|
||||
|
||||
def test_offset_1_limit_2(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_offset_1_limit_2.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_offset_1_limit_2.yaml')
|
||||
|
||||
def test_offset_2_limit_1(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_offset_2_limit_1.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_offset_2_limit_1.yaml')
|
||||
|
||||
def test_int_as_string_offset(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_string_offset.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_string_offset.yaml')
|
||||
|
||||
def test_err_neg_offset_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_neg_offset_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_neg_offset_error.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/offset'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/offset'
|
||||
|
||||
|
||||
class TestGraphQLQueryBoolExpBasic:
|
||||
class TestGraphQLQueryBoolExpBasic(DefaultTestSelectQueries):
|
||||
|
||||
def test_author_article_where_not_equal(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_neq.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_neq.yaml')
|
||||
|
||||
def test_author_article_operator_ne_not_found_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_operator_ne_not_found_err.yaml')
|
||||
|
||||
def test_author_article_where_greater_than(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_gt.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_gt.yaml')
|
||||
|
||||
def test_author_article_where_greater_than_or_equal(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_gte.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_gte.yaml')
|
||||
|
||||
def test_author_article_where_less_than(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_lt.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_lt.yaml')
|
||||
|
||||
def test_author_article_where_less_than_or_equal(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_lte.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_lte.yaml')
|
||||
|
||||
def test_author_article_where_in(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_in.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_in.yaml')
|
||||
|
||||
def test_author_article_where_nin(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_nin.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_nin.yaml')
|
||||
|
||||
def test_order_delivered_at_is_null(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_order_delivered_at_is_null.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_order_delivered_at_is_null.yaml')
|
||||
|
||||
def test_order_delivered_at_is_not_null(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_order_delivered_at_is_not_null.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_order_delivered_at_is_not_null.yaml')
|
||||
|
||||
def test_author_article_where_not_less_than(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_not_lt.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_not_lt.yaml')
|
||||
|
||||
def test_article_author_is_published_and_registered(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_author_is_published_and_registered.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_author_is_published_and_registered.yaml')
|
||||
|
||||
def test_article_author_not_published_nor_registered(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_author_not_published_or_not_registered.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_author_not_published_or_not_registered.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/boolexp/basic'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
def test_article_author_unexpected_operator_in_where_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_unexpected_operator_in_where_err.yaml')
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/boolexp/basic'
|
||||
|
||||
|
||||
class TestGraphqlQueryPermissions:
|
||||
class TestGraphqlQueryPermissions(DefaultTestSelectQueries):
|
||||
|
||||
def test_user_select_unpublished_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/user_select_query_unpublished_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/user_select_query_unpublished_articles.yaml')
|
||||
|
||||
def test_user_only_other_users_published_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/user_can_query_other_users_published_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/user_can_query_other_users_published_articles.yaml')
|
||||
|
||||
def test_anonymous_only_published_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/anonymous_can_only_get_published_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/anonymous_can_only_get_published_articles.yaml')
|
||||
|
||||
def test_user_cannot_access_remarks_col(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/user_cannot_access_remarks_col.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/user_cannot_access_remarks_col.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/permissions'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/permissions'
|
||||
|
||||
|
||||
class TestGraphQLQueryBoolExpSearch:
|
||||
class TestGraphQLQueryBoolExpSearch(DefaultTestSelectQueries):
|
||||
|
||||
def test_city_where_like(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_like.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_like.yaml')
|
||||
|
||||
def test_city_where_not_like(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_nlike.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_nlike.yaml')
|
||||
|
||||
def test_city_where_ilike(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_ilike.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_ilike.yaml')
|
||||
|
||||
def test_city_where_not_ilike(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_nilike.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_nilike.yaml')
|
||||
|
||||
def test_city_where_similar(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_similar.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_similar.yaml')
|
||||
|
||||
def test_city_where_not_similar(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_not_similar.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_not_similar.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/boolexp/search'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/boolexp/search'
|
||||
|
||||
class TestGraphQLQueryBoolExpJsonB:
|
||||
|
||||
class TestGraphQLQueryBoolExpJsonB(DefaultTestSelectQueries):
|
||||
|
||||
def test_jsonb_contains_article_latest(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_author_jsonb_contains_latest.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_author_jsonb_contains_latest.yaml')
|
||||
|
||||
def test_jsonb_contains_article_beststeller(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_jsonb_contains_bestseller.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_jsonb_contains_bestseller.yaml')
|
||||
|
||||
def test_jsonb_contained_in_latest(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_author_jsonb_contained_in_latest.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_author_jsonb_contained_in_latest.yaml')
|
||||
|
||||
def test_jsonb_contained_in_bestseller_latest(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_author_jsonb_contained_in_bestseller_latest.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_author_jsonb_contained_in_bestseller_latest.yaml')
|
||||
|
||||
def test_jsonb_has_key_sim_type(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_product_jsonb_has_key_sim_type.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_product_jsonb_has_key_sim_type.yaml')
|
||||
|
||||
def test_jsonb_has_keys_any_os_operating_system(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_product_jsonb_has_keys_any_os_operating_system.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_product_jsonb_has_keys_any_os_operating_system.yaml')
|
||||
|
||||
def test_jsonb_has_keys_all_touchscreen_ram(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_product_jsonb_has_keys_all_ram_touchscreen.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_product_jsonb_has_keys_all_ram_touchscreen.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/boolexp/jsonb'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/boolexp/jsonb'
|
||||
|
||||
class TestGraphQLQueryOrderBy:
|
||||
|
||||
class TestGraphQLQueryOrderBy(DefaultTestSelectQueries):
|
||||
def test_articles_order_by_without_id(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/articles_order_by_without_id.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/articles_order_by_without_id.yaml')
|
||||
|
||||
def test_articles_order_by_rel_author_id(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/articles_order_by_rel_author_id.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/articles_order_by_rel_author_id.yaml')
|
||||
|
||||
def test_articles_order_by_rel_author_rel_contact_phone(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/articles_order_by_rel_author_rel_contact_phone.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/articles_order_by_rel_author_rel_contact_phone.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/order_by'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/graphql_query/order_by'
|
||||
|
97
server/tests-py/test_jwt.py
Normal file
97
server/tests-py/test_jwt.py
Normal file
@ -0,0 +1,97 @@
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
import jwt
|
||||
from validate import check_query
|
||||
|
||||
if not pytest.config.getoption("--hge-jwt-key-file"):
|
||||
pytest.skip("--hge-jwt-key-file is missing, skipping JWT basic tests", allow_module_level=True)
|
||||
|
||||
|
||||
class TestJWTBasic:
|
||||
|
||||
def test_jwt_invalid_role_in_request_header(self, hge_ctx):
|
||||
self.claims['https://hasura.io/jwt/claims'] = {
|
||||
"x-hasura-user-id": "1",
|
||||
"x-hasura-allowed-roles": ["contractor", "editor"],
|
||||
"x-hasura-default-role": "contractor"
|
||||
}
|
||||
token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512' ).decode('UTF-8')
|
||||
self.conf['headers']['Authorization'] = 'Bearer ' + token
|
||||
self.conf['response'] = {
|
||||
'errors': [{
|
||||
'path': '$',
|
||||
'code': 'access-denied',
|
||||
'error': 'Your current role is not in allowed roles'
|
||||
}]
|
||||
}
|
||||
self.conf['status'] = 400
|
||||
check_query(hge_ctx, self.conf, add_auth=False)
|
||||
|
||||
def test_jwt_no_allowed_roles_in_claim(self, hge_ctx):
|
||||
self.claims['https://hasura.io/jwt/claims'] = {
|
||||
"x-hasura-user-id": "1",
|
||||
"x-hasura-default-role": "user"
|
||||
}
|
||||
token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512' ).decode('UTF-8')
|
||||
self.conf['headers']['Authorization'] = 'Bearer ' + token
|
||||
self.conf['response'] = {
|
||||
'errors': [{
|
||||
'path': '$',
|
||||
'code': 'jwt-missing-role-claims',
|
||||
'error': 'JWT claim does not contain x-hasura-allowed-roles'
|
||||
}]
|
||||
}
|
||||
self.conf['status'] = 400
|
||||
check_query(hge_ctx, self.conf, add_auth=False)
|
||||
|
||||
def test_jwt_invalid_allowed_roles_in_claim(self, hge_ctx):
|
||||
self.claims['https://hasura.io/jwt/claims'] = {
|
||||
"x-hasura-user-id": "1",
|
||||
"x-hasura-allowed-roles": "user",
|
||||
"x-hasura-default-role": "user"
|
||||
}
|
||||
token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512' ).decode('UTF-8')
|
||||
self.conf['headers']['Authorization'] = 'Bearer ' + token
|
||||
self.conf['response'] = {
|
||||
'errors': [{
|
||||
'path': '$',
|
||||
'code': 'jwt-invalid-claims',
|
||||
'error': 'invalid x-hasura-allowed-roles; should be a list of roles'
|
||||
}]
|
||||
}
|
||||
self.conf['status'] = 400
|
||||
check_query(hge_ctx, self.conf, add_auth=False)
|
||||
|
||||
def test_jwt_no_default_role(self, hge_ctx):
|
||||
self.claims['https://hasura.io/jwt/claims'] = {
|
||||
"x-hasura-user-id": "1",
|
||||
"x-hasura-allowed-roles": ["user"],
|
||||
}
|
||||
token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512' ).decode('UTF-8')
|
||||
self.conf['headers']['Authorization'] = 'Bearer ' + token
|
||||
self.conf['response'] = {
|
||||
'errors': [{
|
||||
'path': '$',
|
||||
'code': 'jwt-missing-role-claims',
|
||||
'error': 'JWT claim does not contain x-hasura-default-role'
|
||||
}]
|
||||
}
|
||||
self.conf['status'] = 400
|
||||
check_query(hge_ctx, self.conf, add_auth=False)
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/graphql_query/permissions'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
with open(self.dir + '/user_select_query_unpublished_articles.yaml') as c:
|
||||
self.conf = yaml.safe_load(c)
|
||||
self.claims = {
|
||||
"sub": "1234567890",
|
||||
"name": "John Doe",
|
||||
"iat": 1516239022
|
||||
}
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
@ -9,6 +9,8 @@ import yaml
|
||||
Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_connection_init
|
||||
'''
|
||||
def test_init_without_payload(hge_ctx):
|
||||
if hge_ctx.hge_key is not None:
|
||||
pytest.skip("Payload is needed when access key is set")
|
||||
obj = {
|
||||
'type': 'connection_init'
|
||||
}
|
||||
@ -20,9 +22,16 @@ def test_init_without_payload(hge_ctx):
|
||||
Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_connection_init
|
||||
'''
|
||||
def test_init(hge_ctx):
|
||||
payload = {}
|
||||
if hge_ctx.hge_key is not None:
|
||||
payload = {
|
||||
'headers' : {
|
||||
'X-Hasura-Access-Key': hge_ctx.hge_key
|
||||
}
|
||||
}
|
||||
obj = {
|
||||
'type': 'connection_init',
|
||||
'payload': {},
|
||||
'payload': payload,
|
||||
}
|
||||
hge_ctx.ws.send(json.dumps(obj))
|
||||
ev = hge_ctx.get_ws_event(3)
|
||||
@ -146,8 +155,16 @@ class TestSubscriptionLiveQueries(object):
|
||||
'''
|
||||
Create connection using connection_init
|
||||
'''
|
||||
payload = {}
|
||||
if hge_ctx.hge_key is not None:
|
||||
payload = {
|
||||
'headers' : {
|
||||
'X-Hasura-Access-Key': hge_ctx.hge_key
|
||||
}
|
||||
}
|
||||
obj = {
|
||||
'type': 'connection_init'
|
||||
'type': 'connection_init',
|
||||
'payload' : payload
|
||||
}
|
||||
hge_ctx.ws.send(json.dumps(obj))
|
||||
ev = hge_ctx.get_ws_event(3)
|
||||
|
@ -1,452 +1,459 @@
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from validate import check_query_f
|
||||
from super_classes import DefaultTestSelectQueries, DefaultTestQueries
|
||||
|
||||
class TestV1SelectBasic:
|
||||
class TestV1General(DefaultTestQueries):
|
||||
|
||||
def test_query_string_input_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/query_string_input_err.yaml')
|
||||
|
||||
def test_query_unknown_type_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/query_unknown_type_err.yaml')
|
||||
|
||||
def test_query_args_as_string_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/query_args_as_string_err.yaml')
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/basic"
|
||||
|
||||
class TestV1SelectBasic(DefaultTestSelectQueries):
|
||||
|
||||
def test_select_query_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article.yaml')
|
||||
|
||||
def test_nested_select_article_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/nested_select_query_article_author.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_query_article_author.yaml')
|
||||
|
||||
def test_nested_select_article_author_alias_for_relationship(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_query_article_author_rel_alias.yaml')
|
||||
|
||||
def test_select_author_where(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_author_where.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author_where.yaml')
|
||||
|
||||
def test_select_table_not_present(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_table_not_present_err.yaml')
|
||||
|
||||
def test_select_col_not_present(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_col_not_present_err.yaml')
|
||||
def test_nested_select_query_where(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/nested_select_where_query_author_article.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_col_not_present_err.yaml')
|
||||
|
||||
def test_select_nested_where_query(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_where_query_author_article.yaml')
|
||||
|
||||
def test_select_query_user(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_user.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_user.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/select/basic"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/select/basic"
|
||||
|
||||
|
||||
class TestV1SelectLimits:
|
||||
class TestV1SelectLimits(DefaultTestSelectQueries):
|
||||
|
||||
def test_limit_1(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_limit_1.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_limit_1.yaml')
|
||||
|
||||
def test_limit_2(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_limit_2.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_limit_2.yaml')
|
||||
|
||||
def test_err_str_limit_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_string_limit_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_string_limit_error.yaml')
|
||||
|
||||
def test_err_neg_limit_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_neg_limit_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_neg_limit_error.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/v1/select/limits'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/v1/select/limits'
|
||||
|
||||
|
||||
class TestV1SelectOffset:
|
||||
class TestV1SelectOffset(DefaultTestSelectQueries):
|
||||
|
||||
def test_offset_1_limit_2(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_offset_1_limit_2.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_offset_1_limit_2.yaml')
|
||||
|
||||
def test_offset_2_limit_1(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_offset_2_limit_1.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_offset_2_limit_1.yaml')
|
||||
|
||||
def test_int_as_string_offset_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_int_as_string_offset_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_int_as_string_offset_error.yaml')
|
||||
|
||||
def test_err_neg_offset_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_article_neg_offset_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_article_neg_offset_error.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/v1/select/offset'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/v1/select/offset'
|
||||
|
||||
|
||||
class TestV1SelectBoolExpBasic:
|
||||
class TestV1SelectBoolExpBasic(DefaultTestSelectQueries):
|
||||
|
||||
def test_author_article_where_not_equal(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_neq.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_neq.yaml')
|
||||
|
||||
def test_author_article_where_greater_than(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_gt.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_gt.yaml')
|
||||
|
||||
def test_author_article_where_greater_than_or_equal(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_gte.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_gte.yaml')
|
||||
|
||||
def test_author_article_where_less_than(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_lt.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_lt.yaml')
|
||||
|
||||
def test_author_article_where_less_than_or_equal(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_lte.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_lte.yaml')
|
||||
|
||||
def test_author_article_where_in(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_in.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_in.yaml')
|
||||
|
||||
def test_author_article_where_nin(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_nin.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_nin.yaml')
|
||||
|
||||
def test_order_delivered_at_is_null(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_order_delivered_at_is_null.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_order_delivered_at_is_null.yaml')
|
||||
|
||||
def test_order_delivered_at_is_not_null(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_query_order_delivered_at_is_not_null.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_order_delivered_at_is_not_null.yaml')
|
||||
|
||||
def test_author_article_where_not_less_than(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_author_article_where_not_lt.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_author_article_where_not_lt.yaml')
|
||||
|
||||
def test_article_author_is_published_and_registered(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_author_is_published_and_registered.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_author_is_published_and_registered.yaml')
|
||||
|
||||
def test_article_author_not_published_nor_registered(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_article_author_not_published_or_not_registered.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_author_not_published_or_not_registered.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/v1/select/boolexp/basic'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/v1/select/boolexp/basic'
|
||||
|
||||
|
||||
class TestV1SelectBoolExpSearch:
|
||||
class TestV1SelectBoolExpSearch(DefaultTestSelectQueries):
|
||||
|
||||
def test_city_where_like(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_like.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_like.yaml')
|
||||
|
||||
def test_city_where_not_like(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_nlike.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_nlike.yaml')
|
||||
|
||||
def test_city_where_ilike(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_ilike.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_ilike.yaml')
|
||||
|
||||
def test_city_where_not_ilike(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_nilike.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_nilike.yaml')
|
||||
|
||||
def test_city_where_similar(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_similar.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_similar.yaml')
|
||||
|
||||
def test_city_where_not_similar(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/select_city_where_not_similar.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/select_city_where_not_similar.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/v1/select/boolexp/search'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/v1/select/boolexp/search'
|
||||
|
||||
|
||||
class TestV1SelectPermissions:
|
||||
class TestV1SelectPermissions(DefaultTestSelectQueries):
|
||||
|
||||
def test_user_select_unpublished_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/user_select_query_unpublished_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/user_select_query_unpublished_articles.yaml')
|
||||
|
||||
def test_user_only_other_users_published_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/user_can_query_other_users_published_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/user_can_query_other_users_published_articles.yaml')
|
||||
|
||||
def test_anonymous_only_published_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/anonymous_can_only_get_published_articles.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/anonymous_can_only_get_published_articles.yaml')
|
||||
|
||||
def test_user_cannot_access_remarks_col(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/user_cannot_access_remarks_col.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/user_cannot_access_remarks_col.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = 'queries/v1/select/permissions'
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/v1/select/permissions'
|
||||
|
||||
|
||||
class TestV1InsertBasic:
|
||||
class TestV1InsertBasic(DefaultTestQueries):
|
||||
|
||||
def test_insert_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/insert_author.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/insert_author.yaml')
|
||||
|
||||
def test_insert_author_col_not_present_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/insert_author_col_not_present_err.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/insert_author_col_not_present_err.yaml')
|
||||
|
||||
def test_insert_null_col_value(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/order_col_shipped_null.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/order_col_shipped_null.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/insert/basic"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/insert/basic"
|
||||
|
||||
|
||||
class TestV1InsertOnConflict:
|
||||
|
||||
class TestV1InsertOnConflict(DefaultTestQueries):
|
||||
|
||||
def test_author_on_conflict_update(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/upsert_author.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/upsert_author.yaml')
|
||||
|
||||
def test_on_conflict_no_action_specified(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_no_action_specified.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_no_action_specified.yaml")
|
||||
|
||||
def test_on_conflict_ignore(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_ignore_constraint.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_ignore_constraint.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_err_missing_article_constraint(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_error_missing_article_constraint.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_error_missing_article_constraint.yaml")
|
||||
|
||||
def test_err_unexpected_action(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_unexpected_on_conflict_action.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_unexpected_on_conflict_action.yaml")
|
||||
|
||||
def test_err_unexpected_constraint(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_unexpected_on_conflict_constraint_error.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_unexpected_on_conflict_constraint_error.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/insert/onconflict"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/insert/onconflict"
|
||||
|
||||
|
||||
class TestV1InsertPermissions(object):
|
||||
class TestV1InsertPermissions(DefaultTestQueries):
|
||||
|
||||
def test_user_role_on_conflict_update(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/article_on_conflict_user_role.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/article_on_conflict_user_role.yaml")
|
||||
|
||||
@pytest.mark.xfail(reason="Refer https://github.com/hasura/graphql-engine/issues/563")
|
||||
def test_user_role_on_conflict_ignore(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_on_conflict_ignore_user_role.yaml")
|
||||
|
||||
check_query_f(hge_ctx, self.dir() + "/author_on_conflict_ignore_user_role.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_role_has_no_permissions_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/address_permission_error.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/address_permission_error.yaml")
|
||||
|
||||
def test_author_user_role_insert_check_perm_success(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_user_role_insert_check_perm_success.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_user_role_insert_check_perm_success.yaml")
|
||||
|
||||
def test_user_role_insert_check_is_registered_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_user_role_insert_check_is_registered_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_user_role_insert_check_is_registered_fail.yaml")
|
||||
|
||||
def test_user_role_insert_check_user_id_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_user_role_insert_check_user_id_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_user_role_insert_check_user_id_fail.yaml")
|
||||
|
||||
def test_student_role_insert_check_bio_success(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_student_role_insert_check_bio_success.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_student_role_insert_check_bio_success.yaml")
|
||||
|
||||
def test_student_role_insert_check_bio_fail(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_student_role_insert_check_bio_fail.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_student_role_insert_check_bio_fail.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/insert/permissions"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/insert/permissions"
|
||||
|
||||
|
||||
class TestV1UpdateBasic:
|
||||
class TestV1UpdateBasic(DefaultTestQueries):
|
||||
|
||||
def test_set_author_name(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/author_set_name.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/author_set_name.yaml")
|
||||
|
||||
def test_set_person_details(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_set_details.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_set_details.yaml")
|
||||
|
||||
def test_person_id_inc(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_inc.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_inc.yaml")
|
||||
|
||||
def test_product_mul_price(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/product_mul_price.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/product_mul_price.yaml")
|
||||
|
||||
def test_product_set_default_price(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/product_set_default_price.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/product_set_default_price.yaml")
|
||||
|
||||
def test_no_operator_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_error_no_operator.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_error_no_operator.yaml")
|
||||
|
||||
def test_no_where_clause_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/person_error_no_where_clause.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/person_error_no_where_clause.yaml")
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/update/basic"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/update/basic"
|
||||
|
||||
|
||||
class TestV1UpdatePermissions:
|
||||
class TestV1UpdatePermissions(DefaultTestQueries):
|
||||
|
||||
def test_user_can_update_unpublished_article(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_can_update_unpublished_article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_can_update_unpublished_article.yaml")
|
||||
|
||||
def test_user_cannot_update_published_version_col(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_cannot_update_published_article_version.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_cannot_update_published_article_version.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_user_cannot_update_another_users_article(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_cannot_update_another_users_article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_cannot_update_another_users_article.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_user_cannot_update_id_col(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + "/user_cannot_update_id_col_article.yaml")
|
||||
check_query_f(hge_ctx, self.dir() + "/user_cannot_update_id_col_article.yaml")
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/update/permissions"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/update/permissions"
|
||||
|
||||
|
||||
class TestV1Delete:
|
||||
|
||||
class TestV1CountBasic(DefaultTestSelectQueries):
|
||||
|
||||
def test_count_authors(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_authors.yaml")
|
||||
|
||||
def test_count_published_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_published_articles.yaml")
|
||||
|
||||
def test_count_unpublished_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_unpublished_articles.yaml")
|
||||
|
||||
def test_count_distinct_authors_with_published_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_distinct_authors_with_published_articles.yaml")
|
||||
|
||||
def test_count_articles_registered_authors(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_articles_with_registered_authors.yaml")
|
||||
|
||||
def test_count_articles_non_registered_authors(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_articles_with_non_registered_authors.yaml")
|
||||
|
||||
def test_count_distinct_col_not_present_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_distinct_col_not_present_err.yaml")
|
||||
|
||||
def test_count_distinct_authors_with_unpublished_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_distinct_authors_with_unpublished_articles.yaml")
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/count/basic"
|
||||
|
||||
|
||||
class TestV1CountPermissions(DefaultTestSelectQueries):
|
||||
|
||||
def test_count_user_has_no_select_permission_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_user_has_no_select_perm_error.yaml")
|
||||
|
||||
def test_count_other_users_unpublished_articles(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + "/count_users_unpublished_articles.yaml")
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/count/permissions"
|
||||
|
||||
|
||||
class TestV1Delete(DefaultTestQueries):
|
||||
|
||||
def test_delete_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/delete_article.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/delete_article.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/delete"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/delete"
|
||||
|
||||
class TestMetadata:
|
||||
|
||||
class TestMetadata(DefaultTestQueries):
|
||||
|
||||
def test_reload_metadata(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/reload_metadata.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/reload_metadata.yaml')
|
||||
|
||||
def test_export_metadata(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/export_metadata.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/export_metadata.yaml')
|
||||
|
||||
def test_clear_metadata(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/clear_metadata.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/clear_metadata.yaml')
|
||||
|
||||
def test_dump_internal_state(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/dump_internal_state.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/dump_internal_state.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/metadata"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/metadata"
|
||||
|
||||
|
||||
class TestRunSQL:
|
||||
class TestRunSQL(DefaultTestQueries):
|
||||
|
||||
def test_select_query(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/sql_select_query.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_select_query.yaml')
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_set_timezone(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/sql_set_timezone.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_set_timezone.yaml')
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_sql_timezone__error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/sql_set_timezone_error.yaml')
|
||||
def test_sql_timezone_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_set_timezone_error.yaml')
|
||||
|
||||
def test_sql_query_as_user_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/sql_query_as_user_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_query_as_user_error.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/run_sql"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/run_sql"
|
||||
|
||||
|
||||
class TestRelationships:
|
||||
class TestRelationships(DefaultTestQueries):
|
||||
|
||||
def test_object_relationship_foreign_key(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/object_relationship_foreign_key.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/object_relationship_foreign_key.yaml')
|
||||
|
||||
def test_create_object_relationship_as_not_admin_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/create_object_relationship_as_not_admin_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/create_object_relationship_as_not_admin_error.yaml')
|
||||
|
||||
def test_object_relationship_col_not_foreign_key_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/object_relationship_col_not_foreign_key_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/object_relationship_col_not_foreign_key_error.yaml')
|
||||
|
||||
def test_object_relationship_foreign_key_non_public_schema(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/object_relationship_non_public_schema_foreign_key.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/object_relationship_non_public_schema_foreign_key.yaml')
|
||||
|
||||
def test_object_relationship_manual(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/object_relationship_manual.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/object_relationship_manual.yaml')
|
||||
|
||||
def test_array_relationship_foreign_key(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/array_relationship_foreign_key.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/array_relationship_foreign_key.yaml')
|
||||
|
||||
def test_create_array_relationship_as_not_admin_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/create_array_relationship_as_not_admin_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/create_array_relationship_as_not_admin_error.yaml')
|
||||
|
||||
def test_array_relationship_col_not_foreign_key_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/array_relationship_col_not_foreign_key_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/array_relationship_col_not_foreign_key_error.yaml')
|
||||
|
||||
def test_array_relationship_foreign_key_non_public_schema(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/array_relationship_non_public_schema_foreign_key.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/array_relationship_non_public_schema_foreign_key.yaml')
|
||||
|
||||
def test_array_relationship_manual(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/array_relationship_manual.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/array_relationship_manual.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/relationships"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/relationships"
|
||||
|
||||
|
||||
class TestTrackTables:
|
||||
class TestTrackTables(DefaultTestQueries):
|
||||
|
||||
def test_track_untrack_table(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/track_untrack_table.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/track_untrack_table.yaml')
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_track_untrack_table_non_public_schema(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/track_untrack_table_non_public_schema.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/track_untrack_table_non_public_schema.yaml')
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_track_untrack_table_as_not_admin_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir + '/track_untrack_table_as_not_admin_error.yaml')
|
||||
check_query_f(hge_ctx, self.dir() + '/track_untrack_table_as_not_admin_error.yaml')
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, hge_ctx):
|
||||
self.dir = "queries/v1/track_table"
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
|
||||
assert st_code == 200, resp
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/track_table"
|
||||
|
||||
|
||||
class TestCreatePermission(DefaultTestQueries):
|
||||
|
||||
def test_create_permission_admin_role_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/create_article_permission_role_admin_error.yaml')
|
||||
|
||||
def test_create_permission_user_role_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/create_article_permission_role_user.yaml')
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/v1/permissions"
|
||||
|
18
server/tests-py/test_webhook_insecure.py
Normal file
18
server/tests-py/test_webhook_insecure.py
Normal file
@ -0,0 +1,18 @@
|
||||
import pytest
|
||||
from validate import check_query_f
|
||||
from super_classes import DefaultTestSelectQueries
|
||||
|
||||
if not pytest.config.getoption("--test-webhook-insecure"):
|
||||
pytest.skip("--test-webhook-https-insecure flag is missing, skipping tests", allow_module_level=True)
|
||||
|
||||
class TestHTTPSWebhookInsecure(DefaultTestSelectQueries):
|
||||
|
||||
def test_user_select_unpublished_articles_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/user_select_query_unpublished_articles_fail.yaml')
|
||||
|
||||
def test_user_only_other_users_published_articles_err(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/user_query_other_users_published_articles_fail.yaml')
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'webhook/insecure'
|
@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import yaml
|
||||
import json
|
||||
import os
|
||||
import base64
|
||||
import jsondiff
|
||||
import jwt
|
||||
|
||||
def check_keys(keys, obj):
|
||||
for k in keys:
|
||||
@ -40,25 +45,102 @@ def check_event(hge_ctx, trig_name, table, operation, exp_ev_data, headers, webh
|
||||
assert ev['op'] == operation, ev
|
||||
assert ev['data'] == exp_ev_data, ev
|
||||
|
||||
def check_query(hge_ctx, conf):
|
||||
|
||||
def test_forbidden_when_access_key_reqd(hge_ctx, conf):
|
||||
headers={}
|
||||
if 'headers' in conf:
|
||||
headers = conf['headers']
|
||||
|
||||
#Test without access key
|
||||
code, resp = hge_ctx.anyq( conf['url'], conf['query'], headers)
|
||||
assert code == 401, "\n" + yaml.dump( {
|
||||
"expected" : "Should be access denied as access key is not provided",
|
||||
"actual" : {
|
||||
"code" : code,
|
||||
"response" : resp
|
||||
}
|
||||
} )
|
||||
|
||||
#Test with random access key
|
||||
headers['X-Hasura-Access-Key'] = base64.b64encode(os.urandom(30))
|
||||
code, resp = hge_ctx.anyq( conf['url'], conf['query'], headers)
|
||||
assert code == 401, "\n" + yaml.dump( {
|
||||
"expected" : "Should be access denied as an incorrect access key is provided",
|
||||
"actual" : {
|
||||
"code" : code,
|
||||
"response" : resp
|
||||
}
|
||||
} )
|
||||
|
||||
def test_forbidden_webhook(hge_ctx, conf):
|
||||
|
||||
h = { 'Authorization' : 'Bearer ' + base64.b64encode(base64.b64encode(os.urandom(30))).decode('utf-8') }
|
||||
code, resp = hge_ctx.anyq( conf['url'], conf['query'], h )
|
||||
assert code == 401, "\n" + yaml.dump( {
|
||||
"expected" : "Should be access denied as it is denied from webhook",
|
||||
"actual" : {
|
||||
"code" : code,
|
||||
"response" : resp
|
||||
}
|
||||
} )
|
||||
|
||||
def check_query(hge_ctx, conf, add_auth=True):
|
||||
headers={}
|
||||
if 'headers' in conf:
|
||||
headers = conf['headers']
|
||||
|
||||
if add_auth:
|
||||
if hge_ctx.hge_jwt_key is not None and len(headers) > 0 and 'X-Hasura-Role' in headers:
|
||||
hClaims=dict()
|
||||
hClaims['X-Hasura-Allowed-Roles']=[headers['X-Hasura-Role']]
|
||||
hClaims['X-Hasura-Default-Role']=headers['X-Hasura-Role']
|
||||
for key in headers:
|
||||
if key != 'X-Hasura-Role':
|
||||
hClaims[key]=headers[key]
|
||||
claim={
|
||||
"sub": "foo",
|
||||
"name": "bar",
|
||||
"https://hasura.io/jwt/claims": hClaims
|
||||
}
|
||||
headers['Authorization'] = 'Bearer ' + jwt.encode(claim, hge_ctx.hge_jwt_key, algorithm='RS512').decode('UTF-8')
|
||||
|
||||
if hge_ctx.hge_webhook is not None and len(headers) > 0:
|
||||
if not hge_ctx.webhook_insecure:
|
||||
test_forbidden_webhook(hge_ctx, conf)
|
||||
headers['X-Hasura-Auth-Mode'] = 'webhook'
|
||||
headers_new = dict()
|
||||
headers_new['Authorization'] = 'Bearer ' + base64.b64encode(json.dumps(headers).encode('utf-8')).decode('utf-8')
|
||||
headers = headers_new
|
||||
|
||||
elif (hge_ctx.hge_webhook is not None or hge_ctx.hge_jwt_key is not None) and hge_ctx.hge_key is not None and len(headers) == 0:
|
||||
headers['X-Hasura-Access-Key'] = hge_ctx.hge_key
|
||||
|
||||
elif hge_ctx.hge_key is not None and hge_ctx.hge_webhook is None and hge_ctx.hge_jwt_key is None:
|
||||
test_forbidden_when_access_key_reqd(hge_ctx, conf)
|
||||
headers['X-Hasura-Access-Key'] = hge_ctx.hge_key
|
||||
|
||||
code, resp = hge_ctx.anyq( conf['url'], conf['query'], headers)
|
||||
print (headers)
|
||||
assert code == conf['status'], resp
|
||||
if 'response' in conf:
|
||||
print ('response\n', yaml.dump(resp))
|
||||
print ('expected\n', yaml.dump(conf['response']))
|
||||
assert json_ordered(resp) == json_ordered(conf['response'])
|
||||
assert json_ordered(resp) == json_ordered(conf['response']) , yaml.dump( {
|
||||
'response' : resp,
|
||||
'expected' : conf['response'],
|
||||
'diff': jsondiff.diff(conf['response'], resp)
|
||||
} )
|
||||
return code, resp
|
||||
|
||||
def check_query_f(hge_ctx, f):
|
||||
def check_query_f(hge_ctx, f, add_auth=True):
|
||||
hge_ctx.may_skip_test_teardown = False
|
||||
with open(f) as c:
|
||||
conf = yaml.load(c)
|
||||
conf = yaml.safe_load(c)
|
||||
if isinstance(conf, list):
|
||||
for sconf in conf:
|
||||
check_query( hge_ctx, sconf)
|
||||
else:
|
||||
check_query( hge_ctx, conf )
|
||||
if conf['status'] != 200:
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
check_query( hge_ctx, conf, add_auth )
|
||||
|
||||
def json_ordered(obj):
|
||||
if isinstance(obj, dict):
|
||||
|
64
server/tests-py/webhook.py
Normal file
64
server/tests-py/webhook.py
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Webhook for GraphQL engine
|
||||
For successful authentication
|
||||
1) Add header X-Hasura-Auth-From: webhook to the list of headers
|
||||
2) Base64 encode the required headers (including X-Hasura-Auth-From)
|
||||
3) Pass it as the bearer token with the Authorization header
|
||||
"""
|
||||
import base64
|
||||
import json
|
||||
import ssl
|
||||
import http.server
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
class S(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
def do_GET(self):
|
||||
if 'Authorization' in self.headers:
|
||||
auth = self.headers['Authorization']
|
||||
h = dict()
|
||||
if auth.startswith("Bearer "):
|
||||
try:
|
||||
h = json.loads(base64.b64decode(auth[7:]).decode("utf-8"))
|
||||
if h.get('X-Hasura-Auth-Mode') == 'webhook':
|
||||
print (h)
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(h).encode('utf-8'))
|
||||
else:
|
||||
print ('forbidden')
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
self.wfile.write('{}')
|
||||
except Exception as e:
|
||||
print ('forbidden')
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
print("type error: " + str(e))
|
||||
print(traceback.format_exc())
|
||||
else:
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
print ('forbidden')
|
||||
|
||||
def run(keyfile, certfile, server_class=http.server.HTTPServer, handler_class=S, port=9090):
|
||||
server_address = ('', port)
|
||||
httpd = server_class(server_address, handler_class)
|
||||
httpd.socket = ssl.wrap_socket (
|
||||
httpd.socket,
|
||||
certfile=certfile,
|
||||
keyfile=keyfile,
|
||||
server_side=True,
|
||||
ssl_version=ssl.PROTOCOL_SSLv23)
|
||||
print('Starting httpd...')
|
||||
httpd.serve_forever()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print("Usage: python webhook.py port keyfile certfile")
|
||||
sys.exit(1)
|
||||
run(keyfile=sys.argv[2],certfile=sys.argv[3], port=int(sys.argv[1]))
|
170
server/tests-py/webhook/insecure/setup.yaml
Normal file
170
server/tests-py/webhook/insecure/setup.yaml
Normal file
@ -0,0 +1,170 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
#Author table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique,
|
||||
is_registered boolean not null default false,
|
||||
remarks_internal text
|
||||
);
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
#Article table
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TABLE article (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
author_id INTEGER NOT NULL REFERENCES author(id),
|
||||
is_published BOOLEAN NOT NULL default FALSE,
|
||||
published_on TIMESTAMP
|
||||
)
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: article
|
||||
|
||||
#Object relationship
|
||||
- type: create_object_relationship
|
||||
args:
|
||||
name: author
|
||||
table: article
|
||||
using:
|
||||
foreign_key_constraint_on: author_id
|
||||
|
||||
#Array relationship
|
||||
- type: create_array_relationship
|
||||
args:
|
||||
table: author
|
||||
name: articles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
table: article
|
||||
column: author_id
|
||||
|
||||
#Article select permission for user
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: article
|
||||
role: user
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
- content
|
||||
- is_published
|
||||
filter:
|
||||
$or:
|
||||
- author_id: X-HASURA-USER-ID
|
||||
- is_published: true
|
||||
|
||||
#Article select permission for anonymous (only published articles)
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: article
|
||||
role: anonymous
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
- content
|
||||
- is_published
|
||||
filter:
|
||||
is_published: true
|
||||
|
||||
#Article insert permission for user
|
||||
- type: create_insert_permission
|
||||
args:
|
||||
table: article
|
||||
role: user
|
||||
permission:
|
||||
check:
|
||||
author_id: X-Hasura-User-Id
|
||||
|
||||
#Author select permission for user
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: author
|
||||
role: user
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- name
|
||||
- is_registered
|
||||
filter:
|
||||
_or:
|
||||
- id: X-HASURA-USER-ID
|
||||
- articles:
|
||||
is_published:
|
||||
_eq: true
|
||||
|
||||
#Author select permission for anonymous users
|
||||
#Only authors with atleast one article will be shown
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: author
|
||||
role: anonymous
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- name
|
||||
filter:
|
||||
articles:
|
||||
is_published:
|
||||
_eq: true
|
||||
|
||||
#Author insert permission for user
|
||||
- type: create_insert_permission
|
||||
args:
|
||||
table: author
|
||||
role: user
|
||||
permission:
|
||||
check:
|
||||
id: X-HASURA-USER-ID
|
||||
allow_upsert: true
|
||||
|
||||
#Insert Author values
|
||||
- type: insert
|
||||
args:
|
||||
table: author
|
||||
objects:
|
||||
- name: Author 1
|
||||
remarks_internal: remark 1
|
||||
- name: Author 2
|
||||
remarks_internal: remark 2
|
||||
- name: Author 3
|
||||
remarks_internal: remark 3
|
||||
|
||||
#Insert Article values
|
||||
- type: insert
|
||||
args:
|
||||
table: article
|
||||
objects:
|
||||
- title: Article 1
|
||||
content: Sample article content 1
|
||||
author_id: 1
|
||||
is_published: false
|
||||
|
||||
- title: Article 2
|
||||
content: Sample article content 2
|
||||
author_id: 1
|
||||
is_published: true
|
||||
|
||||
- title: Article 3
|
||||
content: Sample article content 3
|
||||
author_id: 2
|
||||
is_published: true
|
||||
|
||||
- title: Article 4
|
||||
content: Sample article content 4
|
||||
author_id: 3
|
||||
is_published: false
|
14
server/tests-py/webhook/insecure/teardown.yaml
Normal file
14
server/tests-py/webhook/insecure/teardown.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article
|
||||
cascade: true
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table author
|
||||
cascade: true
|
@ -0,0 +1,26 @@
|
||||
description: User can only get his unpublished articles
|
||||
url: /v1alpha1/graphql
|
||||
status: 500
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
X-Hasura-User-Id: '1'
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
article (
|
||||
where: { _and:
|
||||
[ { is_published : {_eq : true}}
|
||||
{ author : { id : {_neq : 1}}}
|
||||
]
|
||||
}
|
||||
) {
|
||||
id
|
||||
title
|
||||
content
|
||||
is_published
|
||||
author {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
description: User can only get his unpublished articles
|
||||
url: /v1alpha1/graphql
|
||||
status: 500
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
X-Hasura-User-Id: '1'
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
article (
|
||||
where: { is_published : {_eq : false}}
|
||||
) {
|
||||
id
|
||||
title
|
||||
content
|
||||
is_published
|
||||
author {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user