README ¶
Test for CSM Operator
This is the test directory for CSM operator.
config
directory includes yaml files consumed by test cases. For example driverconfig/powerscale/v2.x.y/node.yaml
is consumed by pkg/drivers/commonconfig_test.go
.
shared/clientgoclient
implements kubernetes client from client-go package. It has a getter function for each API version like AppsV1Interface
or CoreV1Interface
. AppsV1Interface
is the one that we need as it has getter function for daemonsetInterface
. The daemonsetInterface
has all Create
, Apply
, Delete
etc. methods that we will be using to manipulate Kubernetes runtime objects.
shared/crclient
implements kubernetes client from controller runtime. It has very similar functionalities as the one above except that it can't do apply. These two clients share the same memory to store runtime objects.
Unit Test
To run unit test, go to the root directory of this project and run make unit-test
. It will output a report of tests being run.
E2E Test
The E2E tests will test the installation of Dell CSI Drivers and Dell CSM Modules. The prerequisites and execution of e2e tests are documented below:
Prerequisite
- A supported environment where Dell CSM Operator is running
- All prerequisite for a specific driver and modules to test. For documentation, please visit Container Storage Modules documentation
Run
To run e2e test, go through the following steps:
- Ensure you meet all prerequisites
- Change to the root directory of this project
- Copy or modify the values file at
tests/e2e/testfiles/values.yaml
. Review Values File for more information. - Change to the
scripts
directory - Set your environment variables in the file
env-e2e-test.sh
. You MUST setVALUES_FILE
to point to the path to thevalues.yaml
we created above. - Run the e2e test by executing the commands below:
./env-e2e-test.sh
./run-e2e-test.sh
Values File
An e2e test values file is a yaml file that defines all e2e tests to be ran. An excerpt of the file is shown below:
- scenario: "Install PowerScale Driver(Standalone)"
path: "<path-to-cr-for-powerscale-with-auth-disabled>"
steps:
- "Given an environment with k8s or openshift, and CSM operator installed"
- "Apply custom resources"
- "Validate custom resources"
- "Validate [powerscale] driver is installed"
- "Run custom test"
# Last two steps perform Clean Up
- "Enable forceRemoveDriver on CR"
- "Delete resources"
customTest:
# name of custom test to run
name: Cert CSI
# Provide command-line argument to run. Ginkgo will run the command and return output
# The command should be accessible from e2e test repo.
# Example:
# ./hello_world.sh
# cert-csi test vio --sc <storage class> --chainNumber 2 --chainLength 2
run: cert-csi test vio --sc isilon-plain --chainNumber 2 --chainLength 2
Each test has:
scenario
: The name of the test to runpath
: The path to the custom resources yaml file that has the specific configuration you want to test.steps
: Steps to take for the specific scenearios. Please note that all steps above and the ones in this sample filetests/e2e/testfiles/values.yaml
already have a backend implementation. If you desire to use a different step, see Develop for how to add new E2E TestcustomTest
: An entrypoint for users to run custom test against their environment. You must have"Run custom test"
as part of yoursteps
above for this custom test to run. This object has the following parameter.name
: Name of your custom testrun
: A command line argument that will be run by the e2e test. To ensure the command is accessible from e2e test repo, use absolute paths if you are running a script.
Develop
Most steps to cover common use cases already have their respective backend implementations. Sometimes we run into a situation where we may need to add a new step. For the sake of illustration, please follow the constraints and steps below to add a new test scenario called "Install PowerHello Driver(With a module called World)"
to excerpt of yaml file shown above.
- Add the new test scenario to the existing values file
- scenario: "Install PowerScale Driver(Standalone)"
path: "<path-to-cr-for-powerscale-with-auth-disabled>"
steps:
- "Given an environment with k8s or openshift, and CSM operator installed"
- "Apply custom resources"
- "Validate custom resources"
- "Validate [powerscale] driver is installed"
- "Run custom test"
# Last two steps perform Clean Up
- "Enable forceRemoveDriver on CR"
- "Delete resources"
customTest:
# name of custom test to run
name: Cert CSI
# Provide command-line argument to run. Ginkgo will run the command and return output
# The command should be accessible from e2e test repo.
# Example:
# ./hello_world.sh
# cert-csi test vio --sc <storage class> --chainNumber 2 --chainLength 2
run: cert-csi test vio --sc isilon-plain --chainNumber 2 --chainLength 2
- scenario: "Install PowerHello Driver(With a module called World)"
path: "<path-to-cr-for-powerhello-with-world-enabled>"
steps:
- "Given an environment with k8s or openshift, and CSM operator installed"
- "Apply custom resources" # fully recycled old step
- "Validate custom resources"
- "Validate [powerhello] driver is installed" # partially recycled old step
- "Validate [world] module is installed"
- "Validate Today is Tuesday" # a new simple step without a backend implementation
- "Validate it is [raining], [snowing], [sunny], and [pay-day]" # a new templated step without a backend implementation
- "Run custom test"
# Last two steps perform Clean Up
- "Enable forceRemoveDriver on CR"
- "Delete resources"
customTest:
name: "Hello World"
run: echo HelloWorld
-
Add backend Support: we will cover three case:
Fully recycled old step
: If the desired steps has already been covered in another test scenario, just copy line for line. You don't need any code changepartially recycled old step
: In this case, a very similar test has already been cover. This means there's already an entrypoint insteps
. You should review theStepRunnerInit
function at step_runner.go and trace the implementation function that matches your step. For example the step"Validate [world] module is installed"
. The line that matches this inStepRunnerInit
isrunner.addStep(
^Validate [([^"]*)] module is installed$, step.validateModuleInstalled)
. The implementation to trace isstep.validateModuleInstalled
. We will review the implementation function in steps_def.go to decide whether or not we need to do anything. Make the code changes if needed.new step
: New step can be simple such as"Validate Today is Tuesday"
or a templated such as["Validate it is [raining]"](https://jira.cec.lab.emc.com/browse/KRV-3130)
. The workflow to support these two cases is the same and only varies in the signature of the implementation function. The workflow include:-
Implement steps in steps_def.go. Define a function to implement your step. Note that the steps are stateless! If you want to define a function to test a happy path, your function should return nil if no error occurs and error otherwise. However, if you want to test an error path, your function should return nil if you get error and error otherwise. The constraints of all functions in step_def.go is as follows:
-
must return
error
ornil
-
must take at least one argument. The first one MUST be type
Resource
(even though it may not be used). If your step has any group(a groups is anything in your step enclosed by[]
), the remaining arguments should be the groups in the order they appear on the steps(from left to right). For example, the two new functions above will can be implemented as shown below:// take one argument, res, and return error func (step *Step) isTodayTuesday(res Resource) error { weekday := time.Now().Weekday() if weekday != "Tuesday" { return fmt.Errorf("expected weekday to be Tuesday. Got: %s", weekday) } return nil } /* Takes four more arguments for each group as defined here "Validate it is [raining], [snowing], [sunny], and [pay-day]". Thus function wll be automatically called with: checkWeather(Resource{}, "raining", "snowing", "sunny", "pay-day") Please see "Validate [powerhello] driver is installed" step and the function signature that implemented it */ func (step *Step) checkWeather(res Resource, weather1, weather2, weather3, weather4) error { allValidWeather := true allValid = allValid && (weather1 =="raining") allValid = allValid && (weather1 =="snowing") allValid = allValid && (weather1 =="sunny") allValid = allValid && (weather1 =="pay-day") if !allValid { return fmt.Errorf("not all weather is valid") } return nil }
-
-
Register your new steps in
StepRunnerInit
function at step_runner.go. Please pay special attention to the regex and ensure they actually match your new steps. For instance, the new steps we implemented above can be mapped to their steps in the valus file as follows:func StepRunnerInit(runner *Runner, ctrlClient client.Client, clientSet *kubernetes.Clientset) { step := Step{ ctrlClient: ctrlClient, clientSet: clientSet, } // ... old steps runner.addStep(`^Validate Today is Tuesday$`, step.isTodayTuesday) runner.addStep(`^^Validate it is \[([^"]*)\], \[([^"]*)\], \[([^"]*)\], and \[([^"]*)\]$`, step.checkWeather) }
-
Run your E2E. If you get this error
no method for step: <you step>
, it means you either haven't implemented it or there's a problem with your regex.
-