public static string GetSkipReason(ServerFeatures serverFeatures, ConfigSettings configSettings)
        {
            if (!AppConfig.SupportedFeatures.HasFlag(serverFeatures))
            {
                return($"Requires ServerFeatures.{serverFeatures}");
            }

            if (configSettings == ConfigSettings.None)
            {
                return(null);
            }

            var csb = AppConfig.CreateConnectionStringBuilder();

            if (configSettings.HasFlag(ConfigSettings.RequiresSsl) && (csb.SslMode == MySqlSslMode.None
#if !BASELINE
                                                                       || csb.SslMode == MySqlSslMode.Preferred
#endif
                                                                       ))
            {
                return("Requires SslMode=Required or higher in connection string");
            }

            if (configSettings.HasFlag(ConfigSettings.TrustedHost) &&
                (csb.SslMode == MySqlSslMode.None ||
#if !BASELINE
                 csb.SslMode == MySqlSslMode.Preferred ||
#endif
                 csb.SslMode == MySqlSslMode.Required))
            {
                return("Requires SslMode=VerifyCA or higher in connection string");
            }

            if (configSettings.HasFlag(ConfigSettings.UntrustedHost) &&
                (csb.SslMode == MySqlSslMode.VerifyCA || csb.SslMode == MySqlSslMode.VerifyFull))
            {
                return("Requires SslMode=Required or lower in connection string");
            }

            if (configSettings.HasFlag(ConfigSettings.KnownClientCertificate))
            {
                if (!((csb.CertificateFile?.EndsWith("ssl-client.pfx", StringComparison.OrdinalIgnoreCase) ?? false) || (csb.SslKey?.EndsWith("ssl-client-key.pem", StringComparison.OrdinalIgnoreCase) ?? false)))
                {
                    return("Requires CertificateFile=client.pfx in connection string");
                }
            }

            if (configSettings.HasFlag(ConfigSettings.PasswordlessUser) && string.IsNullOrWhiteSpace(AppConfig.PasswordlessUser))
            {
                return("Requires PasswordlessUser in config.json");
            }

            if (configSettings.HasFlag(ConfigSettings.GSSAPIUser) && string.IsNullOrWhiteSpace(AppConfig.GSSAPIUser))
            {
                return("Requires GSSAPIUser in config.json");
            }

            if (configSettings.HasFlag(ConfigSettings.HasKerberos) && !AppConfig.HasKerberos)
            {
                return("Requires HasKerberos in config.json");
            }

            if (configSettings.HasFlag(ConfigSettings.CsvFile) && string.IsNullOrWhiteSpace(AppConfig.MySqlBulkLoaderCsvFile))
            {
                return("Requires MySqlBulkLoaderCsvFile in config.json");
            }

            if (configSettings.HasFlag(ConfigSettings.LocalCsvFile) && string.IsNullOrWhiteSpace(AppConfig.MySqlBulkLoaderLocalCsvFile))
            {
                return("Requires MySqlBulkLoaderLocalCsvFile in config.json");
            }

            if (configSettings.HasFlag(ConfigSettings.TsvFile) && string.IsNullOrWhiteSpace(AppConfig.MySqlBulkLoaderTsvFile))
            {
                return("Requires MySqlBulkLoaderTsvFile in config.json");
            }

            if (configSettings.HasFlag(ConfigSettings.LocalTsvFile) && string.IsNullOrWhiteSpace(AppConfig.MySqlBulkLoaderLocalTsvFile))
            {
                return("Requires MySqlBulkLoaderLocalTsvFile in config.json");
            }

            if (configSettings.HasFlag(ConfigSettings.TcpConnection) && ((csb.Server.StartsWith("/", StringComparison.Ordinal) || csb.Server.StartsWith("./", StringComparison.Ordinal)) || csb.ConnectionProtocol != MySqlConnectionProtocol.Sockets))
            {
                return("Requires a TCP connection");
            }

            if (configSettings.HasFlag(ConfigSettings.SecondaryDatabase) && string.IsNullOrEmpty(AppConfig.SecondaryDatabase))
            {
                return("Requires SecondaryDatabase in config.json");
            }

            return(null);
        }
        public async Task ClearConnectionPool()
        {
            var csb = AppConfig.CreateConnectionStringBuilder();

            csb.Pooling         = true;
            csb.MinimumPoolSize = 0;
            csb.MaximumPoolSize = 3;

            var connections = new List <MySqlConnection>();

            for (int i = 0; i < csb.MaximumPoolSize; i++)
            {
                var connection = new MySqlConnection(csb.ConnectionString);
                connections.Add(connection);
            }

            Func <HashSet <long> > getConnectionIds = () =>
            {
                var cids = GetConnectionIds(connections);
                Assert.Equal(connections.Count, cids.Count);
                return(cids);
            };

            Func <Task> openConnections = async() =>
            {
                foreach (var connection in connections)
                {
                    await connection.OpenAsync();
                }
            };

            Action closeConnections = () =>
            {
                foreach (var connection in connections)
                {
                    connection.Close();
                }
            };

            // connections should all be disposed when returned to pool
            await openConnections();

            var connectionIds = getConnectionIds();

            await ClearPoolAsync(connections[0]);

            closeConnections();
            await openConnections();

            var connectionIds2 = getConnectionIds();

            Assert.Empty(connectionIds.Intersect(connectionIds2));
            closeConnections();

            // connections should all be disposed in ClearPoolAsync
            await ClearPoolAsync(connections[0]);
            await openConnections();

            var connectionIds3 = getConnectionIds();

            Assert.Empty(connectionIds2.Intersect(connectionIds3));
            closeConnections();

            // some connections may be disposed in ClearPoolAsync, others in OpenAsync
            var clearTask = ClearPoolAsync(connections[0]);

            await openConnections();

            var connectionIds4 = GetConnectionIds(connections);

            Assert.Empty(connectionIds3.Intersect(connectionIds4));
            await clearTask;

            closeConnections();

            foreach (var connection in connections)
            {
                connection.Dispose();
            }
        }