tests: Add tests for the pg-safeupdate library

This commit is contained in:
Laurence Isla
2022-08-10 11:50:57 -05:00
committed by GitHub
parent 57bc3d805c
commit 4ac47df528
8 changed files with 151 additions and 24 deletions
+6 -6
View File
@@ -46,12 +46,12 @@ let
postgresqlVersions = postgresqlVersions =
[ [
{ name = "postgresql-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis ]); } { name = "postgresql-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-13"; postgresql = pkgs.postgresql_13.withPackages (p: [ p.postgis ]); } { name = "postgresql-13"; postgresql = pkgs.postgresql_13.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-12"; postgresql = pkgs.postgresql_12.withPackages (p: [ p.postgis ]); } { name = "postgresql-12"; postgresql = pkgs.postgresql_12.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-11"; postgresql = pkgs.postgresql_11.withPackages (p: [ p.postgis ]); } { name = "postgresql-11"; postgresql = pkgs.postgresql_11.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-10"; postgresql = pkgs.postgresql_10.withPackages (p: [ p.postgis ]); } { name = "postgresql-10"; postgresql = pkgs.postgresql_10.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-9.6"; postgresql = pkgs.postgresql_9_6.withPackages (p: [ p.postgis ]); } { name = "postgresql-9.6"; postgresql = pkgs.postgresql_9_6.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
]; ];
patches = patches =
+1
View File
@@ -201,6 +201,7 @@ test-suite spec
Feature.Query.JsonOperatorSpec Feature.Query.JsonOperatorSpec
Feature.Query.MultipleSchemaSpec Feature.Query.MultipleSchemaSpec
Feature.Query.ErrorSpec Feature.Query.ErrorSpec
Feature.Query.PgSafeUpdateSpec
Feature.Query.PostGISSpec Feature.Query.PostGISSpec
Feature.Query.QueryLimitedSpec Feature.Query.QueryLimitedSpec
Feature.Query.QuerySpec Feature.Query.QuerySpec
@@ -0,0 +1,76 @@
module Feature.Query.PgSafeUpdateSpec where
import Network.Wai (Application)
import Network.HTTP.Types
import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON
import Protolude hiding (get, put)
import SpecHelper
spec :: SpecWith ((), Application)
spec =
describe "Enabling pg-safeupdate" $ do
context "Full table update" $
it "does not update and throws no error if no condition is present" $
request methodPatch "/safe_update"
[("Prefer", "count=exact")]
[json| {"name": "New name"} |]
`shouldRespondWith`
""
{ matchStatus = 404
, matchHeaders = [ matchHeaderAbsent hContentType
, "Content-Range" <:> "*/0" ]
}
context "Full table delete" $ do
it "does not delete and throws error if no condition is present" $
request methodDelete "/safe_delete" [] mempty
`shouldRespondWith`
[json|{
"code": "21000",
"details": null,
"hint": null,
"message": "DELETE requires a WHERE clause"
}|]
{ matchStatus = 400 }
it "allows full table delete if a filter is present" $
request methodDelete "/safe_delete?id=gt.0"
[("Prefer", "count=exact")]
mempty
`shouldRespondWith`
""
{ matchStatus = 204
, matchHeaders = [ matchHeaderAbsent hContentType
, "Content-Range" <:> "*/3" ]
}
disabledSpec :: SpecWith ((), Application)
disabledSpec =
describe "Disabling pg-safeupdate" $ do
context "Full table update" $
it "does not update and does not throw error if no condition is present" $
request methodPatch "/unsafe_update"
[("Prefer", "count=exact")]
[json| {"name": "New name"} |]
`shouldRespondWith`
""
{ matchStatus = 404
, matchHeaders = [ matchHeaderAbsent hContentType
, "Content-Range" <:> "*/0" ]
}
context "Full table delete" $
it "deletes and does not throw error if no condition is present" $ do
request methodDelete "/unsafe_delete"
[("Prefer", "count=exact")]
mempty
`shouldRespondWith`
""
{ matchStatus = 204
, matchHeaders = [ matchHeaderAbsent hContentType
, "Content-Range" <:> "*/3" ]
}
+7
View File
@@ -45,6 +45,7 @@ import qualified Feature.Query.HtmlRawOutputSpec
import qualified Feature.Query.InsertSpec import qualified Feature.Query.InsertSpec
import qualified Feature.Query.JsonOperatorSpec import qualified Feature.Query.JsonOperatorSpec
import qualified Feature.Query.MultipleSchemaSpec import qualified Feature.Query.MultipleSchemaSpec
import qualified Feature.Query.PgSafeUpdateSpec
import qualified Feature.Query.PlanSpec import qualified Feature.Query.PlanSpec
import qualified Feature.Query.PostGISSpec import qualified Feature.Query.PostGISSpec
import qualified Feature.Query.QueryLimitedSpec import qualified Feature.Query.QueryLimitedSpec
@@ -112,6 +113,7 @@ main = do
forceRollbackApp = app testCfgForceRollback forceRollbackApp = app testCfgForceRollback
testCfgLegacyGucsApp = app testCfgLegacyGucs testCfgLegacyGucsApp = app testCfgLegacyGucs
planEnabledApp = app testPlanEnabledCfg planEnabledApp = app testPlanEnabledCfg
pgSafeUpdateApp = app testPgSafeUpdateEnabledCfg
extraSearchPathApp = appDbs testCfgExtraSearchPath extraSearchPathApp = appDbs testCfgExtraSearchPath
unicodeApp = appDbs testUnicodeCfg unicodeApp = appDbs testUnicodeCfg
@@ -137,6 +139,7 @@ main = do
, ("Feature.Query.JsonOperatorSpec" , Feature.Query.JsonOperatorSpec.spec actualPgVersion) , ("Feature.Query.JsonOperatorSpec" , Feature.Query.JsonOperatorSpec.spec actualPgVersion)
, ("Feature.OpenApi.OpenApiSpec" , Feature.OpenApi.OpenApiSpec.spec actualPgVersion) , ("Feature.OpenApi.OpenApiSpec" , Feature.OpenApi.OpenApiSpec.spec actualPgVersion)
, ("Feature.OptionsSpec" , Feature.OptionsSpec.spec actualPgVersion) , ("Feature.OptionsSpec" , Feature.OptionsSpec.spec actualPgVersion)
, ("Feature.Query.PgSafeUpdateSpec.disabledSpec" , Feature.Query.PgSafeUpdateSpec.disabledSpec)
, ("Feature.Query.PlanSpec.disabledSpec" , Feature.Query.PlanSpec.disabledSpec) , ("Feature.Query.PlanSpec.disabledSpec" , Feature.Query.PlanSpec.disabledSpec)
, ("Feature.Query.QuerySpec" , Feature.Query.QuerySpec.spec actualPgVersion) , ("Feature.Query.QuerySpec" , Feature.Query.QuerySpec.spec actualPgVersion)
, ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec) , ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec)
@@ -234,6 +237,10 @@ main = do
parallel $ before planEnabledApp $ parallel $ before planEnabledApp $
describe "Feature.Query.PlanSpec.spec" $ Feature.Query.PlanSpec.spec actualPgVersion describe "Feature.Query.PlanSpec.spec" $ Feature.Query.PlanSpec.spec actualPgVersion
-- this test runs with a pre request to enable the pg-safeupdate library per-session
parallel $ before pgSafeUpdateApp $
describe "Feature.Query.PgSafeUpdateSpec.spec" Feature.Query.PgSafeUpdateSpec.spec
-- Note: the rollback tests can not run in parallel, because they test persistance and -- Note: the rollback tests can not run in parallel, because they test persistance and
-- this results in race conditions -- this results in race conditions
+3
View File
@@ -196,6 +196,9 @@ testMultipleSchemaCfg = baseCfg { configDbSchemas = fromList ["v1", "v2", "SPECI
testCfgLegacyGucs :: AppConfig testCfgLegacyGucs :: AppConfig
testCfgLegacyGucs = baseCfg { configDbUseLegacyGucs = False } testCfgLegacyGucs = baseCfg { configDbUseLegacyGucs = False }
testPgSafeUpdateEnabledCfg :: AppConfig
testPgSafeUpdateEnabledCfg = baseCfg { configDbPreRequest = Just $ QualifiedIdentifier "test" "load_safeupdate" }
analyzeTable :: Text -> IO () analyzeTable :: Text -> IO ()
analyzeTable tableName = analyzeTable tableName =
void $ readProcess "psql" ["--set", "ON_ERROR_STOP=1", "-a", "-c", toS $ "ANALYZE test.\"" <> tableName <> "\""] [] void $ readProcess "psql" ["--set", "ON_ERROR_STOP=1", "-a", "-c", toS $ "ANALYZE test.\"" <> tableName <> "\""] []
+9
View File
@@ -803,3 +803,12 @@ INSERT INTO "SPECIAL ""@/\#~_-".names (id, name) VALUES (1, 'John'), (2, 'Mary')
TRUNCATE TABLE do$llar$s CASCADE; TRUNCATE TABLE do$llar$s CASCADE;
INSERT INTO do$llar$s (a$num$) VALUES (100), (200), (300); INSERT INTO do$llar$s (a$num$) VALUES (100), (200), (300);
TRUNCATE TABLE safe_update CASCADE;
INSERT INTO safe_update(id, name) VALUES (1, 'First'), (2, 'Second'), (3, 'Third');
TRUNCATE TABLE safe_delete CASCADE;
INSERT INTO safe_delete(id, name) VALUES (1, 'First'), (2, 'Second'), (3, 'Third');
TRUNCATE TABLE unsafe_update CASCADE;
INSERT INTO unsafe_update(id, name) VALUES (1, 'First'), (2, 'Second'), (3, 'Third');
TRUNCATE TABLE unsafe_delete CASCADE;
INSERT INTO unsafe_delete(id, name) VALUES (1, 'First'), (2, 'Second'), (3, 'Third');
+4
View File
@@ -195,6 +195,10 @@ GRANT ALL ON TABLE
, shop_bles , shop_bles
, "SPECIAL ""@/\#~_-".names , "SPECIAL ""@/\#~_-".names
, do$llar$s , do$llar$s
, safe_update
, safe_delete
, unsafe_update
, unsafe_delete
TO postgrest_test_anonymous; TO postgrest_test_anonymous;
GRANT INSERT ON TABLE insertonly TO postgrest_test_anonymous; GRANT INSERT ON TABLE insertonly TO postgrest_test_anonymous;
+27
View File
@@ -2689,3 +2689,30 @@ $$ LANGUAGE sql;
CREATE TABLE do$llar$s ( CREATE TABLE do$llar$s (
a$num$ numeric a$num$ numeric
); );
-- Tables and functions to test the pg-safeupdate library
CREATE TABLE test.safe_update(
id INT PRIMARY KEY,
name TEXT
);
CREATE TABLE test.safe_delete(
id INT PRIMARY KEY,
name TEXT
);
CREATE TABLE test.unsafe_update(
id INT PRIMARY KEY,
name TEXT
);
CREATE TABLE test.unsafe_delete(
id INT PRIMARY KEY,
name TEXT
);
CREATE OR REPLACE FUNCTION test.load_safeupdate() RETURNS VOID AS $$
BEGIN
LOAD 'safeupdate';
END; $$ LANGUAGE plpgsql SECURITY DEFINER;