blob: a1710636be7af8c88bf6c5ea6e45aa060beeedfb [file] [log] [blame]
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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 */
16package org.onosproject.net.group.impl;
17
Andrea Campanella6ee73922016-02-03 18:00:00 -080018import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableMap;
20import com.google.common.collect.Iterables;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080021import org.junit.After;
22import org.junit.Before;
23import org.junit.Test;
24import org.onlab.packet.MacAddress;
Michele Santuari4b6019e2014-12-19 11:31:45 +010025import org.onlab.packet.MplsLabel;
Charles Chan0c7c43b2016-01-14 17:39:20 -080026import org.onosproject.cfg.ComponentConfigAdapter;
Andrea Campanella6ee73922016-02-03 18:00:00 -080027import org.onosproject.common.event.impl.TestEventDispatcher;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.DefaultApplicationId;
30import org.onosproject.core.DefaultGroupId;
31import org.onosproject.core.GroupId;
Andrea Campanella6ee73922016-02-03 18:00:00 -080032import org.onosproject.net.AnnotationKeys;
33import org.onosproject.net.DefaultAnnotations;
34import org.onosproject.net.DefaultDevice;
35import org.onosproject.net.Device;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080036import org.onosproject.net.DeviceId;
37import org.onosproject.net.PortNumber;
Andrea Campanella6ee73922016-02-03 18:00:00 -080038import org.onosproject.net.device.DeviceServiceAdapter;
39import org.onosproject.net.driver.AbstractHandlerBehaviour;
40import org.onosproject.net.driver.DefaultDriver;
41import org.onosproject.net.driver.impl.DriverManager;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080042import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.group.DefaultGroup;
45import org.onosproject.net.group.DefaultGroupBucket;
46import org.onosproject.net.group.DefaultGroupDescription;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070047import org.onosproject.net.group.DefaultGroupKey;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080048import org.onosproject.net.group.Group;
49import org.onosproject.net.group.GroupBucket;
50import org.onosproject.net.group.GroupBuckets;
51import org.onosproject.net.group.GroupDescription;
52import org.onosproject.net.group.GroupEvent;
53import org.onosproject.net.group.GroupKey;
54import org.onosproject.net.group.GroupListener;
55import org.onosproject.net.group.GroupOperation;
56import org.onosproject.net.group.GroupOperations;
Andrea Campanella6ee73922016-02-03 18:00:00 -080057import org.onosproject.net.group.GroupProgrammable;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080058import org.onosproject.net.group.GroupProvider;
59import org.onosproject.net.group.GroupProviderRegistry;
60import org.onosproject.net.group.GroupProviderService;
61import org.onosproject.net.group.GroupService;
62import org.onosproject.net.group.StoredGroupEntry;
63import org.onosproject.net.provider.AbstractProvider;
64import org.onosproject.net.provider.ProviderId;
Thomas Vachuskac97aa612015-06-23 16:00:18 -070065import org.onosproject.store.trivial.SimpleGroupStore;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080066
Andrea Campanella6ee73922016-02-03 18:00:00 -080067import java.util.ArrayList;
68import java.util.Arrays;
69import java.util.Collections;
70import java.util.List;
71
72import static org.junit.Assert.*;
73import static org.onosproject.net.NetTestTools.injectEventDispatcher;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080074
75/**
76 * Test codifying the group service & group provider service contracts.
77 */
78public class GroupManagerTest {
79
80 private static final ProviderId PID = new ProviderId("of", "groupfoo");
81 private static final DeviceId DID = DeviceId.deviceId("of:001");
Andrea Campanella6ee73922016-02-03 18:00:00 -080082 private static final ProviderId FOO_PID = new ProviderId("foo", "foo");
83 private static final DeviceId FOO_DID = DeviceId.deviceId("foo:002");
84
85 private static final DefaultAnnotations ANNOTATIONS =
86 DefaultAnnotations.builder().set(AnnotationKeys.DRIVER, "foo").build();
87
88 private static final Device FOO_DEV =
89 new DefaultDevice(FOO_PID, FOO_DID, Device.Type.SWITCH, "", "", "", "", null, ANNOTATIONS);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080090
91 private GroupManager mgr;
92 private GroupService groupService;
93 private GroupProviderRegistry providerRegistry;
94 private TestGroupListener internalListener = new TestGroupListener();
95 private GroupListener listener = internalListener;
96 private TestGroupProvider internalProvider;
97 private GroupProvider provider;
98 private GroupProviderService providerService;
99 private ApplicationId appId;
Andrea Campanella6ee73922016-02-03 18:00:00 -0800100 private TestDriverManager driverService;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800101
102 @Before
103 public void setUp() {
104 mgr = new GroupManager();
105 groupService = mgr;
Andrea Campanella6ee73922016-02-03 18:00:00 -0800106 //mgr.deviceService = new DeviceManager();
107 mgr.deviceService = new TestDeviceService();
Charles Chan0c7c43b2016-01-14 17:39:20 -0800108 mgr.cfgService = new ComponentConfigAdapter();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800109 mgr.store = new SimpleGroupStore();
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700110 injectEventDispatcher(mgr, new TestEventDispatcher());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800111 providerRegistry = mgr;
112
Charles Chan0c7c43b2016-01-14 17:39:20 -0800113 mgr.activate(null);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800114 mgr.addListener(listener);
115
Andrea Campanella6ee73922016-02-03 18:00:00 -0800116 driverService = new TestDriverManager();
117 driverService.addDriver(new DefaultDriver("foo", ImmutableList.of(), "", "", "",
118 ImmutableMap.of(GroupProgrammable.class,
119 TestGroupProgrammable.class),
120 ImmutableMap.of()));
121
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800122 internalProvider = new TestGroupProvider(PID);
123 provider = internalProvider;
124 providerService = providerRegistry.register(provider);
125 appId = new DefaultApplicationId(2, "org.groupmanager.test");
126 assertTrue("provider should be registered",
127 providerRegistry.getProviders().contains(provider.id()));
128 }
129
130 @After
131 public void tearDown() {
132 providerRegistry.unregister(provider);
133 assertFalse("provider should not be registered",
134 providerRegistry.getProviders().contains(provider.id()));
135 mgr.removeListener(listener);
136 mgr.deactivate();
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700137 injectEventDispatcher(mgr, null);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800138 }
139
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800140 /**
Andrea Campanella6ee73922016-02-03 18:00:00 -0800141 * Tests group creation before the device group AUDIT completes.
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800142 */
143 @Test
Andrea Campanella6ee73922016-02-03 18:00:00 -0800144 public void testGroupServiceBasics() {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800145 // Test Group creation before AUDIT process
Andrea Campanella6ee73922016-02-03 18:00:00 -0800146 testGroupCreationBeforeAudit(DID);
147 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800148
Andrea Campanella6ee73922016-02-03 18:00:00 -0800149 /**
150 * Tests initial device group AUDIT process.
151 */
152 @Test
153 public void testGroupServiceInitialAudit() {
154 // Test Group creation before AUDIT process
155 testGroupCreationBeforeAudit(DID);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800156 // Test initial group audit process
Andrea Campanella6ee73922016-02-03 18:00:00 -0800157 testInitialAuditWithPendingGroupRequests(DID);
158 }
159
160 /**
161 * Tests deletion process of any extraneous groups.
162 */
163 @Test
164 public void testGroupServiceAuditExtraneous() {
165 // Test Group creation before AUDIT process
166 testGroupCreationBeforeAudit(DID);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800167
168 // Test audit with extraneous and missing groups
Andrea Campanella6ee73922016-02-03 18:00:00 -0800169 testAuditWithExtraneousMissingGroups(DID);
170 }
171
172 /**
173 * Tests re-apply process of any missing groups tests execution of
174 * any pending group creation request after the device group AUDIT completes
175 * and tests event notifications after receiving confirmation for any
176 * operations from data plane.
177 */
178 @Test
179 public void testGroupServiceAuditConfirmed() {
180 // Test Group creation before AUDIT process
181 testGroupCreationBeforeAudit(DID);
182
183 // Test audit with extraneous and missing groups
184 testAuditWithExtraneousMissingGroups(DID);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800185
186 // Test audit with confirmed groups
Andrea Campanella6ee73922016-02-03 18:00:00 -0800187 testAuditWithConfirmedGroups(DID);
188 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800189
Andrea Campanella6ee73922016-02-03 18:00:00 -0800190 /**
191 * Tests group bucket modifications (additions and deletions) and
192 * Tests group deletion.
193 */
194 @Test
195 public void testGroupServiceBuckets() {
196 // Test Group creation before AUDIT process
197 testGroupCreationBeforeAudit(DID);
198 programmableTestCleanUp();
199
200 testAuditWithExtraneousMissingGroups(DID);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800201 // Test group add bucket operations
Andrea Campanella6ee73922016-02-03 18:00:00 -0800202 testAddBuckets(DID);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800203
204 // Test group remove bucket operations
Andrea Campanella6ee73922016-02-03 18:00:00 -0800205 testRemoveBuckets(DID);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800206
207 // Test group remove operations
Andrea Campanella6ee73922016-02-03 18:00:00 -0800208 testRemoveGroup(DID);
209 }
210
211 /**
212 * Tests group creation before the device group AUDIT completes with fallback
213 * provider.
214 */
215 @Test
216 public void testGroupServiceFallbackBasics() {
217 // Test Group creation before AUDIT process
218 testGroupCreationBeforeAudit(FOO_DID);
219 programmableTestCleanUp();
220
221 }
222
223 /**
224 * Tests initial device group AUDIT process with fallback provider.
225 */
226 @Test
227 public void testGroupServiceFallbackInitialAudit() {
228 // Test Group creation before AUDIT process
229 testGroupCreationBeforeAudit(FOO_DID);
230 programmableTestCleanUp();
231 // Test initial group audit process
232 testInitialAuditWithPendingGroupRequests(FOO_DID);
233 }
234
235 /**
236 * Tests deletion process of any extraneous groups with fallback provider.
237 */
238 @Test
239 public void testGroupServiceFallbackAuditExtraneous() {
240 // Test Group creation before AUDIT process
241 testGroupCreationBeforeAudit(FOO_DID);
242 programmableTestCleanUp();
243
244 // Test audit with extraneous and missing groups
245 testAuditWithExtraneousMissingGroups(FOO_DID);
246 }
247
248 /**
249 * Tests re-apply process of any missing groups tests execution of
250 * any pending group creation request after the device group AUDIT completes
251 * and tests event notifications after receiving confirmation for any
252 * operations from data plane with fallback provider.
253 */
254 @Test
255 public void testGroupServiceFallbackAuditConfirmed() {
256 // Test Group creation before AUDIT process
257 testGroupCreationBeforeAudit(FOO_DID);
258 programmableTestCleanUp();
259
260 // Test audit with extraneous and missing groups
261 testAuditWithExtraneousMissingGroups(FOO_DID);
262
263 // Test audit with confirmed groups
264 testAuditWithConfirmedGroups(FOO_DID);
265 }
266
267 /**
268 * Tests group bucket modifications (additions and deletions) and
269 * Tests group deletion with fallback provider.
270 */
271 @Test
272 public void testGroupServiceFallbackBuckets() {
273 // Test Group creation before AUDIT process
274 testGroupCreationBeforeAudit(FOO_DID);
275 programmableTestCleanUp();
276
277 testAuditWithExtraneousMissingGroups(FOO_DID);
278 // Test group add bucket operations
279 testAddBuckets(FOO_DID);
280
281 // Test group remove bucket operations
282 testRemoveBuckets(FOO_DID);
283
284 // Test group remove operations
285 testRemoveGroup(FOO_DID);
286 }
287
288 private void programmableTestCleanUp() {
289 groupOperations.clear();
290 lastDeviceIdProgrammable = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800291 }
292
293 // Test Group creation before AUDIT process
Andrea Campanella6ee73922016-02-03 18:00:00 -0800294 private void testGroupCreationBeforeAudit(DeviceId deviceId) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800295 PortNumber[] ports1 = {PortNumber.portNumber(31),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800296 PortNumber.portNumber(32)};
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800297 PortNumber[] ports2 = {PortNumber.portNumber(41),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800298 PortNumber.portNumber(42)};
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700299 GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700300 List<GroupBucket> buckets = new ArrayList<>();
301 List<PortNumber> outPorts = new ArrayList<>();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800302 outPorts.addAll(Arrays.asList(ports1));
303 outPorts.addAll(Arrays.asList(ports2));
Andrea Campanella6ee73922016-02-03 18:00:00 -0800304 for (PortNumber portNumber : outPorts) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800305 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
306 tBuilder.setOutput(portNumber)
307 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
308 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
309 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100310 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800311 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800312 tBuilder.build()));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800313 }
314 GroupBuckets groupBuckets = new GroupBuckets(buckets);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800315 GroupDescription newGroupDesc = new DefaultGroupDescription(deviceId,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800316 Group.Type.SELECT,
317 groupBuckets,
318 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700319 null,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800320 appId);
321 groupService.addGroup(newGroupDesc);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800322 assertEquals(null, groupService.getGroup(deviceId, key));
323 assertEquals(0, Iterables.size(groupService.getGroups(deviceId, appId)));
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800324 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800325
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800326 // Test initial AUDIT process with pending group requests
Andrea Campanella6ee73922016-02-03 18:00:00 -0800327 private void testInitialAuditWithPendingGroupRequests(DeviceId deviceId) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800328 PortNumber[] ports1 = {PortNumber.portNumber(31),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800329 PortNumber.portNumber(32)};
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800330 PortNumber[] ports2 = {PortNumber.portNumber(41),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800331 PortNumber.portNumber(42)};
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800332 GroupId gId1 = new DefaultGroupId(1);
333 Group group1 = createSouthboundGroupEntry(gId1,
334 Arrays.asList(ports1),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800335 0, deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800336 GroupId gId2 = new DefaultGroupId(2);
337 // Non zero reference count will make the group manager to queue
338 // the extraneous groups until reference count is zero.
339 Group group2 = createSouthboundGroupEntry(gId2,
340 Arrays.asList(ports2),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800341 2, deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800342 List<Group> groupEntries = Arrays.asList(group1, group2);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800343 providerService.pushGroupMetrics(deviceId, groupEntries);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800344 // First group metrics would trigger the device audit completion
345 // post which all pending group requests are also executed.
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700346 GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
Andrea Campanella6ee73922016-02-03 18:00:00 -0800347 Group createdGroup = groupService.getGroup(deviceId, key);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800348 int createdGroupId = createdGroup.id().id();
349 assertNotEquals(gId1.id(), createdGroupId);
350 assertNotEquals(gId2.id(), createdGroupId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800351
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800352 List<GroupOperation> expectedGroupOps = Arrays.asList(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800353 GroupOperation.createDeleteGroupOperation(gId1,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800354 Group.Type.SELECT),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800355 GroupOperation.createAddGroupOperation(
356 createdGroup.id(),
357 Group.Type.SELECT,
358 createdGroup.buckets()));
359 if (deviceId.equals(DID)) {
360 internalProvider.validate(deviceId, expectedGroupOps);
361 } else {
362 this.validate(deviceId, expectedGroupOps);
363 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800364 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800365
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800366 // Test AUDIT process with extraneous groups and missing groups
Andrea Campanella6ee73922016-02-03 18:00:00 -0800367 private void testAuditWithExtraneousMissingGroups(DeviceId deviceId) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800368 PortNumber[] ports1 = {PortNumber.portNumber(31),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800369 PortNumber.portNumber(32)};
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800370 PortNumber[] ports2 = {PortNumber.portNumber(41),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800371 PortNumber.portNumber(42)};
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800372 GroupId gId1 = new DefaultGroupId(1);
373 Group group1 = createSouthboundGroupEntry(gId1,
Andrea Campanella6ee73922016-02-03 18:00:00 -0800374 Arrays.asList(ports1),
375 0, deviceId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800376 GroupId gId2 = new DefaultGroupId(2);
377 Group group2 = createSouthboundGroupEntry(gId2,
Andrea Campanella6ee73922016-02-03 18:00:00 -0800378 Arrays.asList(ports2),
379 0, deviceId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800380 List<Group> groupEntries = Arrays.asList(group1, group2);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800381 providerService.pushGroupMetrics(deviceId, groupEntries);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700382 GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
Andrea Campanella6ee73922016-02-03 18:00:00 -0800383 Group createdGroup = groupService.getGroup(deviceId, key);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800384 List<GroupOperation> expectedGroupOps = Arrays.asList(
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800385 GroupOperation.createDeleteGroupOperation(gId1,
386 Group.Type.SELECT),
387 GroupOperation.createDeleteGroupOperation(gId2,
388 Group.Type.SELECT),
389 GroupOperation.createAddGroupOperation(createdGroup.id(),
390 Group.Type.SELECT,
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800391 createdGroup.buckets()));
Andrea Campanella6ee73922016-02-03 18:00:00 -0800392 if (deviceId.equals(DID)) {
393 internalProvider.validate(deviceId, expectedGroupOps);
394 } else {
395 this.validate(deviceId, expectedGroupOps);
396 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800397 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800398
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800399 // Test AUDIT with confirmed groups
Andrea Campanella6ee73922016-02-03 18:00:00 -0800400 private void testAuditWithConfirmedGroups(DeviceId deviceId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700401 GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
Andrea Campanella6ee73922016-02-03 18:00:00 -0800402 Group createdGroup = groupService.getGroup(deviceId, key);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800403 createdGroup = new DefaultGroup(createdGroup.id(),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800404 deviceId,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800405 Group.Type.SELECT,
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800406 createdGroup.buckets());
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700407 List<Group> groupEntries = Collections.singletonList(createdGroup);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800408 providerService.pushGroupMetrics(deviceId, groupEntries);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700409 internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADDED));
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800410 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800411
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800412 // Test group add bucket operations
Andrea Campanella6ee73922016-02-03 18:00:00 -0800413 private void testAddBuckets(DeviceId deviceId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700414 GroupKey addKey = new DefaultGroupKey("group1AddBuckets".getBytes());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800415
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700416 GroupKey prevKey = new DefaultGroupKey("group1BeforeAudit".getBytes());
Andrea Campanella6ee73922016-02-03 18:00:00 -0800417 Group createdGroup = groupService.getGroup(deviceId, prevKey);
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700418 List<GroupBucket> buckets = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800419 buckets.addAll(createdGroup.buckets().buckets());
420
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800421 PortNumber[] addPorts = {PortNumber.portNumber(51),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800422 PortNumber.portNumber(52)};
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700423 List<PortNumber> outPorts;
Sho SHIMIZU7a4087b2015-09-10 09:23:16 -0700424 outPorts = new ArrayList<>();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800425 outPorts.addAll(Arrays.asList(addPorts));
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700426 List<GroupBucket> addBuckets;
Sho SHIMIZU7a4087b2015-09-10 09:23:16 -0700427 addBuckets = new ArrayList<>();
Andrea Campanella6ee73922016-02-03 18:00:00 -0800428 for (PortNumber portNumber : outPorts) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800429 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
430 tBuilder.setOutput(portNumber)
431 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
432 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
433 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100434 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800435 addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800436 tBuilder.build()));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800437 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800438 tBuilder.build()));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800439 }
440 GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800441 groupService.addBucketsToGroup(deviceId,
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800442 prevKey,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800443 groupAddBuckets,
444 addKey,
445 appId);
446 GroupBuckets updatedBuckets = new GroupBuckets(buckets);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700447 List<GroupOperation> expectedGroupOps = Collections.singletonList(
448 GroupOperation.createModifyGroupOperation(createdGroup.id(),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800449 Group.Type.SELECT,
450 updatedBuckets));
451 if (deviceId.equals(DID)) {
452 internalProvider.validate(deviceId, expectedGroupOps);
453 } else {
454 this.validate(deviceId, expectedGroupOps);
455 }
456 Group existingGroup = groupService.getGroup(deviceId, addKey);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700457 List<Group> groupEntries = Collections.singletonList(existingGroup);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800458 providerService.pushGroupMetrics(deviceId, groupEntries);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700459 internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800460 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800461
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800462 // Test group remove bucket operations
Andrea Campanella6ee73922016-02-03 18:00:00 -0800463 private void testRemoveBuckets(DeviceId deviceId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700464 GroupKey removeKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800465
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700466 GroupKey prevKey = new DefaultGroupKey("group1AddBuckets".getBytes());
Andrea Campanella6ee73922016-02-03 18:00:00 -0800467 Group createdGroup = groupService.getGroup(deviceId, prevKey);
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700468 List<GroupBucket> buckets = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800469 buckets.addAll(createdGroup.buckets().buckets());
470
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800471 PortNumber[] removePorts = {PortNumber.portNumber(31),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800472 PortNumber.portNumber(32)};
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700473 List<PortNumber> outPorts = new ArrayList<>();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800474 outPorts.addAll(Arrays.asList(removePorts));
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700475 List<GroupBucket> removeBuckets = new ArrayList<>();
Andrea Campanella6ee73922016-02-03 18:00:00 -0800476 for (PortNumber portNumber : outPorts) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800477 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
478 tBuilder.setOutput(portNumber)
479 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
480 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
481 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100482 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800483 removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800484 tBuilder.build()));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800485 buckets.remove(DefaultGroupBucket.createSelectGroupBucket(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800486 tBuilder.build()));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800487 }
488 GroupBuckets groupRemoveBuckets = new GroupBuckets(removeBuckets);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800489 groupService.removeBucketsFromGroup(deviceId,
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800490 prevKey,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800491 groupRemoveBuckets,
492 removeKey,
493 appId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800494 GroupBuckets updatedBuckets = new GroupBuckets(buckets);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700495 List<GroupOperation> expectedGroupOps = Collections.singletonList(
496 GroupOperation.createModifyGroupOperation(createdGroup.id(),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800497 Group.Type.SELECT,
498 updatedBuckets));
499 if (deviceId.equals(DID)) {
500 internalProvider.validate(deviceId, expectedGroupOps);
501 } else {
502 this.validate(deviceId, expectedGroupOps);
503 }
504 Group existingGroup = groupService.getGroup(deviceId, removeKey);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700505 List<Group> groupEntries = Collections.singletonList(existingGroup);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800506 providerService.pushGroupMetrics(deviceId, groupEntries);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700507 internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800508 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800509
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800510 // Test group remove operations
Andrea Campanella6ee73922016-02-03 18:00:00 -0800511 private void testRemoveGroup(DeviceId deviceId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700512 GroupKey currKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
Andrea Campanella6ee73922016-02-03 18:00:00 -0800513 Group existingGroup = groupService.getGroup(deviceId, currKey);
514 groupService.removeGroup(deviceId, currKey, appId);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700515 List<GroupOperation> expectedGroupOps = Collections.singletonList(
516 GroupOperation.createDeleteGroupOperation(existingGroup.id(),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800517 Group.Type.SELECT));
518 if (deviceId.equals(DID)) {
519 internalProvider.validate(deviceId, expectedGroupOps);
520 } else {
521 this.validate(deviceId, expectedGroupOps);
522 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800523 List<Group> groupEntries = Collections.emptyList();
Andrea Campanella6ee73922016-02-03 18:00:00 -0800524 providerService.pushGroupMetrics(deviceId, groupEntries);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700525 internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVED));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800526 }
527
sangho7ff01812015-02-09 16:21:53 -0800528 /**
529 * Test GroupOperationFailure function in Group Manager.
530 * a)GroupAddFailure
531 * b)GroupUpdateFailure
532 * c)GroupRemoteFailure
533 */
534 @Test
535 public void testGroupOperationFailure() {
Andrea Campanella6ee73922016-02-03 18:00:00 -0800536 groupOperationFaliure(DID);
537 }
538
539 /**
540 * Test GroupOperationFailure function in Group Manager
541 * with fallback provider.
542 * a)GroupAddFailure
543 * b)GroupUpdateFailure
544 * c)GroupRemoteFailure
545 */
546 @Test
547 public void testGroupOperationFailureFallBack() {
548 groupOperationFaliure(FOO_DID);
549 }
550
551 private void groupOperationFaliure(DeviceId deviceId) {
sangho7ff01812015-02-09 16:21:53 -0800552 PortNumber[] ports1 = {PortNumber.portNumber(31),
553 PortNumber.portNumber(32)};
554 PortNumber[] ports2 = {PortNumber.portNumber(41),
555 PortNumber.portNumber(42)};
556 // Test Group creation before AUDIT process
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700557 GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700558 List<GroupBucket> buckets = new ArrayList<>();
559 List<PortNumber> outPorts = new ArrayList<>();
sangho7ff01812015-02-09 16:21:53 -0800560 outPorts.addAll(Arrays.asList(ports1));
561 outPorts.addAll(Arrays.asList(ports2));
Andrea Campanella6ee73922016-02-03 18:00:00 -0800562 for (PortNumber portNumber : outPorts) {
sangho7ff01812015-02-09 16:21:53 -0800563 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
564 tBuilder.setOutput(portNumber)
565 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
566 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
567 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100568 .setMpls(MplsLabel.mplsLabel(106));
sangho7ff01812015-02-09 16:21:53 -0800569 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
570 tBuilder.build()));
571 }
572 GroupBuckets groupBuckets = new GroupBuckets(buckets);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800573 GroupDescription newGroupDesc = new DefaultGroupDescription(deviceId,
574 Group.Type.SELECT,
575 groupBuckets,
576 key,
577 null,
578 appId);
sangho7ff01812015-02-09 16:21:53 -0800579 groupService.addGroup(newGroupDesc);
580
581 // Test initial group audit process
582 GroupId gId1 = new DefaultGroupId(1);
583 Group group1 = createSouthboundGroupEntry(gId1,
Andrea Campanella6ee73922016-02-03 18:00:00 -0800584 Arrays.asList(ports1),
585 0, deviceId);
sangho7ff01812015-02-09 16:21:53 -0800586 GroupId gId2 = new DefaultGroupId(2);
587 // Non zero reference count will make the group manager to queue
588 // the extraneous groups until reference count is zero.
589 Group group2 = createSouthboundGroupEntry(gId2,
Andrea Campanella6ee73922016-02-03 18:00:00 -0800590 Arrays.asList(ports2),
591 2, deviceId);
sangho7ff01812015-02-09 16:21:53 -0800592 List<Group> groupEntries = Arrays.asList(group1, group2);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800593 providerService.pushGroupMetrics(deviceId, groupEntries);
594 Group createdGroup = groupService.getGroup(deviceId, key);
sangho7ff01812015-02-09 16:21:53 -0800595
596 // Group Add failure test
597 GroupOperation groupAddOp = GroupOperation.
598 createAddGroupOperation(createdGroup.id(),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800599 createdGroup.type(),
600 createdGroup.buckets());
601 providerService.groupOperationFailed(deviceId, groupAddOp);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700602 internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADD_FAILED));
sangho7ff01812015-02-09 16:21:53 -0800603
604 // Group Mod failure test
605 groupService.addGroup(newGroupDesc);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800606 createdGroup = groupService.getGroup(deviceId, key);
sangho7ff01812015-02-09 16:21:53 -0800607 assertNotNull(createdGroup);
608
609 GroupOperation groupModOp = GroupOperation.
610 createModifyGroupOperation(createdGroup.id(),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800611 createdGroup.type(),
612 createdGroup.buckets());
613 providerService.groupOperationFailed(deviceId, groupModOp);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700614 internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATE_FAILED));
sangho7ff01812015-02-09 16:21:53 -0800615
616 // Group Delete failure test
617 groupService.addGroup(newGroupDesc);
Andrea Campanella6ee73922016-02-03 18:00:00 -0800618 createdGroup = groupService.getGroup(deviceId, key);
sangho7ff01812015-02-09 16:21:53 -0800619 assertNotNull(createdGroup);
620
621 GroupOperation groupDelOp = GroupOperation.
622 createDeleteGroupOperation(createdGroup.id(),
Andrea Campanella6ee73922016-02-03 18:00:00 -0800623 createdGroup.type());
624 providerService.groupOperationFailed(deviceId, groupDelOp);
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700625 internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVE_FAILED));
sangho7ff01812015-02-09 16:21:53 -0800626 }
627
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800628 private Group createSouthboundGroupEntry(GroupId gId,
629 List<PortNumber> ports,
Andrea Campanella6ee73922016-02-03 18:00:00 -0800630 long referenceCount, DeviceId deviceId) {
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700631 List<PortNumber> outPorts = new ArrayList<>();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800632 outPorts.addAll(ports);
633
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700634 List<GroupBucket> buckets = new ArrayList<>();
Andrea Campanella6ee73922016-02-03 18:00:00 -0800635 for (PortNumber portNumber : outPorts) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800636 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
637 tBuilder.setOutput(portNumber)
638 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
639 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
640 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100641 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800642 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800643 tBuilder.build()));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800644 }
645 GroupBuckets groupBuckets = new GroupBuckets(buckets);
646 StoredGroupEntry group = new DefaultGroup(
Andrea Campanella6ee73922016-02-03 18:00:00 -0800647 gId, deviceId, Group.Type.SELECT, groupBuckets);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800648 group.setReferenceCount(referenceCount);
649 return group;
650 }
651
652 private static class TestGroupListener implements GroupListener {
653 final List<GroupEvent> events = new ArrayList<>();
654
655 @Override
656 public void event(GroupEvent event) {
657 events.add(event);
658 }
659
660 public void validateEvent(List<GroupEvent.Type> expectedEvents) {
661 int i = 0;
662 System.err.println("events :" + events);
663 for (GroupEvent e : events) {
664 assertEquals("unexpected event", expectedEvents.get(i), e.type());
665 i++;
666 }
667 assertEquals("mispredicted number of events",
668 expectedEvents.size(), events.size());
669 events.clear();
670 }
671 }
672
673 private class TestGroupProvider
Andrea Campanella6ee73922016-02-03 18:00:00 -0800674 extends AbstractProvider implements GroupProvider {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800675 DeviceId lastDeviceId;
Sho SHIMIZUd88db6f2015-09-09 14:22:06 -0700676 List<GroupOperation> groupOperations = new ArrayList<>();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800677
678 protected TestGroupProvider(ProviderId id) {
679 super(id);
680 }
681
682 @Override
683 public void performGroupOperation(DeviceId deviceId,
684 GroupOperations groupOps) {
685 lastDeviceId = deviceId;
686 groupOperations.addAll(groupOps.operations());
687 }
688
689 public void validate(DeviceId expectedDeviceId,
690 List<GroupOperation> expectedGroupOps) {
691 if (expectedGroupOps == null) {
692 assertTrue("events generated", groupOperations.isEmpty());
693 return;
694 }
695
696 assertEquals(lastDeviceId, expectedDeviceId);
697 assertTrue((this.groupOperations.containsAll(expectedGroupOps) &&
698 expectedGroupOps.containsAll(groupOperations)));
699
700 groupOperations.clear();
701 lastDeviceId = null;
702 }
703
704 }
705
Andrea Campanella6ee73922016-02-03 18:00:00 -0800706 private static class TestDeviceService extends DeviceServiceAdapter {
707 @Override
708 public int getDeviceCount() {
709 return 1;
710 }
711
712 @Override
713 public Iterable<Device> getDevices() {
714 return ImmutableList.of(FOO_DEV);
715 }
716
717 @Override
718 public Iterable<Device> getAvailableDevices() {
719 return getDevices();
720 }
721
722 @Override
723 public Device getDevice(DeviceId deviceId) {
724 return FOO_DEV;
725 }
726 }
727
728 private class TestDriverManager extends DriverManager {
729 TestDriverManager() {
730 this.deviceService = mgr.deviceService;
731 activate();
732 }
733 }
734
735 private static DeviceId lastDeviceIdProgrammable;
736 private static List<GroupOperation> groupOperations = new ArrayList<>();
737
738 public static class TestGroupProgrammable extends AbstractHandlerBehaviour implements GroupProgrammable {
739 @Override
740 public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) {
741 lastDeviceIdProgrammable = deviceId;
742 groupOperations.addAll(groupOps.operations());
743 }
744 }
745
746 public void validate(DeviceId expectedDeviceId,
747 List<GroupOperation> expectedGroupOps) {
748 if (expectedGroupOps == null) {
749 assertTrue("events generated", groupOperations.isEmpty());
750 return;
751 }
752
753 assertEquals(lastDeviceIdProgrammable, expectedDeviceId);
754 assertTrue((this.groupOperations.containsAll(expectedGroupOps) &&
755 expectedGroupOps.containsAll(groupOperations)));
756
757 groupOperations.clear();
758 lastDeviceIdProgrammable = null;
759 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800760}
761
762