package com.linkedin.databus.core.test; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * 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. * */ import java.lang.reflect.Field; import java.nio.ByteBuffer; import com.linkedin.databus.core.DbusEvent; import com.linkedin.databus.core.DbusEventInternalWritable; import com.linkedin.databus.core.DbusEventSerializable; import com.linkedin.databus.core.DbusEventV1; import com.linkedin.databus.core.DbusEventV2; import com.linkedin.databus.core.InvalidEventException; /** * Methods to corrupt (or uncorrupt) various fields of an event. * * This class is for testing only! * * @author snagaraj */ public class DbusEventCorrupter { private static final byte CORRUPTION_PATTERN = 0x55; // 01010101 /** * Converts an event (readable or otherwise) to writable for testing. EEEEEEEVIL! * * Note that all DbusEvents are fundamentally just little windows into some * DbusEventBuffer; the various event classes differ only in the methods they * expose. So pulling the buffer and offset variables out of a readable and * using them to construct a writable is effectively the same as typecasting * the readable to writable (i.e., "const_cast<DbusEventInternalWritable>()", * so to speak). * * @param event DbusEvent to be abused */ public static DbusEventInternalWritable makeWritable(DbusEvent event) throws InvalidEventException { byte version = event.getRawBytes().get(0); // version is always in the first byte // TODO: add DbusEvent version() accessor? seems like good idea... ByteBuffer buf; int pos; try { Field reflectedBuf = DbusEventSerializable.class.getDeclaredField("_buf"); Field reflectedPosition = DbusEventSerializable.class.getDeclaredField("_position"); reflectedBuf.setAccessible(true); reflectedPosition.setAccessible(true); buf = (ByteBuffer)reflectedBuf.get(event); pos = reflectedPosition.getInt(event); } catch (Exception e) { throw new InvalidEventException(e); } return (version == 0)? new DbusEventV1(buf, pos) : new DbusEventV2(buf, pos); } /** * Toggles corrupted state of event. Final event state is determined by # incoming event and specified subfield of event. * * @param type part of event in which to inject corruption * @param event DbusEvent that will be modified */ public static void toggleEventCorruption(EventCorruptionType type, DbusEvent event) throws InvalidEventException { // Regardless of the underlying event type (e.g., readable), we're writing to its // internal state, so "convert" it to a writable event. DbusEventInternalWritable writableEvent = makeWritable(event); // bruuuuuuutal... switch (type) { case LENGTH: int newSize = writableEvent.size() ^ CORRUPTION_PATTERN; writableEvent.setSize(newSize); break; case HEADERCRC: long headerCrc = writableEvent.headerCrc() ^ CORRUPTION_PATTERN; writableEvent.setHeaderCrc(headerCrc); break; case PAYLOAD: if (writableEvent.payloadLength() > 0) { byte[] payload = new byte[writableEvent.payloadLength()]; writableEvent.value().get(payload); payload[0] ^= CORRUPTION_PATTERN; writableEvent.setValue(payload); } break; case PAYLOADCRC: long payloadCrc = writableEvent.bodyCrc() ^ CORRUPTION_PATTERN; writableEvent.setValueCrc(payloadCrc); break; } } public enum EventCorruptionType { LENGTH, HEADERCRC, PAYLOAD, PAYLOADCRC, NONE, } }