From eb238f0ffb684e59f090cfdf5f59b5802cd56252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Mon, 18 Jul 2022 18:48:04 +0200 Subject: [PATCH] Fix tests and impl --- .../0.0.0-dev/src/Connection/PostgreSQL.enso | 17 ++++++- .../src/Internal/Postgres/Pgpass.enso | 17 ++++--- .../src/Database/Postgresql_Spec.enso | 46 +++++++++++++------ 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/PostgreSQL.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/PostgreSQL.enso index 0077f9856eab7..ccf3db30d0952 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/PostgreSQL.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/PostgreSQL.enso @@ -1,5 +1,7 @@ from Standard.Base import all +from Standard.Base.Data.Numbers import Parse_Error + import Standard.Database.Data.Dialect import Standard.Database.Connection.Connection from Standard.Database.Connection.Credentials as Credentials_Module import Credentials @@ -21,7 +23,7 @@ type PostgreSQL - credentials: The credentials to use for the connection (defaults to PGPass or No Authentication). - use_ssl: Whether to use SSL (defaults to `Prefer`). - client_cert: The client certificate to use or `Nothing` if not needed. - type PostgreSQL (host:Text = Environment.get_or_else "PGHOST" "localhost") (port:Integer = Environment.get_or_else "PGPORT" 5432) (database:Text = Environment.get_or_else "PGDATABASE" "") (credentials:(Credentials|Nothing)=Nothing) (use_ssl:SSL_Mode=Prefer) (client_cert:(Client_Certificate|Nothing)=Nothing) + type PostgreSQL (host:Text=default_postgres_host) (port:Integer=default_postgres_port) (database:Text=default_postgres_database) (credentials:(Credentials|Nothing)=Nothing) (use_ssl:SSL_Mode=Prefer) (client_cert:(Client_Certificate|Nothing)=Nothing) ## Build the Connection resource. @@ -83,3 +85,16 @@ ssl_mode_to_jdbc_properties use_ssl = case use_ssl of Full_Verification cert_file -> if cert_file.is_nothing then [Pair 'sslmode' 'verify-full'] else [Pair 'sslmode' 'verify-full', Pair 'sslrootcert' (File.new cert_file).absolute.path] + +## PRIVATE +default_postgres_host = Environment.get_or_else "PGHOST" "localhost" + +## PRIVATE +default_postgres_port = + hardcoded_port = 5432 + case Environment.get "PGPORT" of + Nothing -> hardcoded_port + port -> Integer.parse port . catch Parse_Error (_->hardcoded_port) + +## PRIVATE +default_postgres_database = Environment.get_or_else "PGDATABASE" "" diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso index e44db589c69bd..1442aae96367e 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso @@ -24,14 +24,13 @@ polyglot java import java.lang.StringBuilder as Java_String_Builder - host: The hostname of the database server. - port: The port of the database server. - database: The database to connect to. -read : Text -> Integer -> Text -> [Pair Text Text] -read host port database = +read : Text -> Integer -> Text -> Text -> [Pair Text Text] +read host port database username=Nothing = pgpass_file = locate if pgpass_file.is_nothing || (verify pgpass_file . not) then [] else entries = parse_file pgpass_file - # TODO possibly? determine username from env found = entries.find entry-> - entry.matches host port database + entry.matches host port database username case found.catch Nothing of Nothing -> [] entry -> [Pair 'user' entry.username, Pair 'password' entry.password] @@ -51,7 +50,7 @@ type Pgpass_Entry Text -> port self.port==normalized_port database_match = self.database==wildcard || self.database==database - username_match = username==Nothing || self.username==wildcard || self.username=username + username_match = username==Nothing || self.username==wildcard || self.username==username host_match && port_match && database_match && username_match ## PRIVATE @@ -98,7 +97,7 @@ parse_line line = existing_entries.append current_entry.toString current_entry.setLength 0 characters = line.characters - go ix is_escape = case ix>=line.length of + go ix is_escape = case ix>=characters.length of True -> if is_escape then # Handle the trailing escape character. @@ -110,19 +109,19 @@ parse_line line = True -> if is_escape then current_entry.append '\\' - go (ix+1) is_escape.not + @Tail_Call go (ix+1) is_escape.not False -> case c==':' of True -> case is_escape of True -> current_entry.append ':' False -> next_entry - go (ix+1) False + @Tail_Call go (ix+1) False False -> if is_escape then # Handle escape character followed by other characters. current_entry.append '\\' # Any other character is just appended and escape is reset. current_entry.append c - go (ix+1) False + @Tail_Call go (ix+1) False go 0 False existing_entries.to_vector diff --git a/test/Table_Tests/src/Database/Postgresql_Spec.enso b/test/Table_Tests/src/Database/Postgresql_Spec.enso index 657be231967f2..487f2fd97d2cd 100644 --- a/test/Table_Tests/src/Database/Postgresql_Spec.enso +++ b/test/Table_Tests/src/Database/Postgresql_Spec.enso @@ -202,43 +202,59 @@ connection_setup_spec = Test.group "[PostgreSQL] Connection setup" <| c3.database . should_equal "ensoDB" c3.jdbc_url . should_equal "jdbc:postgresql://192.168.0.1:1000/ensoDB" + ## Currently we require the port to be numeric. When we support + Unix-sockets, we may lift that restriction. + c4 = Environment.unsafe_with_environment_override "PGPORT" "foobar" <| + PostgreSQL + c4.host . should_equal "localhost" + c4.port . should_equal 5432 + c4.database . should_equal "" + c4.jdbc_url . should_equal "jdbc:postgresql://localhost:5432" + + add_ssl props = props+[Pair 'sslmode' 'prefer'] Test.specify "should use the given credentials" <| c = PostgreSQL credentials=(Credentials "myuser" "mypass") c.jdbc_url . should_equal "jdbc:postgresql://localhost:5432" - c.jdbc_properties . should_equal [Pair "user" "myuser", Pair "password" "mypass"] + c.jdbc_properties . should_equal <| add_ssl [Pair "user" "myuser", Pair "password" "mypass"] Test.specify "should fallback to environment variables and fill-out missing information based on the PGPASS file (if available)" <| c1 = PostgreSQL c1.jdbc_url . should_equal "jdbc:postgresql://localhost:5432" - c1.jdbc_properties . should_equal [] - Environment.unsafe_with_environment_override "PGPASS" "somepassword" <| + c1.jdbc_properties . should_equal <| add_ssl [] + Environment.unsafe_with_environment_override "PGPASSWORD" "somepassword" <| c1.jdbc_properties . should_fail_with Illegal_State_Error c1.jdbc_properties.catch.message . should_equal "PGPASSWORD is set, but PGUSER is not." Environment.unsafe_with_environment_override "PGUSER" "someuser" <| - c1.jdbc_properties . should_equal [Pair "user" "someuser", Pair "password" "somepassword"] + c1.jdbc_properties . should_equal <| add_ssl [Pair "user" "someuser", Pair "password" "somepassword"] c2 = PostgreSQL "192.168.4.0" 1234 "foo" c3 = PostgreSQL "::1" 55999 "database_name" c4 = PostgreSQL "::1" 55999 "otherDB" - c2.jdbc_properties . should_equal [] - c3.jdbc_properties . should_equal [] - c4.jdbc_properties . should_equal [] + c2.jdbc_properties . should_equal <| add_ssl [] + c3.jdbc_properties . should_equal <| add_ssl [] + c4.jdbc_properties . should_equal <| add_ssl [] - Environment.unsafe_with_environment_override "PGPASS" pgpass_file.absolute.path <| - c2.jdbc_properties . should_equal [Pair "user" "bar", Pair "password" "baz"] - c3.jdbc_properties . should_equal [Pair "user" "user_that_has_no_password", Pair "password" ""] - c4.jdbc_properties . should_equal [Pair "user" "*", Pair "password" "fallback_password"] + Environment.unsafe_with_environment_override "PGPASSFILE" pgpass_file.absolute.path <| + c2.jdbc_properties . should_equal <| add_ssl [Pair "user" "bar", Pair "password" "baz"] + c3.jdbc_properties . should_equal <| add_ssl [Pair "user" "user_that_has_no_password", Pair "password" ""] + c4.jdbc_properties . should_equal <| add_ssl [Pair "user" "*", Pair "password" "fallback_password"] + + Environment.unsafe_with_environment_override "PGUSER" "bar" <| + c2.jdbc_properties . should_equal <| add_ssl [Pair "user" "bar", Pair "password" "baz"] + [c3, c4].each c-> + c.jdbc_properties . should_equal <| + add_ssl [Pair "user" "*", Pair "password" "fallback_password"] Environment.unsafe_with_environment_override "PGUSER" "other user" <| - c2.jdbc_properties . should_equal [] - c3.jdbc_properties . should_equal [] - c4.jdbc_properties . should_equal [Pair "user" "other user", Pair "password" "fallback_password"] + [c2, c3, c4].each c-> + c.jdbc_properties . should_equal <| + add_ssl [Pair "user" "*", Pair "password" "fallback_password"] Environment.unsafe_with_environment_override "PGPASSWORD" "other password" <| [c2, c3, c4].each c-> - c.jdbc_properties . should_equal [Pair "user" "other user", Pair "password" "other password"] + c.jdbc_properties . should_equal <| add_ssl [Pair "user" "other user", Pair "password" "other password"] spec = table_spec