blob: fbd134f486f8c5b213194ab82c99653b73d3a7df [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
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;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.flow.TrafficSelector;
34import org.onosproject.net.flow.TrafficTreatment;
35import org.onosproject.net.flow.criteria.Criterion;
36import org.onosproject.net.flow.criteria.Criterion.Type;
37import org.onosproject.net.flow.instructions.Instruction;
alshabib346b5b32015-03-06 00:42:16 -080038import org.onosproject.net.flow.instructions.Instructions;
Saurav Das86af8f12015-05-25 23:55:33 -070039import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
Luca Pretede10c782017-01-05 17:23:08 -080040import org.onosproject.net.provider.ProviderId;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.topology.DefaultTopologyEdge;
42import org.onosproject.net.topology.DefaultTopologyVertex;
Andrey Komarov2398d962016-09-26 15:11:23 +030043import org.onosproject.net.topology.LinkWeigher;
Thomas Vachuska48e64e42015-09-22 15:32:55 -070044import org.onosproject.net.topology.PathServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.topology.TopologyVertex;
Ray Milkey5a7787a2015-02-23 11:44:30 -080046import org.onosproject.store.Timestamp;
Ray Milkeye6684082014-10-16 16:59:47 -070047
Luca Pretede10c782017-01-05 17:23:08 -080048import java.util.ArrayList;
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070049import java.util.Arrays;
50import java.util.Collection;
51import java.util.Collections;
52import java.util.HashSet;
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070053import java.util.List;
54import java.util.Objects;
55import java.util.Set;
56import java.util.concurrent.atomic.AtomicLong;
57
Thomas Vachuska48e64e42015-09-22 15:32:55 -070058import static org.onosproject.net.NetTestTools.*;
Ray Milkey43a28222015-02-23 13:57:58 -080059
Ray Milkeye6684082014-10-16 16:59:47 -070060/**
61 * Common mocks used by the intent framework tests.
62 */
63public class IntentTestsMocks {
64 /**
65 * Mock traffic selector class used for satisfying API requirements.
66 */
67 public static class MockSelector implements TrafficSelector {
68 @Override
69 public Set<Criterion> criteria() {
70 return new HashSet<>();
71 }
Jonathan Hart936c49d2014-10-23 16:38:59 -070072
73 @Override
74 public Criterion getCriterion(Type type) {
75 return null;
76 }
Ray Milkeye6684082014-10-16 16:59:47 -070077 }
78
79 /**
80 * Mock traffic treatment class used for satisfying API requirements.
81 */
82 public static class MockTreatment implements TrafficTreatment {
83 @Override
alshabib346b5b32015-03-06 00:42:16 -080084 public List<Instruction> deferred() {
Jonathan Hart4a0ba562015-03-23 17:23:33 -070085 return Collections.emptyList();
alshabib346b5b32015-03-06 00:42:16 -080086 }
87
88 @Override
89 public List<Instruction> immediate() {
Jonathan Hart4a0ba562015-03-23 17:23:33 -070090 return Collections.emptyList();
alshabib346b5b32015-03-06 00:42:16 -080091 }
92
93 @Override
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070094 public List<Instruction> allInstructions() {
Jonathan Hart4a0ba562015-03-23 17:23:33 -070095 return Collections.emptyList();
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070096 }
97
98 @Override
alshabib346b5b32015-03-06 00:42:16 -080099 public Instructions.TableTypeTransition tableTransition() {
100 return null;
101 }
102
103 @Override
Jonathan Hart4a0ba562015-03-23 17:23:33 -0700104 public boolean clearedDeferred() {
105 return false;
alshabib346b5b32015-03-06 00:42:16 -0800106 }
Saurav Das86af8f12015-05-25 23:55:33 -0700107
108 @Override
109 public MetadataInstruction writeMetadata() {
110 return null;
111 }
alshabib10c810b2015-08-18 16:59:04 -0700112
113 @Override
114 public Instructions.MeterInstruction metered() {
115 return null;
116 }
Ray Milkeye6684082014-10-16 16:59:47 -0700117 }
118
119 /**
120 * Mock path service for creating paths within the test.
121 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700122 public static class MockPathService extends PathServiceAdapter {
Ray Milkeye6684082014-10-16 16:59:47 -0700123
124 final String[] pathHops;
125 final String[] reversePathHops;
126
127 /**
128 * Constructor that provides a set of hops to mock.
129 *
130 * @param pathHops path hops to mock
131 */
132 public MockPathService(String[] pathHops) {
133 this.pathHops = pathHops;
134 String[] reversed = pathHops.clone();
135 Collections.reverse(Arrays.asList(reversed));
136 reversePathHops = reversed;
137 }
138
139 @Override
140 public Set<Path> getPaths(ElementId src, ElementId dst) {
141 Set<Path> result = new HashSet<>();
142
143 String[] allHops = new String[pathHops.length];
144
145 if (src.toString().endsWith(pathHops[0])) {
146 System.arraycopy(pathHops, 0, allHops, 0, pathHops.length);
147 } else {
148 System.arraycopy(reversePathHops, 0, allHops, 0, pathHops.length);
149 }
150
Thomas Vachuskadc91b552016-03-29 14:02:47 -0700151 result.add(createPath(src instanceof HostId, dst instanceof HostId, allHops));
Ray Milkeye6684082014-10-16 16:59:47 -0700152 return result;
153 }
154
155 @Override
Andrey Komarov2398d962016-09-26 15:11:23 +0300156 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
157 Set<Path> paths = getPaths(src, dst);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800158
159 for (Path path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300160 DeviceId srcDevice = path.src().elementId() instanceof DeviceId ? path.src().deviceId() : null;
161 DeviceId dstDevice = path.dst().elementId() instanceof DeviceId ? path.dst().deviceId() : null;
Thomas Vachuskadc91b552016-03-29 14:02:47 -0700162 if (srcDevice != null && dstDevice != null) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300163 TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice);
164 TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice);
165 Link link = link(src.toString(), 1, dst.toString(), 1);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800166
Andrey Komarov2398d962016-09-26 15:11:23 +0300167 Weight weightValue = weigher.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link));
168 if (weightValue.isNegative()) {
Thomas Vachuskadc91b552016-03-29 14:02:47 -0700169 return new HashSet<>();
170 }
Ray Milkey8d3ce432014-11-07 16:21:10 -0800171 }
172 }
173 return paths;
Ray Milkeye6684082014-10-16 16:59:47 -0700174 }
175 }
Ray Milkey8d3ce432014-11-07 16:21:10 -0800176
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700177 /**
178 * Mock path service for creating paths within the test.
179 *
180 */
Luca Pretede10c782017-01-05 17:23:08 -0800181 public static class Mp2MpMockPathService extends PathServiceAdapter {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700182
183 final String[] pathHops;
184 final String[] reversePathHops;
185
186 /**
187 * Constructor that provides a set of hops to mock.
188 *
189 * @param pathHops path hops to mock
190 */
191 public Mp2MpMockPathService(String[] pathHops) {
192 this.pathHops = pathHops;
193 String[] reversed = pathHops.clone();
194 Collections.reverse(Arrays.asList(reversed));
195 reversePathHops = reversed;
196 }
197
198 @Override
199 public Set<Path> getPaths(ElementId src, ElementId dst) {
200 Set<Path> result = new HashSet<>();
201
202 String[] allHops = new String[pathHops.length + 2];
203 allHops[0] = src.toString();
204 allHops[allHops.length - 1] = dst.toString();
205
206 if (pathHops.length != 0) {
207 System.arraycopy(pathHops, 0, allHops, 1, pathHops.length);
208 }
209
210 result.add(createPath(allHops));
211
212 return result;
213 }
214
215 @Override
Andrey Komarov2398d962016-09-26 15:11:23 +0300216 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700217 final Set<Path> paths = getPaths(src, dst);
218
219 for (Path path : paths) {
220 final DeviceId srcDevice = path.src().elementId() instanceof DeviceId ? path.src().deviceId() : null;
221 final DeviceId dstDevice = path.dst().elementId() instanceof DeviceId ? path.dst().deviceId() : null;
222 if (srcDevice != null && dstDevice != null) {
223 final TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice);
224 final TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice);
225 final Link link = link(src.toString(), 1, dst.toString(), 1);
226
Andrey Komarov2398d962016-09-26 15:11:23 +0300227 final Weight weightValue = weigher.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link));
228 if (weightValue.isNegative()) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700229 return new HashSet<>();
230 }
231 }
232 }
233 return paths;
234 }
235 }
236
Luca Pretede10c782017-01-05 17:23:08 -0800237 /**
238 * Mock path service for creating paths for MP2SP intent tests, returning
239 * pre-determined paths.
240 */
241 public static class FixedMP2MPMockPathService extends PathServiceAdapter {
Sho SHIMIZUb1681bd2016-02-22 12:47:50 -0800242
Luca Pretede10c782017-01-05 17:23:08 -0800243 final String[] pathHops;
Sho SHIMIZUb1681bd2016-02-22 12:47:50 -0800244
Luca Pretede10c782017-01-05 17:23:08 -0800245 public static final String DPID_1 = "of:s1";
246 public static final String DPID_2 = "of:s2";
247 public static final String DPID_3 = "of:s3";
248 public static final String DPID_4 = "of:s4";
Sho SHIMIZUb1681bd2016-02-22 12:47:50 -0800249
Luca Pretede10c782017-01-05 17:23:08 -0800250 /**
251 * Constructor that provides a set of hops to mock.
252 *
253 * @param pathHops path hops to mock
254 */
255 public FixedMP2MPMockPathService(String[] pathHops) {
256 this.pathHops = pathHops;
Ray Milkey8d3ce432014-11-07 16:21:10 -0800257 }
258
HIGUCHI Yutaca9cc8e2015-10-29 23:26:51 -0700259 @Override
Luca Pretede10c782017-01-05 17:23:08 -0800260 public Set<Path> getPaths(ElementId src, ElementId dst) {
261 List<Link> links = new ArrayList<>();
262 Set<Path> result = new HashSet<>();
263 ProviderId providerId = new ProviderId("of", "foo");
264 DefaultPath path;
265 if (src.toString().equals(DPID_1) && dst.toString().equals(DPID_4)) {
266 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 1));
267 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 2, dst.toString(), 1));
268 } else if (src.toString().equals(DPID_2) && dst.toString().equals(DPID_4)) {
269 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 3));
270 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 2, dst.toString(), 1));
271 } else if (src.toString().equals(DPID_4) && dst.toString().equals(DPID_1)) {
272 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 1));
273 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 2, dst.toString(), 1));
274 } else if (src.toString().equals(DPID_4) && dst.toString().equals(DPID_2)) {
275 links.add(NetTestTools.linkNoPrefixes(src.toString(), 2, pathHops[0], 1));
276 links.add(NetTestTools.linkNoPrefixes(pathHops[0], 3, dst.toString(), 1));
277 } else {
278 return result;
Ray Milkey8d3ce432014-11-07 16:21:10 -0800279 }
Luca Pretede10c782017-01-05 17:23:08 -0800280 path = new DefaultPath(providerId, links, 3);
281 result.add(path);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800282
Luca Pretede10c782017-01-05 17:23:08 -0800283 return result;
Ray Milkey8d3ce432014-11-07 16:21:10 -0800284 }
285
286 @Override
Luca Pretede10c782017-01-05 17:23:08 -0800287 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
288 final Set<Path> paths = getPaths(src, dst);
Ray Milkey8d3ce432014-11-07 16:21:10 -0800289
Luca Pretede10c782017-01-05 17:23:08 -0800290 for (Path path : paths) {
291 final DeviceId srcDevice = path.src().elementId() instanceof DeviceId ? path.src().deviceId() : null;
292 final DeviceId dstDevice = path.dst().elementId() instanceof DeviceId ? path.dst().deviceId() : null;
293 if (srcDevice != null && dstDevice != null) {
294 final TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice);
295 final TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice);
296 final Link link = link(src.toString(), 1, dst.toString(), 1);
297
298 final Weight weightValue = weigher.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link));
299 if (weightValue.isNegative()) {
300 return new HashSet<>();
301 }
302 }
303 }
304 return paths;
Ray Milkeye97ede92014-11-20 10:43:12 -0800305 }
Ray Milkey8d3ce432014-11-07 16:21:10 -0800306 }
307
Ray Milkey930fc662014-11-11 16:07:45 -0800308 private static final IntentTestsMocks.MockSelector SELECTOR =
309 new IntentTestsMocks.MockSelector();
310 private static final IntentTestsMocks.MockTreatment TREATMENT =
311 new IntentTestsMocks.MockTreatment();
312
313 public static class MockFlowRule implements FlowRule {
Ray Milkey77a455f2015-03-27 10:08:17 -0700314 static int nextId = 0;
Ray Milkey930fc662014-11-11 16:07:45 -0800315
316 int priority;
alshabib08d98982015-04-21 16:25:50 -0700317 int tableId;
Ray Milkey77a455f2015-03-27 10:08:17 -0700318 long timestamp;
319 int id;
jcc3d4e14a2015-04-21 11:32:05 +0800320 FlowRuleExtPayLoad payLoad;
sangho11c30ac2015-01-22 14:30:55 -0800321
Ray Milkey930fc662014-11-11 16:07:45 -0800322 public MockFlowRule(int priority) {
323 this.priority = priority;
alshabib08d98982015-04-21 16:25:50 -0700324 this.tableId = 0;
Ray Milkey77a455f2015-03-27 10:08:17 -0700325 this.timestamp = System.currentTimeMillis();
326 this.id = nextId++;
jcc3d4e14a2015-04-21 11:32:05 +0800327 this.payLoad = null;
328 }
329
330 public MockFlowRule(int priority, FlowRuleExtPayLoad payLoad) {
331 this.priority = priority;
332 this.timestamp = System.currentTimeMillis();
333 this.id = nextId++;
334 this.payLoad = payLoad;
Ray Milkey930fc662014-11-11 16:07:45 -0800335 }
336
337 @Override
338 public FlowId id() {
Ray Milkey77a455f2015-03-27 10:08:17 -0700339 return FlowId.valueOf(id);
Ray Milkey930fc662014-11-11 16:07:45 -0800340 }
341
342 @Override
343 public short appId() {
344 return 0;
345 }
346
347 @Override
Sho SHIMIZU75a5bd92014-11-25 11:22:56 -0800348 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800349 return new GroupId(0);
alshabib28204e52014-11-12 18:29:45 -0800350 }
351
352 @Override
Ray Milkey930fc662014-11-11 16:07:45 -0800353 public int priority() {
354 return priority;
355 }
356
357 @Override
358 public DeviceId deviceId() {
359 return did("1");
360 }
361
362 @Override
363 public TrafficSelector selector() {
364 return SELECTOR;
365 }
366
367 @Override
368 public TrafficTreatment treatment() {
369 return TREATMENT;
370 }
371
372 @Override
373 public int timeout() {
374 return 0;
375 }
376
377 @Override
Murat Parlakisikc6759e82016-06-29 03:22:22 -0700378 public int hardTimeout() {
379 return 0;
380 }
381
382 @Override
383 public FlowRemoveReason reason() {
384 return FlowRemoveReason.NO_REASON;
385 }
386
387 @Override
Ray Milkey930fc662014-11-11 16:07:45 -0800388 public boolean isPermanent() {
389 return false;
390 }
391
Brian O'Connor427a1762014-11-19 18:40:32 -0800392 @Override
393 public int hashCode() {
HIGUCHI Yutaca9cc8e2015-10-29 23:26:51 -0700394 return priority;
Brian O'Connor427a1762014-11-19 18:40:32 -0800395 }
Ray Milkey930fc662014-11-11 16:07:45 -0800396
Brian O'Connor427a1762014-11-19 18:40:32 -0800397 @Override
398 public boolean equals(Object obj) {
399 if (this == obj) {
400 return true;
401 }
402 if (obj == null || getClass() != obj.getClass()) {
403 return false;
404 }
405 final MockFlowRule other = (MockFlowRule) obj;
Ray Milkey77a455f2015-03-27 10:08:17 -0700406 return Objects.equals(this.timestamp, other.timestamp) &&
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700407 this.id == other.id;
Brian O'Connor427a1762014-11-19 18:40:32 -0800408 }
sangho11c30ac2015-01-22 14:30:55 -0800409
410 @Override
Jonathan Hartf44e42c2015-08-04 09:58:46 -0700411 public boolean exactMatch(FlowRule rule) {
412 return this.equals(rule);
413 }
414
415 @Override
alshabibdb774072015-04-20 13:13:51 -0700416 public int tableId() {
alshabib08d98982015-04-21 16:25:50 -0700417 return tableId;
alshabibdb774072015-04-20 13:13:51 -0700418 }
jcc3d4e14a2015-04-21 11:32:05 +0800419
420 @Override
421 public FlowRuleExtPayLoad payLoad() {
422 return payLoad;
423 }
Ray Milkey930fc662014-11-11 16:07:45 -0800424 }
425
Ray Milkey5a7787a2015-02-23 11:44:30 -0800426 public static class MockIntent extends Intent {
427 private static AtomicLong counter = new AtomicLong(0);
428
429 private final Long number;
430
431 public MockIntent(Long number) {
Ray Milkeyebc5d222015-03-18 15:45:36 -0700432 super(NetTestTools.APP_ID, null, Collections.emptyList(),
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700433 Intent.DEFAULT_INTENT_PRIORITY);
Ray Milkey5a7787a2015-02-23 11:44:30 -0800434 this.number = number;
435 }
436
Ray Milkey43a28222015-02-23 13:57:58 -0800437 public MockIntent(Long number, Collection<NetworkResource> resources) {
Ray Milkeyebc5d222015-03-18 15:45:36 -0700438 super(NetTestTools.APP_ID, null, resources, Intent.DEFAULT_INTENT_PRIORITY);
Ray Milkey43a28222015-02-23 13:57:58 -0800439 this.number = number;
440 }
441
Ray Milkey5a7787a2015-02-23 11:44:30 -0800442 public Long number() {
443 return number;
444 }
445
446 public static Long nextId() {
447 return counter.getAndIncrement();
448 }
Ray Milkey43a28222015-02-23 13:57:58 -0800449
450 @Override
451 public String toString() {
452 return MoreObjects.toStringHelper(getClass())
453 .add("id", id())
454 .add("appId", appId())
455 .toString();
456 }
Ray Milkey5a7787a2015-02-23 11:44:30 -0800457 }
458
459 public static class MockTimestamp implements Timestamp {
460 final int value;
461
462 public MockTimestamp(int value) {
463 this.value = value;
464 }
465
466 @Override
467 public int compareTo(Timestamp o) {
468 if (!(o instanceof MockTimestamp)) {
469 return -1;
470 }
471 MockTimestamp that = (MockTimestamp) o;
Jonathan Hart72175c22015-03-24 18:55:58 -0700472 return this.value - that.value;
Ray Milkey5a7787a2015-02-23 11:44:30 -0800473 }
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700474
475 @Override
476 public int hashCode() {
477 return value;
478 }
479
480 @Override
481 public boolean equals(Object obj) {
482 if (obj instanceof MockTimestamp) {
483 return this.compareTo((MockTimestamp) obj) == 0;
484 }
485 return false;
486 }
Ray Milkey5a7787a2015-02-23 11:44:30 -0800487 }
488
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700489 /**
490 * Mocks the device service so that a device appears available in the test.
491 */
492 public static class MockDeviceService extends DeviceServiceAdapter {
493 @Override
494 public boolean isAvailable(DeviceId deviceId) {
495 return true;
496 }
497 }
Ray Milkeye6684082014-10-16 16:59:47 -0700498}