/*
* Licensed to Crate under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership. Crate licenses this file
* to you under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial
* agreement.
*/
package io.crate.protocols.postgres;
import io.crate.action.sql.SQLOperations;
import io.crate.action.sql.SessionContext;
import io.crate.executor.Executor;
import io.crate.operation.auth.AuthenticationProvider;
import io.crate.operation.collect.stats.JobsLogs;
import io.crate.test.integration.CrateDummyClusterServiceUnitTest;
import io.crate.testing.SQLExecutor;
import org.elasticsearch.common.settings.Settings;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.codec.embedder.DecoderEmbedder;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.*;
public class ConnectionContextTest extends CrateDummyClusterServiceUnitTest {
private SQLOperations sqlOperations;
private List<SQLOperations.Session> sessions = new ArrayList<>();
@Before
public void prepare() {
SQLExecutor e = SQLExecutor.builder(clusterService).build();
sqlOperations = new SQLOperations(
e.analyzer,
e.planner,
() -> mock(Executor.class),
new JobsLogs(() -> true),
Settings.EMPTY,
clusterService
) {
@Override
public Session createSession(SessionContext sessionContext) {
Session session = super.createSession(sessionContext);
sessions.add(session);
return session;
}
};
}
@Test
public void testHandleEmptySimpleQuery() throws Exception {
ConnectionContext ctx = new ConnectionContext(mock(SQLOperations.class), AuthenticationProvider.NOOP_AUTH);
ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();
Messages.writeCString(channelBuffer, ";".getBytes(StandardCharsets.UTF_8));
Channel channel = mock(Channel.class);
ctx.handleSimpleQuery(channelBuffer, channel);
ArgumentCaptor<ChannelBuffer> argumentCaptor = ArgumentCaptor.forClass(ChannelBuffer.class);
// once for EmptyQueryResponse and a second time for ReadyForQuery
verify(channel, times(2)).write(argumentCaptor.capture());
ChannelBuffer firstResponse = argumentCaptor.getAllValues().get(0);
byte[] responseBytes = new byte[5];
firstResponse.readBytes(responseBytes);
assertThat(responseBytes, is(new byte[]{'I', 0, 0, 0, 4}));
}
@Test
public void testFlushMessageResultsInSyncCallOnSession() throws Exception {
SQLOperations sqlOperations = mock(SQLOperations.class);
SQLOperations.Session session = mock(SQLOperations.Session.class);
when(sqlOperations.createSession(any(SessionContext.class))).thenReturn(session);
ConnectionContext ctx = new ConnectionContext(sqlOperations, AuthenticationProvider.NOOP_AUTH);
DecoderEmbedder<ChannelBuffer> e = new DecoderEmbedder<>(ctx.decoder, ctx.handler);
ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
ClientMessages.sendStartupMessage(buffer, "doc");
ClientMessages.sendParseMessage(buffer, "", "select ?", new int[0]);
ClientMessages.sendFlush(buffer);
e.offer(buffer);
verify(session, times(1)).sync();
}
@Test
public void testBindMessageCanBeReadIfTypeForParamsIsUnknown() throws Exception {
ConnectionContext ctx = new ConnectionContext(sqlOperations, AuthenticationProvider.NOOP_AUTH);
DecoderEmbedder<ChannelBuffer> e = new DecoderEmbedder<>(ctx.decoder, ctx.handler);
ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
ClientMessages.sendStartupMessage(buffer, "doc");
ClientMessages.sendParseMessage(buffer, "S1", "select ?, ?", new int[0]); // no type hints for parameters
List<Object> params = Arrays.asList(10, 20);
ClientMessages.sendBindMessage(buffer, "P1", "S1", params);
e.offer(buffer);
SQLOperations.Session session = sessions.get(0);
// If the query can be retrieved via portalName it means bind worked
assertThat(session.getQuery("P1"), is("select ?, ?"));
}
}