/** * Copyright 2015-2016 the original author or authors. * * Licensed 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. */ package org.glowroot.agent.plugin.cassandra; import java.util.Collections; import java.util.Iterator; import java.util.List; import com.datastax.driver.core.BatchStatement; import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Row; import com.datastax.driver.core.Session; import com.datastax.driver.core.SimpleStatement; import com.google.common.collect.Lists; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.glowroot.agent.it.harness.AppUnderTest; import org.glowroot.agent.it.harness.Container; import org.glowroot.agent.it.harness.TransactionMarker; import org.glowroot.wire.api.model.TraceOuterClass.Trace; import static org.assertj.core.api.Assertions.assertThat; public class CassandraAsyncIT { private static Container container; @BeforeClass public static void setUp() throws Exception { container = SharedSetupRunListener.getContainer(); } @AfterClass public static void tearDown() throws Exception { SharedSetupRunListener.close(container); } @After public void afterEachTest() throws Exception { container.checkAndReset(); } @Test public void shouldAsyncExecuteStatement() throws Exception { // when Trace trace = container.execute(ExecuteAsyncStatement.class); // then checkTimers(trace, false); Iterator<Trace.Entry> i = trace.getEntryList().iterator(); List<Trace.SharedQueryText> sharedQueryTexts = trace.getSharedQueryTextList(); Trace.Entry entry = i.next(); assertThat(entry.getDepth()).isEqualTo(0); assertThat(entry.getMessage()).isEmpty(); assertThat(sharedQueryTexts.get(entry.getQueryEntryMessage().getSharedQueryTextIndex()) .getFullText()).isEqualTo("SELECT * FROM test.users"); assertThat(entry.getQueryEntryMessage().getPrefix()).isEqualTo("cql execution: "); assertThat(entry.getQueryEntryMessage().getSuffix()).isEqualTo(" => 10 rows"); assertThat(i.hasNext()).isFalse(); } @Test public void shouldAsyncExecuteStatementReturningNoRecords() throws Exception { // when Trace trace = container.execute(ExecuteAsyncStatementReturningNoRecords.class); // then checkTimers(trace, false); Iterator<Trace.Entry> i = trace.getEntryList().iterator(); List<Trace.SharedQueryText> sharedQueryTexts = trace.getSharedQueryTextList(); Trace.Entry entry = i.next(); assertThat(entry.getDepth()).isEqualTo(0); assertThat(entry.getMessage()).isEmpty(); assertThat(sharedQueryTexts.get(entry.getQueryEntryMessage().getSharedQueryTextIndex()) .getFullText()).isEqualTo("SELECT * FROM test.users where id = 12345"); assertThat(entry.getQueryEntryMessage().getPrefix()).isEqualTo("cql execution: "); assertThat(entry.getQueryEntryMessage().getSuffix()).isEqualTo(" => 0 rows"); assertThat(i.hasNext()).isFalse(); } @Test public void shouldAsyncIterateUsingOneAndAll() throws Exception { // when Trace trace = container.execute(AsyncIterateUsingOneAndAll.class); // then checkTimers(trace, false); Iterator<Trace.Entry> i = trace.getEntryList().iterator(); List<Trace.SharedQueryText> sharedQueryTexts = trace.getSharedQueryTextList(); Trace.Entry entry = i.next(); assertThat(entry.getDepth()).isEqualTo(0); assertThat(entry.getMessage()).isEmpty(); assertThat(sharedQueryTexts.get(entry.getQueryEntryMessage().getSharedQueryTextIndex()) .getFullText()).isEqualTo("SELECT * FROM test.users"); assertThat(entry.getQueryEntryMessage().getPrefix()).isEqualTo("cql execution: "); assertThat(entry.getQueryEntryMessage().getSuffix()).isEqualTo(" => 10 rows"); assertThat(i.hasNext()).isFalse(); } @Test public void shouldAsyncExecuteBoundStatement() throws Exception { // when Trace trace = container.execute(AsyncExecuteBoundStatement.class); // then checkTimers(trace, true); Iterator<Trace.Entry> i = trace.getEntryList().iterator(); List<Trace.SharedQueryText> sharedQueryTexts = trace.getSharedQueryTextList(); Trace.Entry entry = i.next(); assertThat(entry.getDepth()).isEqualTo(0); assertThat(entry.getMessage()).isEmpty(); assertThat(sharedQueryTexts.get(entry.getQueryEntryMessage().getSharedQueryTextIndex()) .getFullText()) .isEqualTo("INSERT INTO test.users (id, fname, lname) VALUES (?, ?, ?)"); assertThat(entry.getQueryEntryMessage().getPrefix()).isEqualTo("cql execution: "); assertThat(entry.getQueryEntryMessage().getSuffix()).isEmpty(); assertThat(i.hasNext()).isFalse(); } @Test public void shouldAsyncExecuteBatchStatement() throws Exception { // when Trace trace = container.execute(AsyncExecuteBatchStatement.class); // then checkTimers(trace, true); Iterator<Trace.Entry> i = trace.getEntryList().iterator(); List<Trace.SharedQueryText> sharedQueryTexts = trace.getSharedQueryTextList(); Trace.Entry entry = i.next(); assertThat(entry.getDepth()).isEqualTo(0); assertThat(entry.getMessage()).isEmpty(); assertThat(sharedQueryTexts.get(entry.getQueryEntryMessage().getSharedQueryTextIndex()) .getFullText()).isEqualTo("[batch] INSERT INTO test.users (id, fname, lname)" + " VALUES (100, 'f100', 'l100')," + " INSERT INTO test.users (id, fname, lname)" + " VALUES (101, 'f101', 'l101')," + " 10 x INSERT INTO test.users (id, fname, lname) VALUES (?, ?, ?)," + " INSERT INTO test.users (id, fname, lname)" + " VALUES (300, 'f300', 'l300')"); assertThat(entry.getQueryEntryMessage().getPrefix()).isEqualTo("cql execution: "); assertThat(entry.getQueryEntryMessage().getSuffix()).isEmpty(); assertThat(i.hasNext()).isFalse(); } private static void checkTimers(Trace trace, boolean prepared) { Trace.Timer rootTimer = trace.getHeader().getMainThreadRootTimer(); List<String> timerNames = Lists.newArrayList(); for (Trace.Timer timer : rootTimer.getChildTimerList()) { timerNames.add(timer.getName()); } Collections.sort(timerNames); if (prepared) { assertThat(timerNames).containsExactly("cql execute", "cql prepare"); } else { assertThat(timerNames).containsExactly("cql execute"); } for (Trace.Timer timer : rootTimer.getChildTimerList()) { assertThat(timer.getChildTimerList()).isEmpty(); } assertThat(trace.getHeader().getAsyncTimerCount()).isEqualTo(1); Trace.Timer asyncTimer = trace.getHeader().getAsyncTimer(0); assertThat(asyncTimer.getChildTimerCount()).isZero(); assertThat(asyncTimer.getName()).isEqualTo("cql execute"); assertThat(asyncTimer.getCount()).isEqualTo(1); } public static class ExecuteAsyncStatement implements AppUnderTest, TransactionMarker { private Session session; @Override public void executeApp() throws Exception { session = Sessions.createSession(); transactionMarker(); Sessions.closeSession(session); } @Override public void transactionMarker() throws Exception { ResultSet results = session.executeAsync("SELECT * FROM test.users").get(); for (Row row : results) { row.getInt("id"); } } } public static class ExecuteAsyncStatementReturningNoRecords implements AppUnderTest, TransactionMarker { private Session session; @Override public void executeApp() throws Exception { session = Sessions.createSession(); transactionMarker(); Sessions.closeSession(session); } @Override public void transactionMarker() throws Exception { ResultSet results = session.executeAsync("SELECT * FROM test.users where id = 12345").get(); for (Row row : results) { row.getInt("id"); } } } public static class AsyncIterateUsingOneAndAll implements AppUnderTest, TransactionMarker { private Session session; @Override public void executeApp() throws Exception { session = Sessions.createSession(); transactionMarker(); Sessions.closeSession(session); } @Override public void transactionMarker() throws Exception { ResultSet results = session.executeAsync("SELECT * FROM test.users").get(); results.one(); results.one(); results.one(); results.all(); } } public static class AsyncExecuteBoundStatement implements AppUnderTest, TransactionMarker { private Session session; @Override public void executeApp() throws Exception { session = Sessions.createSession(); transactionMarker(); Sessions.closeSession(session); } @Override public void transactionMarker() throws Exception { PreparedStatement preparedStatement = session.prepare("INSERT INTO test.users (id, fname, lname) VALUES (?, ?, ?)"); BoundStatement boundStatement = new BoundStatement(preparedStatement); boundStatement.bind(100, "f100", "l100"); session.executeAsync(boundStatement).get(); } } public static class AsyncExecuteBatchStatement implements AppUnderTest, TransactionMarker { private Session session; @Override public void executeApp() throws Exception { session = Sessions.createSession(); transactionMarker(); Sessions.closeSession(session); } @Override public void transactionMarker() throws Exception { BatchStatement batchStatement = new BatchStatement(); batchStatement.add(new SimpleStatement( "INSERT INTO test.users (id, fname, lname) VALUES (100, 'f100', 'l100')")); batchStatement.add(new SimpleStatement( "INSERT INTO test.users (id, fname, lname) VALUES (101, 'f101', 'l101')")); PreparedStatement preparedStatement = session.prepare("INSERT INTO test.users (id, fname, lname) VALUES (?, ?, ?)"); for (int i = 200; i < 210; i++) { BoundStatement boundStatement = new BoundStatement(preparedStatement); boundStatement.bind(i, "f" + i, "l" + i); batchStatement.add(boundStatement); } batchStatement.add(new SimpleStatement( "INSERT INTO test.users (id, fname, lname) VALUES (300, 'f300', 'l300')")); session.executeAsync(batchStatement).get(); } } }