diff --git a/pom.xml b/pom.xml index 73ffe765b..2efed71a0 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,7 @@ 1.15.1 6.14.3 1.10.19 + 2.27.2 3.2.0 3.0.0-M1 1.6.8 @@ -151,6 +152,12 @@ ${mockito.version} test + + com.github.tomakehurst + wiremock-jre8 + ${wiremock.version} + test + diff --git a/src/main/java/ru/yandex/clickhouse/ClickHouseConnectionImpl.java b/src/main/java/ru/yandex/clickhouse/ClickHouseConnectionImpl.java index d5edba5ae..e767bd445 100644 --- a/src/main/java/ru/yandex/clickhouse/ClickHouseConnectionImpl.java +++ b/src/main/java/ru/yandex/clickhouse/ClickHouseConnectionImpl.java @@ -111,7 +111,13 @@ public ClickHouseStatement createStatement() throws SQLException { } public ClickHouseStatement createStatement(int resultSetType) throws SQLException { - return LogProxy.wrap(ClickHouseStatement.class, new ClickHouseStatementImpl(httpclient, this, properties, resultSetType)); + return LogProxy.wrap( + ClickHouseStatement.class, + new ClickHouseStatementImpl( + httpclient, + this, + properties, + resultSetType)); } @Deprecated @@ -126,15 +132,37 @@ public TimeZone getTimeZone() { } private ClickHouseStatement createClickHouseStatement(CloseableHttpClient httpClient) throws SQLException { - return LogProxy.wrap(ClickHouseStatement.class, new ClickHouseStatementImpl(httpClient, this, properties, DEFAULT_RESULTSET_TYPE)); + return LogProxy.wrap( + ClickHouseStatement.class, + new ClickHouseStatementImpl( + httpClient, + this, + properties, + DEFAULT_RESULTSET_TYPE)); } public PreparedStatement createPreparedStatement(String sql, int resultSetType) throws SQLException { - return LogProxy.wrap(PreparedStatement.class, new ClickHousePreparedStatementImpl(httpclient, this, properties, sql, getTimeZone(), resultSetType)); + return LogProxy.wrap( + PreparedStatement.class, + new ClickHousePreparedStatementImpl( + httpclient, + this, + properties, + sql, + getTimeZone(), + resultSetType)); } public ClickHousePreparedStatement createClickHousePreparedStatement(String sql, int resultSetType) throws SQLException { - return LogProxy.wrap(ClickHousePreparedStatement.class, new ClickHousePreparedStatementImpl(httpclient, this, properties, sql, getTimeZone(), resultSetType)); + return LogProxy.wrap( + ClickHousePreparedStatement.class, + new ClickHousePreparedStatementImpl( + httpclient, + this, + properties, + sql, + getTimeZone(), + resultSetType)); } @@ -408,12 +436,13 @@ public boolean isValid(int timeout) throws SQLException { return false; } finally { - if (isAnotherHttpClient) + if (isAnotherHttpClient) { try { closeableHttpClient.close(); } catch (IOException e) { log.warn("Can't close a http client", e); } + } } } @@ -462,22 +491,27 @@ public boolean isWrapperFor(Class iface) throws SQLException { return iface.isAssignableFrom(getClass()); } + @Override public void setSchema(String schema) throws SQLException { properties.setDatabase(schema); } + @Override public String getSchema() throws SQLException { return properties.getDatabase(); } + @Override public void abort(Executor executor) throws SQLException { this.close(); } + @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { } + @Override public int getNetworkTimeout() throws SQLException { return 0; } diff --git a/src/main/java/ru/yandex/clickhouse/ClickHousePreparedStatementImpl.java b/src/main/java/ru/yandex/clickhouse/ClickHousePreparedStatementImpl.java index e5e1fae0c..bd4cf4cb6 100644 --- a/src/main/java/ru/yandex/clickhouse/ClickHousePreparedStatementImpl.java +++ b/src/main/java/ru/yandex/clickhouse/ClickHousePreparedStatementImpl.java @@ -1,26 +1,48 @@ package ru.yandex.clickhouse; -import org.apache.http.entity.AbstractHttpEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import ru.yandex.clickhouse.response.ClickHouseResponse; -import ru.yandex.clickhouse.settings.ClickHouseProperties; -import ru.yandex.clickhouse.settings.ClickHouseQueryParam; -import ru.yandex.clickhouse.util.ClickHouseArrayUtil; -import ru.yandex.clickhouse.util.ClickHouseValueFormatter; -import ru.yandex.clickhouse.util.guava.StreamUtils; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; import java.sql.Date; -import java.sql.*; -import java.util.*; +import java.sql.NClob; +import java.sql.ParameterMetaData; +import java.sql.Ref; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.RowId; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLSyntaxErrorException; +import java.sql.SQLXML; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.http.entity.AbstractHttpEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import ru.yandex.clickhouse.response.ClickHouseResponse; +import ru.yandex.clickhouse.settings.ClickHouseProperties; +import ru.yandex.clickhouse.settings.ClickHouseQueryParam; +import ru.yandex.clickhouse.util.ClickHouseArrayUtil; +import ru.yandex.clickhouse.util.ClickHouseValueFormatter; +import ru.yandex.clickhouse.util.guava.StreamUtils; + public class ClickHousePreparedStatementImpl extends ClickHouseStatementImpl implements ClickHousePreparedStatement { @@ -36,11 +58,11 @@ public class ClickHousePreparedStatementImpl extends ClickHouseStatementImpl imp private final ClickHousePreparedStatementParameter[] binds; private final List> parameterList; private final boolean insertBatchMode; - private List batchRows = new ArrayList(); + private List batchRows = new ArrayList<>(); - public ClickHousePreparedStatementImpl(CloseableHttpClient client, ClickHouseConnection connection, - ClickHouseProperties properties, String sql, TimeZone serverTimeZone, - int resultSetType) throws SQLException + public ClickHousePreparedStatementImpl(CloseableHttpClient client, + ClickHouseConnection connection, ClickHouseProperties properties, String sql, + TimeZone serverTimeZone, int resultSetType) throws SQLException { super(client, connection, properties, resultSetType); this.sql = sql; @@ -295,7 +317,7 @@ public void addBatch() throws SQLException { private List buildBatch() throws SQLException { checkBinded(); - List newBatches = new ArrayList(parameterList.size()); + List newBatches = new ArrayList<>(parameterList.size()); StringBuilder sb = new StringBuilder(); for (int i = 0, p = 0; i < parameterList.size(); i++) { List pList = parameterList.get(i); @@ -338,7 +360,7 @@ public int[] executeBatch(Map additionalDBParams) sendStream(entity, insertSql, additionalDBParams); int[] result = new int[batchRows.size()]; Arrays.fill(result, 1); - batchRows = new ArrayList(); + batchRows = new ArrayList<>(); return result; } diff --git a/src/main/java/ru/yandex/clickhouse/ClickHouseStatementImpl.java b/src/main/java/ru/yandex/clickhouse/ClickHouseStatementImpl.java index 19bcc402a..89c10a556 100644 --- a/src/main/java/ru/yandex/clickhouse/ClickHouseStatementImpl.java +++ b/src/main/java/ru/yandex/clickhouse/ClickHouseStatementImpl.java @@ -1,12 +1,28 @@ package ru.yandex.clickhouse; -import com.google.common.base.Strings; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; + import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; @@ -16,35 +32,34 @@ import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import com.google.common.base.Strings; + import ru.yandex.clickhouse.domain.ClickHouseFormat; import ru.yandex.clickhouse.except.ClickHouseException; import ru.yandex.clickhouse.except.ClickHouseExceptionSpecifier; -import ru.yandex.clickhouse.response.*; +import ru.yandex.clickhouse.response.ClickHouseLZ4Stream; +import ru.yandex.clickhouse.response.ClickHouseResponse; +import ru.yandex.clickhouse.response.ClickHouseResponseSummary; +import ru.yandex.clickhouse.response.ClickHouseResultSet; +import ru.yandex.clickhouse.response.ClickHouseScrollableResultSet; +import ru.yandex.clickhouse.response.FastByteArrayOutputStream; import ru.yandex.clickhouse.settings.ClickHouseProperties; import ru.yandex.clickhouse.settings.ClickHouseQueryParam; +import ru.yandex.clickhouse.util.ClickHouseHttpClientBuilder; import ru.yandex.clickhouse.util.ClickHouseRowBinaryInputStream; import ru.yandex.clickhouse.util.ClickHouseStreamCallback; import ru.yandex.clickhouse.util.Utils; import ru.yandex.clickhouse.util.guava.StreamUtils; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.SQLWarning; -import java.util.*; - - public class ClickHouseStatementImpl extends ConfigurableApi implements ClickHouseStatement { private static final Logger log = LoggerFactory.getLogger(ClickHouseStatementImpl.class); private final CloseableHttpClient client; + private final HttpClientContext httpContext; + protected ClickHouseProperties properties; private ClickHouseConnection connection; @@ -79,10 +94,12 @@ public class ClickHouseStatementImpl extends ConfigurableApi(ClickHouseQueryParam.class); + additionalDBParams = new EnumMap<>(ClickHouseQueryParam.class); } else { - additionalDBParams = new EnumMap(additionalDBParams); + additionalDBParams = new EnumMap<>(additionalDBParams); } additionalDBParams.put(ClickHouseQueryParam.EXTREMES, "0"); @@ -621,7 +638,7 @@ private InputStream getInputStream( HttpPost post = new HttpPost(uri); post.setEntity(requestEntity); - HttpResponse response = client.execute(post); + HttpResponse response = client.execute(post, httpContext); entity = response.getEntity(); checkForErrorAndThrow(entity, response); @@ -687,7 +704,7 @@ private List getUrlQueryParams( Map additionalRequestParams, boolean ignoreDatabase ) { - List result = new ArrayList(); + List result = new ArrayList<>(); if (sql != null) { result.add(new BasicNameValuePair("query", sql)); @@ -755,17 +772,21 @@ private boolean isQueryParamSet(ClickHouseQueryParam param, Map additionalClickHouseDBParams, Map additionalRequestParams) { - if (additionalRequestParams != null && additionalRequestParams.containsKey(param.getKey()) && !Strings.isNullOrEmpty(additionalRequestParams.get(param.getKey()))) + if (additionalRequestParams != null && additionalRequestParams.containsKey(param.getKey()) && !Strings.isNullOrEmpty(additionalRequestParams.get(param.getKey()))) { return additionalRequestParams.get(param.getKey()); + } - if (getRequestParams().containsKey(param.getKey()) && !Strings.isNullOrEmpty(getRequestParams().get(param.getKey()))) + if (getRequestParams().containsKey(param.getKey()) && !Strings.isNullOrEmpty(getRequestParams().get(param.getKey()))) { return getRequestParams().get(param.getKey()); + } - if (additionalClickHouseDBParams != null && additionalClickHouseDBParams.containsKey(param) && !Strings.isNullOrEmpty(additionalClickHouseDBParams.get(param))) + if (additionalClickHouseDBParams != null && additionalClickHouseDBParams.containsKey(param) && !Strings.isNullOrEmpty(additionalClickHouseDBParams.get(param))) { return additionalClickHouseDBParams.get(param); + } - if (getAdditionalDBParams().containsKey(param) && !Strings.isNullOrEmpty(getAdditionalDBParams().get(param))) + if (getAdditionalDBParams().containsKey(param) && !Strings.isNullOrEmpty(getAdditionalDBParams().get(param))) { return getAdditionalDBParams().get(param); + } return properties.asProperties().getProperty(param.getKey()); } @@ -775,7 +796,7 @@ private URI followRedirects(URI uri) throws IOException, URISyntaxException { int redirects = 0; while (redirects < properties.getMaxRedirects()) { HttpGet httpGet = new HttpGet(uri); - HttpResponse response = client.execute(httpGet); + HttpResponse response = client.execute(httpGet, httpContext); if (response.getStatusLine().getStatusCode() == 307) { uri = new URI(response.getHeaders("Location")[0].getValue()); redirects++; @@ -896,7 +917,7 @@ void sendStream(Writer writer, HttpEntity content) throws ClickHouseException { httpPost.addHeader("Content-Encoding", writer.getCompression().name()); } httpPost.setEntity(content); - HttpResponse response = client.execute(httpPost); + HttpResponse response = client.execute(httpPost, httpContext); entity = response.getEntity(); checkForErrorAndThrow(entity, response); @@ -932,10 +953,12 @@ private void checkForErrorAndThrow(HttpEntity entity, HttpResponse response) thr } } + @Override public void closeOnCompletion() throws SQLException { closeOnCompletion = true; } + @Override public boolean isCloseOnCompletion() throws SQLException { return closeOnCompletion; } diff --git a/src/main/java/ru/yandex/clickhouse/settings/ClickHouseProperties.java b/src/main/java/ru/yandex/clickhouse/settings/ClickHouseProperties.java index 14ce0774f..b368917e9 100644 --- a/src/main/java/ru/yandex/clickhouse/settings/ClickHouseProperties.java +++ b/src/main/java/ru/yandex/clickhouse/settings/ClickHouseProperties.java @@ -1,11 +1,11 @@ package ru.yandex.clickhouse.settings; -import ru.yandex.clickhouse.util.apache.StringUtils; - import java.util.HashMap; import java.util.Map; import java.util.Properties; +import ru.yandex.clickhouse.util.apache.StringUtils; + public class ClickHouseProperties { @@ -302,22 +302,42 @@ public ClickHouseProperties(ClickHouseProperties properties) { } public Map buildQueryParams(boolean ignoreDatabase){ - Map params = new HashMap(); + Map params = new HashMap<>(); - if (maxParallelReplicas != null) params.put(ClickHouseQueryParam.MAX_PARALLEL_REPLICAS, String.valueOf(maxParallelReplicas)); - if (maxPartitionsPerInsertBlock != null) params.put(ClickHouseQueryParam.MAX_PARTITIONS_PER_INSERT_BLOCK, String.valueOf(maxPartitionsPerInsertBlock)); - if (maxRowsToGroupBy != null) params.put(ClickHouseQueryParam.MAX_ROWS_TO_GROUP_BY, String.valueOf(maxRowsToGroupBy)); - if (totalsMode != null) params.put(ClickHouseQueryParam.TOTALS_MODE, totalsMode); - if (quotaKey != null) params.put(ClickHouseQueryParam.QUOTA_KEY, quotaKey); - if (priority != null) params.put(ClickHouseQueryParam.PRIORITY, String.valueOf(priority)); + if (maxParallelReplicas != null) { + params.put(ClickHouseQueryParam.MAX_PARALLEL_REPLICAS, String.valueOf(maxParallelReplicas)); + } + if (maxPartitionsPerInsertBlock != null) { + params.put(ClickHouseQueryParam.MAX_PARTITIONS_PER_INSERT_BLOCK, String.valueOf(maxPartitionsPerInsertBlock)); + } + if (maxRowsToGroupBy != null) { + params.put(ClickHouseQueryParam.MAX_ROWS_TO_GROUP_BY, String.valueOf(maxRowsToGroupBy)); + } + if (totalsMode != null) { + params.put(ClickHouseQueryParam.TOTALS_MODE, totalsMode); + } + if (quotaKey != null) { + params.put(ClickHouseQueryParam.QUOTA_KEY, quotaKey); + } + if (priority != null) { + params.put(ClickHouseQueryParam.PRIORITY, String.valueOf(priority)); + } - if (!StringUtils.isBlank(database) && !ignoreDatabase) params.put(ClickHouseQueryParam.DATABASE, getDatabase()); + if (!StringUtils.isBlank(database) && !ignoreDatabase) { + params.put(ClickHouseQueryParam.DATABASE, getDatabase()); + } - if (compress) params.put(ClickHouseQueryParam.COMPRESS, "1"); - if (decompress) params.put(ClickHouseQueryParam.DECOMPRESS, "1"); + if (compress) { + params.put(ClickHouseQueryParam.COMPRESS, "1"); + } + if (decompress) { + params.put(ClickHouseQueryParam.DECOMPRESS, "1"); + } - if (extremes) params.put(ClickHouseQueryParam.EXTREMES, "1"); + if (extremes) { + params.put(ClickHouseQueryParam.EXTREMES, "1"); + } if (StringUtils.isBlank(profile)) { if (getMaxThreads() != null) { @@ -336,13 +356,16 @@ public Map buildQueryParams(boolean ignoreDatabase params.put(ClickHouseQueryParam.PROFILE, profile); } - if (user != null) params.put(ClickHouseQueryParam.USER, user); - if (password != null) params.put(ClickHouseQueryParam.PASSWORD, password); - - if (distributedAggregationMemoryEfficient) params.put(ClickHouseQueryParam.DISTRIBUTED_AGGREGATION_MEMORY_EFFICIENT, "1"); + if (distributedAggregationMemoryEfficient) { + params.put(ClickHouseQueryParam.DISTRIBUTED_AGGREGATION_MEMORY_EFFICIENT, "1"); + } - if (maxBytesBeforeExternalGroupBy != null) params.put(ClickHouseQueryParam.MAX_BYTES_BEFORE_EXTERNAL_GROUP_BY, String.valueOf(maxBytesBeforeExternalGroupBy)); - if (maxBytesBeforeExternalSort != null) params.put(ClickHouseQueryParam.MAX_BYTES_BEFORE_EXTERNAL_SORT, String.valueOf(maxBytesBeforeExternalSort)); + if (maxBytesBeforeExternalGroupBy != null) { + params.put(ClickHouseQueryParam.MAX_BYTES_BEFORE_EXTERNAL_GROUP_BY, String.valueOf(maxBytesBeforeExternalGroupBy)); + } + if (maxBytesBeforeExternalSort != null) { + params.put(ClickHouseQueryParam.MAX_BYTES_BEFORE_EXTERNAL_SORT, String.valueOf(maxBytesBeforeExternalSort)); + } if (maxMemoryUsage != null) { params.put(ClickHouseQueryParam.MAX_MEMORY_USAGE, String.valueOf(maxMemoryUsage)); } @@ -421,8 +444,9 @@ private T getSetting(Properties info, ClickHouseConnectionSettings settings) @SuppressWarnings("unchecked") private T getSetting(Properties info, String key, Object defaultValue, Class clazz){ String val = info.getProperty(key); - if (val == null) + if (val == null) { return (T)defaultValue; + } if (clazz == int.class || clazz == Integer.class) { return (T) clazz.cast(Integer.valueOf(val)); } @@ -974,16 +998,18 @@ public Properties getProperties() { public ClickHouseProperties merge(ClickHouseProperties second){ Properties properties = this.asProperties(); - for (Map.Entry entry : second.asProperties().entrySet()) + for (Map.Entry entry : second.asProperties().entrySet()) { properties.put(entry.getKey(), entry.getValue()); + } return new ClickHouseProperties(properties); } public ClickHouseProperties merge(Properties other){ Properties properties = this.asProperties(); - for (Map.Entry entry : other.entrySet()) + for (Map.Entry entry : other.entrySet()) { properties.put(entry.getKey(), entry.getValue()); + } return new ClickHouseProperties(properties); } diff --git a/src/main/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilder.java b/src/main/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilder.java index 34a3abec1..59e893147 100644 --- a/src/main/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilder.java +++ b/src/main/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilder.java @@ -1,30 +1,5 @@ package ru.yandex.clickhouse.util; -import org.apache.http.*; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.config.ConnectionConfig; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.DefaultConnectionReuseStrategy; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.message.BasicHeader; -import org.apache.http.message.BasicHeaderElementIterator; -import org.apache.http.protocol.HTTP; -import org.apache.http.protocol.HttpContext; -import ru.yandex.clickhouse.settings.ClickHouseProperties; -import ru.yandex.clickhouse.util.ssl.NonValidatingTrustManager; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -44,6 +19,47 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import org.apache.http.ConnectionReuseStrategy; +import org.apache.http.Header; +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.ConnectionConfig; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.DefaultConnectionReuseStrategy; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; +import org.apache.http.protocol.HttpContext; + +import ru.yandex.clickhouse.settings.ClickHouseProperties; +import ru.yandex.clickhouse.util.ssl.NonValidatingTrustManager; + public class ClickHouseHttpClientBuilder { private final ClickHouseProperties properties; @@ -59,11 +75,26 @@ public CloseableHttpClient buildClient() throws Exception { .setDefaultConnectionConfig(getConnectionConfig()) .setDefaultRequestConfig(getRequestConfig()) .setDefaultHeaders(getDefaultHeaders()) + .setDefaultCredentialsProvider(getDefaultCredentialsProvider()) .disableContentCompression() // gzip здесь ни к чему. Используется lz4 при compress=1 .disableRedirectHandling() .build(); } + public static HttpClientContext createClientContext(ClickHouseProperties props) { + if (props == null + || !isConfigurationValidForAuth(props)) + { + return HttpClientContext.create(); + } + AuthCache authCache = new BasicAuthCache(); + BasicScheme basicAuth = new BasicScheme(); + authCache.put(getTargetHost(props), basicAuth); + HttpClientContext ctx = HttpClientContext.create(); + ctx.setAuthCache(authCache); + return ctx; + } + private ConnectionReuseStrategy getConnectionReuseStrategy() { return new DefaultConnectionReuseStrategy() { @Override @@ -117,7 +148,7 @@ private RequestConfig getRequestConfig() { } private Collection
getDefaultHeaders() { - List
headers = new ArrayList
(); + List
headers = new ArrayList<>(); if (properties.getHttpAuthorization() != null) { headers.add(new BasicHeader(HttpHeaders.AUTHORIZATION, properties.getHttpAuthorization())); } @@ -147,7 +178,7 @@ public long getKeepAliveDuration(HttpResponse httpResponse, HttpContext httpCont }; } - private SSLContext getSSLContext() + private SSLContext getSSLContext() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { SSLContext ctx = SSLContext.getInstance("TLS"); TrustManager[] tms = null; @@ -210,4 +241,31 @@ private KeyStore getKeyStore() caInputStream.close(); } } + + private CredentialsProvider getDefaultCredentialsProvider() { + if (!isConfigurationValidForAuth(properties)) { + return null; + } + HttpHost targetHost = getTargetHost(properties); + CredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials( + new AuthScope(targetHost.getHostName(), targetHost.getPort()), + new UsernamePasswordCredentials( + properties.getUser() != null ? properties.getUser() : "default", + properties.getPassword() != null ? properties.getPassword() : "")); + return credsProvider; + } + + private static HttpHost getTargetHost(ClickHouseProperties props) { + return new HttpHost( + props.getHost(), + props.getPort(), + props.getSsl() ? "https" : "http"); + } + + private static boolean isConfigurationValidForAuth(ClickHouseProperties props) { + return props.getHost() != null + && props.getHttpAuthorization() == null + && (props.getUser() != null || props.getPassword() != null); + } } diff --git a/src/test/java/ru/yandex/clickhouse/BalancedClickhouseDataSourceTest.java b/src/test/java/ru/yandex/clickhouse/BalancedClickhouseDataSourceTest.java index 61f69325a..b21c4b21b 100644 --- a/src/test/java/ru/yandex/clickhouse/BalancedClickhouseDataSourceTest.java +++ b/src/test/java/ru/yandex/clickhouse/BalancedClickhouseDataSourceTest.java @@ -1,15 +1,18 @@ package ru.yandex.clickhouse; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import ru.yandex.clickhouse.settings.ClickHouseProperties; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.util.Arrays; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import ru.yandex.clickhouse.settings.ClickHouseProperties; + import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; public class BalancedClickhouseDataSourceTest { @@ -46,7 +49,6 @@ public void testUrlSplitInvalidHostName() throws Exception { } - @BeforeTest public void setUp() throws Exception { dataSource = ClickHouseContainerForTest.newBalancedDataSource(); @@ -54,7 +56,6 @@ public void setUp() throws Exception { doubleDataSource = ClickHouseContainerForTest.newBalancedDataSource(address, address); } - @Test public void testSingleDatabaseConnection() throws Exception { Connection connection = dataSource.getConnection(); @@ -77,7 +78,6 @@ public void testSingleDatabaseConnection() throws Exception { assertEquals(42, rs.getInt("i")); } - @Test public void testDoubleDatabaseConnection() throws Exception { Connection connection = doubleDataSource.getConnection(); @@ -116,7 +116,6 @@ public void testDoubleDatabaseConnection() throws Exception { } - @Test public void testCorrectActualizationDatabaseConnection() throws Exception { dataSource.actualize(); @@ -212,4 +211,105 @@ public void testConstructWithClickHouseProperties() { assertEquals(dataSource.getAllClickhouseUrls().get(1), "jdbc:clickhouse://" + ipAddr + "/click?socket_timeout=12345&user=readonly"); } + @Test + public void testConnectionWithAuth() throws SQLException { + final ClickHouseProperties properties = new ClickHouseProperties(); + final String hostAddr = ClickHouseContainerForTest.getClickHouseHttpAddress(); + final String ipAddr = ClickHouseContainerForTest.getClickHouseHttpAddress(true); + + final BalancedClickhouseDataSource dataSource0 = ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default?user=foo&password=bar", + properties, + hostAddr, + ipAddr); + assertTrue(dataSource0.getConnection().createStatement().execute("SELECT 1")); + + final BalancedClickhouseDataSource dataSource1 = ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default?user=foo", + properties, + hostAddr, + ipAddr); + // assertThrows(RuntimeException.class, + // () -> dataSource1.getConnection().createStatement().execute("SELECT 1")); + + + final BalancedClickhouseDataSource dataSource2 = ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default?user=oof", + properties, + hostAddr, + ipAddr); + assertTrue(dataSource2.getConnection().createStatement().execute("SELECT 1")); + + properties.setUser("foo"); + properties.setPassword("bar"); + final BalancedClickhouseDataSource dataSource3 = ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default", + properties, + hostAddr, + ipAddr); + assertTrue(dataSource3.getConnection().createStatement().execute("SELECT 1")); + + properties.setPassword("bar"); + final BalancedClickhouseDataSource dataSource4 = ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default?user=oof", + properties, + hostAddr, + ipAddr); + // JDK 1.8 + // assertThrows(RuntimeException.class, + // () -> dataSource4.getConnection().createStatement().execute("SELECT 1")); + try { + dataSource4.getConnection().createStatement().execute("SELECT 1"); + fail(); + } catch (RuntimeException re) { + // expected + } + + // it is not allowed to have query parameters per host + try { + ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default?user=oof", + properties, + hostAddr + "/default?user=foo&password=bar", + ipAddr); + fail(); + } catch (IllegalArgumentException iae) { + // expected + } + + // the following behavior is quite unexpected, honestly + // but query params always have precedence over properties + final BalancedClickhouseDataSource dataSource5 = ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default?user=foo&password=bar", + properties, + hostAddr, + ipAddr); + assertTrue( + dataSource5.getConnection("broken", "hacker").createStatement().execute("SELECT 1")); + + // now the other way round, also strange + final BalancedClickhouseDataSource dataSource6 = ClickHouseContainerForTest + .newBalancedDataSourceWithSuffix( + "default?user=broken&password=hacker", + properties, + hostAddr, + ipAddr); + // JDK 1.8 + // assertThrows(RuntimeException.class, + // () -> dataSource6.getConnection("foo", "bar").createStatement().execute("SELECT 1")); + try { + dataSource6.getConnection("foo", "bar").createStatement().execute("SELECT 1"); + fail(); + } catch (RuntimeException re) { + // expected + } + } + } diff --git a/src/test/java/ru/yandex/clickhouse/ClickHouseContainerForTest.java b/src/test/java/ru/yandex/clickhouse/ClickHouseContainerForTest.java index c98b649ee..05c2c1b2a 100644 --- a/src/test/java/ru/yandex/clickhouse/ClickHouseContainerForTest.java +++ b/src/test/java/ru/yandex/clickhouse/ClickHouseContainerForTest.java @@ -1,16 +1,16 @@ package ru.yandex.clickhouse; +import java.time.Duration; + +import org.testcontainers.containers.BindMode; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; import ru.yandex.clickhouse.settings.ClickHouseProperties; import ru.yandex.clickhouse.util.ClickHouseVersionNumberUtil; -import java.time.Duration; - -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.Wait; - import static java.time.temporal.ChronoUnit.SECONDS; public class ClickHouseContainerForTest { @@ -33,11 +33,15 @@ public class ClickHouseContainerForTest { } imageTag = ":" + imageTag; } - clickhouseContainer = new GenericContainer<>("yandex/clickhouse-server" + imageTag) + .withExposedPorts(HTTP_PORT, NATIVE_PORT, MYSQL_PORT) + .withClasspathResourceMapping( + "ru/yandex/clickhouse/users.d", + "/etc/clickhouse-server/users.d", + BindMode.READ_ONLY) .waitingFor(Wait.forHttp("/ping").forPort(HTTP_PORT).forStatusCode(200) - .withStartupTimeout(Duration.of(60, SECONDS))) - .withExposedPorts(HTTP_PORT, NATIVE_PORT, MYSQL_PORT); + .withStartupTimeout(Duration.of(60, SECONDS))); + } public static String getClickHouseVersion() { @@ -110,13 +114,13 @@ public static BalancedClickhouseDataSource newBalancedDataSourceWithSuffix(Strin return new BalancedClickhouseDataSource(url.toString(), properties); } - @BeforeSuite - public void beforeSuite() { + @BeforeSuite() + public static void beforeSuite() { clickhouseContainer.start(); } - @AfterSuite - public void afterSuite() { + @AfterSuite() + public static void afterSuite() { clickhouseContainer.stop(); } } diff --git a/src/test/java/ru/yandex/clickhouse/ClickHouseStatementTest.java b/src/test/java/ru/yandex/clickhouse/ClickHouseStatementTest.java index c45738411..337910976 100644 --- a/src/test/java/ru/yandex/clickhouse/ClickHouseStatementTest.java +++ b/src/test/java/ru/yandex/clickhouse/ClickHouseStatementTest.java @@ -73,37 +73,38 @@ public void testCredentials() throws SQLException, URISyntaxException { assertEquals(withCredentials.getPassword(), "test_password"); ClickHouseStatementImpl statement = new ClickHouseStatementImpl( - HttpClientBuilder.create().build(),null, withCredentials, ResultSet.TYPE_FORWARD_ONLY - ); + HttpClientBuilder.create().build(), + null, withCredentials, ResultSet.TYPE_FORWARD_ONLY); URI uri = statement.buildRequestUri(null, null, null, null, false); String query = uri.getQuery(); - assertTrue(query.contains("password=test_password")); - assertTrue(query.contains("user=test_user")); + // we use Basic AUTH nowadays + assertFalse(query.contains("password=test_password")); + assertFalse(query.contains("user=test_user")); } @Test public void testMaxExecutionTime() throws Exception { ClickHouseProperties properties = new ClickHouseProperties(); properties.setMaxExecutionTime(20); - ClickHouseStatementImpl statement = new ClickHouseStatementImpl(HttpClientBuilder.create().build(), null, - properties, ResultSet.TYPE_FORWARD_ONLY); + ClickHouseStatementImpl statement = new ClickHouseStatementImpl(HttpClientBuilder.create().build(), + null, properties, ResultSet.TYPE_FORWARD_ONLY); URI uri = statement.buildRequestUri(null, null, null, null, false); String query = uri.getQuery(); assertTrue(query.contains("max_execution_time=20"), "max_execution_time param is missing in URL"); - + statement.setQueryTimeout(10); uri = statement.buildRequestUri(null, null, null, null, false); query = uri.getQuery(); assertTrue(query.contains("max_execution_time=10"), "max_execution_time param is missing in URL"); } - + @Test public void testMaxMemoryUsage() throws Exception { ClickHouseProperties properties = new ClickHouseProperties(); properties.setMaxMemoryUsage(41L); - ClickHouseStatementImpl statement = new ClickHouseStatementImpl(HttpClientBuilder.create().build(), null, - properties, ResultSet.TYPE_FORWARD_ONLY); + ClickHouseStatementImpl statement = new ClickHouseStatementImpl(HttpClientBuilder.create().build(), + null, properties, ResultSet.TYPE_FORWARD_ONLY); URI uri = statement.buildRequestUri(null, null, null, null, false); String query = uri.getQuery(); diff --git a/src/test/java/ru/yandex/clickhouse/integration/ClickHouseConnectionImplTest.java b/src/test/java/ru/yandex/clickhouse/integration/ClickHouseConnectionImplTest.java new file mode 100644 index 000000000..990581e5e --- /dev/null +++ b/src/test/java/ru/yandex/clickhouse/integration/ClickHouseConnectionImplTest.java @@ -0,0 +1,94 @@ +package ru.yandex.clickhouse.integration; + +import java.sql.Connection; + +import javax.sql.DataSource; + +import org.testng.annotations.Test; + +import ru.yandex.clickhouse.ClickHouseContainerForTest; +import ru.yandex.clickhouse.settings.ClickHouseProperties; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +public class ClickHouseConnectionImplTest { + + @Test + public void testDefaultEmpty() throws Exception { + assertSuccess(createDataSource(null, null)); + } + + @Test + public void testDefaultUserOnly() throws Exception { + assertSuccess(createDataSource("default", null)); + } + + @Test + public void testDefaultUserEmptyPassword() throws Exception { + assertSuccess(createDataSource("default", "")); + } + + @Test + public void testDefaultUserPass() throws Exception { + assertFailure(createDataSource("default", "bar")); + } + + @Test + public void testDefaultPass() throws Exception { + assertFailure(createDataSource(null, "bar")); + } + + @Test + public void testFooEmpty() throws Exception { + assertFailure(createDataSource("foo", null)); + } + + @Test + public void testFooWrongPass() throws Exception { + assertFailure(createDataSource("foo", "baz")); + } + + @Test + public void testFooPass() throws Exception { + assertSuccess(createDataSource("foo", "bar")); + } + + @Test + public void testFooWrongUser() throws Exception { + assertFailure(createDataSource("baz", "bar")); + } + + @Test + public void testOofNoPassword() throws Exception { + assertSuccess(createDataSource("oof", null)); + } + + @Test + public void testOofWrongPassword() throws Exception { + assertFailure(createDataSource("oof", "baz")); + } + + private static void assertSuccess(DataSource dataSource) throws Exception { + Connection connection = dataSource.getConnection(); + assertTrue(connection.createStatement().execute("SELECT 1")); + } + + private static void assertFailure(DataSource dataSource) throws Exception { + // grrr, no JDK 1.8 + // assertThrows(SQLException.class, () -> dataSource.getConnection()); + try { + dataSource.getConnection(); + fail(); + } catch (RuntimeException e) { + // exppected + } + } + + private static DataSource createDataSource(String user, String password) { + ClickHouseProperties props = new ClickHouseProperties(); + props.setUser(user); + props.setPassword(password); + return ClickHouseContainerForTest.newDataSource(props); + } +} diff --git a/src/test/java/ru/yandex/clickhouse/integration/ClickHouseStatementImplTest.java b/src/test/java/ru/yandex/clickhouse/integration/ClickHouseStatementImplTest.java index a1c6556c4..6700534b3 100644 --- a/src/test/java/ru/yandex/clickhouse/integration/ClickHouseStatementImplTest.java +++ b/src/test/java/ru/yandex/clickhouse/integration/ClickHouseStatementImplTest.java @@ -36,6 +36,7 @@ import static org.testng.AssertJUnit.assertTrue; public class ClickHouseStatementImplTest { + private ClickHouseDataSource dataSource; private ClickHouseConnection connection; @@ -223,12 +224,12 @@ public void testSelectQueryStartingWithWith() throws SQLException { public void cancelTest_queryId_is_not_set() throws Exception { final ClickHouseStatement firstStatement = dataSource.getConnection().createStatement(); - final AtomicReference exceptionAtomicReference = new AtomicReference(); + final AtomicReference exceptionAtomicReference = new AtomicReference<>(); Thread thread = new Thread() { @Override public void run() { try { - Map params = new EnumMap(ClickHouseQueryParam.class); + Map params = new EnumMap<>(ClickHouseQueryParam.class); params.put(ClickHouseQueryParam.CONNECT_TIMEOUT, Long.toString(TimeUnit.MINUTES.toMillis(1))); firstStatement.executeQuery("SELECT count() FROM system.numbers", params); } catch (Exception e) { @@ -261,12 +262,12 @@ public void cancelTest_queryId_is_set() throws Exception { final ClickHouseStatement firstStatement = dataSource.getConnection().createStatement(); final CountDownLatch countDownLatch = new CountDownLatch(1); - final AtomicReference exceptionAtomicReference = new AtomicReference(); + final AtomicReference exceptionAtomicReference = new AtomicReference<>(); Thread thread = new Thread() { @Override public void run() { try { - Map params = new EnumMap(ClickHouseQueryParam.class); + Map params = new EnumMap<>(ClickHouseQueryParam.class); params.put(ClickHouseQueryParam.CONNECT_TIMEOUT, Long.toString(TimeUnit.MINUTES.toMillis(1))); params.put(ClickHouseQueryParam.QUERY_ID, queryId); countDownLatch.countDown(); diff --git a/src/test/java/ru/yandex/clickhouse/settings/ClickHousePropertiesTest.java b/src/test/java/ru/yandex/clickhouse/settings/ClickHousePropertiesTest.java index 094aa5dfe..7818fa969 100644 --- a/src/test/java/ru/yandex/clickhouse/settings/ClickHousePropertiesTest.java +++ b/src/test/java/ru/yandex/clickhouse/settings/ClickHousePropertiesTest.java @@ -1,14 +1,16 @@ package ru.yandex.clickhouse.settings; +import java.net.URI; +import java.util.Map; +import java.util.Properties; + import org.testng.Assert; import org.testng.annotations.Test; + import ru.yandex.clickhouse.BalancedClickhouseDataSource; import ru.yandex.clickhouse.ClickHouseDataSource; -import java.net.URI; -import java.util.Map; -import java.util.Properties; - +import static org.testng.Assert.assertFalse; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; @@ -143,6 +145,8 @@ public void buildQueryParamsTest() { clickHouseProperties.setMaxInsertBlockSize(42L); clickHouseProperties.setInsertDeduplicate(true); clickHouseProperties.setInsertDistributedSync(true); + clickHouseProperties.setUser("myUser"); + clickHouseProperties.setPassword("myPassword"); Map clickHouseQueryParams = clickHouseProperties.buildQueryParams(true); Assert.assertEquals(clickHouseQueryParams.get(ClickHouseQueryParam.INSERT_QUORUM), "3"); @@ -151,6 +155,8 @@ public void buildQueryParamsTest() { Assert.assertEquals(clickHouseQueryParams.get(ClickHouseQueryParam.MAX_INSERT_BLOCK_SIZE), "42"); Assert.assertEquals(clickHouseQueryParams.get(ClickHouseQueryParam.INSERT_DEDUPLICATE), "1"); Assert.assertEquals(clickHouseQueryParams.get(ClickHouseQueryParam.INSERT_DISTRIBUTED_SYNC), "1"); + assertFalse(clickHouseQueryParams.containsKey(ClickHouseQueryParam.USER)); + assertFalse(clickHouseQueryParams.containsKey(ClickHouseQueryParam.PASSWORD)); } @Test diff --git a/src/test/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilderTest.java b/src/test/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilderTest.java new file mode 100644 index 000000000..e7cc88027 --- /dev/null +++ b/src/test/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilderTest.java @@ -0,0 +1,147 @@ +package ru.yandex.clickhouse.util; + +import org.apache.http.HttpHost; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; + +import ru.yandex.clickhouse.settings.ClickHouseProperties; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; + + +public class ClickHouseHttpClientBuilderTest { + + private static WireMockServer mockServer; + + @BeforeClass + public static void beforeAll() { + mockServer = new WireMockServer( + WireMockConfiguration.wireMockConfig().dynamicPort()); + mockServer.start(); + } + + @AfterMethod + public void afterTest() { + mockServer.resetAll(); + } + + @AfterClass + public static void afterAll() { + mockServer.stop(); + mockServer = null; + } + + @Test + public void testCreateClientContextNull() { + assertNull(ClickHouseHttpClientBuilder.createClientContext(null).getAuthCache()); + } + + @Test + public void testCreateClientContextNoUserNoPass() { + assertNull(ClickHouseHttpClientBuilder.createClientContext(new ClickHouseProperties()) + .getAuthCache()); + } + + @Test + public void testCreateClientContextNoHost() { + ClickHouseProperties props = new ClickHouseProperties(); + props.setUser("myUser"); + props.setPassword("mySecret"); + assertNull(ClickHouseHttpClientBuilder.createClientContext(props).getAuthCache()); + } + + @Test + public void testCreateClientContextUserPass() { + ClickHouseProperties props = new ClickHouseProperties(); + props.setUser("myUser"); + props.setPassword("mySecret"); + props.setHost("127.0.0.1"); + assertEquals( + ClickHouseHttpClientBuilder.createClientContext(props).getAuthCache() + .get(HttpHost.create("http://127.0.0.1:80")).getSchemeName(), + "basic"); + } + + @Test + public void testCreateClientContextOnlyUser() { + ClickHouseProperties props = new ClickHouseProperties(); + props.setUser("myUser"); + props.setHost("127.0.0.1"); + assertEquals( + ClickHouseHttpClientBuilder.createClientContext(props).getAuthCache() + .get(HttpHost.create("http://127.0.0.1:80")).getSchemeName(), + "basic"); + } + + @Test + public void testCreateClientContextOnlyPass() { + ClickHouseProperties props = new ClickHouseProperties(); + props.setPassword("myPass"); + props.setHost("127.0.0.1"); + assertEquals( + ClickHouseHttpClientBuilder.createClientContext(props).getAuthCache() + .get(HttpHost.create("http://127.0.0.1:80")).getSchemeName(), + "basic"); + } + + + @Test(dataProvider = "authUserPassword") + public void testHttpAuthParametersCombination(String authorization, String user, + String password, String expectedAuthHeader) throws Exception + { + ClickHouseProperties props = new ClickHouseProperties(); + props.setHost("localhost"); + props.setPort(mockServer.port()); + props.setUser(user); + props.setPassword(password); + props.setHttpAuthorization(authorization); + CloseableHttpClient client = new ClickHouseHttpClientBuilder(props).buildClient(); + HttpPost post = new HttpPost(mockServer.baseUrl()); + client.execute(post, ClickHouseHttpClientBuilder.createClientContext(props)); + mockServer.verify( + postRequestedFor(WireMock.anyUrl()) + .withHeader("Authorization", equalTo(expectedAuthHeader))); + } + + @DataProvider(name = "authUserPassword") + private static Object[][] provideAuthUserPasswordTestData() { + return new Object[][] { + { + "Digest username=\"foo\"", null, null, "Digest username=\"foo\"" + }, + { + "Digest username=\"foo\"", "bar", null, "Digest username=\"foo\"" + }, + { + "Digest username=\"foo\"", null, "baz", "Digest username=\"foo\"" + }, + { + "Digest username=\"foo\"", "bar", "baz", "Digest username=\"foo\"" + }, + { + null, "bar", "baz", "Basic YmFyOmJheg==" // bar:baz + }, + { + null, "bar", null, "Basic YmFyOg==" // bar: + }, + { + null, null, "baz", "Basic ZGVmYXVsdDpiYXo=" // default:baz + }, + }; + + } + +} diff --git a/src/test/resources/ru/yandex/clickhouse/users.d/foo.xml b/src/test/resources/ru/yandex/clickhouse/users.d/foo.xml new file mode 100644 index 000000000..5083e230b --- /dev/null +++ b/src/test/resources/ru/yandex/clickhouse/users.d/foo.xml @@ -0,0 +1,12 @@ + + + + default + + ::/0 + + bar + default + + + diff --git a/src/test/resources/ru/yandex/clickhouse/users.d/oof.xml b/src/test/resources/ru/yandex/clickhouse/users.d/oof.xml new file mode 100644 index 000000000..24c239f08 --- /dev/null +++ b/src/test/resources/ru/yandex/clickhouse/users.d/oof.xml @@ -0,0 +1,12 @@ + + + + default + + ::/0 + + default + + + +