blob: 5a2524dd68638018b0b57ff4a48c93526a5fc9df [file] [log] [blame]
/**
* 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[] {};
}
}