| /** |
| * 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.apache.aurora.scheduler.storage.log.testing; |
| |
| import java.util.Objects; |
| |
| import com.google.common.base.Throwables; |
| import com.google.common.collect.ImmutableList; |
| |
| import org.apache.aurora.codec.ThriftBinaryCodec; |
| import org.apache.aurora.codec.ThriftBinaryCodec.CodingException; |
| import org.apache.aurora.gen.storage.DeduplicatedSnapshot; |
| import org.apache.aurora.gen.storage.LogEntry; |
| import org.apache.aurora.gen.storage.Op; |
| import org.apache.aurora.gen.storage.Transaction; |
| import org.apache.aurora.gen.storage.storageConstants; |
| import org.apache.aurora.scheduler.log.Log.Position; |
| import org.apache.aurora.scheduler.log.Log.Stream; |
| import org.apache.aurora.scheduler.storage.log.Entries; |
| import org.easymock.EasyMock; |
| import org.easymock.IArgumentMatcher; |
| import org.easymock.IExpectationSetters; |
| |
| import static org.easymock.EasyMock.expect; |
| |
| /** |
| * A junit argument matcher that detects same-value {@link LogEntry} objects in a more human |
| * readable way than byte array comparison. |
| */ |
| public class LogOpMatcher implements IArgumentMatcher { |
| private final LogEntry expected; |
| |
| public LogOpMatcher(LogEntry expected) { |
| this.expected = expected; |
| } |
| |
| @Override |
| public boolean matches(Object argument) { |
| try { |
| return expected.equals(ThriftBinaryCodec.decodeNonNull(LogEntry.class, (byte[]) argument)); |
| } catch (CodingException e) { |
| return false; |
| } |
| } |
| |
| @Override |
| public void appendTo(StringBuffer buffer) { |
| buffer.append(expected); |
| } |
| |
| /** |
| * Creates a stream matcher that will set expectations on the provided {@code stream}. |
| * |
| * @param stream Mocked stream. |
| * @return A stream matcher to set expectations against {@code stream}. |
| */ |
| public static StreamMatcher matcherFor(Stream stream) { |
| return new StreamMatcher(stream); |
| } |
| |
| public static final class StreamMatcher { |
| private final Stream stream; |
| |
| StreamMatcher(Stream stream) { |
| this.stream = Objects.requireNonNull(stream); |
| } |
| |
| /** |
| * Sets an expectation for a stream transaction containing the provided {@code ops}. |
| * |
| * @param ops Operations to expect in the transaction. |
| * @return An expectation setter. |
| */ |
| public IExpectationSetters<Position> expectTransaction(Op...ops) { |
| LogEntry entry = LogEntry.transaction( |
| new Transaction(ImmutableList.copyOf(ops), storageConstants.CURRENT_SCHEMA_VERSION)); |
| return expect(stream.append(sameEntry(entry))); |
| } |
| |
| /** |
| * Sets an expectation for a snapshot. |
| * |
| * @param snapshot Expected snapshot. |
| * @return An expectation setter. |
| */ |
| public IExpectationSetters<Position> expectSnapshot(DeduplicatedSnapshot snapshot) { |
| try { |
| LogEntry entry = Entries.deflate(LogEntry.deduplicatedSnapshot(snapshot)); |
| return expect(stream.append(sameEntry(entry))); |
| } catch (CodingException e) { |
| throw Throwables.propagate(e); |
| } |
| } |
| } |
| |
| /** |
| * Creates a matcher that supports value matching between a serialized {@link LogEntry} byte array |
| * and a log entry object. |
| * |
| * @param entry Entry to match against. |
| * @return {@code null}, return value included for easymock-style embedding. |
| */ |
| private static byte[] sameEntry(LogEntry entry) { |
| EasyMock.reportMatcher(new LogOpMatcher(entry)); |
| return new byte[] {}; |
| } |
| } |