| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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. |
| */ |
| |
| package org.apache.cassandra.distributed.test; |
| |
| import java.io.IOException; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| import org.junit.Test; |
| |
| import net.bytebuddy.ByteBuddy; |
| import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; |
| import net.bytebuddy.implementation.MethodDelegation; |
| import net.bytebuddy.implementation.bind.annotation.SuperCall; |
| import org.apache.cassandra.cql3.QueryOptions; |
| import org.apache.cassandra.cql3.statements.ModificationStatement; |
| import org.apache.cassandra.cql3.statements.SelectStatement; |
| import org.apache.cassandra.distributed.Cluster; |
| import org.apache.cassandra.distributed.api.ConsistencyLevel; |
| import org.apache.cassandra.service.QueryState; |
| import org.apache.cassandra.transport.messages.ResultMessage; |
| |
| import static net.bytebuddy.matcher.ElementMatchers.named; |
| import static net.bytebuddy.matcher.ElementMatchers.takesArguments; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.fail; |
| |
| public class ByteBuddyExamples extends TestBaseImpl |
| { |
| @Test |
| public void writeFailureTest() throws Throwable |
| { |
| try(Cluster cluster = init(Cluster.build(1) |
| .withInstanceInitializer(BBFailHelper::install) |
| .start())) |
| { |
| cluster.schemaChange("create table " + KEYSPACE + ".tbl (id int primary key, t int)"); |
| try |
| { |
| cluster.coordinator(1).execute("insert into " + KEYSPACE + ".tbl (id, t) values (1, 1)", ConsistencyLevel.ALL); |
| fail("Should fail"); |
| } |
| catch (RuntimeException e) |
| { |
| // expected |
| } |
| } |
| } |
| |
| public static class BBFailHelper |
| { |
| static void install(ClassLoader cl, int nodeNumber) |
| { |
| new ByteBuddy().redefine(ModificationStatement.class) |
| .method(named("execute")) |
| .intercept(MethodDelegation.to(BBFailHelper.class)) |
| .make() |
| .load(cl, ClassLoadingStrategy.Default.INJECTION); |
| } |
| public static ResultMessage execute() |
| { |
| throw new RuntimeException(); |
| } |
| } |
| |
| @Test |
| public void countTest() throws IOException |
| { |
| try(Cluster cluster = init(Cluster.build(2) |
| .withInstanceInitializer(BBCountHelper::install) |
| .start())) |
| { |
| cluster.schemaChange("create table " + KEYSPACE + ".tbl (id int primary key, t int)"); |
| cluster.coordinator(1).execute("select * from " + KEYSPACE + ".tbl;", ConsistencyLevel.ALL); |
| cluster.coordinator(2).execute("select * from " + KEYSPACE + ".tbl;", ConsistencyLevel.ALL); |
| cluster.get(1).runOnInstance(() -> { |
| assertEquals(1, BBCountHelper.count.get()); |
| }); |
| cluster.get(2).runOnInstance(() -> { |
| assertEquals(0, BBCountHelper.count.get()); |
| }); |
| |
| } |
| } |
| |
| public static class BBCountHelper |
| { |
| static AtomicInteger count = new AtomicInteger(); |
| static void install(ClassLoader cl, int nodeNumber) |
| { |
| if (nodeNumber != 1) |
| return; |
| new ByteBuddy().rebase(SelectStatement.class) |
| .method(named("execute").and(takesArguments(3))) |
| .intercept(MethodDelegation.to(BBCountHelper.class)) |
| .make() |
| .load(cl, ClassLoadingStrategy.Default.INJECTION); |
| } |
| |
| public static ResultMessage.Rows execute(QueryState state, QueryOptions options, long queryStartNanoTime, @SuperCall Callable<ResultMessage.Rows> r) throws Exception |
| { |
| count.incrementAndGet(); |
| return r.call(); |
| } |
| } |
| |
| } |