1 /* 2 Copyright 2020 The Kubernetes Authors. 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 */ 16 17 package framework 18 19 import ( 20 "fmt" 21 22 "github.com/onsi/ginkgo/v2" 23 24 "k8s.io/kubernetes/test/e2e/framework" 25 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" 26 e2evolume "k8s.io/kubernetes/test/e2e/framework/volume" 27 ) 28 29 // TestSuite represents an interface for a set of tests which works with TestDriver. 30 // Each testsuite should implement this interface. 31 // All the functions except GetTestSuiteInfo() should not be called directly. Instead, 32 // use RegisterTests() to register the tests in a more standard way. 33 type TestSuite interface { 34 GetTestSuiteInfo() TestSuiteInfo 35 // DefineTests defines tests of the testpattern for the driver. 36 // Called inside a Ginkgo context that reflects the current driver and test pattern, 37 // so the test suite can define tests directly with ginkgo.It. 38 DefineTests(TestDriver, TestPattern) 39 // SkipUnsupportedTests will skip the test suite based on the given TestPattern, TestDriver 40 // Testsuite should check if the given pattern and driver works for the "whole testsuite" 41 // Testcase specific check should happen inside defineTests 42 SkipUnsupportedTests(TestDriver, TestPattern) 43 } 44 45 // RegisterTests register the driver + pattern combination to the inside TestSuite 46 // This function actually register tests inside testsuite 47 func RegisterTests(suite TestSuite, driver TestDriver, pattern TestPattern) { 48 tsInfo := suite.GetTestSuiteInfo() 49 var args []interface{} 50 args = append(args, fmt.Sprintf("[Testpattern: %s]", pattern.Name)) 51 args = append(args, pattern.TestTags...) 52 args = append(args, tsInfo.Name) 53 args = append(args, tsInfo.TestTags...) 54 args = append(args, func() { 55 ginkgo.BeforeEach(func() { 56 // skip all the invalid combination of driver and pattern 57 SkipInvalidDriverPatternCombination(driver, pattern) 58 // skip the unsupported test pattern and driver combination specific for this TestSuite 59 suite.SkipUnsupportedTests(driver, pattern) 60 }) 61 // actually define the tests 62 // at this step the testsuite should not worry about if the pattern and driver 63 // does not fit for the whole testsuite. But driver&pattern check 64 // might still needed for specific independent test cases. 65 suite.DefineTests(driver, pattern) 66 }) 67 framework.Context(args...) 68 } 69 70 // DefineTestSuites defines tests for all testpatterns and all testSuites for a driver 71 func DefineTestSuites(driver TestDriver, tsInits []func() TestSuite) { 72 for _, testSuiteInit := range tsInits { 73 suite := testSuiteInit() 74 for _, pattern := range suite.GetTestSuiteInfo().TestPatterns { 75 RegisterTests(suite, driver, pattern) 76 } 77 } 78 } 79 80 // TestSuiteInfo represents a set of parameters for TestSuite 81 type TestSuiteInfo struct { 82 Name string // name of the TestSuite 83 TestTags []interface{} // additional parameters for framework.It, like framework.WithDisruptive() 84 TestPatterns []TestPattern // Slice of TestPattern for the TestSuite 85 SupportedSizeRange e2evolume.SizeRange // Size range supported by the test suite 86 } 87 88 // SkipInvalidDriverPatternCombination will skip tests if the combination of driver, and testpattern 89 // is not compatible to be tested. This function will be called in the RegisterTests() to make 90 // sure all the testsuites we defined are valid. 91 // 92 // Whether it needs to be skipped is checked by following steps: 93 // 0. Check with driver SkipUnsupportedTest 94 // 1. Check if volType is supported by driver from its interface 95 // 2. Check if fsType is supported 96 // 97 // Test suites can also skip tests inside their own skipUnsupportedTests function or in 98 // individual tests. 99 func SkipInvalidDriverPatternCombination(driver TestDriver, pattern TestPattern) { 100 dInfo := driver.GetDriverInfo() 101 var isSupported bool 102 103 // 0. Check with driver specific logic 104 driver.SkipUnsupportedTest(pattern) 105 106 // 1. Check if Whether volType is supported by driver from its interface 107 switch pattern.VolType { 108 case InlineVolume: 109 _, isSupported = driver.(InlineVolumeTestDriver) 110 case PreprovisionedPV: 111 _, isSupported = driver.(PreprovisionedPVTestDriver) 112 case DynamicPV, GenericEphemeralVolume: 113 _, isSupported = driver.(DynamicPVTestDriver) 114 case CSIInlineVolume: 115 _, isSupported = driver.(EphemeralTestDriver) 116 default: 117 isSupported = false 118 } 119 120 if !isSupported { 121 e2eskipper.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.VolType) 122 } 123 124 // 2. Check if fsType is supported 125 if !dInfo.SupportedFsType.Has(pattern.FsType) { 126 e2eskipper.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.FsType) 127 } 128 if pattern.FsType == "xfs" && framework.NodeOSDistroIs("windows") { 129 e2eskipper.Skipf("Distro doesn't support xfs -- skipping") 130 } 131 if pattern.FsType == "ntfs" && !framework.NodeOSDistroIs("windows") { 132 e2eskipper.Skipf("Distro %s doesn't support ntfs -- skipping", framework.TestContext.NodeOSDistro) 133 } 134 } 135