| /* |
| * Copyright 2016-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.net.optical.intent.impl.compiler; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Sets; |
| import org.easymock.EasyMock; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.onlab.packet.ChassisId; |
| import org.onosproject.TestApplicationId; |
| import org.onosproject.cfg.ComponentConfigService; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.core.CoreService; |
| import org.onosproject.net.AbstractProjectableModel; |
| import org.onosproject.net.Annotations; |
| import org.onosproject.net.ChannelSpacing; |
| import org.onosproject.net.CltSignalType; |
| import org.onosproject.net.ConnectPoint; |
| import org.onosproject.net.DefaultAnnotations; |
| import org.onosproject.net.DefaultDevice; |
| import org.onosproject.net.DefaultPort; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.OchSignal; |
| import org.onosproject.net.OduSignalId; |
| import org.onosproject.net.OduSignalType; |
| import org.onosproject.net.OduSignalUtils; |
| import org.onosproject.net.Port; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.TributarySlot; |
| import org.onosproject.net.behaviour.TributarySlotQuery; |
| import org.onosproject.net.device.DeviceServiceAdapter; |
| import org.onosproject.net.driver.Behaviour; |
| import org.onosproject.net.driver.DefaultDriver; |
| import org.onosproject.net.driver.Driver; |
| import org.onosproject.net.driver.DriverHandler; |
| import org.onosproject.net.driver.DriverService; |
| import org.onosproject.net.driver.DriverServiceAdapter; |
| import org.onosproject.net.driver.TestBehaviourImpl; |
| import org.onosproject.net.driver.TestBehaviourTwoImpl; |
| import org.onosproject.net.flow.DefaultTrafficSelector; |
| import org.onosproject.net.flow.DefaultTrafficTreatment; |
| import org.onosproject.net.flow.FlowRule; |
| import org.onosproject.net.flow.TrafficSelector; |
| import org.onosproject.net.flow.TrafficTreatment; |
| import org.onosproject.net.flow.criteria.Criteria; |
| import org.onosproject.net.flow.instructions.Instructions; |
| import org.onosproject.net.intent.AbstractIntentTest; |
| import org.onosproject.net.intent.FlowRuleIntent; |
| import org.onosproject.net.intent.Intent; |
| import org.onosproject.net.intent.IntentExtensionService; |
| import org.onosproject.net.intent.IntentId; |
| import org.onosproject.net.intent.IntentServiceAdapter; |
| import org.onosproject.net.intent.IntentSetMultimap; |
| import org.onosproject.net.intent.Key; |
| import org.onosproject.net.intent.OpticalCircuitIntent; |
| import org.onosproject.net.optical.OchPort; |
| import org.onosproject.net.optical.OduCltPort; |
| import org.onosproject.net.optical.impl.DefaultOchPort; |
| import org.onosproject.net.optical.impl.DefaultOduCltPort; |
| import org.onosproject.net.provider.ProviderId; |
| import org.onosproject.net.resource.MockResourceService; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| |
| import static org.easymock.EasyMock.*; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.Matchers.*; |
| import static org.junit.Assert.assertEquals; |
| import static org.onosproject.net.AnnotationKeys.PORT_NAME; |
| import static org.onosproject.net.AnnotationKeys.STATIC_PORT; |
| import static org.onosproject.net.Device.Type.ROADM; |
| import static org.onosproject.net.DeviceId.deviceId; |
| import static org.onosproject.net.NetTestTools.APP_ID; |
| |
| public class OpticalCircuitIntentCompilerTest extends AbstractIntentTest { |
| |
| private static final String DEV1 = "of:1"; |
| private static final String DEV2 = "of:2"; |
| |
| static final Key KEY1 = Key.of(5L, APP_ID); |
| |
| private static final String STATIC_TRUE = "true"; |
| private static final String PNAME = "p2"; |
| |
| private CoreService coreService; |
| private IntentExtensionService intentExtensionService; |
| private OpticalCircuitIntentCompiler sut; |
| |
| private final ApplicationId appId = new TestApplicationId("test"); |
| private static Device device1 = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), ROADM, |
| "m", "h", "s", "n", new ChassisId(0L)); |
| private static Device device2 = new DefaultDevice(ProviderId.NONE, deviceId(DEV2), ROADM, |
| "m", "h", "s", "n", new ChassisId(1L)); |
| |
| private static Annotations annotations1 = DefaultAnnotations.builder().set(STATIC_PORT, STATIC_TRUE).build(); |
| private static Annotations annotations2 = DefaultAnnotations.builder().set(PORT_NAME, PNAME).build(); |
| |
| // OduClt ports with signalType=1GBE |
| private static final OduCltPort D1P1 = |
| new DefaultOduCltPort(new DefaultPort(device1, PortNumber.portNumber(1), true, annotations1), |
| CltSignalType.CLT_1GBE); |
| private static final OduCltPort D2P1 = |
| new DefaultOduCltPort(new DefaultPort(device2, PortNumber.portNumber(1), true, annotations1), |
| CltSignalType.CLT_1GBE); |
| |
| // Och ports with signalType=ODU2 |
| private static final OchPort D1P2 = |
| new DefaultOchPort(new DefaultPort(device1, PortNumber.portNumber(2), true, annotations2), |
| OduSignalType.ODU2, |
| true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1)); |
| private static final OchPort D2P2 = |
| new DefaultOchPort(new DefaultPort(device2, PortNumber.portNumber(2), true, annotations2), |
| OduSignalType.ODU2, |
| true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1)); |
| |
| // OduClt ports with signalType=10GBE |
| private static final OduCltPort D1P3 = |
| new DefaultOduCltPort(new DefaultPort(device1, PortNumber.portNumber(3), true, annotations1), |
| CltSignalType.CLT_10GBE); |
| private static final OduCltPort D2P3 = |
| new DefaultOduCltPort(new DefaultPort(device2, PortNumber.portNumber(3), true, annotations1), |
| CltSignalType.CLT_10GBE); |
| |
| |
| private OpticalCircuitIntent intent; |
| |
| /** |
| * Mocks the device service so that devices and ports appear available in the test. |
| */ |
| private static class MockDeviceService extends DeviceServiceAdapter { |
| @Override |
| public boolean isAvailable(DeviceId deviceId) { |
| return true; |
| } |
| |
| @Override |
| public List<Port> getPorts(DeviceId deviceId) { |
| if (deviceId.equals(deviceId(DEV1))) { |
| return ImmutableList.of((Port) D1P1, (Port) D1P2, (Port) D1P3); |
| } |
| |
| if (deviceId.equals(deviceId(DEV2))) { |
| return ImmutableList.of((Port) D2P1, (Port) D2P2, (Port) D2P3); |
| } |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public Port getPort(DeviceId deviceId, PortNumber portNumber) { |
| if (deviceId.equals(deviceId(DEV1))) { |
| switch (portNumber.toString()) { |
| case "1": |
| return D1P1; |
| case "2": |
| return D1P2; |
| case "3": |
| return D1P3; |
| default: |
| return null; |
| } |
| } |
| if (deviceId.equals(deviceId(DEV2))) { |
| switch (portNumber.toString()) { |
| case "1": |
| return D2P1; |
| case "2": |
| return D2P2; |
| case "3": |
| return D2P3; |
| default: |
| return null; |
| } |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * Mocks the driver service so it will appear supporting TributarySlotQuery Behaviour in the test. |
| */ |
| private static class MockDriverServiceWithTs implements DriverService { |
| @Override |
| public Driver getDriver(String driverName) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Set<Driver> getDrivers() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Driver getDriver(String mfr, String hw, String sw) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Driver getDriver(DeviceId deviceId) { |
| DefaultDriver ddp = new DefaultDriver("foo.base", new ArrayList<>(), "Circus", "lux", "1.2a", |
| ImmutableMap.of(Behaviour.class, |
| TestBehaviourImpl.class, |
| TributarySlotQuery.class, |
| TestBehaviourTwoImpl.class), |
| ImmutableMap.of("foo", "bar")); |
| return ddp; |
| } |
| |
| @Override |
| public DriverHandler createHandler(DeviceId deviceId, |
| String... credentials) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| } |
| |
| /** |
| * Mocks the driver service so it will appear not-supporting TributarySlotQuery Behaviour in the test. |
| */ |
| private static class MockDriverServiceNoTs implements DriverService { |
| @Override |
| public Driver getDriver(String driverName) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Set<Driver> getDrivers() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Driver getDriver(String mfr, String hw, String sw) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Driver getDriver(DeviceId deviceId) { |
| DefaultDriver ddp = new DefaultDriver("foo.base", new ArrayList<>(), "Circus", "lux", "1.2a", |
| ImmutableMap.of(Behaviour.class, |
| TestBehaviourImpl.class), |
| ImmutableMap.of("foo", "bar")); |
| return ddp; |
| } |
| |
| @Override |
| public DriverHandler createHandler(DeviceId deviceId, |
| String... credentials) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| } |
| |
| private static class MockIntentSetMultimap implements IntentSetMultimap { |
| @Override |
| public boolean allocateMapping(IntentId keyIntentId, |
| IntentId valIntentId) { |
| // TODO Auto-generated method stub |
| return false; |
| } |
| |
| @Override |
| public Set<IntentId> getMapping(IntentId intentId) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public void releaseMapping(IntentId intentId) { |
| // TODO Auto-generated method stub |
| } |
| |
| } |
| |
| /** |
| * Represents a fake IntentService class that easily allows to store and |
| * retrieve intents without implementing the IntentService logic. |
| */ |
| private class TestIntentService extends IntentServiceAdapter { |
| |
| private Set<Intent> intents; |
| |
| public TestIntentService() { |
| intents = Sets.newHashSet(); |
| } |
| |
| @Override |
| public void submit(Intent intent) { |
| intents.add(intent); |
| } |
| |
| @Override |
| public long getIntentCount() { |
| return intents.size(); |
| } |
| |
| @Override |
| public Iterable<Intent> getIntents() { |
| return intents; |
| } |
| |
| @Override |
| public Intent getIntent(Key intentKey) { |
| for (Intent intent : intents) { |
| if (intent.key().equals(intentKey)) { |
| return intent; |
| } |
| } |
| return null; |
| } |
| } |
| |
| @BeforeClass |
| public static void setUpClass() { |
| AbstractProjectableModel.setDriverService("key", new DriverServiceAdapter()); |
| } |
| |
| @Before |
| public void setUp() { |
| sut = new OpticalCircuitIntentCompiler(); |
| coreService = createMock(CoreService.class); |
| expect(coreService.registerApplication("org.onosproject.net.intent")) |
| .andReturn(appId); |
| sut.coreService = coreService; |
| sut.deviceService = new MockDeviceService(); |
| sut.resourceService = new MockResourceService(); |
| sut.intentService = new TestIntentService(); |
| sut.intentSetMultimap = new MockIntentSetMultimap(); |
| |
| super.setUp(); |
| |
| intentExtensionService = createMock(IntentExtensionService.class); |
| intentExtensionService.registerCompiler(OpticalCircuitIntent.class, sut); |
| intentExtensionService.unregisterCompiler(OpticalCircuitIntent.class); |
| sut.intentManager = intentExtensionService; |
| replay(coreService, intentExtensionService); |
| |
| // mocking ComponentConfigService |
| ComponentConfigService mockConfigService = |
| EasyMock.createMock(ComponentConfigService.class); |
| expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); |
| mockConfigService.registerProperties(sut.getClass()); |
| expectLastCall(); |
| mockConfigService.unregisterProperties(sut.getClass(), false); |
| expectLastCall(); |
| expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); |
| sut.cfgService = mockConfigService; |
| replay(mockConfigService); |
| |
| } |
| |
| /** |
| * Tests compile of OpticalCircuitIntent with allocation of TributarySlots. |
| * Compile two ODUCLT ports (with CLT_1GBE), over OCH ports (with ODU2): |
| * - only one TributarySlot is used |
| */ |
| @Test |
| public void test1GbeMultiplexOverOdu2() { |
| |
| // Use driver with TributarySlotQuery Behaviour |
| sut.driverService = new MockDriverServiceWithTs(); |
| |
| ConnectPoint oduCltSrcCP = new ConnectPoint(device1.id(), D1P1.number()); |
| ConnectPoint oduCltDstCP = new ConnectPoint(device2.id(), D2P1.number()); |
| ConnectPoint ochSrcCP = new ConnectPoint(device1.id(), D1P2.number()); |
| ConnectPoint ochDstCP = new ConnectPoint(device2.id(), D2P2.number()); |
| |
| intent = OpticalCircuitIntent.builder() |
| .appId(APP_ID) |
| .key(KEY1) |
| .src(oduCltSrcCP) |
| .dst(oduCltDstCP) |
| .signalType(D1P1.signalType()) |
| .bidirectional(false) |
| .build(); |
| |
| sut.activate(null); |
| |
| List<Intent> compiled = sut.compile(intent, Collections.emptyList()); |
| assertThat(compiled, hasSize(1)); |
| |
| assertThat("key is inherited", |
| compiled.stream().map(Intent::key).collect(Collectors.toList()), |
| everyItem(is(intent.key()))); |
| |
| Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); |
| |
| FlowRule rule1 = rules.stream() |
| .filter(x -> x.deviceId().equals(device1.id())) |
| .findFirst() |
| .get(); |
| // validate SRC selector |
| TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); |
| selectorBuilder1.matchInPort(oduCltSrcCP.port()); |
| selectorBuilder1.add(Criteria.matchOduSignalType(OduSignalType.ODU0)); |
| assertThat(rule1.selector(), is(selectorBuilder1.build())); |
| |
| // validate SRC treatment (with OduSignalId, where 1 TributarySlot is used) |
| TrafficTreatment.Builder treatmentBuilder1 = DefaultTrafficTreatment.builder(); |
| Set<TributarySlot> slots = new HashSet<>(); |
| slots.add(TributarySlot.of(1)); |
| OduSignalId oduSignalId = OduSignalUtils.buildOduSignalId(D1P2.signalType(), slots); |
| treatmentBuilder1.add(Instructions.modL1OduSignalId(oduSignalId)); |
| treatmentBuilder1.setOutput(ochSrcCP.port()); |
| assertThat(rule1.treatment(), is(treatmentBuilder1.build())); |
| |
| FlowRule rule2 = rules.stream() |
| .filter(x -> x.deviceId().equals(device2.id())) |
| .findFirst() |
| .get(); |
| // validate DST selector (with OduSignalId, where the same TributarySlot is used) |
| TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); |
| selectorBuilder2.matchInPort(ochDstCP.port()); |
| selectorBuilder2.add(Criteria.matchOduSignalType(OduSignalType.ODU0)); |
| selectorBuilder2.add(Criteria.matchOduSignalId(oduSignalId)); |
| assertThat(rule2.selector(), is(selectorBuilder2.build())); |
| |
| // validate DST treatment |
| assertThat(rule2.treatment(), is( |
| DefaultTrafficTreatment.builder().setOutput(oduCltDstCP.port()).build() |
| )); |
| |
| rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", |
| intent.priority(), rule.priority())); |
| |
| sut.deactivate(); |
| } |
| |
| /** |
| * Tests compile of OpticalCircuitIntent with allocation of TributarySlots. |
| * Compile two ODUCLT ports (with CLT_10GBE), over OCH ports (with ODU2): |
| * - All TributarySlots are used |
| */ |
| @Test |
| public void test10GbeMultiplexOverOdu2() { |
| |
| // Use driver with TributarySlotQuery Behaviour |
| sut.driverService = new MockDriverServiceWithTs(); |
| |
| ConnectPoint oduCltSrcCP = new ConnectPoint(device1.id(), D1P3.number()); |
| ConnectPoint oduCltDstCP = new ConnectPoint(device2.id(), D2P3.number()); |
| ConnectPoint ochSrcCP = new ConnectPoint(device1.id(), D1P2.number()); |
| ConnectPoint ochDstCP = new ConnectPoint(device2.id(), D2P2.number()); |
| |
| intent = OpticalCircuitIntent.builder() |
| .appId(APP_ID) |
| .key(KEY1) |
| .src(oduCltSrcCP) |
| .dst(oduCltDstCP) |
| .signalType(D1P3.signalType()) |
| .bidirectional(false) |
| .build(); |
| |
| sut.activate(null); |
| |
| List<Intent> compiled = sut.compile(intent, Collections.emptyList()); |
| assertThat(compiled, hasSize(1)); |
| |
| assertThat("key is inherited", |
| compiled.stream().map(Intent::key).collect(Collectors.toList()), |
| everyItem(is(intent.key()))); |
| |
| Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); |
| |
| FlowRule rule1 = rules.stream() |
| .filter(x -> x.deviceId().equals(device1.id())) |
| .findFirst() |
| .get(); |
| // validate SRC selector |
| TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); |
| selectorBuilder1.matchInPort(oduCltSrcCP.port()); |
| selectorBuilder1.add(Criteria.matchOduSignalType(OduSignalType.ODU2)); |
| assertThat(rule1.selector(), is(selectorBuilder1.build())); |
| |
| // validate SRC treatment (without OduSignalId, i.e. All TributarySlots are used) |
| TrafficTreatment.Builder treatmentBuilder1 = DefaultTrafficTreatment.builder(); |
| treatmentBuilder1.setOutput(ochSrcCP.port()); |
| assertThat(rule1.treatment(), is(treatmentBuilder1.build())); |
| |
| FlowRule rule2 = rules.stream() |
| .filter(x -> x.deviceId().equals(device2.id())) |
| .findFirst() |
| .get(); |
| // validate DST selector (without OduSignalId, i.e. All TributarySlots are used) |
| TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); |
| selectorBuilder2.matchInPort(ochDstCP.port()); |
| selectorBuilder2.add(Criteria.matchOduSignalType(OduSignalType.ODU2)); |
| assertThat(rule2.selector(), is(selectorBuilder2.build())); |
| |
| // validate DST treatment |
| assertThat(rule2.treatment(), is( |
| DefaultTrafficTreatment.builder().setOutput(oduCltDstCP.port()).build() |
| )); |
| |
| rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", |
| intent.priority(), rule.priority())); |
| |
| sut.deactivate(); |
| } |
| |
| /** |
| * Tests compile of OpticalCircuitIntent without allocation of TributarySlots. |
| * Compile two ODUCLT ports (with CLT_10GBE), over OCH ports (with ODU2): |
| * - No TributarySlots are used |
| */ |
| @Test |
| public void test10GbeNoMuxOverOdu2() { |
| |
| // Use driver without support for TributarySlotQuery Behaviour |
| sut.driverService = new MockDriverServiceNoTs(); |
| |
| ConnectPoint oduCltSrcCP = new ConnectPoint(device1.id(), D1P3.number()); |
| ConnectPoint oduCltDstCP = new ConnectPoint(device2.id(), D2P3.number()); |
| ConnectPoint ochSrcCP = new ConnectPoint(device1.id(), D1P2.number()); |
| ConnectPoint ochDstCP = new ConnectPoint(device2.id(), D2P2.number()); |
| |
| intent = OpticalCircuitIntent.builder() |
| .appId(APP_ID) |
| .key(KEY1) |
| .src(oduCltSrcCP) |
| .dst(oduCltDstCP) |
| .signalType(D1P3.signalType()) |
| .bidirectional(false) |
| .build(); |
| |
| sut.activate(null); |
| |
| List<Intent> compiled = sut.compile(intent, Collections.emptyList()); |
| assertThat(compiled, hasSize(1)); |
| |
| assertThat("key is inherited", |
| compiled.stream().map(Intent::key).collect(Collectors.toList()), |
| everyItem(is(intent.key()))); |
| |
| |
| Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); |
| |
| FlowRule rule1 = rules.stream() |
| .filter(x -> x.deviceId().equals(device1.id())) |
| .findFirst() |
| .get(); |
| // validate SRC selector |
| TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); |
| selectorBuilder1.matchInPort(oduCltSrcCP.port()); |
| assertThat(rule1.selector(), is(selectorBuilder1.build())); |
| |
| // validate SRC treatment (without OduSignalType and OduSignalId: i.e. No TributarySlots are used) |
| TrafficTreatment.Builder treatmentBuilder1 = DefaultTrafficTreatment.builder(); |
| treatmentBuilder1.setOutput(ochSrcCP.port()); |
| assertThat(rule1.treatment(), is(treatmentBuilder1.build())); |
| |
| FlowRule rule2 = rules.stream() |
| .filter(x -> x.deviceId().equals(device2.id())) |
| .findFirst() |
| .get(); |
| // validate DST selector (without OduSignalType and OduSignalId: i.e. No TributarySlots are used) |
| TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); |
| selectorBuilder2.matchInPort(ochDstCP.port()); |
| assertThat(rule2.selector(), is(selectorBuilder2.build())); |
| // validate DST treatment |
| assertThat(rule2.treatment(), is( |
| DefaultTrafficTreatment.builder().setOutput(oduCltDstCP.port()).build() |
| )); |
| |
| rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", |
| intent.priority(), rule.priority())); |
| |
| sut.deactivate(); |
| } |
| |
| } |