2016-05-17 08:55:22 -04:00
/ *
2016-06-02 20:25:58 -04:00
Copyright 2016 The Kubernetes Authors .
2016-05-17 08:55:22 -04:00
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 persistentvolume
import (
"errors"
"testing"
2017-06-22 13:25:57 -04:00
"k8s.io/api/core/v1"
2017-06-22 14:04:37 -04:00
storage "k8s.io/api/storage/v1"
2018-02-05 09:40:25 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2016-05-17 08:55:22 -04:00
)
// Test single call to syncVolume, expecting recycling to happen.
// 1. Fill in the controller with initial data
// 2. Call the syncVolume *once*.
// 3. Compare resulting volumes with expected volumes.
func TestRecycleSync ( t * testing . T ) {
2018-02-05 09:40:25 -05:00
runningPod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "runningPod" ,
Namespace : testNamespace ,
} ,
Spec : v1 . PodSpec {
Volumes : [ ] v1 . Volume {
{
Name : "vol1" ,
VolumeSource : v1 . VolumeSource {
PersistentVolumeClaim : & v1 . PersistentVolumeClaimVolumeSource {
ClaimName : "runningClaim" ,
} ,
} ,
} ,
} ,
} ,
Status : v1 . PodStatus {
Phase : v1 . PodRunning ,
} ,
}
pendingPod := runningPod . DeepCopy ( )
pendingPod . Name = "pendingPod"
pendingPod . Status . Phase = v1 . PodPending
pendingPod . Spec . Volumes [ 0 ] . PersistentVolumeClaim . ClaimName = "pendingClaim"
completedPod := runningPod . DeepCopy ( )
completedPod . Name = "completedPod"
completedPod . Status . Phase = v1 . PodSucceeded
completedPod . Spec . Volumes [ 0 ] . PersistentVolumeClaim . ClaimName = "completedClaim"
pods := [ ] * v1 . Pod {
runningPod ,
pendingPod ,
completedPod ,
}
2016-05-17 08:55:22 -04:00
tests := [ ] controllerTest {
{
// recycle volume bound by controller
"6-1 - successful recycle" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-1" , "1Gi" , "uid6-1" , "claim6-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume6-1" , "1Gi" , "" , "" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
noevents , noerrors ,
2016-05-17 08:55:22 -04:00
// Inject recycler into the controller and call syncVolume. The
// recycler simulates one recycle() call that succeeds.
2016-08-18 04:36:49 -04:00
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 08:55:22 -04:00
} ,
{
// recycle volume bound by user
"6-2 - successful recycle with prebound volume" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-2" , "1Gi" , "uid6-2" , "claim6-2" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
newVolumeArray ( "volume6-2" , "1Gi" , "" , "claim6-2" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
noevents , noerrors ,
2016-05-17 08:55:22 -04:00
// Inject recycler into the controller and call syncVolume. The
// recycler simulates one recycle() call that succeeds.
2016-08-18 04:36:49 -04:00
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 08:55:22 -04:00
} ,
{
// recycle failure - plugin not found
"6-3 - plugin not found" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-3" , "1Gi" , "uid6-3" , "claim6-3" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
withMessage ( "No recycler plugin found for the volume!" , newVolumeArray ( "volume6-3" , "1Gi" , "uid6-3" , "claim6-3" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
[ ] string { "Warning VolumeFailedRecycle" } , noerrors , testSyncVolume ,
2016-05-17 08:55:22 -04:00
} ,
{
2017-01-23 14:49:00 -05:00
// recycle failure - Recycle returns error
2016-05-17 08:55:22 -04:00
"6-4 - newRecycler returns error" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-4" , "1Gi" , "uid6-4" , "claim6-4" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
withMessage ( "Recycle failed: Mock plugin error: no recycleCalls configured" , newVolumeArray ( "volume6-4" , "1Gi" , "uid6-4" , "claim6-4" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
[ ] string { "Warning VolumeFailedRecycle" } , noerrors ,
2016-08-18 04:36:49 -04:00
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { } , testSyncVolume ) ,
2016-05-17 08:55:22 -04:00
} ,
{
// recycle failure - recycle returns error
"6-5 - recycle returns error" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-5" , "1Gi" , "uid6-5" , "claim6-5" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
withMessage ( "Recycle failed: Mock recycle error" , newVolumeArray ( "volume6-5" , "1Gi" , "uid6-5" , "claim6-5" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
[ ] string { "Warning VolumeFailedRecycle" } , noerrors ,
2016-08-18 04:36:49 -04:00
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { errors . New ( "Mock recycle error" ) } , testSyncVolume ) ,
2016-05-17 08:55:22 -04:00
} ,
{
// recycle success(?) - volume is deleted before doRecycle() starts
"6-6 - volume is deleted before recycling" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-6" , "1Gi" , "uid6-6" , "claim6-6" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
2016-05-17 08:55:22 -04:00
novolumes ,
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
noevents , noerrors ,
2016-08-18 04:36:49 -04:00
wrapTestWithInjectedOperation ( wrapTestWithReclaimCalls ( operationRecycle , [ ] error { } , testSyncVolume ) , func ( ctrl * PersistentVolumeController , reactor * volumeReactor ) {
2016-05-17 08:55:22 -04:00
// Delete the volume before recycle operation starts
reactor . lock . Lock ( )
delete ( reactor . volumes , "volume6-6" )
reactor . lock . Unlock ( )
} ) ,
} ,
{
// recycle success(?) - volume is recycled by previous recycler just
// at the time new doRecycle() starts. This simulates "volume no
// longer needs recycling, skipping".
"6-7 - volume is deleted before recycling" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-7" , "1Gi" , "uid6-7" , "claim6-7" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume6-7" , "1Gi" , "" , "" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
noevents , noerrors ,
2016-08-18 04:36:49 -04:00
wrapTestWithInjectedOperation ( wrapTestWithReclaimCalls ( operationRecycle , [ ] error { } , testSyncVolume ) , func ( ctrl * PersistentVolumeController , reactor * volumeReactor ) {
2016-05-17 08:55:22 -04:00
// Mark the volume as Available before the recycler starts
reactor . lock . Lock ( )
volume := reactor . volumes [ "volume6-7" ]
volume . Spec . ClaimRef = nil
2016-11-18 15:50:17 -05:00
volume . Status . Phase = v1 . VolumeAvailable
2016-05-17 08:55:22 -04:00
volume . Annotations = nil
reactor . lock . Unlock ( )
} ) ,
} ,
{
// recycle success(?) - volume bound by user is recycled by previous
// recycler just at the time new doRecycle() starts. This simulates
// "volume no longer needs recycling, skipping" with volume bound by
// user.
"6-8 - prebound volume is deleted before recycling" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-8" , "1Gi" , "uid6-8" , "claim6-8" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
newVolumeArray ( "volume6-8" , "1Gi" , "" , "claim6-8" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
noevents , noerrors ,
2016-08-18 04:36:49 -04:00
wrapTestWithInjectedOperation ( wrapTestWithReclaimCalls ( operationRecycle , [ ] error { } , testSyncVolume ) , func ( ctrl * PersistentVolumeController , reactor * volumeReactor ) {
2016-05-17 08:55:22 -04:00
// Mark the volume as Available before the recycler starts
reactor . lock . Lock ( )
volume := reactor . volumes [ "volume6-8" ]
volume . Spec . ClaimRef . UID = ""
2016-11-18 15:50:17 -05:00
volume . Status . Phase = v1 . VolumeAvailable
2016-05-17 08:55:22 -04:00
reactor . lock . Unlock ( )
} ) ,
} ,
{
// recycle success - volume bound by user is recycled, while a new
// claim is created with another UID.
"6-9 - prebound volume is recycled while the claim exists" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-9" , "1Gi" , "uid6-9" , "claim6-9" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
newVolumeArray ( "volume6-9" , "1Gi" , "" , "claim6-9" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
newClaimArray ( "claim6-9" , "uid6-9-x" , "10Gi" , "" , v1 . ClaimPending , nil ) ,
newClaimArray ( "claim6-9" , "uid6-9-x" , "10Gi" , "" , v1 . ClaimPending , nil ) ,
2016-05-17 08:55:28 -04:00
noevents , noerrors ,
2016-05-17 08:55:22 -04:00
// Inject recycler into the controller and call syncVolume. The
// recycler simulates one recycle() call that succeeds.
2016-08-18 04:36:49 -04:00
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 08:55:22 -04:00
} ,
{
// volume has unknown reclaim policy - failure expected
"6-10 - unknown reclaim policy" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume6-10" , "1Gi" , "uid6-10" , "claim6-10" , v1 . VolumeBound , "Unknown" , classEmpty ) ,
withMessage ( "Volume has unrecognized PersistentVolumeReclaimPolicy" , newVolumeArray ( "volume6-10" , "1Gi" , "uid6-10" , "claim6-10" , v1 . VolumeFailed , "Unknown" , classEmpty ) ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
[ ] string { "Warning VolumeUnknownReclaimPolicy" } , noerrors , testSyncVolume ,
2016-05-17 08:55:22 -04:00
} ,
2018-02-05 09:40:25 -05:00
{
// volume is used by a running pod - failure expected
"6-11 - used by running pod" ,
newVolumeArray ( "volume6-11" , "1Gi" , "uid6-11" , "runningClaim" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume6-11" , "1Gi" , "uid6-11" , "runningClaim" , v1 . VolumeReleased , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
noclaims ,
noclaims ,
[ ] string { "Normal VolumeFailedRecycle" } , noerrors , testSyncVolume ,
} ,
{
// volume is used by a pending pod - failure expected
"6-12 - used by pending pod" ,
newVolumeArray ( "volume6-12" , "1Gi" , "uid6-12" , "pendingClaim" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume6-12" , "1Gi" , "uid6-12" , "pendingClaim" , v1 . VolumeReleased , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
noclaims ,
noclaims ,
[ ] string { "Normal VolumeFailedRecycle" } , noerrors , testSyncVolume ,
} ,
{
// volume is used by a completed pod - recycle succeeds
"6-13 - used by completed pod" ,
newVolumeArray ( "volume6-13" , "1Gi" , "uid6-13" , "completedClaim" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume6-13" , "1Gi" , "" , "" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
noclaims ,
noclaims ,
noevents , noerrors ,
// Inject recycler into the controller and call syncVolume. The
// recycler simulates one recycle() call that succeeds.
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { nil } , testSyncVolume ) ,
} ,
2018-10-30 10:06:39 -04:00
{
// volume is used by a completed pod, pod using claim with the same name bound to different pv is running, should recycle
"6-14 - seemingly used by running pod" ,
newVolumeArray ( "volume6-14" , "1Gi" , "uid6-14" , "completedClaim" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume6-14" , "1Gi" , "" , "" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
newClaimArray ( "completedClaim" , "uid6-14-x" , "10Gi" , "" , v1 . ClaimBound , nil ) ,
newClaimArray ( "completedClaim" , "uid6-14-x" , "10Gi" , "" , v1 . ClaimBound , nil ) ,
noevents , noerrors ,
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { nil } , testSyncVolume ) ,
} ,
2016-05-17 08:55:22 -04:00
}
2018-02-05 09:40:25 -05:00
runSyncTests ( t , tests , [ ] * storage . StorageClass { } , pods )
2016-05-17 08:55:22 -04:00
}
// Test multiple calls to syncClaim/syncVolume and periodic sync of all
// volume/claims. The test follows this pattern:
// 0. Load the controller with initial data.
// 1. Call controllerTest.testCall() once as in TestSync()
// 2. For all volumes/claims changed by previous syncVolume/syncClaim calls,
// call appropriate syncVolume/syncClaim (simulating "volume/claim changed"
// events). Go to 2. if these calls change anything.
// 3. When all changes are processed and no new changes were made, call
// syncVolume/syncClaim on all volumes/claims (simulating "periodic sync").
// 4. If some changes were done by step 3., go to 2. (simulation of
// "volume/claim updated" events, eventually performing step 3. again)
// 5. When 3. does not do any changes, finish the tests and compare final set
// of volumes/claims with expected claims/volumes and report differences.
// Some limit of calls in enforced to prevent endless loops.
func TestRecycleMultiSync ( t * testing . T ) {
tests := [ ] controllerTest {
{
// recycle failure - recycle returns error. The controller should
// try again.
"7-1 - recycle returns error" ,
2017-03-02 04:23:56 -05:00
newVolumeArray ( "volume7-1" , "1Gi" , "uid7-1" , "claim7-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
newVolumeArray ( "volume7-1" , "1Gi" , "" , "claim7-1" , v1 . VolumeAvailable , v1 . PersistentVolumeReclaimRecycle , classEmpty ) ,
2016-05-17 08:55:22 -04:00
noclaims ,
noclaims ,
2016-05-17 08:55:28 -04:00
[ ] string { "Warning VolumeFailedRecycle" } , noerrors ,
2016-08-18 04:36:49 -04:00
wrapTestWithReclaimCalls ( operationRecycle , [ ] error { errors . New ( "Mock recycle error" ) , nil } , testSyncVolume ) ,
2016-05-17 08:55:22 -04:00
} ,
}
2016-09-01 11:29:26 -04:00
runMultisyncTests ( t , tests , [ ] * storage . StorageClass { } , "" )
2016-05-17 08:55:22 -04:00
}