blob: 74636718f545044073bb293cb3bc8a13566cd1e0 [file] [log] [blame]
tombe988312014-09-19 18:38:47 -07001package org.onlab.onos.net.flow.impl;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -07002
3import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertFalse;
5import static org.junit.Assert.assertNotNull;
6import static org.junit.Assert.assertTrue;
alshabib97044902014-09-18 14:52:16 -07007import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
8import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
alshabib219ebaa2014-09-22 15:41:24 -07009import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070010
11import java.util.ArrayList;
alshabibba5ac482014-10-02 17:15:20 -070012import java.util.Collections;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070013import java.util.List;
alshabibba5ac482014-10-02 17:15:20 -070014import java.util.Set;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070015
16import org.junit.After;
17import org.junit.Before;
18import org.junit.Test;
alshabiba68eb962014-09-24 20:34:13 -070019import org.onlab.onos.ApplicationId;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070020import org.onlab.onos.event.impl.TestEventDispatcher;
21import org.onlab.onos.net.DefaultDevice;
22import org.onlab.onos.net.Device;
23import org.onlab.onos.net.Device.Type;
24import org.onlab.onos.net.DeviceId;
25import org.onlab.onos.net.MastershipRole;
26import org.onlab.onos.net.Port;
27import org.onlab.onos.net.PortNumber;
28import org.onlab.onos.net.device.DeviceListener;
29import org.onlab.onos.net.device.DeviceService;
alshabib1c319ff2014-10-04 20:29:09 -070030import org.onlab.onos.net.flow.DefaultFlowEntry;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070031import org.onlab.onos.net.flow.DefaultFlowRule;
alshabib1c319ff2014-10-04 20:29:09 -070032import org.onlab.onos.net.flow.FlowEntry;
33import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070034import org.onlab.onos.net.flow.FlowRule;
35import org.onlab.onos.net.flow.FlowRuleEvent;
36import org.onlab.onos.net.flow.FlowRuleListener;
37import org.onlab.onos.net.flow.FlowRuleProvider;
38import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
39import org.onlab.onos.net.flow.FlowRuleProviderService;
40import org.onlab.onos.net.flow.FlowRuleService;
41import org.onlab.onos.net.flow.TrafficSelector;
42import org.onlab.onos.net.flow.TrafficTreatment;
43import org.onlab.onos.net.flow.criteria.Criterion;
44import org.onlab.onos.net.flow.instructions.Instruction;
45import org.onlab.onos.net.provider.AbstractProvider;
46import org.onlab.onos.net.provider.ProviderId;
tomea961ff2014-10-01 12:45:15 -070047import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070048
alshabibba5ac482014-10-02 17:15:20 -070049import com.google.common.collect.ImmutableList;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070050import com.google.common.collect.Lists;
51import com.google.common.collect.Sets;
52
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070053/**
54 * Test codifying the flow rule service & flow rule provider service contracts.
55 */
tom202175a2014-09-19 19:00:11 -070056public class FlowRuleManagerTest {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070057
tomf6ab2152014-09-18 12:08:29 -070058 private static final ProviderId PID = new ProviderId("of", "foo");
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070059 private static final DeviceId DID = DeviceId.deviceId("of:001");
alshabibba5ac482014-10-02 17:15:20 -070060 private static final int TIMEOUT = 10;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070061 private static final Device DEV = new DefaultDevice(
62 PID, DID, Type.SWITCH, "", "", "", "");
63
tom202175a2014-09-19 19:00:11 -070064 private FlowRuleManager mgr;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070065
66 protected FlowRuleService service;
67 protected FlowRuleProviderRegistry registry;
alshabibbb8b1282014-09-22 17:00:18 -070068 protected FlowRuleProviderService providerService;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070069 protected TestProvider provider;
70 protected TestListener listener = new TestListener();
alshabiba68eb962014-09-24 20:34:13 -070071 private ApplicationId appId;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070072
73 @Before
74 public void setUp() {
tom202175a2014-09-19 19:00:11 -070075 mgr = new FlowRuleManager();
tombe988312014-09-19 18:38:47 -070076 mgr.store = new SimpleFlowRuleStore();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070077 mgr.eventDispatcher = new TestEventDispatcher();
78 mgr.deviceService = new TestDeviceService();
79 service = mgr;
80 registry = mgr;
81
82 mgr.activate();
83 mgr.addListener(listener);
84 provider = new TestProvider(PID);
alshabibbb8b1282014-09-22 17:00:18 -070085 providerService = registry.register(provider);
alshabiba68eb962014-09-24 20:34:13 -070086 appId = ApplicationId.getAppId();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070087 assertTrue("provider should be registered",
88 registry.getProviders().contains(provider.id()));
89 }
90
91 @After
92 public void tearDown() {
93 registry.unregister(provider);
94 assertFalse("provider should not be registered",
alshabib97044902014-09-18 14:52:16 -070095 registry.getProviders().contains(provider.id()));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070096 service.removeListener(listener);
97 mgr.deactivate();
98 mgr.eventDispatcher = null;
99 mgr.deviceService = null;
100 }
101
102 private FlowRule flowRule(int tsval, int trval) {
103 TestSelector ts = new TestSelector(tsval);
104 TestTreatment tr = new TestTreatment(trval);
alshabiba0e04982014-10-03 13:03:19 -0700105 return new DefaultFlowRule(DID, ts, tr, 10, appId, TIMEOUT);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700106 }
107
alshabibbb8b1282014-09-22 17:00:18 -0700108
109 private FlowRule addFlowRule(int hval) {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700110 FlowRule rule = flowRule(hval, hval);
alshabibba5ac482014-10-02 17:15:20 -0700111 service.applyFlowRules(rule);
112
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700113 assertNotNull("rule should be found", service.getFlowEntries(DID));
alshabibbb8b1282014-09-22 17:00:18 -0700114 return rule;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700115 }
116
117 private void validateEvents(FlowRuleEvent.Type ... events) {
118 if (events == null) {
119 assertTrue("events generated", listener.events.isEmpty());
120 }
121
122 int i = 0;
alshabibbb42cad2014-09-25 11:43:05 -0700123 System.err.println("events :" + listener.events);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700124 for (FlowRuleEvent e : listener.events) {
125 assertTrue("unexpected event", e.type().equals(events[i]));
126 i++;
127 }
128
129 assertEquals("mispredicted number of events",
130 events.length, listener.events.size());
131
132 listener.events.clear();
133 }
134
135 private int flowCount() {
136 return Sets.newHashSet(service.getFlowEntries(DID)).size();
137 }
138 @Test
139 public void getFlowEntries() {
140 assertTrue("store should be empty",
141 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabibba5ac482014-10-02 17:15:20 -0700142 FlowRule f1 = addFlowRule(1);
143 FlowRule f2 = addFlowRule(2);
144
alshabib1c319ff2014-10-04 20:29:09 -0700145 FlowEntry fe1 = new DefaultFlowEntry(f1);
146 FlowEntry fe2 = new DefaultFlowEntry(f2);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700147 assertEquals("2 rules should exist", 2, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700148
alshabib1c319ff2014-10-04 20:29:09 -0700149 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700150 validateEvents(RULE_ADDED, RULE_ADDED);
151
152 addFlowRule(1);
153 assertEquals("should still be 2 rules", 2, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700154
alshabib1c319ff2014-10-04 20:29:09 -0700155 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1));
alshabib219ebaa2014-09-22 15:41:24 -0700156 validateEvents(RULE_UPDATED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700157 }
158
alshabibbb8b1282014-09-22 17:00:18 -0700159
160 //backing store is sensitive to the order of additions/removals
alshabib1c319ff2014-10-04 20:29:09 -0700161 private boolean validateState(FlowEntryState... state) {
162 Iterable<FlowEntry> rules = service.getFlowEntries(DID);
alshabibbb8b1282014-09-22 17:00:18 -0700163 int i = 0;
alshabib1c319ff2014-10-04 20:29:09 -0700164 for (FlowEntry f : rules) {
alshabibbb8b1282014-09-22 17:00:18 -0700165 if (f.state() != state[i]) {
166 return false;
167 }
168 i++;
169 }
170 return true;
171 }
172
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700173 @Test
174 public void applyFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700175
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700176 FlowRule r1 = flowRule(1, 1);
alshabiba68eb962014-09-24 20:34:13 -0700177 FlowRule r2 = flowRule(2, 2);
178 FlowRule r3 = flowRule(3, 3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700179
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700180 assertTrue("store should be empty",
181 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabib219ebaa2014-09-22 15:41:24 -0700182 mgr.applyFlowRules(r1, r2, r3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700183 assertEquals("3 rules should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700184 assertTrue("Entries should be pending add.",
alshabib1c319ff2014-10-04 20:29:09 -0700185 validateState(FlowEntryState.PENDING_ADD, FlowEntryState.PENDING_ADD,
186 FlowEntryState.PENDING_ADD));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700187 }
188
189 @Test
190 public void removeFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700191 FlowRule f1 = addFlowRule(1);
192 FlowRule f2 = addFlowRule(2);
alshabibba5ac482014-10-02 17:15:20 -0700193 FlowRule f3 = addFlowRule(3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700194 assertEquals("3 rules should exist", 3, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700195
alshabib1c319ff2014-10-04 20:29:09 -0700196 FlowEntry fe1 = new DefaultFlowEntry(f1);
197 FlowEntry fe2 = new DefaultFlowEntry(f2);
198 FlowEntry fe3 = new DefaultFlowEntry(f3);
199 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2, fe3));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700200 validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED);
201
alshabib1c319ff2014-10-04 20:29:09 -0700202 mgr.removeFlowRules(f1, f2);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700203 //removing from north, so no events generated
204 validateEvents();
alshabib219ebaa2014-09-22 15:41:24 -0700205 assertEquals("3 rule should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700206 assertTrue("Entries should be pending remove.",
alshabib1c319ff2014-10-04 20:29:09 -0700207 validateState(FlowEntryState.PENDING_REMOVE, FlowEntryState.PENDING_REMOVE,
208 FlowEntryState.ADDED));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700209
alshabib1c319ff2014-10-04 20:29:09 -0700210 mgr.removeFlowRules(f1);
alshabib219ebaa2014-09-22 15:41:24 -0700211 assertEquals("3 rule should still exist", 3, flowCount());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700212 }
213
214 @Test
215 public void flowRemoved() {
alshabibbb8b1282014-09-22 17:00:18 -0700216 FlowRule f1 = addFlowRule(1);
alshabibba5ac482014-10-02 17:15:20 -0700217 FlowRule f2 = addFlowRule(2);
alshabib1c319ff2014-10-04 20:29:09 -0700218 FlowEntry fe1 = new DefaultFlowEntry(f1);
219 FlowEntry fe2 = new DefaultFlowEntry(f2);
220 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
alshabiba68eb962014-09-24 20:34:13 -0700221 service.removeFlowRules(f1);
alshabib1c319ff2014-10-04 20:29:09 -0700222 fe1.setState(FlowEntryState.REMOVED);
223 providerService.flowRemoved(fe1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700224 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED);
225
alshabib1c319ff2014-10-04 20:29:09 -0700226 providerService.flowRemoved(fe1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700227 validateEvents();
alshabibbb42cad2014-09-25 11:43:05 -0700228
alshabibba5ac482014-10-02 17:15:20 -0700229 FlowRule f3 = flowRule(3, 3);
alshabib1c319ff2014-10-04 20:29:09 -0700230 FlowEntry fe3 = new DefaultFlowEntry(f3);
alshabibba5ac482014-10-02 17:15:20 -0700231 service.applyFlowRules(f3);
alshabib1c319ff2014-10-04 20:29:09 -0700232 providerService.pushFlowMetrics(DID, Collections.singletonList(fe3));
alshabibbb42cad2014-09-25 11:43:05 -0700233 validateEvents(RULE_ADDED);
alshabibba5ac482014-10-02 17:15:20 -0700234
alshabib1c319ff2014-10-04 20:29:09 -0700235 providerService.flowRemoved(fe3);
alshabibbb42cad2014-09-25 11:43:05 -0700236 validateEvents();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700237 }
238
alshabibbb8b1282014-09-22 17:00:18 -0700239 @Test
240 public void flowMetrics() {
241 FlowRule f1 = flowRule(1, 1);
242 FlowRule f2 = flowRule(2, 2);
243 FlowRule f3 = flowRule(3, 3);
244
alshabibba5ac482014-10-02 17:15:20 -0700245 mgr.applyFlowRules(f1, f2, f3);
alshabibbb8b1282014-09-22 17:00:18 -0700246
alshabib1c319ff2014-10-04 20:29:09 -0700247 FlowEntry fe1 = new DefaultFlowEntry(f1);
248 FlowEntry fe2 = new DefaultFlowEntry(f2);
249
250
251 //FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
252 //FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
253
254 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2));
alshabibbb8b1282014-09-22 17:00:18 -0700255
256 assertTrue("Entries should be added.",
alshabib1c319ff2014-10-04 20:29:09 -0700257 validateState(FlowEntryState.ADDED, FlowEntryState.ADDED,
258 FlowEntryState.PENDING_ADD));
alshabibbb42cad2014-09-25 11:43:05 -0700259
alshabibba5ac482014-10-02 17:15:20 -0700260 validateEvents(RULE_ADDED, RULE_ADDED);
alshabibbb42cad2014-09-25 11:43:05 -0700261 }
262
263 @Test
264 public void extraneousFlow() {
265 FlowRule f1 = flowRule(1, 1);
266 FlowRule f2 = flowRule(2, 2);
267 FlowRule f3 = flowRule(3, 3);
alshabibba5ac482014-10-02 17:15:20 -0700268 mgr.applyFlowRules(f1, f2);
alshabibbb42cad2014-09-25 11:43:05 -0700269
alshabib1c319ff2014-10-04 20:29:09 -0700270// FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
271// FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
272// FlowRule updatedF3 = flowRule(f3, FlowRuleState.ADDED);
273 FlowEntry fe1 = new DefaultFlowEntry(f1);
274 FlowEntry fe2 = new DefaultFlowEntry(f2);
275 FlowEntry fe3 = new DefaultFlowEntry(f3);
alshabibbb42cad2014-09-25 11:43:05 -0700276
alshabib1c319ff2014-10-04 20:29:09 -0700277
278 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2, fe3));
alshabibbb42cad2014-09-25 11:43:05 -0700279
alshabibba5ac482014-10-02 17:15:20 -0700280 validateEvents(RULE_ADDED, RULE_ADDED);
alshabibbb42cad2014-09-25 11:43:05 -0700281
282 }
283
284 /*
285 * Tests whether a rule that was marked for removal but no flowRemoved was received
286 * is indeed removed at the next stats update.
287 */
288 @Test
289 public void flowMissingRemove() {
290 FlowRule f1 = flowRule(1, 1);
291 FlowRule f2 = flowRule(2, 2);
292 FlowRule f3 = flowRule(3, 3);
293
alshabib1c319ff2014-10-04 20:29:09 -0700294// FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
295// FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
296
297 FlowEntry fe1 = new DefaultFlowEntry(f1);
298 FlowEntry fe2 = new DefaultFlowEntry(f2);
alshabibbb42cad2014-09-25 11:43:05 -0700299 mgr.applyFlowRules(f1, f2, f3);
300
301 mgr.removeFlowRules(f3);
302
alshabib1c319ff2014-10-04 20:29:09 -0700303 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2));
alshabibbb42cad2014-09-25 11:43:05 -0700304
alshabibba5ac482014-10-02 17:15:20 -0700305 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED);
alshabibbb42cad2014-09-25 11:43:05 -0700306
307 }
308
309 @Test
310 public void getByAppId() {
311 FlowRule f1 = flowRule(1, 1);
312 FlowRule f2 = flowRule(2, 2);
313 mgr.applyFlowRules(f1, f2);
314
315 assertTrue("should have two rules",
316 Lists.newLinkedList(mgr.getFlowRulesById(appId)).size() == 2);
317 }
318
319 @Test
320 public void removeByAppId() {
321 FlowRule f1 = flowRule(1, 1);
322 FlowRule f2 = flowRule(2, 2);
323 mgr.applyFlowRules(f1, f2);
324
325
326 mgr.removeFlowRulesById(appId);
327
328 //only check that we are in pending remove. Events and actual remove state will
329 // be set by flowRemoved call.
alshabib1c319ff2014-10-04 20:29:09 -0700330 validateState(FlowEntryState.PENDING_REMOVE, FlowEntryState.PENDING_REMOVE);
alshabibbb8b1282014-09-22 17:00:18 -0700331 }
332
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700333 private static class TestListener implements FlowRuleListener {
334 final List<FlowRuleEvent> events = new ArrayList<>();
335
336 @Override
337 public void event(FlowRuleEvent event) {
338 events.add(event);
339 }
340 }
341
342 private static class TestDeviceService implements DeviceService {
343
344 @Override
345 public int getDeviceCount() {
346 return 0;
347 }
348
349 @Override
350 public Iterable<Device> getDevices() {
351 return null;
352 }
353
354 @Override
355 public Device getDevice(DeviceId deviceId) {
356 return DEV;
357 }
358
359 @Override
360 public MastershipRole getRole(DeviceId deviceId) {
361 return null;
362 }
363
364 @Override
365 public List<Port> getPorts(DeviceId deviceId) {
366 return null;
367 }
368
369 @Override
370 public Port getPort(DeviceId deviceId, PortNumber portNumber) {
371 return null;
372 }
373
374 @Override
375 public boolean isAvailable(DeviceId deviceId) {
376 return false;
377 }
378
379 @Override
380 public void addListener(DeviceListener listener) {
381 }
382
383 @Override
384 public void removeListener(DeviceListener listener) {
385 }
386
387 }
388
389 private class TestProvider extends AbstractProvider implements FlowRuleProvider {
390
391 protected TestProvider(ProviderId id) {
392 super(PID);
393 }
394
395 @Override
396 public void applyFlowRule(FlowRule... flowRules) {
397 }
398
399 @Override
400 public void removeFlowRule(FlowRule... flowRules) {
401 }
402
alshabiba68eb962014-09-24 20:34:13 -0700403 @Override
404 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
405 }
406
407
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700408 }
409
410 private class TestSelector implements TrafficSelector {
411
412 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700413 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700414
415 public TestSelector(int val) {
416 testval = val;
417 }
418
419 @Override
alshabibba5ac482014-10-02 17:15:20 -0700420 public Set<Criterion> criteria() {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700421 return null;
422 }
423
424 @Override
425 public int hashCode() {
426 return testval;
427 }
428
429 @Override
430 public boolean equals(Object o) {
431 if (o instanceof TestSelector) {
432 return this.testval == ((TestSelector) o).testval;
433 }
434 return false;
435 }
436 }
437
438 private class TestTreatment implements TrafficTreatment {
439
440 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700441 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700442
443 public TestTreatment(int val) {
444 testval = val;
445 }
446
447 @Override
448 public List<Instruction> instructions() {
449 return null;
450 }
451
452 @Override
453 public int hashCode() {
454 return testval;
455 }
456
457 @Override
458 public boolean equals(Object o) {
459 if (o instanceof TestTreatment) {
460 return this.testval == ((TestTreatment) o).testval;
461 }
462 return false;
463 }
464
465 }
466
467}