mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
server: add tests ensuring the correct functioning of all endpoints based on user roles
https://github.com/hasura/graphql-engine-mono/pull/1625 Co-authored-by: Sameer Kolhar <6604943+kolharsam@users.noreply.github.com> GitOrigin-RevId: 6b56efc838d2ed1acc44b2847161fde22d6aee17
This commit is contained in:
parent
08847566d8
commit
d88e2bbcce
@ -33,3 +33,4 @@ insecure-webhook-with-admin-secret
|
||||
allowlist-queries
|
||||
jwk-url
|
||||
horizontal-scaling
|
||||
developer-api-tests
|
||||
|
@ -219,6 +219,7 @@ export HASURA_GRAPHQL_STRINGIFY_NUMERIC_TYPES=true
|
||||
export REMOTE_SCHEMAS_WEBHOOK_DOMAIN="http://127.0.0.1:5000"
|
||||
|
||||
export PYTEST_ADDOPTS="-vv"
|
||||
|
||||
HGE_PIDS=""
|
||||
WH_PID=""
|
||||
WHC_PID=""
|
||||
@ -274,6 +275,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
TEST_TYPE="admin-secret"
|
||||
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
start_multiple_hge_servers
|
||||
|
||||
@ -288,6 +290,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
export HASURA_GRAPHQL_UNAUTHORIZED_ROLE="anonymous"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
|
||||
@ -306,7 +309,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
|
||||
init_jwt
|
||||
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key }')"
|
||||
|
||||
start_multiple_hge_servers
|
||||
@ -325,6 +328,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
init_jwt
|
||||
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , claims_format: "stringified_json"}')"
|
||||
|
||||
run_hge_with_args serve
|
||||
@ -343,6 +347,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
init_jwt
|
||||
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , audience: "myapp-1234"}')"
|
||||
|
||||
run_hge_with_args serve
|
||||
@ -363,6 +368,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , audience: ["myapp-1234", "myapp-9876"]}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -381,6 +387,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
init_jwt
|
||||
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , issuer: "https://hasura.com"}')"
|
||||
|
||||
run_hge_with_args serve
|
||||
@ -404,6 +411,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
# hasura claims at one level of nesting
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , claims_namespace_path: "$.hasura_claims"}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -417,6 +425,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
# hasura claims at two levels of nesting with claims_namespace_path containing special character
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , claims_namespace_path: "$.hasura['\''claims%'\'']"}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -430,6 +439,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
# hasura claims at the root of the JWT token
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , claims_namespace_path: "$"}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -450,6 +460,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , claims_map: {"x-hasura-user-id": {"path":"$.['"'"'https://myapp.com/jwt/claims'"'"'].user.id"}, "x-hasura-allowed-roles": {"path":"$.['"'"'https://myapp.com/jwt/claims'"'"'].role.allowed"}, "x-hasura-default-role": {"path":"$.['"'"'https://myapp.com/jwt/claims'"'"'].role.default"}}}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -465,6 +476,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , claims_map: {"x-hasura-user-id": {"path":"$.['"'"'https://myapp.com/jwt/claims'"'"'].user.id", "default":"1"}, "x-hasura-allowed-roles": {"path":"$.['"'"'https://myapp.com/jwt/claims'"'"'].role.allowed", "default":["user","editor"]}, "x-hasura-default-role": {"path":"$.['"'"'https://myapp.com/jwt/claims'"'"'].role.default","default":"user"}}}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -483,6 +495,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
init_jwt
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , allowed_skew: 60}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -503,6 +516,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , claims_map: {"x-hasura-user-id": {"path":"$.['"'"'https://myapp.com/jwt/claims'"'"'].user.id"}, "x-hasura-allowed-roles": ["user","editor"], "x-hasura-default-role": "user","x-hasura-custom-header":"custom-value"}}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -523,6 +537,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
|
||||
export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jwt_public.key)" '{ type: "RS512", key: $key , header: {"type": "Cookie", "name": "hasura_user"}}')"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
|
||||
run_hge_with_args serve
|
||||
wait_for_port 8080
|
||||
@ -539,6 +554,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
echo -e "\n$(time_elapsed): <########## TEST GRAPHQL-ENGINE WITH CORS DOMAINS ########>\n"
|
||||
export HASURA_GRAPHQL_CORS_DOMAIN="http://*.localhost, http://localhost:3000, https://*.foo.bar.com"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
TEST_TYPE="cors-domains"
|
||||
|
||||
run_hge_with_args serve
|
||||
@ -575,6 +591,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
ws-init-cookie-noread)
|
||||
echo "$(time_elapsed): testcase 2: no read cookie, cors disabled"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
TEST_TYPE="ws-init-cookie-noread"
|
||||
export HASURA_GRAPHQL_AUTH_HOOK="http://localhost:9876/auth"
|
||||
export HASURA_GRAPHQL_AUTH_HOOK_MODE="POST"
|
||||
@ -593,6 +610,7 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
ws-init-cookie-read-cors-disabled)
|
||||
echo "$(time_elapsed): testcase 3: read cookie, cors disabled and ws-read-cookie"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
TEST_TYPE="ws-init-cookie-read-cors-disabled"
|
||||
export HASURA_GRAPHQL_AUTH_HOOK="http://localhost:9876/auth"
|
||||
export HASURA_GRAPHQL_AUTH_HOOK_MODE="POST"
|
||||
@ -925,6 +943,22 @@ case "$SERVER_TEST_TO_RUN" in
|
||||
kill_hge_servers
|
||||
# end allowlist queries test
|
||||
;;
|
||||
|
||||
developer-api-tests)
|
||||
echo -e "\n$(time_elapsed): <########## TEST GRAPHQL-ENGINE WITH DEVELOPER API ENABLED ########>\n"
|
||||
TEST_TYPE="developer-api-tests"
|
||||
export HASURA_GRAPHQL_ENABLED_APIS="metadata,graphql,developer,config,pgdump"
|
||||
export HASURA_GRAPHQL_ADMIN_SECRET="HGE$RANDOM$RANDOM"
|
||||
|
||||
run_hge_with_args serve --enabled-apis "$HASURA_GRAPHQL_ENABLED_APIS"
|
||||
wait_for_port 8080
|
||||
|
||||
pytest -n 1 -vv --hge-urls "$HGE_URL" --pg-urls "$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-developer-api-enabled test_dev_endpoints.py
|
||||
|
||||
unset HASURA_GRAPHQL_ENABLED_APIS
|
||||
|
||||
kill_hge_servers
|
||||
;;
|
||||
|
||||
jwk-url)
|
||||
# TODO(swann): ditto, these have to be parallelised
|
||||
|
@ -41,7 +41,6 @@ import Network.Mime (defaultMimeLookup)
|
||||
import System.FilePath (joinPath, takeFileName)
|
||||
import Web.Spock.Core ((<//>))
|
||||
|
||||
import qualified Hasura.Backends.Postgres.SQL.Types as PG
|
||||
import qualified Hasura.GraphQL.Execute as E
|
||||
import qualified Hasura.GraphQL.Execute.LiveQuery.Options as EL
|
||||
import qualified Hasura.GraphQL.Execute.LiveQuery.Poll as EL
|
||||
@ -672,41 +671,6 @@ renderHtmlTemplate template jVal =
|
||||
errMsg = "template rendering failed: " ++ show errs
|
||||
(errs, res) = M.checkedSubstitute template jVal
|
||||
|
||||
newtype LegacyQueryParser m
|
||||
= LegacyQueryParser
|
||||
{ getLegacyQueryParser :: PG.QualifiedTable -> Object -> m RQLQueryV1 }
|
||||
|
||||
queryParsers :: (MonadError QErr m) => M.HashMap Text (LegacyQueryParser m)
|
||||
queryParsers =
|
||||
M.fromList
|
||||
[ ("select", mkLegacyQueryParser RQSelect)
|
||||
, ("insert", mkLegacyQueryParser RQInsert)
|
||||
, ("update", mkLegacyQueryParser RQUpdate)
|
||||
, ("delete", mkLegacyQueryParser RQDelete)
|
||||
, ("count", mkLegacyQueryParser RQCount)
|
||||
]
|
||||
where
|
||||
mkLegacyQueryParser f =
|
||||
LegacyQueryParser $ \qt obj -> do
|
||||
let val = Object $ M.insert "table" (toJSON qt) obj
|
||||
q <- decodeValue val
|
||||
return $ f q
|
||||
|
||||
legacyQueryHandler
|
||||
:: ( HasVersion, MonadIO m, MonadBaseControl IO m, MonadMetadataApiAuthorization m, Tracing.MonadTrace m
|
||||
, MonadReader HandlerCtx m
|
||||
, MonadMetadataStorage m
|
||||
, MonadResolveSource m
|
||||
)
|
||||
=> PG.TableName -> Text -> Object
|
||||
-> m (HttpResponse EncJSON)
|
||||
legacyQueryHandler tn queryType req =
|
||||
case M.lookup queryType queryParsers of
|
||||
Just queryParser -> getLegacyQueryParser queryParser qt req >>= v1QueryHandler . RQV1
|
||||
Nothing -> throw404 "No such resource exists"
|
||||
where
|
||||
qt = PG.QualifiedObject PG.publicSchema tn
|
||||
|
||||
-- | Default implementation of the 'MonadConfigApiHandler'
|
||||
configApiGetHandler
|
||||
:: forall m. (HasVersion, MonadIO m, MonadBaseControl IO m, UserAuthentication (Tracing.TraceT m), HttpLog m, Tracing.HasReporter m, HasResourceLimits m)
|
||||
@ -981,12 +945,6 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir enableTelemet
|
||||
Spock.post "v2/query" $ spockAction encodeQErr id $
|
||||
mkPostHandler $ fmap (emptyHttpLogMetadata @m, ) <$> mkAPIRespHandler v2QueryHandler
|
||||
|
||||
Spock.post ("api/1/table" <//> Spock.var <//> Spock.var) $ \tableName queryType ->
|
||||
mkSpockAction serverCtx encodeQErr id $
|
||||
mkPostHandler $
|
||||
fmap (emptyHttpLogMetadata @m, )
|
||||
<$> mkAPIRespHandler (legacyQueryHandler (PG.TableName tableName) queryType)
|
||||
|
||||
when enablePGDump $
|
||||
Spock.post "v1alpha1/pg_dump" $ spockAction encodeQErr id $
|
||||
mkPostHandler $ fmap (emptyHttpLogMetadata @m,) <$> v1Alpha1PGDumpHandler
|
||||
@ -1022,7 +980,7 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir enableTelemet
|
||||
Spock.get "dev/plan_cache" $ spockAction encodeQErr id $
|
||||
mkGetHandler $ do
|
||||
onlyAdmin
|
||||
respJ <- liftIO $ E.dumpPlanCache {- scPlanCache serverCtx -}
|
||||
respJ <- liftIO E.dumpPlanCache {- scPlanCache serverCtx -}
|
||||
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue respJ) [])
|
||||
Spock.get "dev/subscriptions" $ spockAction encodeQErr id $
|
||||
mkGetHandler $ do
|
||||
|
@ -187,6 +187,12 @@ This option may result in test failures if the schema has to change between the
|
||||
help="Flag to specify if the pro tests are to be run"
|
||||
)
|
||||
|
||||
parser.addoption(
|
||||
"--test-developer-api-enabled", action="store_true",
|
||||
help="Run Test cases with the Developer API Enabled",
|
||||
default=False
|
||||
)
|
||||
|
||||
|
||||
|
||||
#By default,
|
||||
|
@ -625,3 +625,14 @@ class HGECtx:
|
||||
self.ws_client.teardown()
|
||||
self.ws_client_v1alpha1.teardown()
|
||||
self.ws_client_relay.teardown()
|
||||
|
||||
def v1GraphqlExplain(self, q, hdrs=None):
|
||||
headers = {}
|
||||
|
||||
if hdrs != None:
|
||||
headers = hdrs
|
||||
if self.hge_key != None:
|
||||
headers['X-Hasura-Admin-Secret'] = self.hge_key
|
||||
|
||||
resp = self.http.post(self.hge_url + '/v1/graphql/explain', json=q, headers=headers)
|
||||
return resp.status_code, resp.json()
|
||||
|
@ -1,6 +1,8 @@
|
||||
# Test output of pg_dump clean output.
|
||||
# Including "SET check_function_bodies = false;" avoids https://github.com/hasura/graphql-engine-mono/issues/1007
|
||||
descriptions: Execute pg_dump on public schema
|
||||
headers:
|
||||
X-Hasura-Role: admin
|
||||
url: /v1alpha1/pg_dump
|
||||
status: 200
|
||||
query:
|
||||
|
11
server/tests-py/queries/endpoints/endpoint_as_user_err.yaml
Normal file
11
server/tests-py/queries/endpoints/endpoint_as_user_err.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
- description: call the new custom endpoint with the wrong role
|
||||
url: /api/rest/simple
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
method: GET
|
||||
status: 400
|
||||
query:
|
||||
response:
|
||||
path: $.selectionSet.test_table
|
||||
error: "field \"test_table\" not found in type: 'query_root'"
|
||||
code: validation-failed
|
@ -1,5 +1,7 @@
|
||||
- description: call the new custom endpoint
|
||||
url: /api/rest/simple
|
||||
headers:
|
||||
X-Hasura-Role: admin
|
||||
method: GET
|
||||
status: 200
|
||||
query:
|
||||
|
@ -0,0 +1,27 @@
|
||||
description: Simple GraphQL object query on author, excercising multiple operations
|
||||
url: /v1alpha1/graphql
|
||||
headers:
|
||||
X-Hasura-Role: admin
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
author:
|
||||
- id: 1
|
||||
name: Author 1
|
||||
- id: 2
|
||||
name: Author 2
|
||||
query:
|
||||
# https://graphql.org/learn/serving-over-http/#post-request
|
||||
operationName: chooseThisOne
|
||||
query: |
|
||||
query ignoreThisOne {
|
||||
author {
|
||||
name
|
||||
}
|
||||
}
|
||||
query chooseThisOne {
|
||||
author {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
- description: Other Users cannot see unpublished articles
|
||||
url: /v1alpha1/graphql
|
||||
status: 200
|
||||
headers:
|
||||
X-Hasura-Role: anonymous
|
||||
response:
|
||||
data:
|
||||
article: []
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
article (
|
||||
where: { is_published: {_eq: false}}
|
||||
) {
|
||||
id
|
||||
title
|
||||
content
|
||||
is_published
|
||||
author {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
- description: Other Users can only see published articles
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
headers:
|
||||
X-Hasura-Role: anonymous
|
||||
response:
|
||||
data:
|
||||
article:
|
||||
- id: 2
|
||||
title: Article 2
|
||||
content: Sample article content 2
|
||||
is_published: true
|
||||
author:
|
||||
id: 1
|
||||
name: Author 1
|
||||
- id: 3
|
||||
title: Article 3
|
||||
content: Sample article content 3
|
||||
is_published: true
|
||||
author:
|
||||
id: 2
|
||||
name: Author 2
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
article {
|
||||
id
|
||||
title
|
||||
content
|
||||
is_published
|
||||
author {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
- description: Clear metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: admin
|
||||
status: 200
|
||||
response:
|
||||
message: success
|
||||
@ -9,6 +11,8 @@
|
||||
|
||||
- description: Check if metadata is cleared
|
||||
url: /v1/query
|
||||
headers:
|
||||
X-Hasura-Role: admin
|
||||
status: 200
|
||||
# FIXME:- Using export_metadata will dump
|
||||
# the source configuration dependent on --database-url
|
||||
|
490
server/tests-py/queries/v1/metadata/metadata_as_user_err.yaml
Normal file
490
server/tests-py/queries/v1/metadata/metadata_as_user_err.yaml
Normal file
@ -0,0 +1,490 @@
|
||||
- description: Clear metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: clear_metadata
|
||||
args: {}
|
||||
|
||||
- description: Check if metadata is cleared
|
||||
url: /v1/query
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
query:
|
||||
type: export_metadata
|
||||
args: {}
|
||||
|
||||
- description: Export metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: export_metadata
|
||||
args: {}
|
||||
|
||||
- description: Replace metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: replace_metadata
|
||||
args:
|
||||
allow_inconsistent_metadata: true
|
||||
metadata:
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [
|
||||
{
|
||||
"name": "default",
|
||||
"kind": "postgres",
|
||||
"tables": [],
|
||||
"configuration": {
|
||||
"connection_info": {
|
||||
"database_url": "postgres://postgres:postgrespassword@127.0.0.1:10432/tenant1",
|
||||
"pool_settings": {
|
||||
"retries": 1,
|
||||
"idle_timeout": 185,
|
||||
"max_connections": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
- description: Reload metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: reload_metadata
|
||||
args:
|
||||
reload_remote_schemas: true
|
||||
|
||||
- description: Get Inconsistent Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: get_inconsistent_metadata
|
||||
args: {}
|
||||
|
||||
- description: Drop Inconsistent Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: drop_inconsistent_metadata
|
||||
args: {}
|
||||
|
||||
- description: PG Add Source Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_add_source
|
||||
args:
|
||||
{
|
||||
"name": "pg1",
|
||||
"configuration": {
|
||||
"connection_info": {
|
||||
"database_url": {
|
||||
"from_env": "DB_URL_ENV_VAR"
|
||||
},
|
||||
"pool_settings": {
|
||||
"max_connections": 50,
|
||||
"idle_timeout": 180,
|
||||
"retries": 1,
|
||||
"pool_timeout": 360,
|
||||
"connection_lifetime": 600
|
||||
},
|
||||
"use_prepared_statements": true,
|
||||
"isolation_level": "read-committed",
|
||||
}
|
||||
},
|
||||
"replace_configuration": false
|
||||
}
|
||||
|
||||
- description: PG Drop Source Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_drop_source
|
||||
args:
|
||||
name: pg1
|
||||
cascade: true
|
||||
|
||||
- description: PG Rename Source Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: rename_source
|
||||
args:
|
||||
name: pg1
|
||||
new_name: pg2
|
||||
|
||||
- description: PG Track Table Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_track_table
|
||||
args: {
|
||||
"table": "author",
|
||||
"source": "default",
|
||||
"configuration": {
|
||||
"custom_root_fields": {
|
||||
"select": "Authors",
|
||||
"select_by_pk": "Author",
|
||||
"select_aggregate": "AuthorAggregate",
|
||||
"insert": "AddAuthors",
|
||||
"insert_one":"AddAuthor",
|
||||
"update": "UpdateAuthors",
|
||||
"update_by_pk": "UpdateAuthor",
|
||||
"delete": "DeleteAuthors",
|
||||
"delete_by_pk": "DeleteAuthor"
|
||||
},
|
||||
"custom_column_names": {
|
||||
"id": "authorId"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- description: PG Untrack Table Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_untrack_table
|
||||
args: {
|
||||
"table": {
|
||||
"schema": "public",
|
||||
"name": "author"
|
||||
},
|
||||
"source": "default",
|
||||
"cascade": true
|
||||
}
|
||||
|
||||
- description: PG Set Table Is Enum Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_set_table_is_enum
|
||||
args: {
|
||||
"table": {
|
||||
"schema": "public",
|
||||
"name": "user_role"
|
||||
},
|
||||
"source": "default",
|
||||
"is_enum": true
|
||||
}
|
||||
|
||||
- description: PG Set Table Customization
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_set_table_customization
|
||||
args: {
|
||||
"table": "author_details",
|
||||
"source": "default",
|
||||
"configuration": {
|
||||
"identifier": "author",
|
||||
"custom_root_fields": {
|
||||
"select": "Authors",
|
||||
"select_by_pk": "Author",
|
||||
"select_aggregate": "AuthorAggregate",
|
||||
"insert": "AddAuthors",
|
||||
"insert_one":"AddAuthor",
|
||||
"update": "UpdateAuthors",
|
||||
"update_by_pk": "UpdateAuthor",
|
||||
"delete": "DeleteAuthors",
|
||||
"delete_by_pk": "DeleteAuthor"
|
||||
},
|
||||
"custom_column_names": {
|
||||
"id": "authorId"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- description: PG Track Function
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_track_function
|
||||
args: {
|
||||
"function": {
|
||||
"schema": "public",
|
||||
"name": "search_articles"
|
||||
},
|
||||
"source": "default",
|
||||
"configuration": {
|
||||
"session_argument": "hasura_session"
|
||||
}
|
||||
}
|
||||
|
||||
- description: PG Untrack Function
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_untrack_function
|
||||
args: {
|
||||
"function": {
|
||||
"schema": "public",
|
||||
"name": "search_articles"
|
||||
},
|
||||
"source": "default"
|
||||
}
|
||||
|
||||
- description: PG Create Function Permission
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_create_function_permission
|
||||
args: {
|
||||
"function": "get_articles",
|
||||
"source": "default",
|
||||
"role": "user"
|
||||
}
|
||||
|
||||
- description: PG Drop Function Permission
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: pg_drop_function_permission
|
||||
args: {
|
||||
"function": "get_articles",
|
||||
"role": "user",
|
||||
"source": "default"
|
||||
}
|
||||
|
||||
- description: MSSQL Add Source Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: mssql_add_source
|
||||
args: {
|
||||
"name": "mssql1",
|
||||
"configuration": {
|
||||
"connection_info": {
|
||||
"connection_string": {
|
||||
"from_env": "CONN_STRING_ENV_VAR"
|
||||
},
|
||||
"pool_settings": {
|
||||
"max_connections": 50,
|
||||
"idle_timeout": 180
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- description: MSSQL Drop Source Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: mssql_drop_source
|
||||
args:
|
||||
name: mssql1
|
||||
|
||||
- description: MSSQL Track Table
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: mssql_track_table
|
||||
args: {
|
||||
"table": "author",
|
||||
"source": "default"
|
||||
}
|
||||
|
||||
- description: MSSQL Untrack Table
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: mssql_untrack_table
|
||||
args: {
|
||||
"table": {
|
||||
"schema": "dbo",
|
||||
"name": "author"
|
||||
},
|
||||
"source": "default",
|
||||
"cascade": true
|
||||
}
|
||||
|
||||
- description: MSSQL Set Table Customization
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: mssql_set_table_customization
|
||||
args: {
|
||||
"table": "author_details",
|
||||
"source": "default",
|
||||
"configuration": {
|
||||
"identifier": "author",
|
||||
"custom_root_fields": {
|
||||
"select": "Authors",
|
||||
"select_aggregate": "AuthorAggregate",
|
||||
},
|
||||
"custom_column_names": {
|
||||
"id": "authorId"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# TODO: Failing to parse `configuration.service_account`
|
||||
# - description: BigQuery Add Source Metadata
|
||||
# url: /v1/metadata
|
||||
# headers:
|
||||
# X-Hasura-Role: user
|
||||
# status: 400
|
||||
# response:
|
||||
# path: $.args
|
||||
# error: 'restricted access : admin only'
|
||||
# code: access-denied
|
||||
# query:
|
||||
# type: bigquery_add_source
|
||||
# args:
|
||||
# {
|
||||
# "name": "bigquery1",
|
||||
# "configuration": {
|
||||
# "service_account": "bigquery_service_account",
|
||||
# "project_id": "bigquery_project_id",
|
||||
# "datasets": "dataset1, dataset2"
|
||||
# }
|
||||
# }
|
||||
|
||||
- description: BigQuery Drop Source Metadata
|
||||
url: /v1/metadata
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
status: 400
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: bigquery_drop_source
|
||||
args:
|
||||
name: bigquery1
|
@ -0,0 +1,14 @@
|
||||
url: /v2/query
|
||||
status: 400
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
X-Hasura-User-Id: '1'
|
||||
response:
|
||||
path: $.args
|
||||
error: 'restricted access : admin only'
|
||||
code: access-denied
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
SELECT * from author
|
21
server/tests-py/queries/v1/run_sql/sql_select_query_v2.yaml
Normal file
21
server/tests-py/queries/v1/run_sql/sql_select_query_v2.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
url: /v2/query
|
||||
headers:
|
||||
X-Hasura-Role: admin
|
||||
status: 200
|
||||
response:
|
||||
result_type: TuplesOk
|
||||
result:
|
||||
-
|
||||
- id
|
||||
- name
|
||||
-
|
||||
- '1'
|
||||
- Author 1
|
||||
-
|
||||
- '2'
|
||||
- Author 2
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
SELECT * from author
|
@ -31,4 +31,4 @@ query:
|
||||
- name: author
|
||||
columns:
|
||||
- id
|
||||
- name
|
||||
- name
|
||||
|
@ -1,10 +1,11 @@
|
||||
description: foo
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
- id: 1
|
||||
name: Author 1
|
||||
- id: 2
|
||||
name: Author 2
|
||||
- id: 1
|
||||
name: Author 1
|
||||
- id: 2
|
||||
name: Author 2
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
|
@ -0,0 +1,15 @@
|
||||
url: /v1/query
|
||||
headers:
|
||||
x-hasura-role: user
|
||||
status: 400
|
||||
response:
|
||||
code: permission-denied
|
||||
error: role "user" does not have permission to select column "id"
|
||||
path: $.args.columns[0]
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
table: author
|
||||
columns:
|
||||
- id
|
||||
- name
|
@ -0,0 +1,13 @@
|
||||
url: /v1/query
|
||||
headers:
|
||||
x-hasura-role: user
|
||||
status: 200
|
||||
response:
|
||||
- name: Author 1
|
||||
- name: Author 2
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
table: author
|
||||
columns:
|
||||
- name
|
@ -1,15 +1,14 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
#Author table
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique
|
||||
CREATE TABLE author (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT UNIQUE
|
||||
);
|
||||
|
||||
CREATE TABLE article (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT,
|
||||
@ -18,12 +17,14 @@ args:
|
||||
is_published BOOLEAN,
|
||||
published_on TIMESTAMP
|
||||
);
|
||||
insert into author (name)
|
||||
values
|
||||
|
||||
INSERT INTO author (name)
|
||||
VALUES
|
||||
('Author 1'),
|
||||
('Author 2') ;
|
||||
insert into article (title,content,author_id,is_published)
|
||||
values
|
||||
('Author 2');
|
||||
|
||||
INSERT INTO article (title,content,author_id,is_published)
|
||||
VALUES
|
||||
(
|
||||
'Article 1',
|
||||
'Sample article content 1',
|
||||
@ -42,6 +43,7 @@ args:
|
||||
2,
|
||||
true
|
||||
);
|
||||
|
||||
CREATE TABLE "user" (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
@ -53,13 +55,25 @@ args:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
#Article table
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: article
|
||||
|
||||
#Object relationship
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: user
|
||||
|
||||
- type: insert
|
||||
args:
|
||||
table: user
|
||||
objects:
|
||||
- name: User 1
|
||||
number: '123456789'
|
||||
- name: User 2
|
||||
number: '123456780'
|
||||
|
||||
- type: create_object_relationship
|
||||
args:
|
||||
table: article
|
||||
@ -67,7 +81,6 @@ args:
|
||||
using:
|
||||
foreign_key_constraint_on: author_id
|
||||
|
||||
#Array relationship
|
||||
- type: create_array_relationship
|
||||
args:
|
||||
table: author
|
||||
@ -77,17 +90,11 @@ args:
|
||||
table: article
|
||||
column: author_id
|
||||
|
||||
|
||||
#Insert values
|
||||
- type: track_table
|
||||
- type: create_select_permission
|
||||
args:
|
||||
schema: public
|
||||
name: user
|
||||
- type: insert
|
||||
args:
|
||||
table: user
|
||||
objects:
|
||||
- name: User 1
|
||||
number: '123456789'
|
||||
- name: User 2
|
||||
number: '123456780'
|
||||
table: author
|
||||
role: user
|
||||
permission:
|
||||
columns:
|
||||
- name
|
||||
filter: {}
|
||||
|
@ -1,16 +1,9 @@
|
||||
type: bulk
|
||||
args:
|
||||
#Drop relationship first
|
||||
- type: drop_relationship
|
||||
args:
|
||||
relationship: articles
|
||||
table:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article;
|
||||
drop table author;
|
||||
drop table "user";
|
||||
DROP TABLE article;
|
||||
DROP TABLE author;
|
||||
DROP TABLE "user";
|
||||
cascade: true
|
||||
|
14
server/tests-py/queries/v2/basic/select_article.yaml
Normal file
14
server/tests-py/queries/v2/basic/select_article.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
url: /v2/query
|
||||
status: 200
|
||||
response:
|
||||
- id: 1
|
||||
name: Author 1
|
||||
- id: 2
|
||||
name: Author 2
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
table: author
|
||||
columns:
|
||||
- id
|
||||
- name
|
@ -0,0 +1,15 @@
|
||||
url: /v2/query
|
||||
headers:
|
||||
x-hasura-role: user
|
||||
status: 400
|
||||
response:
|
||||
code: access-denied
|
||||
error: 'restricted access : admin only'
|
||||
path: $.args
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
table: article
|
||||
columns:
|
||||
- id
|
||||
- name
|
@ -0,0 +1,11 @@
|
||||
url: /v2/query
|
||||
status: 200
|
||||
response:
|
||||
- name: Author 1
|
||||
- name: Author 2
|
||||
query:
|
||||
type: select
|
||||
args:
|
||||
table: author
|
||||
columns:
|
||||
- name
|
104
server/tests-py/queries/v2/basic/setup.yaml
Normal file
104
server/tests-py/queries/v2/basic/setup.yaml
Normal file
@ -0,0 +1,104 @@
|
||||
type: bulk
|
||||
args:
|
||||
|
||||
#Author table
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
create table author(
|
||||
id serial primary key,
|
||||
name text unique
|
||||
);
|
||||
CREATE TABLE article (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
author_id INTEGER REFERENCES author(id),
|
||||
is_published BOOLEAN,
|
||||
published_on TIMESTAMP
|
||||
);
|
||||
insert into author (name)
|
||||
values
|
||||
('Author 1'),
|
||||
('Author 2') ;
|
||||
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,
|
||||
true
|
||||
);
|
||||
CREATE TABLE "user" (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
number BIGINT
|
||||
);
|
||||
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
#Article table
|
||||
- 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
|
||||
|
||||
#Array relationship
|
||||
- type: create_array_relationship
|
||||
args:
|
||||
table: author
|
||||
name: articles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
table: article
|
||||
column: author_id
|
||||
|
||||
|
||||
#Insert values
|
||||
- type: track_table
|
||||
args:
|
||||
schema: public
|
||||
name: user
|
||||
- type: insert
|
||||
args:
|
||||
table: user
|
||||
objects:
|
||||
- name: User 1
|
||||
number: '123456789'
|
||||
- name: User 2
|
||||
number: '123456780'
|
||||
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table:
|
||||
schema: public
|
||||
name: author
|
||||
role: user
|
||||
permission:
|
||||
columns:
|
||||
- name
|
||||
filter: {}
|
16
server/tests-py/queries/v2/basic/teardown.yaml
Normal file
16
server/tests-py/queries/v2/basic/teardown.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
type: bulk
|
||||
args:
|
||||
#Drop relationship first
|
||||
- type: drop_relationship
|
||||
args:
|
||||
relationship: articles
|
||||
table:
|
||||
schema: public
|
||||
name: author
|
||||
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
drop table article cascade;
|
||||
drop table author cascade;
|
||||
drop table "user" cascade;
|
@ -3,6 +3,20 @@ import re
|
||||
import json
|
||||
|
||||
class TestConfigAPI():
|
||||
def test_config_api_user_role_error(self, hge_ctx):
|
||||
admin_secret = hge_ctx.hge_key
|
||||
auth_hook = hge_ctx.hge_webhook
|
||||
jwt_conf = hge_ctx.hge_jwt_conf
|
||||
if jwt_conf is not None:
|
||||
jwt_conf_dict = json.loads(hge_ctx.hge_jwt_conf)
|
||||
|
||||
headers = { 'x-hasura-role': 'user' }
|
||||
if admin_secret is not None:
|
||||
headers['x-hasura-admin-secret'] = admin_secret
|
||||
|
||||
resp = hge_ctx.http.get(hge_ctx.hge_url + '/v1alpha1/config', headers=headers)
|
||||
|
||||
assert resp.status_code == 400, resp
|
||||
|
||||
def test_config_api(self, hge_ctx):
|
||||
admin_secret = hge_ctx.hge_key
|
||||
@ -11,14 +25,14 @@ class TestConfigAPI():
|
||||
if jwt_conf is not None:
|
||||
jwt_conf_dict = json.loads(hge_ctx.hge_jwt_conf)
|
||||
|
||||
headers = {}
|
||||
headers = { 'x-hasura-role': 'admin' }
|
||||
if admin_secret is not None:
|
||||
headers['x-hasura-admin-secret'] = admin_secret
|
||||
|
||||
resp = hge_ctx.http.get(hge_ctx.hge_url + '/v1alpha1/config', headers=headers)
|
||||
|
||||
|
||||
assert resp.status_code == 200, resp
|
||||
|
||||
|
||||
body = resp.json()
|
||||
# The tree may be dirty because we're developing tests locally while
|
||||
# graphql-engine was built previously when tree was clean. If we're
|
||||
|
63
server/tests-py/test_dev_endpoints.py
Normal file
63
server/tests-py/test_dev_endpoints.py
Normal file
@ -0,0 +1,63 @@
|
||||
import requests
|
||||
import pytest
|
||||
from context import PytestConf
|
||||
|
||||
"""
|
||||
|
||||
NOTE:
|
||||
These endpoints are admin-only
|
||||
|
||||
"dev/ekg"
|
||||
"dev/plan_cache"
|
||||
"dev/subscriptions"
|
||||
"dev/subscriptions/extended"
|
||||
|
||||
This needs RTS to be enabled and mainly used for benchmarking:
|
||||
(hence not adding any tests for this)
|
||||
"dev/rts_stats" - has no "admin" role requirements
|
||||
|
||||
"""
|
||||
|
||||
def get_headers(hge_ctx, role='admin'):
|
||||
headers = {}
|
||||
if hge_ctx.hge_key != None:
|
||||
headers['x-hasura-admin-secret'] = hge_ctx.hge_key
|
||||
headers['x-hasura-role'] = role
|
||||
return headers
|
||||
|
||||
developer_api_enabled = PytestConf.config.getoption("--test-developer-api-enabled")
|
||||
@pytest.mark.skipif(not developer_api_enabled,
|
||||
reason="flag --test-developer-api-enabled is not set. Cannot run tests for metadata disabled")
|
||||
class TestDevEndpoints:
|
||||
|
||||
def test_ekg_endpoint_admin_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/ekg', headers=get_headers(hge_ctx))
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_ekg_endpoint_user_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/ekg', headers=get_headers(hge_ctx, 'user'))
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_plan_cache_endpoint_admin_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/plan_cache', headers=get_headers(hge_ctx))
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_plan_cache_endpoint_user_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/plan_cache', headers=get_headers(hge_ctx, 'user'))
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_subscriptions_endpoint_admin_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/subscriptions', headers=get_headers(hge_ctx))
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_subscriptions_endpoint_user_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/subscriptions', headers=get_headers(hge_ctx, 'user'))
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_subscriptions_extended_endpoint_admin_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/subscriptions/extended', headers=get_headers(hge_ctx))
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_subscriptions_extended_endpoint_user_role(self, hge_ctx):
|
||||
resp = requests.get(hge_ctx.hge_url + '/dev/subscriptions/extended', headers=get_headers(hge_ctx, 'user'))
|
||||
assert resp.status_code == 400
|
@ -20,6 +20,9 @@ class TestCustomEndpoints:
|
||||
def test_missing_endpoint(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/endpoint_missing.yaml', transport)
|
||||
|
||||
def test_endpoint_as_user_err(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/endpoint_as_user_err.yaml', transport)
|
||||
|
||||
def test_simple_endpoint(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/endpoint_simple.yaml', transport)
|
||||
|
||||
|
@ -138,6 +138,9 @@ class TestGraphQLQueryBasicCommon:
|
||||
def test_select_query_author(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author.yaml', transport)
|
||||
|
||||
def test_select_query_author(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author_v1alpha1.yaml', transport)
|
||||
|
||||
def test_select_query_author_quoted_col(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_query_author_col_quoted.yaml', transport)
|
||||
|
||||
@ -544,6 +547,9 @@ class TestGraphqlQueryPermissions:
|
||||
def test_anonymous_only_published_articles(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/anonymous_can_only_get_published_articles.yaml', transport)
|
||||
|
||||
def test_anonymous_only_published_articles_v1alpha1(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/anonymous_can_only_get_published_articles_v1alpha1.yaml', transport)
|
||||
|
||||
def test_user_cannot_access_remarks_col(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/user_cannot_access_remarks_col.yaml', transport)
|
||||
|
||||
@ -1008,20 +1014,40 @@ class TestGraphQLExplain:
|
||||
def dir(cls):
|
||||
return 'queries/explain'
|
||||
|
||||
def test_simple_query_as_admin(self, hge_ctx, backend):
|
||||
q = {"query": {"query": "query abc { __typename }", "operationName": "abc"}}
|
||||
st_code, resp = hge_ctx.v1GraphqlExplain(q)
|
||||
assert st_code == 200, resp
|
||||
|
||||
def test_simple_query_as_user(self, hge_ctx, backend):
|
||||
q = {"query": {"query": "query abc { __typename }", "operationName": "abc"}}
|
||||
st_code, resp = hge_ctx.v1GraphqlExplain(q, {"x-hasura-role": "random_user"})
|
||||
assert st_code == 400, resp
|
||||
|
||||
def test_simple_query_as_admin_with_user_role(self, hge_ctx, backend):
|
||||
self.with_admin_secret(hge_ctx, self.dir() + hge_ctx.backend_suffix('/permissions_query') + ".yaml")
|
||||
|
||||
def test_simple_query(self, hge_ctx, backend):
|
||||
self.with_admin_secret(hge_ctx, self.dir() + hge_ctx.backend_suffix('/simple_query') + ".yaml")
|
||||
|
||||
def test_permissions_query(self, hge_ctx, backend):
|
||||
self.with_admin_secret(hge_ctx, self.dir() + hge_ctx.backend_suffix('/permissions_query') + ".yaml")
|
||||
|
||||
def with_admin_secret(self, hge_ctx, f):
|
||||
def with_admin_secret(self, hge_ctx, f, hdrs=None, req_st=200):
|
||||
conf = get_conf_f(f)
|
||||
admin_secret = hge_ctx.hge_key
|
||||
headers = {}
|
||||
if admin_secret:
|
||||
headers['X-Hasura-Admin-Secret'] = hge_ctx.hge_key
|
||||
if hdrs != None:
|
||||
headers = hdrs
|
||||
elif admin_secret and hdrs == None:
|
||||
headers['X-Hasura-Admin-Secret'] = admin_secret
|
||||
status_code, resp_json, _ = hge_ctx.anyq(conf['url'], conf['query'], headers)
|
||||
assert status_code == 200, resp_json
|
||||
assert status_code == req_st, resp_json
|
||||
|
||||
if req_st != 200:
|
||||
# return early in case we're testing for failures
|
||||
return
|
||||
|
||||
# Comparing only with generated 'sql' since the 'plan' may differ
|
||||
resp_sql = resp_json[0]['sql']
|
||||
exp_sql = conf['response'][0]['sql']
|
||||
|
@ -25,6 +25,9 @@ class TestMetadata:
|
||||
def test_clear_metadata(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/clear_metadata.yaml')
|
||||
|
||||
def test_clear_metadata_as_user(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/metadata_as_user_err.yaml')
|
||||
|
||||
def test_replace_metadata(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/replace_metadata.yaml')
|
||||
|
||||
|
@ -20,7 +20,7 @@ class TestPGDump:
|
||||
PG_VERSION = os.getenv('PG_VERSION', 'latest')
|
||||
with open(query_file, 'r') as stream:
|
||||
q = yaml.safe_load(stream)
|
||||
headers = {}
|
||||
headers = q['headers'] or {}
|
||||
if hge_ctx.hge_key is not None:
|
||||
headers['x-hasura-admin-secret'] = hge_ctx.hge_key
|
||||
resp = hge_ctx.http.post(hge_ctx.hge_url + q['url'], json=q['query'], headers=headers)
|
||||
@ -30,6 +30,18 @@ class TestPGDump:
|
||||
print(q[resp_pg_version_map[PG_VERSION]])
|
||||
assert body == q[resp_pg_version_map[PG_VERSION]]
|
||||
|
||||
def test_pg_dump_for_public_schema_for_user_role(self, hge_ctx):
|
||||
query_file = self.dir() + '/pg_dump_public.yaml'
|
||||
with open(query_file, 'r') as stream:
|
||||
q = yaml.safe_load(stream)
|
||||
headers = q['headers'] or {}
|
||||
if hge_ctx.hge_key is not None:
|
||||
headers['x-hasura-admin-secret'] = hge_ctx.hge_key
|
||||
headers['X-Hasura-Role'] = 'user'
|
||||
resp = hge_ctx.http.post(hge_ctx.hge_url + q['url'], json=q['query'], headers=headers)
|
||||
body = resp.text
|
||||
assert resp.status_code == 400, body
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "pgdump"
|
||||
|
@ -34,9 +34,16 @@ class TestV1General:
|
||||
@usefixtures('per_class_tests_db_state')
|
||||
class TestV1SelectBasic:
|
||||
|
||||
def test_select_query_author(self, hge_ctx):
|
||||
def test_select_query_author_with_admin_role(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article.yaml')
|
||||
|
||||
# TODO: fix these tests for JWT tests
|
||||
# def test_select_query_author_with_user_role_success(self, hge_ctx):
|
||||
# check_query_f(hge_ctx, self.dir() + '/select_article_role_success.yaml')
|
||||
|
||||
# def test_select_query_author_with_user_role_failure(self, hge_ctx):
|
||||
# check_query_f(hge_ctx, self.dir() + '/select_article_role_error.yaml')
|
||||
|
||||
def test_nested_select_article_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/nested_select_query_article_author.yaml')
|
||||
|
||||
@ -498,6 +505,11 @@ class TestRunSQL:
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_select_query.yaml')
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
# TODO: create a v2 query tests module
|
||||
def test_select_query_v2(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_select_query_v2.yaml')
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
|
||||
def test_select_query_read_only(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_select_query_read_only.yaml')
|
||||
hge_ctx.may_skip_test_teardown = True
|
||||
@ -512,6 +524,10 @@ class TestRunSQL:
|
||||
def test_sql_query_as_user_error(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_query_as_user_error.yaml')
|
||||
|
||||
# TODO: create a v2 query tests module
|
||||
def test_sql_query_as_user_error_v2(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_query_as_user_error_v2.yaml')
|
||||
|
||||
def test_sql_rename_table(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/sql_rename_table.yaml')
|
||||
|
||||
|
25
server/tests-py/test_v2_queries.py
Normal file
25
server/tests-py/test_v2_queries.py
Normal file
@ -0,0 +1,25 @@
|
||||
from validate import check_query_f
|
||||
import pytest
|
||||
|
||||
usefixtures = pytest.mark.usefixtures
|
||||
|
||||
# use_mutation_fixtures = usefixtures(
|
||||
# 'per_class_db_schema_for_mutation_tests',
|
||||
# 'per_method_db_data_for_mutation_tests'
|
||||
# )
|
||||
|
||||
@usefixtures('per_class_tests_db_state')
|
||||
class TestV2SelectBasic: # Basic RQL Tests on v2/query
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return 'queries/v2/basic'
|
||||
|
||||
def test_select_query_author(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article.yaml')
|
||||
|
||||
def test_select_query_author_with_user_role_success(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_article_role_success.yaml')
|
||||
|
||||
# TODO: Fix this test for JWT
|
||||
# def test_select_query_author_with_user_role_failure(self, hge_ctx):
|
||||
# check_query_f(hge_ctx, self.dir() + '/select_article_role_error.yaml')
|
Loading…
Reference in New Issue
Block a user