blob: a05745cae236d6b262e93d3d13e07829fa310fb7 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.intent;
Ray Milkeye6684082014-10-16 16:59:47 -070017
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070018import com.google.common.base.MoreObjects;
Andrey Komarov2398d962016-09-26 15:11:23 +030019import org.onlab.graph.Weight;
Brian O'Connorabafb502014-12-02 22:26:20 -080020import org.onosproject.core.GroupId;
Luca Pretede10c782017-01-05 17:23:08 -080021import org.onosproject.net.DefaultPath;
Brian O'Connorabafb502014-12-02 22:26:20 -080022import org.onosproject.net.DeviceId;
23import org.onosproject.net.ElementId;
Thomas Vachuskadc91b552016-03-29 14:02:47 -070024import org.onosproject.net.HostId;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.net.Link;
Ray Milkey5a7787a2015-02-23 11:44:30 -080026import org.onosproject.net.NetTestTools;
Ray Milkey43a28222015-02-23 13:57:58 -080027import org.onosproject.net.NetworkResource;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.net.Path;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070029import org.onosproject.net.device.DeviceServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.net.flow.FlowId;
31import org.onosproject.net.flow.FlowRule;
jcc3d4e14a2015-04-21 11:32:05 +080032import org.onosproject.net.flow.FlowRuleExtPayLoad;
Carmelo Cascone41605742017-06-19 15:46:44 +090033import org.onosproject.net.flow.IndexTableId;
34import org.onosproject.net.flow.TableId;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.flow.criteria.Criterion;
38import org.onosproject.net.flow.criteria.Criterion.Type;
39import org.onosproject.net.flow.instructions.Instruction;
alshabib346b5b32015-03-06 00:42:16 -080040import org.onosproject.net.flow.instructions.Instructions;
Saurav Das86af8f12015-05-25 23:55:33 -070041import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
Luca Pretede10c782017-01-05 17:23:08 -080042import org.onosproject.net.provider.ProviderId;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.topology.DefaultTopologyEdge;
44import org.onosproject.net.topology.DefaultTopologyVertex;
Andrey Komarov2398d962016-09-26 15:11:23 +030045import org.onosproject.net.topology.LinkWeigher;
Thomas Vachuska48e64e42015-09-22 15:32:55 -070046import org.onosproject.net.topology.PathServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080047import org.onosproject.net.topology.TopologyVertex;
Ray Milkey5a7787a2015-02-23 11:44:30 -080048import org.onosproject.store.Timestamp;
Ray Milkeye6684082014-10-16 16:59:47 -070049
Luca Pretede10c782017-01-05 17:23:08 -080050import java.util.ArrayList;
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070051import java.util.Arrays;
52import java.util.Collection;
53import java.util.Collections;
54import java.util.HashSet;
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070055import java.util.List;
56import java.util.Objects;
57import java.util.Set;
58import java.util.concurrent.atomic.AtomicLong;
59
Thomas Vachuska48e64e42015-09-22 15:32:55 -070060import static org.onosproject.net.NetTestTools.*;
Ray Milkey43a28222015-02-23 13:57:58 -080061
Ray Milkeye6684082014-10-16 16:59:47 -070062/**
63 * Common mocks used by the intent framework tests.
64 */
65public class IntentTestsMocks {
66 /**
67 * Mock traffic selector class used for satisfying API requirements.
68 */
69 public static class MockSelector implements TrafficSelector {
70 @Override
71 public Set<Criterion> criteria() {
72 return new HashSet<>();
73 }
Jonathan Hart936c49d2014-10-23 16:38:59 -070074
75 @Override
76 public Criterion getCriterion(Type type) {
77 return null;
78 }
Ray Milkeye6684082014-10-16 16:59:47 -070079 }
80
81 /**
82 * Mock traffic treatment class used for satisfying API requirements.
83 */
84 public static class MockTreatment implements TrafficTreatment {
85 @Override
alshabib346b5b32015-03-06 00:42:16 -080086 public List<Instruction> deferred() {
Jonathan Hart4a0ba562015-03-23 17:23:33 -070087 return Collections.emptyList();
alshabib346b5b32015-03-06 00:42:16 -080088 }
89
90 @Override
91 public List<Instruction> immediate() {
Jonathan Hart4a0ba562015-03-23 17:23:33 -070092 return Collections.emptyList();
alshabib346b5b32015-03-06 00:42:16 -080093 }
94
95 @Override
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070096 public List<Instruction> allInstructions() {
Jonathan Hart4a0ba562015-03-23 17:23:33 -070097 return Collections.emptyList();
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070098 }
99
100 @Override
alshabib346b5b32015-03-06 00:42:16 -0800101 public Instructions.TableTypeTransition tableTransition() {
102 return null;
103 }
104
105 @Override
Jonathan Hart4a0ba562015-03-23 17:23:33 -0700106 public boolean clearedDeferred() {
107 return false;
alshabib346b5b32015-03-06 00:42:16 -0800108 }
Saurav Das86af8f12015-05-25 23:55:33 -0700109
110 @Override
111 public MetadataInstruction writeMetadata() {
112 return null;
113 }
alshabib10c810b2015-08-18 16:59:04 -0700114
115 @Override
Cem Türker3baff672017-10-12 15:09:01 +0300116 public Instructions.StatTriggerInstruction statTrigger() {
117 return null;
118 }
119
120 @Override
alshabib10c810b2015-08-18 16:59:04 -0700121 public Instructions.MeterInstruction metered() {
122 return null;
123 }
Ray Milkeye6684082014-10-16 16:59:47 -0700124 }
125
126 /**
127 * Mock path service for creating paths within the test.
128 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700129 public static class MockPathService extends PathServiceAdapter {
Ray Milkeye6684082014-10-16 16:59:47 -0700130
131 final String[] pathHops;
132 final String[] reversePathHops;
133
134 /**
135 * Constructor that provides a set of hops to mock.
136 *
137 * @param pathHops path hops to mock
138 */
139 public MockPathService(String[] pathHops) {
140 this.pathHops = pathHops;
141 String[] reversed = pathHops.clone();
142 Collections.reverse(Arrays.asList(reversed));
143 reversePathHops = reversed;
144 }
145
146 @Override
147 public Set<Path> getPaths(ElementId src, ElementId dst) {
148 Set<Path> result = new HashSet<>();
149
150 String[] allHops = new String[pathHops.length];
151
152 if (src.toString().endsWith(pathHops[0])) {
153 System.arraycopy(pathHops, 0, allHops, 0, pathHops.length);
154 } else {
155 System.arraycopy(reversePathHops, 0, allHops, 0, pathHops.length);
156 }
157
Thomas Vachuskadc91b552016-03-29 14:02:47 -0700158 result.add(createPath(src instanceof HostId, dst instanceof HostId, allHops));
Ray Milkeye6684082014-10-16 16:59:47 -0700159 return result;
160 }
161
162 @Override
Andrey Komarov2398d962016-09-26 15:11:23 +0300163 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
164 Set<Path> paths = getPaths(src, dst);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800165
166 for (Path path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300167 DeviceId srcDevice = path.src().elementId() instanceof DeviceId ? path.src().deviceId() : null;
168 DeviceId dstDevice = path.dst().elementId() instanceof DeviceId ? path.dst().deviceId() : null;
Thomas Vachuskadc91b552016-03-29 14:02:47 -0700169 if (srcDevice != null && dstDevice != null) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300170 TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice);
171 TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice);
172 Link link = link(src.toString(), 1, dst.toString(), 1);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800173
Andrey Komarov2398d962016-09-26 15:11:23 +0300174 Weight weightValue = weigher.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link));
175 if (weightValue.isNegative()) {
Thomas Vachuskadc91b552016-03-29 14:02:47 -0700176 return new HashSet<>();
177 }
Ray Milkey8d3ce432014-11-07 16:21:10 -0800178 }
179 }
180 return paths;
Ray Milkeye6684082014-10-16 16:59:47 -0700181 }
182 }
Ray Milkey8d3ce432014-11-07 16:21:10 -0800183
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700184 /**
185 * Mock path service for creating paths within the test.
186 *
187 */
Luca Pretede10c782017-01-05 17:23:08 -0800188 public static class Mp2MpMockPathService extends PathServiceAdapter {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700189
190 final String[] pathHops;
191 final String[] reversePathHops;
192
193 /**
194 * Constructor that provides a set of hops to mock.
195 *
196 * @param pathHops path hops to mock
197 */
198 public Mp2MpMockPathService(String[] pathHops) {
199 this.pathHops = pathHops;
200 String[] reversed = pathHops.clone();
201 Collections.reverse(Arrays.asList(reversed));
202 reversePathHops = reversed;
203 }
204
205 @Override
206 public Set<Path> getPaths(ElementId src, ElementId dst) {
207 Set<Path> result = new HashSet<>();
208
209 String[] allHops = new String[pathHops.length + 2];
210 allHops[0] = src.toString();
211 allHops[allHops.length - 1] = dst.toString();
212
213 if (pathHops.length != 0) {
214 System.arraycopy(pathHops, 0, allHops, 1, pathHops.length);
215 }
216
217 result.add(createPath(allHops));
218
219 return result;
220 }
221
222 @Override
Andrey Komarov2398d962016-09-26 15:11:23 +0300223 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700224 final Set<Path> paths = getPaths(src, dst);
225
226 for (Path path : paths) {
227 final DeviceId srcDevice = path.src().elementId() instanceof DeviceId ? path.src().deviceId() : null;
228 final DeviceId dstDevice = path.dst().elementId() instanceof DeviceId ? path.dst().deviceId() : null;
229 if (srcDevice != null && dstDevice != null) {
230 final TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice);
231 final TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice);
232 final Link link = link(src.toString(), 1, dst.toString(), 1);
233
Andrey Komarov2398d962016-09-26 15:11:23 +0300234 final Weight weightValue = weigher.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link));
235 if (weightValue.isNegative()) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700236 return new HashSet<>();
237 }
238 }
239 }
240 return paths;
241 }
242 }
243
Luca Pretede10c782017-01-05 17:23:08 -0800244 /**
245 * Mock path service for creating paths for MP2SP intent tests, returning
246 * pre-determined paths.
247 */
248 public static class FixedMP2MPMockPathService extends PathServiceAdapter {
Sho SHIMIZUb1681bd2016-02-22 12:47:50 -0800249
Luca Pretede10c782017-01-05 17:23:08 -0800250 final String[] pathHops;
Sho SHIMIZUb1681bd2016-02-22 12:47:50 -0800251
Luca Pretede10c782017-01-05 17:23:08 -0800252 public static final String DPID_1 = "of:s1";
253 public static final String DPID_2 = "of:s2";
254 public static final String DPID_3 = "of:s3";
255 public static final String DPID_4 = "of:s4";
Sho SHIMIZUb1681bd2016-02-22 12:47:50 -0800256
Luca Pretede10c782017-01-05 17:23:08 -0800257 /**
258 * Constructor that provides a set of hops to mock.
259 *
260 * @param pathHops path hops to mock
261 */
262 public FixedMP2MPMockPathService(String[] pathHops) {
263 this.pathHops = pathHops;
Ray Milkey8d3ce432014-11-07 16:21:10 -0800264 }
265
HIGUCHI Yutaca9cc8e2015-10-29 23:26:51 -0700266 @Override
Luca Pretede10c782017-01-05 17:23:08 -0800267 public Set<Path> getPaths(ElementId src, ElementId dst) {
268 List<Link> links = new ArrayList<>();
269 Set<Path> result = new HashSet<>();
270 ProviderId providerId = new ProviderId("of", "foo");
271 DefaultPath path;
272 if (src.toString().equals(DPID_1) && dst.toString().equals(DPID_4)) {
273 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 1));
274 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 2, dst.toString(), 1));
275 } else if (src.toString().equals(DPID_2) && dst.toString().equals(DPID_4)) {
276 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 3));
277 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 2, dst.toString(), 1));
278 } else if (src.toString().equals(DPID_4) && dst.toString().equals(DPID_1)) {
279 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 1));
280 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 2, dst.toString(), 1));
281 } else if (src.toString().equals(DPID_4) && dst.toString().equals(DPID_2)) {
282 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 1));
283 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 3, dst.toString(), 1));
284 } else {
285 return result;
Ray Milkey8d3ce432014-11-07 16:21:10 -0800286 }
Luca Pretede10c782017-01-05 17:23:08 -0800287 path = new DefaultPath(providerId, links, 3);
288 result.add(path);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800289
Luca Pretede10c782017-01-05 17:23:08 -0800290 return result;
Ray Milkey8d3ce432014-11-07 16:21:10 -0800291 }
292
293 @Override
Luca Pretede10c782017-01-05 17:23:08 -0800294 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
295 final Set<Path> paths = getPaths(src, dst);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800296
Luca Pretede10c782017-01-05 17:23:08 -0800297 for (Path path : paths) {
298 final DeviceId srcDevice = path.src().elementId() instanceof DeviceId ? path.src().deviceId() : null;
299 final DeviceId dstDevice = path.dst().elementId() instanceof DeviceId ? path.dst().deviceId() : null;
300 if (srcDevice != null && dstDevice != null) {
301 final TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice);
302 final TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice);
303 final Link link = link(src.toString(), 1, dst.toString(), 1);
304
305 final Weight weightValue = weigher.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link));
306 if (weightValue.isNegative()) {
307 return new HashSet<>();
308 }
309 }
310 }
311 return paths;
Ray Milkeye97ede92014-11-20 10:43:12 -0800312 }
Ray Milkey8d3ce432014-11-07 16:21:10 -0800313 }
314
Ray Milkey930fc662014-11-11 16:07:45 -0800315 private static final IntentTestsMocks.MockSelector SELECTOR =
316 new IntentTestsMocks.MockSelector();
317 private static final IntentTestsMocks.MockTreatment TREATMENT =
318 new IntentTestsMocks.MockTreatment();
319
320 public static class MockFlowRule implements FlowRule {
Ray Milkey77a455f2015-03-27 10:08:17 -0700321 static int nextId = 0;
Ray Milkey930fc662014-11-11 16:07:45 -0800322
323 int priority;
Carmelo Cascone41605742017-06-19 15:46:44 +0900324 IndexTableId tableId;
Ray Milkey77a455f2015-03-27 10:08:17 -0700325 long timestamp;
326 int id;
jcc3d4e14a2015-04-21 11:32:05 +0800327 FlowRuleExtPayLoad payLoad;
sangho11c30ac2015-01-22 14:30:55 -0800328
Ray Milkey930fc662014-11-11 16:07:45 -0800329 public MockFlowRule(int priority) {
330 this.priority = priority;
Carmelo Cascone41605742017-06-19 15:46:44 +0900331 this.tableId = DEFAULT_TABLE;
Ray Milkey77a455f2015-03-27 10:08:17 -0700332 this.timestamp = System.currentTimeMillis();
333 this.id = nextId++;
jcc3d4e14a2015-04-21 11:32:05 +0800334 this.payLoad = null;
335 }
336
337 public MockFlowRule(int priority, FlowRuleExtPayLoad payLoad) {
338 this.priority = priority;
339 this.timestamp = System.currentTimeMillis();
340 this.id = nextId++;
341 this.payLoad = payLoad;
Ray Milkey930fc662014-11-11 16:07:45 -0800342 }
343
344 @Override
345 public FlowId id() {
Ray Milkey77a455f2015-03-27 10:08:17 -0700346 return FlowId.valueOf(id);
Ray Milkey930fc662014-11-11 16:07:45 -0800347 }
348
349 @Override
350 public short appId() {
351 return 0;
352 }
353
354 @Override
Sho SHIMIZU75a5bd92014-11-25 11:22:56 -0800355 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800356 return new GroupId(0);
alshabib28204e52014-11-12 18:29:45 -0800357 }
358
359 @Override
Ray Milkey930fc662014-11-11 16:07:45 -0800360 public int priority() {
361 return priority;
362 }
363
364 @Override
365 public DeviceId deviceId() {
366 return did("1");
367 }
368
369 @Override
370 public TrafficSelector selector() {
371 return SELECTOR;
372 }
373
374 @Override
375 public TrafficTreatment treatment() {
376 return TREATMENT;
377 }
378
379 @Override
380 public int timeout() {
381 return 0;
382 }
383
384 @Override
Murat Parlakisikc6759e82016-06-29 03:22:22 -0700385 public int hardTimeout() {
386 return 0;
387 }
388
389 @Override
390 public FlowRemoveReason reason() {
391 return FlowRemoveReason.NO_REASON;
392 }
393
394 @Override
Ray Milkey930fc662014-11-11 16:07:45 -0800395 public boolean isPermanent() {
396 return false;
397 }
398
Brian O'Connor427a1762014-11-19 18:40:32 -0800399 @Override
400 public int hashCode() {
HIGUCHI Yutaca9cc8e2015-10-29 23:26:51 -0700401 return priority;
Brian O'Connor427a1762014-11-19 18:40:32 -0800402 }
Ray Milkey930fc662014-11-11 16:07:45 -0800403
Brian O'Connor427a1762014-11-19 18:40:32 -0800404 @Override
405 public boolean equals(Object obj) {
406 if (this == obj) {
407 return true;
408 }
409 if (obj == null || getClass() != obj.getClass()) {
410 return false;
411 }
412 final MockFlowRule other = (MockFlowRule) obj;
Ray Milkey77a455f2015-03-27 10:08:17 -0700413 return Objects.equals(this.timestamp, other.timestamp) &&
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700414 this.id == other.id;
Brian O'Connor427a1762014-11-19 18:40:32 -0800415 }
sangho11c30ac2015-01-22 14:30:55 -0800416
417 @Override
Jonathan Hartf44e42c2015-08-04 09:58:46 -0700418 public boolean exactMatch(FlowRule rule) {
419 return this.equals(rule);
420 }
421
422 @Override
alshabibdb774072015-04-20 13:13:51 -0700423 public int tableId() {
Carmelo Cascone41605742017-06-19 15:46:44 +0900424 return tableId.id();
425 }
426
427 @Override
428 public TableId table() {
alshabib08d98982015-04-21 16:25:50 -0700429 return tableId;
alshabibdb774072015-04-20 13:13:51 -0700430 }
jcc3d4e14a2015-04-21 11:32:05 +0800431
432 @Override
433 public FlowRuleExtPayLoad payLoad() {
434 return payLoad;
435 }
Ray Milkey930fc662014-11-11 16:07:45 -0800436 }
437
Ray Milkey5a7787a2015-02-23 11:44:30 -0800438 public static class MockIntent extends Intent {
439 private static AtomicLong counter = new AtomicLong(0);
440
441 private final Long number;
442
443 public MockIntent(Long number) {
Ray Milkeyebc5d222015-03-18 15:45:36 -0700444 super(NetTestTools.APP_ID, null, Collections.emptyList(),
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700445 Intent.DEFAULT_INTENT_PRIORITY);
Ray Milkey5a7787a2015-02-23 11:44:30 -0800446 this.number = number;
447 }
448
Ray Milkey43a28222015-02-23 13:57:58 -0800449 public MockIntent(Long number, Collection<NetworkResource> resources) {
Ray Milkeyebc5d222015-03-18 15:45:36 -0700450 super(NetTestTools.APP_ID, null, resources, Intent.DEFAULT_INTENT_PRIORITY);
Ray Milkey43a28222015-02-23 13:57:58 -0800451 this.number = number;
452 }
453
Ray Milkey5a7787a2015-02-23 11:44:30 -0800454 public Long number() {
455 return number;
456 }
457
458 public static Long nextId() {
459 return counter.getAndIncrement();
460 }
Ray Milkey43a28222015-02-23 13:57:58 -0800461
462 @Override
463 public String toString() {
464 return MoreObjects.toStringHelper(getClass())
465 .add("id", id())
466 .add("appId", appId())
467 .toString();
468 }
Ray Milkey5a7787a2015-02-23 11:44:30 -0800469 }
470
471 public static class MockTimestamp implements Timestamp {
472 final int value;
473
474 public MockTimestamp(int value) {
475 this.value = value;
476 }
477
478 @Override
479 public int compareTo(Timestamp o) {
480 if (!(o instanceof MockTimestamp)) {
481 return -1;
482 }
483 MockTimestamp that = (MockTimestamp) o;
Jonathan Hart72175c22015-03-24 18:55:58 -0700484 return this.value - that.value;
Ray Milkey5a7787a2015-02-23 11:44:30 -0800485 }
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700486
487 @Override
488 public int hashCode() {
489 return value;
490 }
491
492 @Override
493 public boolean equals(Object obj) {
494 if (obj instanceof MockTimestamp) {
495 return this.compareTo((MockTimestamp) obj) == 0;
496 }
497 return false;
498 }
Ray Milkey5a7787a2015-02-23 11:44:30 -0800499 }
500
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700501 /**
502 * Mocks the device service so that a device appears available in the test.
503 */
504 public static class MockDeviceService extends DeviceServiceAdapter {
505 @Override
506 public boolean isAvailable(DeviceId deviceId) {
507 return true;
508 }
509 }
Ray Milkeye6684082014-10-16 16:59:47 -0700510}