Skip to content

Commit

Permalink
[TEST]: Improvement: Switches: New interaction approach: Phase3
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuliia Miroshnychenko committed Jan 17, 2025
1 parent a65ed7b commit 241d75e
Show file tree
Hide file tree
Showing 9 changed files with 773 additions and 938 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import org.openkilda.northbound.dto.v2.switches.LagPortRequest
import org.openkilda.northbound.dto.v2.switches.LagPortResponse
import org.openkilda.northbound.dto.v2.switches.MeterInfoDtoV2
import org.openkilda.northbound.dto.v2.switches.PortPropertiesDto
import org.openkilda.northbound.dto.v2.switches.SwitchDtoV2
import org.openkilda.northbound.dto.v2.switches.SwitchFlowsPerPortResponse
import org.openkilda.northbound.dto.v2.switches.SwitchLocationDtoV2
import org.openkilda.northbound.dto.v2.switches.SwitchPatchDto
Expand Down Expand Up @@ -56,12 +55,9 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Scope
import org.springframework.stereotype.Component

import java.math.RoundingMode

import static groovyx.gpars.GParsPool.withPool
import static org.hamcrest.MatcherAssert.assertThat
import static org.hamcrest.Matchers.hasItem
import static org.hamcrest.Matchers.notNullValue
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.DELETE_LAG_LOGICAL_PORT
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.DELETE_MIRROR
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.OTHER
Expand Down Expand Up @@ -165,16 +161,6 @@ class SwitchHelper {
"${sw.nbFormat().hardware} ${sw.nbFormat().software}"
}

@Memoized
static String getHwSwString(SwitchDto sw) {
"${sw.hardware} ${sw.software}"
}

@Memoized
static String getHwSwString(SwitchDtoV2 sw) {
"${sw.hardware} ${sw.software}"
}

static List<TraffGen> getTraffGens(Switch sw) {
topology.get().activeTraffGens.findAll { it.switchConnected.dpId == sw.dpId }
}
Expand Down Expand Up @@ -414,39 +400,6 @@ class SwitchHelper {
return northboundV2.get().getSwitchFlows(switchId, []).flowsByPort.keySet().asList()
}

/**
* This method calculates expected burst for different types of switches. The common burst equals to
* `rate * burstCoefficient`. There are couple exceptions though:<br>
* <b>Noviflow</b>: Does not use our common burst coefficient and overrides it with its own coefficient (see static
* variables at the top of the class).<br>
* <b>Centec</b>: Follows our burst coefficient policy, except for restrictions for the minimum and maximum burst.
* In cases when calculated burst is higher or lower of the Centec max/min - the max/min burst value will be used
* instead.
*
* @param sw switchId where burst is being calculated. Needed to get the switch manufacturer and apply special
* calculations if required
* @param rate meter rate which is used to calculate burst
* @return the expected burst value for given switch and rate
*/
def getExpectedBurst(SwitchId sw, long rate) {
def descr = getDescription(sw).toLowerCase()
def hardware = northbound.get().getSwitch(sw).hardware
if (descr.contains("noviflow") || hardware =~ "WB5164") {
return (rate * NOVIFLOW_BURST_COEFFICIENT - 1).setScale(0, RoundingMode.CEILING)
} else if (descr.contains("centec")) {
def burst = (rate * burstCoefficient).toBigDecimal().setScale(0, RoundingMode.FLOOR)
if (burst <= CENTEC_MIN_BURST) {
return CENTEC_MIN_BURST
} else if (burst > CENTEC_MIN_BURST && burst <= CENTEC_MAX_BURST) {
return burst
} else {
return CENTEC_MAX_BURST
}
} else {
return (rate * burstCoefficient).round(0)
}
}

