diff --git a/src/EdgeDB.Net.Driver/EdgeDBClient.cs b/src/EdgeDB.Net.Driver/EdgeDBClient.cs index a02fb911..af4d0e8c 100644 --- a/src/EdgeDB.Net.Driver/EdgeDBClient.cs +++ b/src/EdgeDB.Net.Driver/EdgeDBClient.cs @@ -146,19 +146,19 @@ private void RemoveClient(ulong id) /// /// This constructor uses the default config and will attempt to find your EdgeDB project toml file in the current /// working directory. If - /// no file is found this method will throw a . + /// no file is found this method will throw a . /// - public EdgeDBClient() : this(EdgeDBConnection.ResolveEdgeDBTOML(), new EdgeDBClientPoolConfig()) { } + public EdgeDBClient() : this(EdgeDBConnection.Create(), new EdgeDBClientPoolConfig()) { } /// /// Creates a new instance of a EdgeDB client pool allowing you to execute commands. /// /// /// This constructor will attempt to find your EdgeDB project toml file in the current working directory. If - /// no file is found this method will throw a . + /// no file is found this method will throw a . /// /// The config for this client pool. - public EdgeDBClient(EdgeDBClientPoolConfig clientPoolConfig) : this(EdgeDBConnection.ResolveEdgeDBTOML(), + public EdgeDBClient(EdgeDBClientPoolConfig clientPoolConfig) : this(EdgeDBConnection.Create(), clientPoolConfig) { } diff --git a/src/EdgeDB.Net.Driver/EdgeDBConnection.cs b/src/EdgeDB.Net.Driver/EdgeDBConnection.cs index 80f5d8df..c6ab8a8c 100644 --- a/src/EdgeDB.Net.Driver/EdgeDBConnection.cs +++ b/src/EdgeDB.Net.Driver/EdgeDBConnection.cs @@ -67,54 +67,6 @@ public sealed class EdgeDBConnection private const string CLOUD_PROFILE_ENV_NAME = "CLOUD_PROFILE"; private const int DOMAIN_NAME_MAX_LEN = 62; - private EdgeDBConnection MergeInto(EdgeDBConnection other) - { - other._hostname ??= _hostname; - other._port ??= _port; - if (other._branch is null && other._database is null) - { - if (_branch is not null) - { - other._branch = _branch; - } - else if (_database is not null) - { - other._database = _database; - } - } - other.Password ??= Password; - other._user ??= _user; - other._password ??= _password; - other.TLSCertificateAuthority ??= TLSCertificateAuthority; - other._tlsSecurity ??= _tlsSecurity; - return other; - } - - internal bool ValidateServerCertificateCallback(object sender, X509Certificate? certificate, X509Chain? chain, - SslPolicyErrors sslPolicyErrors) - { - if (TLSSecurity is TLSSecurityMode.Insecure) - return true; - - if (TLSCertificateAuthority is not null) - { - var cert = this.GetCertificate()!; - - X509Chain chain2 = new(); - chain2.ChainPolicy.ExtraStore.Add(cert); - chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; - chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; - - var isValid = chain2.Build(new X509Certificate2(certificate!)); - var chainRoot = chain2.ChainElements[^1].Certificate; - isValid = isValid && chainRoot.RawData.SequenceEqual(cert.RawData); - - return isValid; - } - - return sslPolicyErrors is SslPolicyErrors.None; - } - /// public override string ToString() { @@ -137,7 +89,7 @@ public override string ToString() #region Main connection args /// - /// Gets or sets the hostname of the edgedb instance to connect to. + /// Gets the hostname of the edgedb instance to connect to. /// /// /// This property defaults to localhost. @@ -145,168 +97,109 @@ public override string ToString() public string Hostname { get => _hostname ?? "localhost"; - set => _hostname = value; } + private string? _hostname; /// - /// Gets or sets the port of the edgedb instance to connect to. + /// Gets the port of the edgedb instance to connect to. /// /// /// This property defaults to 5656 /// - [JsonProperty("port")] public int Port { get => _port ?? 5656; - set => _port = value; } + private int? _port; /// - /// Gets or sets the database name to use when connecting. + /// Gets the database name to use when connecting. /// /// /// This property defaults to edgedb. It is mutually exclusive with . /// /// already contains a value; they're mutually exclusive - [JsonProperty("database")] public string? Database { get => _database ?? _branch ?? _defaultDatabase; - set - { - if (_branch is not null) - { - _branch = null; - } - - if (value == _defaultDatabase) - { - _database = null; - } - else - { - _database = value; - } - } } + private string? _database; private static readonly string _defaultDatabase = "edgedb"; /// - /// Gets or sets the branch name to use when connecting. + /// Gets the branch name to use when connecting. /// /// /// This property defaults to __default__. It is mutually exclusive with /// /// already contains a value; they're mutually exclusive - [JsonProperty("branch")] public string? Branch { get => _database ?? _branch ?? _defaultBranch; - set - { - if (_database is not null) - { - _database = null; - } - - if (value == _defaultBranch) - { - _branch = null; - } - else - { - _branch = value; - } - } } + private string? _branch; private static readonly string _defaultBranch = "__default__"; /// - /// Gets or sets the username used to connect to the database. + /// Gets the username used to connect to the database. /// /// /// This property defaults to edgedb /// - [JsonProperty("user")] public string Username { get => _user ?? "edgedb"; - set => _user = value; } + private string? _user; /// - /// Gets or sets the password to connect to the database. + /// Gets the password to connect to the database. /// - [JsonProperty("password")] - public string? Password { + public string? Password + { get => _password ?? ""; - set => _password = value; } + private string? _password; /// - /// Gets or sets the secret key used to authenticate with cloud instances. + /// Gets the secret key used to authenticate with cloud instances. /// - public string? SecretKey { get; set; } + public string? SecretKey { get; private set; } /// - /// Gets or sets the TLS Certificate Authority. + /// Gets the TLS Certificate Authority. /// - [JsonProperty("tls_ca")] - public string? TLSCertificateAuthority { get; set; } + public string? TLSCertificateAuthority { get; private set; } /// - /// Gets or sets the TLS security level. + /// Gets the TLS security level. /// /// /// The default value is . /// - [JsonProperty("tls_security")] public TLSSecurityMode TLSSecurity { get => _tlsSecurity ?? TLSSecurityMode.Strict; - set => _tlsSecurity = value; } + private TLSSecurityMode? _tlsSecurity; /// - /// Gets or sets the TLS server name to be used. + /// Gets the TLS server name to be used. /// /// /// Overrides the value provided by Hostname. /// - [JsonProperty("tls_server_name")] - public string? TLSServerName { get; set; } + public string? TLSServerName { get; private set; } /// - /// Gets or sets the number of miliseconds a client will wait for a connection to be + /// Gets the number of miliseconds a client will wait for a connection to be /// established with the server. /// - [JsonProperty("wait_until_available")] public int WaitUntilAvailable { get => _waitUntilAvailable ?? 30000; - set => _waitUntilAvailable = value; } - - /// - /// Gets or sets the name of the cloud profile to use to resolve the . - /// - /// - /// The default cloud profile is called 'default' - /// - public string CloudProfile - { - get => _cloudProfile ?? _defaultCloudProfile; - set - { - if (value is null) - { - throw new ArgumentNullException(nameof(value), "Cloud Profile must not be null"); - } - - _cloudProfile = value; - } - } - private static readonly string _defaultCloudProfile = "default"; + private int? _waitUntilAvailable; /// /// Additional settings for the server connection. @@ -314,21 +207,7 @@ public string CloudProfile /// /// This currently has no effect. /// - public Dictionary ServerSettings { get; set; } = new(); - - #endregion - - #region Backing fields - - private string? _hostname; - private int? _port; - private string? _database; - private string? _branch; - private string? _user; - private string? _password; - private TLSSecurityMode? _tlsSecurity; - private int? _waitUntilAvailable; - private string? _cloudProfile; + public Dictionary ServerSettings { get; private set; } = new(); #endregion @@ -901,21 +780,6 @@ internal static EdgeDBConnection _FromResolvedFields(ConfigUtils.ResolvedFields }; } - /// - /// Creates an from a - /// valid DSN. - /// - /// The DSN to create the connection from. - /// A representing the DSN. - /// A query parameter has already been defined in the DSN. - /// Port was not in the correct format of int. - /// A file parameter wasn't found. - /// An environment variable couldn't be found. - public static EdgeDBConnection FromDSN(string dsn) - { - return _FromResolvedFields(_FromDSN(dsn, null), null); - } - static private readonly Regex _dsnRegex = new( @"^(?:(?:edgedb|gel|(?\w+))://)" + @"(?:" @@ -1196,18 +1060,6 @@ internal static ConfigUtils.ResolvedFields _FromDSN(string dsn, ISystemProvider? return resolvedFields; } - /// - /// Creates a new EdgeDBConnection from a .toml project file. - /// - /// The path to the .toml project file. - /// A representing the project defined in the .toml file. - /// The supplied file path, credentials path, or instance-name file doesn't exist. - /// The project directory doesn't exist for the supplied toml file. - public static EdgeDBConnection FromProjectFile(string path) - { - return _FromResolvedFields(_FromProjectFile(path, null), null); - } - internal static ConfigUtils.ResolvedFields _FromProjectFile(string path, ISystemProvider? platform) { platform ??= ConfigUtils.DefaultPlatformProvider; @@ -1238,25 +1090,6 @@ internal static ConfigUtils.ResolvedFields _FromProjectFile(string path, ISystem return resolvedFields; } - /// - /// Creates a new from an instance name. - /// - /// - /// This method supports both local instances and cloud instances. Environment - /// variables will not be applied to the returned , - /// instead, use to - /// apply environment variables. - /// - /// The name of the instance. - /// The optional cloud profile if the instance name is a cloud instance. - /// A containing connection details for the specific instance. - /// The instances config file couldn't be found. - /// The configuration is invalid. - public static EdgeDBConnection FromInstanceName(string name, string? cloudProfile = null) - { - return _FromResolvedFields(_FromInstanceName(name, cloudProfile, null), null); - } - internal static ConfigUtils.ResolvedFields _FromInstanceName(string name, string? cloudProfile, ISystemProvider? platform) { platform ??= ConfigUtils.DefaultPlatformProvider; @@ -1284,22 +1117,6 @@ internal static ConfigUtils.ResolvedFields _FromInstanceName(string name, string throw new ConfigurationException($"Invalid instance name '{name}'"); } - /// - /// Resolves a connection by traversing the current working directory and its parents - /// to find an 'edgedb.toml' file. - /// - /// A resolved . - /// No 'edgedb.toml' file could be found. - public static EdgeDBConnection ResolveEdgeDBTOML() - { - ConfigUtils.ResolvedFields? resolvedFields = _ResolveEdgeDBTOML(null); - if (resolvedFields is null) - { - throw new ConfigurationException("Couldn't resolve gel.toml file"); - } - return _FromResolvedFields(resolvedFields, null); - } - internal static ConfigUtils.ResolvedFields? _ResolveEdgeDBTOML(ISystemProvider? platform) { platform ??= ConfigUtils.DefaultPlatformProvider; @@ -1323,6 +1140,7 @@ public static EdgeDBConnection ResolveEdgeDBTOML() } } + private static readonly string _defaultCloudProfile = "default"; private static ConfigUtils.ResolvedFields ParseCloudInstanceName( string name, string? secretKey, string? cloudProfile, ISystemProvider? platform) { @@ -1379,247 +1197,6 @@ private static ConfigUtils.ResolvedFields ParseCloudInstanceName( }; } - /// - /// Parses the provided arguments to build an class; Parse logic follows - /// the - /// Priority levels - /// of arguments. - /// - /// The instance name to connect to. - /// A DSN string or cloud instance name. - /// A configuration delegate. - /// Whether or not to autoresolve a connection using . - /// - /// A class that can be used to connect to a EdgeDB instance. - /// - /// - /// An error occured while parsing or configuring the . - /// - /// A configuration file could not be found. - public static EdgeDBConnection Parse(string? instance = null, string? dsn = null, - Action? configure = null, bool autoResolve = true) - { - return _Parse(instance, dsn, configure, autoResolve, null); - } - - internal static EdgeDBConnection _Parse(string? instance, string? dsn, - Action? configure, bool autoResolve, ISystemProvider? platform) - { - platform ??= ConfigUtils.DefaultPlatformProvider; - - EdgeDBConnection? connection = null; - - // try to resolve the toml, don't do this for cloud-like conn params. - if (autoResolve && !((instance is not null && instance.Contains('/')) || - (dsn is not null && !dsn.StartsWith("edgedb://") && !dsn.StartsWith("gel://")))) - { - ConfigUtils.ResolvedFields? resolvedFields = _ResolveEdgeDBTOML(platform); - if (resolvedFields is not null) - { - connection = _FromResolvedFields(resolvedFields, platform); - } - } - - #region Old Env - - var envName = string.Empty; - var envVar = string.Empty; - - if (platform.GetGelEnvVariable(CLOUD_PROFILE_ENV_NAME, out envName, out envVar)) - { - connection ??= new EdgeDBConnection(); - connection.CloudProfile = envVar; - } - - if (platform.GetGelEnvVariable(SECRET_KEY_ENV_NAME, out envName, out envVar)) - { - connection ??= new EdgeDBConnection(); - connection.SecretKey = envVar; - } - - if (platform.GetGelEnvVariable(INSTANCE_ENV_NAME, out envName, out envVar)) - { - var fromInst = _FromResolvedFields(_FromInstanceName(envVar, null, platform), platform); - connection = connection?.MergeInto(fromInst) ?? fromInst; - } - - if (platform.GetGelEnvVariable(DSN_ENV_NAME, out envName, out envVar)) - { - var fromDSN = _FromResolvedFields(_FromDSN(envVar, platform), platform); - connection = connection?.MergeInto(fromDSN) ?? fromDSN; - } - - if (platform.GetGelEnvVariable(HOST_ENV_NAME, out envName, out envVar)) - { - connection ??= new EdgeDBConnection(); - try - { - connection.Hostname = envVar; - } - catch (ConfigurationException x) - { - switch (x.Message) - { - case "DSN cannot contain more than one host": - throw new ConfigurationException( - $"Enviroment variable '{envName}' cannot contain more than one host", x); - default: - throw; - } - } - } - - if (platform.GetGelEnvVariable(PORT_ENV_NAME, out envName, out envVar)) - { - connection ??= new EdgeDBConnection(); - - if (!int.TryParse(envVar, out var port)) - throw new ConfigurationException( - $"Expected integer for environment variable '{envName}' but got '{envVar}'"); - - connection.Port = port; - } - - if (platform.GetGelEnvVariable(CREDENTIALS_FILE_ENV_NAME, out envName, out envVar)) - { - // check if file exists - var path = envVar; - if (!platform.FileExists(path)) - throw new FileNotFoundException( - $"Could not find the file specified in '{envName}'"); - - var credentials = JsonConvert.DeserializeObject(platform.FileReadAllText(path))!; - connection = connection?.MergeInto(credentials) ?? credentials; - } - - if (platform.GetGelEnvVariable(USER_ENV_NAME, out envName, out envVar)) - { - connection ??= new EdgeDBConnection(); - connection.Username = envVar; - } - - if (platform.GetGelEnvVariable(PASSWORD_ENV_NAME, out envName, out envVar)) - { - connection ??= new EdgeDBConnection(); - connection.Password = envVar; - } - - if (platform.GetGelEnvVariable(DATABASE_ENV_NAME, out envName, out envVar)) - { - var altName = string.Empty; - var altVal = string.Empty; - if (platform.GetGelEnvVariable(BRANCH_ENV_NAME, out altName, out altVal)) - throw new ArgumentException($"{envName} and {altName} are mutually exclusive"); - - connection ??= new EdgeDBConnection(); - - connection.Database = envVar; - } - - if (platform.GetGelEnvVariable(BRANCH_ENV_NAME, out envName, out envVar)) - { - connection ??= new EdgeDBConnection(); - - connection.Branch = envVar; - } - - { - string clientSecurityEnvName; - string clientTlsSecurityEnvName; - TLSSecurityMode? clientSecurity = null; - TLSSecurityMode? clientTlsSecurity = null; - if (platform.GetGelEnvVariable(CLIENT_SECURITY_ENV_NAME, out clientSecurityEnvName, out envVar)) - { - connection ??= new EdgeDBConnection(); - - clientSecurity = TLSSecurityModeParser.Parse(envVar); - if (clientSecurity == TLSSecurityMode.Default) - { - // ignore explicit defaults - clientSecurity = null; - } - - if (clientSecurity is not null) - { - connection.TLSSecurity = clientSecurity.Value; - } - } - if (platform.GetGelEnvVariable(CLIENT_TLS_SECURITY_ENV_NAME, out clientTlsSecurityEnvName, out envVar)) - { - connection ??= new EdgeDBConnection(); - - clientTlsSecurity = TLSSecurityModeParser.Parse(envVar); - if (clientTlsSecurity == TLSSecurityMode.Default) - { - // ignore explicit defaults - clientTlsSecurity = null; - } - - if (clientTlsSecurity is null) - { - // do nothing - } - else if (clientSecurity is null) - { - // overwrite default value - connection.TLSSecurity = clientTlsSecurity.Value; - } - else if (clientSecurity == TLSSecurityMode.Strict - && clientTlsSecurity != TLSSecurityMode.Strict) - { - throw new ConfigurationException( - $"{clientSecurityEnvName}=strict but {clientTlsSecurityEnvName}={envVar}. " - + $"{clientTlsSecurityEnvName} must be strict when {clientSecurityEnvName} " - + $"is strict" - ); - } - else - { - // overwrite existing value - connection.TLSSecurity = clientTlsSecurity.Value; - } - } - } - - #endregion - - if (instance is not null) - { - var fromInst = _FromResolvedFields(_FromInstanceName(instance, null, platform), platform); - connection = connection?.MergeInto(fromInst) ?? fromInst; - } - - if (dsn is not null) - { - if (Regex.IsMatch(dsn, @"^([A-Za-z0-9](-?[A-Za-z0-9])*)\/([A-Za-z0-9](-?[A-Za-z0-9])*)$")) - { - // cloud - var fromCloud = _FromResolvedFields(ParseCloudInstanceName(dsn, connection?.SecretKey, null, platform), platform); - connection = connection?.MergeInto(fromCloud) ?? fromCloud; - } - else - { - var fromDSN = _FromResolvedFields(_FromDSN(dsn, platform), platform); - connection = connection?.MergeInto(fromDSN) ?? fromDSN; - } - } - - if (configure is not null) - { - connection ??= new EdgeDBConnection(); - - var cloned = (EdgeDBConnection)connection.MemberwiseClone()!; - configure(cloned); - - if (dsn is not null && cloned._hostname is not null) - throw new ConfigurationException("Cannot specify DSN and 'Hostname'; they are mutually exclusive"); - - connection = connection.MergeInto(cloned); - } - - return connection ?? new EdgeDBConnection(); - } - #endregion #region HTTP-based connection methods @@ -1638,4 +1215,29 @@ internal string GetExecUri() => _execUri ??= GetBaseUri() + $"/db/{Database}"; #endregion + + internal bool ValidateServerCertificateCallback(object sender, X509Certificate? certificate, X509Chain? chain, + SslPolicyErrors sslPolicyErrors) + { + if (TLSSecurity is TLSSecurityMode.Insecure) + return true; + + if (TLSCertificateAuthority is not null) + { + var cert = this.GetCertificate()!; + + X509Chain chain2 = new(); + chain2.ChainPolicy.ExtraStore.Add(cert); + chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; + chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + + var isValid = chain2.Build(new X509Certificate2(certificate!)); + var chainRoot = chain2.ChainElements[^1].Certificate; + isValid = isValid && chainRoot.RawData.SequenceEqual(cert.RawData); + + return isValid; + } + + return sslPolicyErrors is SslPolicyErrors.None; + } } diff --git a/src/EdgeDB.Net.Driver/Extensions/EdgeDBHostingExtensions.cs b/src/EdgeDB.Net.Driver/Extensions/EdgeDBHostingExtensions.cs index 9ba83a8e..2573726f 100644 --- a/src/EdgeDB.Net.Driver/Extensions/EdgeDBHostingExtensions.cs +++ b/src/EdgeDB.Net.Driver/Extensions/EdgeDBHostingExtensions.cs @@ -22,7 +22,7 @@ public static class EdgeDBHostingExtensions public static IServiceCollection AddEdgeDB(this IServiceCollection collection, EdgeDBConnection? connection = null, Action? clientConfig = null) { - var conn = connection ?? EdgeDBConnection.ResolveEdgeDBTOML(); + var conn = connection ?? EdgeDBConnection.Create(); collection.AddSingleton(conn); collection.AddSingleton(provider => diff --git a/tests/EdgeDB.Tests.Unit/ConnectionTests.cs b/tests/EdgeDB.Tests.Unit/ConnectionTests.cs index b681487f..bcb3ddc0 100644 --- a/tests/EdgeDB.Tests.Unit/ConnectionTests.cs +++ b/tests/EdgeDB.Tests.Unit/ConnectionTests.cs @@ -1,207 +1,12 @@ -using EdgeDB.Abstractions; using EdgeDB.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; namespace EdgeDB.Tests.Unit; [TestClass] public class ConnectionTests { - #region Parse - - [TestMethod] - public void HostAndUser() => - Expect(ParseConnection(configure: x => - { - x.Username = "user"; - x.Hostname = "localhost"; - }), new EdgeDBConnection - { - Hostname = "localhost", - Port = 5656, - Username = "user", - Database = "edgedb", - TLSSecurity = TLSSecurityMode.Strict - }); - - [TestMethod] - public void AllEnviromentVariables() => - Expect( - ParseConnection(envVars: new Dictionary - { - {"EDGEDB_USER", "user"}, - {"EDGEDB_DATABASE", "testdb"}, - {"EDGEDB_PASSWORD", "passw"}, - {"EDGEDB_HOST", "host"}, - {"EDGEDB_PORT", "123"} - }), new EdgeDBConnection - { - Hostname = "host", - Port = 123, - Username = "user", - Password = "passw", - Database = "testdb", - TLSSecurity = TLSSecurityMode.Strict - }); - - [TestMethod] - public void OptionsBeforeEnv() => - Expect(ParseConnection(configure: x => - { - x.Hostname = "host2"; - x.Port = 456; - x.Username = "user2"; - x.Password = "passw2"; - x.Database = "db2"; - }, - envVars: new Dictionary - { - {"EDGEDB_USER", "user"}, - {"EDGEDB_DATABASE", "testdb"}, - {"EDGEDB_PASSWORD", "passw"}, - {"EDGEDB_HOST", "host"}, - {"EDGEDB_PORT", "123"} - }), new EdgeDBConnection - { - Hostname = "host2", - Port = 456, - Username = "user2", - Password = "passw2", - Database = "db2", - TLSSecurity = TLSSecurityMode.Strict - }); - - [TestMethod] - public void DSNBeforeEnv() => - Expect( - ParseConnection("edgedb://user3:123123@localhost:5555/abcdef", - envVars: new Dictionary - { - {"EDGEDB_USER", "user"}, - {"EDGEDB_DATABASE", "testdb"}, - {"EDGEDB_PASSWORD", "passw"}, - {"EDGEDB_HOST", "host"}, - {"EDGEDB_PORT", "123"} - }), - new EdgeDBConnection - { - Hostname = "localhost", - Port = 5555, - Username = "user3", - Password = "123123", - Database = "abcdef", - TLSSecurity = TLSSecurityMode.Strict - }); - - [TestMethod] - public void DSNOnly() => - Expect(ParseConnection("edgedb://user3:123123@localhost:5555/abcdef"), - new EdgeDBConnection - { - Hostname = "localhost", - Port = 5555, - Username = "user3", - Password = "123123", - Database = "abcdef", - TLSSecurity = TLSSecurityMode.Strict - }); - - [TestMethod] - public void DSNWithMultipleHosts() => - ExpectError(ParseConnection("edgedb://user@host1,host2/db"), - "Invalid host: \"host1,host2\", DSN cannot contain more than one host"); - - [TestMethod] - public void DSNWIthMultipleHostsAndPorts() => - ExpectError(ParseConnection("edgedb://user@host1:1111,host2:2222/db"), - "Invalid DSN: Could not parse host/port"); - - [TestMethod] - public void MultipleCompoundOptions() => - ExpectError( - ParseConnection("edgedb:///db", x => x.Hostname = "host1", - new Dictionary {{"EDGEDB_USER", "foo"}}), - "Cannot specify DSN and 'Hostname'; they are mutually exclusive"); - - [TestMethod] - public void DSNRequiresEdgeDBSchema() => - ExpectError(ParseConnection("pq:///dbname?host=/unix_sock/test&user=spam"), - "Invalid DSN scheme. Expected \"gel\" but got \"pq\""); - - [TestMethod] - public void TestConnectionFormat() - { - var connection = EdgeDBConnection.FromDSN("edgedb://user3:123123@localhost:5555/abcdef"); - - Assert.AreEqual("gel://user3:123123@localhost:5555/abcdef", connection.ToString()); - } - - private static void Expect(Result result, EdgeDBConnection expected) - { - Assert.IsNotNull(result.Connection); - var actual = result.Connection; - - Assert.AreEqual(expected.Username, actual.Username); - Assert.AreEqual(expected.Password, actual.Password); - Assert.AreEqual(expected.Hostname, actual.Hostname); - Assert.AreEqual(expected.Port, actual.Port); - Assert.AreEqual(expected.Database, actual.Database); - Assert.AreEqual(expected.TLSCertificateAuthority, actual.TLSCertificateAuthority); - Assert.AreEqual(expected.TLSSecurity, actual.TLSSecurity); - } - - private static void ExpectError(Result result, string message) - { - Assert.IsNotNull(result.Exception); - Assert.IsInstanceOfType(result.Exception, typeof(TError), - $"Exception type {typeof(TError)} expected but got {result.Exception.GetType()}"); - Assert.AreEqual(message, result.Exception.Message); - } - - private static Result ParseConnection(string? dsn = null, Action? configure = null, - Dictionary? envVars = null) - { - try - { - MockSystemProvider mockSystem = new(envVars ?? new()); - - return EdgeDBConnection._Parse(instance: null, dsn: dsn, configure: configure, autoResolve: false, platform: mockSystem); - } - catch (Exception x) - { - return x; - } - } - - private class Result - { - public EdgeDBConnection? Connection { get; init; } - public Exception? Exception { get; init; } - - public static implicit operator Result(EdgeDBConnection c) => new() {Connection = c}; - public static implicit operator Result(Exception x) => new() {Exception = x}; - } - - private class MockSystemProvider : BaseDefaultSystemProvider - { - private readonly Dictionary _envVars; - - public MockSystemProvider(Dictionary envVars) - { - _envVars = envVars; - } - - public override string? GetEnvVariable(string name) - => _envVars.TryGetValue(name, out var val) - ? val - : null; - } - - #endregion - #region Wait until available [TestMethod]