blob: 3355097ba9817cff3cdd8acdb1626bed03fa5bb0 [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.impl.google.lib.discovery;
import com.google.common.base.Equivalence;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Maps;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import com.google.common.truth.Truth;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import io.v.v23.V;
import io.v.v23.VFutures;
import io.v.v23.context.VContext;
import io.v.v23.discovery.Advertisement;
import io.v.v23.discovery.Update;
import io.v.v23.verror.VException;
import io.v.x.ref.lib.discovery.AdInfo;
/**
* Various test utilities for discovery.
*/
public class DiscoveryTestUtil {
/**
* Allows a runtime to use a mock discovery instance.
* <p>
* This should be called before V.newDiscovery() is called.
*/
private static native void injectMockDiscovery(VContext ctx) throws VException;
/**
* Initializes a runtime with a mock discovery instance.
*/
public static VContext withMockDiscovery() throws VException {
VContext ctx = V.init();
injectMockDiscovery(ctx);
return ctx;
}
private static final Equivalence<byte[]> BYTE_ARRAY_EQUIVALENCE =
new Equivalence<byte[]>() {
@Override
protected boolean doEquivalent(byte[] a, byte[] b) {
return Arrays.equals(a, b);
}
@Override
protected int doHash(byte[] bytes) {
return Arrays.hashCode(bytes);
}
};
private static final Equivalence<Advertisement> ADVERTISEMENT_EQUIVALENCE =
new Equivalence<Advertisement>() {
@Override
protected boolean doEquivalent(Advertisement a, Advertisement b) {
return a.getId().equals(b.getId())
&& a.getInterfaceName().equals(b.getInterfaceName())
&& a.getAddresses().equals(b.getAddresses())
&& a.getAttributes().equals(b.getAttributes())
&& Maps.difference(
a.getAttachments(),
b.getAttachments(),
BYTE_ARRAY_EQUIVALENCE)
.areEqual();
}
@Override
protected int doHash(Advertisement ad) {
return Objects.hashCode(ad.getId());
}
};
private static final Equivalence<AdInfo> ADINFO_EQUIVALENCE =
new Equivalence<AdInfo>() {
@Override
protected boolean doEquivalent(AdInfo a, AdInfo b) {
return ADVERTISEMENT_EQUIVALENCE.equivalent(a.getAd(), b.getAd())
&& a.getEncryptionAlgorithm().equals(b.getEncryptionAlgorithm())
&& a.getEncryptionKeys().equals(b.getEncryptionKeys())
&& a.getHash().equals(b.getHash())
&& a.getDirAddrs().equals(b.getDirAddrs());
}
@Override
protected int doHash(AdInfo adInfo) {
return Objects.hashCode(adInfo.getAd().getId(), adInfo.getHash());
}
};
private static final Function<AdInfo, Equivalence.Wrapper<AdInfo>> ADINFO_WRAPPER =
new Function<AdInfo, Equivalence.Wrapper<AdInfo>>() {
@Override
public Equivalence.Wrapper<AdInfo> apply(AdInfo adinfo) {
return ADINFO_EQUIVALENCE.wrap(adinfo);
}
};
/**
* {@link SubjectFactory} for {@link Advertisement}.
*/
public static class AdvertisementSubject extends Subject<AdvertisementSubject, Advertisement> {
public AdvertisementSubject(FailureStrategy fs, Advertisement subject) {
super(fs, subject);
}
public void isEqualTo(Advertisement expected) {
if (!ADVERTISEMENT_EQUIVALENCE.equivalent(getSubject(), expected)) {
fail("is equal to", expected);
}
}
}
private static final SubjectFactory<AdvertisementSubject, Advertisement> ADVERTISEMENT_SF =
new SubjectFactory<AdvertisementSubject, Advertisement>() {
@Override
public AdvertisementSubject getSubject(FailureStrategy fs, Advertisement target) {
return new AdvertisementSubject(fs, target);
}
};
public static AdvertisementSubject assertThat(Advertisement actual) {
return Truth.assertAbout(ADVERTISEMENT_SF).that(actual);
}
/**
* {@link SubjectFactory} for {@link AdInfo}.
*/
public static class AdInfoSubject extends Subject<AdInfoSubject, AdInfo> {
public AdInfoSubject(FailureStrategy fs, AdInfo subject) {
super(fs, subject);
}
public void isEqualTo(AdInfo expected) {
if (!ADINFO_EQUIVALENCE.equivalent(getSubject(), expected)
|| getSubject().getLost() != expected.getLost()) {
fail("is equal to", expected);
}
}
public void isEqualTo(AdInfo expected, boolean lost) {
if (!ADINFO_EQUIVALENCE.equivalent(getSubject(), expected)) {
fail("is equal to", expected, lost);
}
if (getSubject().getLost() != lost) {
failWithCustomSubject("is equal to", getSubject().getLost(), lost);
}
}
}
private static final SubjectFactory<AdInfoSubject, AdInfo> ADINFO_SF =
new SubjectFactory<AdInfoSubject, AdInfo>() {
@Override
public AdInfoSubject getSubject(FailureStrategy fs, AdInfo target) {
return new AdInfoSubject(fs, target);
}
};
public static AdInfoSubject assertThat(AdInfo actual) {
return Truth.assertAbout(ADINFO_SF).that(actual);
}
/**
* {@link SubjectFactory} for {@link List<AdInfo>}.
*/
public static class AdInfoListSubject extends Subject<AdInfoListSubject, List<AdInfo>> {
public AdInfoListSubject(FailureStrategy fs, List<AdInfo> subject) {
super(fs, subject);
}
public void isEqualTo(AdInfo... expected) {
List<Equivalence.Wrapper<AdInfo>> actualWrapped =
FluentIterable.of(expected).transform(ADINFO_WRAPPER).toList();
List<Equivalence.Wrapper<AdInfo>> expectedWrapped =
FluentIterable.from(getSubject()).transform(ADINFO_WRAPPER).toList();
if (!ImmutableMultiset.copyOf(actualWrapped)
.equals(ImmutableMultiset.copyOf(expectedWrapped))) {
fail("is equal to", FluentIterable.of(expected));
}
}
}
private static final SubjectFactory<AdInfoListSubject, List<AdInfo>> ADINFO_LIST_SF =
new SubjectFactory<AdInfoListSubject, List<AdInfo>>() {
@Override
public AdInfoListSubject getSubject(FailureStrategy fs, List<AdInfo> target) {
return new AdInfoListSubject(fs, target);
}
};
public static AdInfoListSubject assertThat(List<AdInfo> actual) {
return Truth.assertAbout(ADINFO_LIST_SF).that(actual);
}
/**
* {@link SubjectFactory} for {@link Update}.
*/
public static class UpdateSubject extends Subject<UpdateSubject, Update> {
public UpdateSubject(FailureStrategy fs, Update subject) {
super(fs, subject);
}
public void isEqualTo(VContext ctx, Advertisement expected) throws VException {
if (!equivalent(ctx, getSubject(), expected)) {
fail("is equal to", expected);
}
}
private static boolean equivalent(VContext ctx, Update update, Advertisement ad)
throws VException {
if (!update.getId().equals(ad.getId())) {
return false;
}
if (!update.getInterfaceName().equals(ad.getInterfaceName())) {
return false;
}
if (!update.getAddresses().equals(ad.getAddresses())) {
return false;
}
for (Map.Entry<String, String> entry : ad.getAttributes().entrySet()) {
if (!entry.getValue().equals(update.getAttribute(entry.getKey()))) {
return false;
}
}
for (Map.Entry<String, byte[]> e : ad.getAttachments().entrySet()) {
byte[] data = VFutures.sync(update.getAttachment(ctx, e.getKey()));
if (!Arrays.equals(e.getValue(), data)) {
return false;
}
}
return true;
}
}
private static final SubjectFactory<UpdateSubject, Update> UPDATE_SF =
new SubjectFactory<UpdateSubject, Update>() {
@Override
public UpdateSubject getSubject(FailureStrategy fs, Update target) {
return new UpdateSubject(fs, target);
}
};
public static UpdateSubject assertThat(Update actual) {
return Truth.assertAbout(UPDATE_SF).that(actual);
}
}