/**
* Verifies that specified meter sections in the validation response are empty.
* NOTE: will filter out default meters for 'proper' section, so that switch without flow meters, but only with
Expand All @@ -469,24 +422,6 @@ class SwitchHelper {
assertions.verify()
}

static void verifyMeterSectionsAreEmpty(SwitchValidationV2ExtendedResult switchValidateInfo,
List<String> sections = ["missing", "misconfigured", "proper", "excess"]) {
def assertions = new SoftAssertions()
if (switchValidateInfo.meters) {
sections.each { section ->
if (section == "proper") {
assertions.checkSucceeds {
assert switchValidateInfo.meters.proper.findAll { !it.defaultMeter }.empty
}
} else {
assertions.checkSucceeds { assert switchValidateInfo.meters."$section".empty }
}
}
}
assertions.verify()
}


/**
* Verifies that specified rule sections in the validation response are empty.
* NOTE: will filter out default rules, except default flow rules(multiTable flow)
Expand All @@ -511,54 +446,6 @@ class SwitchHelper {
assertions.verify()
}

static void verifyRuleSectionsAreEmpty(SwitchValidationV2ExtendedResult switchValidateInfo,
List<String> sections = ["missing", "proper", "excess", "misconfigured"]) {
def assertions = new SoftAssertions()
sections.each { String section ->
if (section == "proper") {
assertions.checkSucceeds {
assert switchValidateInfo.rules.proper.findAll {
def cookie = new Cookie(it.cookie)
!cookie.serviceFlag && cookie.type != CookieType.SHARED_OF_FLOW
}.empty
}
} else {
assertions.checkSucceeds { assert switchValidateInfo.rules."$section".empty }
}
}
assertions.verify()
}

/**
* Verifies that specified hexRule sections in the validation response are empty.
* NOTE: will filter out default rules, except default flow rules(multiTable flow)
* Default flow rules for the system looks like as a simple default rule.
* Based on that you have to use extra filter to detect these rules in
* missingHex/excessHex/misconfiguredHex sections.
*/
static void verifyHexRuleSectionsAreEmpty(SwitchValidationExtendedResult switchValidateInfo,
List<String> sections = ["properHex", "excessHex", "missingHex",
"misconfiguredHex"]) {
def assertions = new SoftAssertions()
sections.each { String section ->
if (section == "properHex") {
def defaultCookies = switchValidateInfo.rules.proper.findAll {
def cookie = new Cookie(it)
cookie.serviceFlag || cookie.type == CookieType.SHARED_OF_FLOW
}

def defaultHexCookies = []
defaultCookies.each { defaultHexCookies.add(Long.toHexString(it)) }
assertions.checkSucceeds {
assert switchValidateInfo.rules.properHex.findAll { !(it in defaultHexCookies) }.empty
}
} else {
assertions.checkSucceeds { assert switchValidateInfo.rules."$section".empty }
}
}
assertions.verify()
}

static boolean isDefaultMeter(MeterInfoDto dto) {
return MeterId.isMeterIdOfDefaultRule(dto.getMeterId())
}
Expand All @@ -567,25 +454,6 @@ class SwitchHelper {
return MeterId.isMeterIdOfDefaultRule(dto.getMeterId())
}

/**
* Verifies that actual and expected burst size are the same.
*/
static void verifyBurstSizeIsCorrect(Switch sw, Long expected, Long actual) {
if (sw.isWb5164()) {
assert Math.abs(expected - actual) <= expected * 0.01
} else {
assert Math.abs(expected - actual) <= 1
}
}

static void verifyRateSizeIsCorrect(Switch sw, Long expected, Long actual) {
if (sw.isWb5164()) {
assert Math.abs(expected - actual) <= expected * 0.01
} else {
assert Math.abs(expected - actual) <= 1
}
}

static SwitchProperties getDummyServer42Props() {
return new SwitchProperties(true, 33, "00:00:00:00:00:00", 1, null)
}
Expand Down Expand Up @@ -676,25 +544,6 @@ class SwitchHelper {
reviveSwitch(sw, flResourceAddress, false)
}

static void verifySectionInSwitchValidationInfo(SwitchValidationV2ExtendedResult switchValidateInfo,
List<String> sections = ["groups", "meters", "logical_ports", "rules"]) {
sections.each { String section ->
assertThat(switchValidateInfo."$section", notNullValue())
}

}

static void verifySectionsAsExpectedFields(SwitchValidationV2ExtendedResult switchValidateInfo,
List<String> sections = ["groups", "meters", "logical_ports", "rules"]) {
boolean result = true;
sections.each { String section ->
if (!switchValidateInfo."$section".asExpected) {
result = false
}
}
assert result == switchValidateInfo.asExpected
}

static SwitchSyncResult synchronize(SwitchId switchId, boolean removeExcess=true) {
return northbound.get().synchronizeSwitch(switchId, removeExcess)
}
Expand Down Expand Up @@ -755,15 +604,6 @@ class SwitchHelper {
return Optional.ofNullable(validateAndCollectFoundDiscrepancies([switchToValidate]).get(switchToValidate))
}

static void synchronizeAndValidateRulesInstallation(Switch srcSwitch, Switch dstSwitch) {
synchronizeAndCollectFixedDiscrepancies([srcSwitch.dpId, dstSwitch.dpId])
[srcSwitch, dstSwitch].each { sw ->
Wrappers.wait(RULES_INSTALLATION_TIME) {
validate(sw.dpId).verifyRuleSectionsAreEmpty()
}
}
}

static SwitchValidationV2ExtendedResult validate(SwitchId switchId, String include = null, String exclude = null) {
return northboundV2.get().validateSwitch(switchId, include, exclude)
}
Expand Down Expand Up @@ -966,13 +806,6 @@ class SwitchHelper {
return northboundV2.get().partialSwitchUpdate(switchId, updateDto)
}

static boolean isServer42Supported(SwitchId switchId) {
def swProps = northbound.get().getSwitchProperties(switchId)
def featureToggles = northbound.get().getFeatureToggles()
def isServer42 = swProps.server42FlowRtt && featureToggles.server42FlowRtt
return isServer42
}

static int randomVlan() {
return randomVlan([])
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package org.openkilda.functionaltests.helpers.model
import static groovyx.gpars.GParsPool.withPool
import static org.hamcrest.MatcherAssert.assertThat
import static org.hamcrest.Matchers.hasItem
import static org.hamcrest.Matchers.notNullValue
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.OTHER
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.RESET_SWITCH_MAINTENANCE
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.RESTORE_SWITCH_PROPERTIES
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.REVIVE_SWITCH
import static org.openkilda.functionaltests.model.cleanup.CleanupActionType.SYNCHRONIZE_SWITCH
import static org.openkilda.messaging.info.event.IslChangeType.DISCOVERED
import static org.openkilda.messaging.info.event.IslChangeType.FAILED
import static org.openkilda.messaging.info.event.SwitchChangeType.ACTIVATED
Expand Down Expand Up @@ -400,7 +402,8 @@ class SwitchExtended {
* reinstalled according to config
*/
SwitchPropertiesDto updateProperties(SwitchPropertiesDto switchProperties) {
cleanupManager.addAction(OTHER, { northbound.updateSwitchProperties(sw.dpId, getCashedProps()) })
def initialProps = getCashedProps()
cleanupManager.addAction(OTHER, { northbound.updateSwitchProperties(sw.dpId, initialProps) })
def response = northbound.updateSwitchProperties(sw.dpId, switchProperties)
Wrappers.wait(RULES_INSTALLATION_TIME) {
def actualHexCookie = []
Expand Down Expand Up @@ -512,6 +515,10 @@ class SwitchExtended {
return northbound.deleteSwitch(sw.dpId, force)
}

SwitchPropertiesDto getPropsV1() {
northbound.getSwitchProperties(sw.dpId)
}

boolean isS42FlowRttEnabled() {
def swProps = northbound.getSwitchProperties(sw.dpId)
def featureToggles = northbound.getFeatureToggles()
Expand Down Expand Up @@ -600,6 +607,11 @@ class SwitchExtended {
revive(flResourceAddress, false)
}

void updateBurstSizeAndRate(Long meterId, Long newBurstSize, Long newRate) {
cleanupManager.addAction(SYNCHRONIZE_SWITCH, { synchronize() })
lockKeeper.updateBurstSizeAndRate(sw, meterId, newBurstSize, newRate)
}

void verifyRelatedLinksState(IslChangeType expectedState) {
def relatedLinks = northbound.getAllLinks().findAll {
switchId in [it.source.switchId, it.destination.switchId]
Expand Down Expand Up @@ -662,6 +674,11 @@ class SwitchExtended {
database.getSwitch(sw.dpId).features
}

void setFeaturesInDb(Set<SwitchFeature> features) {
cleanupManager.addAction(OTHER, { database.setSwitchFeatures(sw.dpId, getDbFeatures())})
database.setSwitchFeatures(sw.dpId, features)
}

boolean isVxlanFeatureEnabled() {
!getDbFeatures().intersect([NOVIFLOW_PUSH_POP_VXLAN, KILDA_OVS_PUSH_POP_MATCH_VXLAN]).isEmpty()
}
Expand Down Expand Up @@ -856,4 +873,22 @@ class SwitchExtended {
}
assertions.verify()
}

static void verifySectionInSwitchValidationInfo(SwitchValidationV2ExtendedResult switchValidateInfo,
List<String> sections = ["groups", "meters", "logical_ports", "rules"]) {
sections.each { String section ->
assertThat(switchValidateInfo."$section", notNullValue())
}
}

static void verifySectionsAsExpectedFields(SwitchValidationV2ExtendedResult switchValidateInfo,
List<String> sections = ["groups", "meters", "logical_ports", "rules"]) {
boolean result = true;
sections.each { String section ->
if (!switchValidateInfo."$section".asExpected) {
result = false
}
}
assert result == switchValidateInfo.asExpected
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import static org.springframework.beans.factory.config.ConfigurableBeanFactory.S

import org.openkilda.functionaltests.helpers.factory.SwitchFactory
import org.openkilda.functionaltests.model.switches.Manufacturer
import org.openkilda.model.SwitchFeature
import org.openkilda.model.SwitchId
import org.openkilda.northbound.dto.v1.switches.SwitchDto
import org.openkilda.testing.model.topology.TopologyDefinition
Expand Down Expand Up @@ -71,12 +72,21 @@ class Switches {
switches.unique { it.hwSwString() }
}

List<SwitchExtended> notOF12Version() {
switches.findAll { it.ofVersion != "OF_12" }
}

Switches withS42Support(){
def swsProps = northboundV2.getAllSwitchProperties().switchProperties
switches = switches.findAll { sw -> isS42Supported(swsProps.find { it.switchId == sw.switchId}) }
return this
}

Switches withoutLagSupport() {
switches = switches.findAll { !it.dbFeatures.contains(SwitchFeature.LAG) }
return this
}

SwitchExtended random() {
assumeFalse(switches.isEmpty(), "No suiting switch found")
switches.shuffled().first()
Expand All @@ -93,6 +103,12 @@ class Switches {
sw
}

SwitchExtended findWithVxlanFeatureEnabled() {
def sw = switches.find { it.isVxlanFeatureEnabled() }
assumeTrue(sw as Boolean, "No suiting switch(vxlan-enabled) found")
sw
}

@Memoized
private List<SwitchExtended> collectSwitches() {
List<SwitchDto> switchesDetails = northbound.allSwitches
Expand Down
Loading

0 comments on commit 241d75e

Please sign in to comment.