2016-05-17 12:55:23 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2016 The Kubernetes Authors .
2016-05-17 12:55:23 +00: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 17:25:57 +00:00
"k8s.io/api/core/v1"
2017-06-22 18:04:37 +00:00
storage "k8s.io/api/storage/v1"
2016-05-17 12:55:23 +00: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 TestDeleteSync ( t * testing . T ) {
tests := [ ] controllerTest {
{
// delete volume bound by controller
"8-1 - successful delete" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-1" , "1Gi" , "uid8-1" , "claim8-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annBoundByController ) ,
2016-05-17 12:55:23 +00:00
novolumes ,
noclaims ,
noclaims ,
2016-05-17 12:55:28 +00:00
noevents , noerrors ,
2016-05-17 12:55:23 +00:00
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
2016-08-18 08:36:49 +00:00
wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 12:55:23 +00:00
} ,
{
// delete volume bound by user
"8-2 - successful delete with prebound volume" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-2" , "1Gi" , "uid8-2" , "claim8-2" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
2016-05-17 12:55:23 +00:00
novolumes ,
noclaims ,
noclaims ,
2016-05-17 12:55:28 +00:00
noevents , noerrors ,
2016-05-17 12:55:23 +00:00
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
2016-08-18 08:36:49 +00:00
wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 12:55:23 +00:00
} ,
{
// delete failure - plugin not found
"8-3 - plugin not found" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-3" , "1Gi" , "uid8-3" , "claim8-3" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
withMessage ( "Error getting deleter volume plugin for volume \"volume8-3\": no volume plugin matched" , newVolumeArray ( "volume8-3" , "1Gi" , "uid8-3" , "claim8-3" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimDelete , classEmpty ) ) ,
2016-05-17 12:55:23 +00:00
noclaims ,
noclaims ,
2016-05-17 12:55:28 +00:00
[ ] string { "Warning VolumeFailedDelete" } , noerrors , testSyncVolume ,
2016-05-17 12:55:23 +00:00
} ,
{
// delete failure - newDeleter returns error
"8-4 - newDeleter returns error" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-4" , "1Gi" , "uid8-4" , "claim8-4" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
withMessage ( "Failed to create deleter for volume \"volume8-4\": Mock plugin error: no deleteCalls configured" , newVolumeArray ( "volume8-4" , "1Gi" , "uid8-4" , "claim8-4" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimDelete , classEmpty ) ) ,
2016-05-17 12:55:23 +00:00
noclaims ,
noclaims ,
2016-05-17 12:55:28 +00:00
[ ] string { "Warning VolumeFailedDelete" } , noerrors ,
2016-08-18 08:36:49 +00:00
wrapTestWithReclaimCalls ( operationDelete , [ ] error { } , testSyncVolume ) ,
2016-05-17 12:55:23 +00:00
} ,
{
// delete failure - delete() returns error
"8-5 - delete returns error" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-5" , "1Gi" , "uid8-5" , "claim8-5" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
withMessage ( "Mock delete error" , newVolumeArray ( "volume8-5" , "1Gi" , "uid8-5" , "claim8-5" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimDelete , classEmpty ) ) ,
2016-05-17 12:55:23 +00:00
noclaims ,
noclaims ,
2016-05-17 12:55:28 +00:00
[ ] string { "Warning VolumeFailedDelete" } , noerrors ,
2016-08-18 08:36:49 +00:00
wrapTestWithReclaimCalls ( operationDelete , [ ] error { errors . New ( "Mock delete error" ) } , testSyncVolume ) ,
2016-05-17 12:55:23 +00:00
} ,
{
// delete success(?) - volume is deleted before doDelete() starts
"8-6 - volume is deleted before deleting" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-6" , "1Gi" , "uid8-6" , "claim8-6" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
2016-05-17 12:55:23 +00:00
novolumes ,
noclaims ,
noclaims ,
2016-05-17 12:55:28 +00:00
noevents , noerrors ,
2016-08-18 08:36:49 +00:00
wrapTestWithInjectedOperation ( wrapTestWithReclaimCalls ( operationDelete , [ ] error { } , testSyncVolume ) , func ( ctrl * PersistentVolumeController , reactor * volumeReactor ) {
2016-05-17 12:55:23 +00:00
// Delete the volume before delete operation starts
reactor . lock . Lock ( )
delete ( reactor . volumes , "volume8-6" )
reactor . lock . Unlock ( )
} ) ,
} ,
{
// delete success(?) - volume is bound just at the time doDelete()
// starts. This simulates "volume no longer needs recycling,
// skipping".
"8-7 - volume is bound before deleting" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-7" , "1Gi" , "uid8-7" , "claim8-7" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume8-7" , "1Gi" , "uid8-7" , "claim8-7" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annBoundByController ) ,
2016-05-17 12:55:23 +00:00
noclaims ,
2017-03-02 09:23:56 +00:00
newClaimArray ( "claim8-7" , "uid8-7" , "10Gi" , "volume8-7" , v1 . ClaimBound , nil ) ,
2016-05-17 12:55:28 +00:00
noevents , noerrors ,
2016-08-18 08:36:49 +00:00
wrapTestWithInjectedOperation ( wrapTestWithReclaimCalls ( operationDelete , [ ] error { } , testSyncVolume ) , func ( ctrl * PersistentVolumeController , reactor * volumeReactor ) {
2016-05-17 12:55:23 +00:00
reactor . lock . Lock ( )
defer reactor . lock . Unlock ( )
2016-06-17 16:27:25 +00:00
// Bind the volume to resurrected claim (this should never
2016-05-17 12:55:23 +00:00
// happen)
2017-03-02 09:23:56 +00:00
claim := newClaim ( "claim8-7" , "uid8-7" , "10Gi" , "volume8-7" , v1 . ClaimBound , nil )
2016-05-17 12:55:23 +00:00
reactor . claims [ claim . Name ] = claim
ctrl . claims . Add ( claim )
volume := reactor . volumes [ "volume8-7" ]
2016-11-18 20:50:17 +00:00
volume . Status . Phase = v1 . VolumeBound
2016-05-17 12:55:23 +00:00
} ) ,
} ,
{
// delete success - volume bound by user is deleted, while a new
// claim is created with another UID.
"8-9 - prebound volume is deleted while the claim exists" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-9" , "1Gi" , "uid8-9" , "claim8-9" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
2016-05-17 12:55:23 +00:00
novolumes ,
2017-03-02 09:23:56 +00:00
newClaimArray ( "claim8-9" , "uid8-9-x" , "10Gi" , "" , v1 . ClaimPending , nil ) ,
newClaimArray ( "claim8-9" , "uid8-9-x" , "10Gi" , "" , v1 . ClaimPending , nil ) ,
2016-05-17 12:55:28 +00:00
noevents , noerrors ,
2016-05-17 12:55:23 +00:00
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
2016-08-18 08:36:49 +00:00
wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 12:55:23 +00:00
} ,
2016-09-13 08:39:45 +00:00
{
// PV requires external deleter
"8-10 - external deleter" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume8-10" , "1Gi" , "uid10-1" , "claim10-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annBoundByController ) ,
newVolumeArray ( "volume8-10" , "1Gi" , "uid10-1" , "claim10-1" , v1 . VolumeReleased , v1 . PersistentVolumeReclaimDelete , classEmpty , annBoundByController ) ,
2016-09-13 08:39:45 +00:00
noclaims ,
noclaims ,
noevents , noerrors ,
func ( ctrl * PersistentVolumeController , reactor * volumeReactor , test controllerTest ) error {
// Inject external deleter annotation
test . initialVolumes [ 0 ] . Annotations [ annDynamicallyProvisioned ] = "external.io/test"
test . expectedVolumes [ 0 ] . Annotations [ annDynamicallyProvisioned ] = "external.io/test"
return testSyncVolume ( ctrl , reactor , test )
} ,
} ,
2016-11-03 15:58:25 +00:00
{
// delete success - two PVs are provisioned for a single claim.
// One of the PVs is deleted.
"8-11 - two PVs provisioned for a single claim" ,
2016-11-18 20:50:17 +00:00
[ ] * v1 . PersistentVolume {
2017-03-02 09:23:56 +00:00
newVolume ( "volume8-11-1" , "1Gi" , "uid8-11" , "claim8-11" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annDynamicallyProvisioned ) ,
newVolume ( "volume8-11-2" , "1Gi" , "uid8-11" , "claim8-11" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annDynamicallyProvisioned ) ,
2016-11-03 15:58:25 +00:00
} ,
2016-11-18 20:50:17 +00:00
[ ] * v1 . PersistentVolume {
2017-03-02 09:23:56 +00:00
newVolume ( "volume8-11-2" , "1Gi" , "uid8-11" , "claim8-11" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annDynamicallyProvisioned ) ,
2016-11-03 15:58:25 +00:00
} ,
// the claim is bound to volume8-11-2 -> volume8-11-1 has lost the race and will be deleted
2017-03-02 09:23:56 +00:00
newClaimArray ( "claim8-11" , "uid8-11" , "10Gi" , "volume8-11-2" , v1 . ClaimBound , nil ) ,
newClaimArray ( "claim8-11" , "uid8-11" , "10Gi" , "volume8-11-2" , v1 . ClaimBound , nil ) ,
2016-11-03 15:58:25 +00:00
noevents , noerrors ,
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
} ,
{
// delete success - two PVs are externally provisioned for a single
// claim. One of the PVs is marked as Released to be deleted by the
// external provisioner.
"8-12 - two PVs externally provisioned for a single claim" ,
2016-11-18 20:50:17 +00:00
[ ] * v1 . PersistentVolume {
2017-03-02 09:23:56 +00:00
newVolume ( "volume8-12-1" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annDynamicallyProvisioned ) ,
newVolume ( "volume8-12-2" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annDynamicallyProvisioned ) ,
2016-11-03 15:58:25 +00:00
} ,
2016-11-18 20:50:17 +00:00
[ ] * v1 . PersistentVolume {
2017-03-02 09:23:56 +00:00
newVolume ( "volume8-12-1" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeReleased , v1 . PersistentVolumeReclaimDelete , classEmpty , annDynamicallyProvisioned ) ,
newVolume ( "volume8-12-2" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , annDynamicallyProvisioned ) ,
2016-11-03 15:58:25 +00:00
} ,
// the claim is bound to volume8-12-2 -> volume8-12-1 has lost the race and will be "Released"
2017-03-02 09:23:56 +00:00
newClaimArray ( "claim8-12" , "uid8-12" , "10Gi" , "volume8-12-2" , v1 . ClaimBound , nil ) ,
newClaimArray ( "claim8-12" , "uid8-12" , "10Gi" , "volume8-12-2" , v1 . ClaimBound , nil ) ,
2016-11-03 15:58:25 +00:00
noevents , noerrors ,
func ( ctrl * PersistentVolumeController , reactor * volumeReactor , test controllerTest ) error {
// Inject external deleter annotation
test . initialVolumes [ 0 ] . Annotations [ annDynamicallyProvisioned ] = "external.io/test"
test . expectedVolumes [ 0 ] . Annotations [ annDynamicallyProvisioned ] = "external.io/test"
return testSyncVolume ( ctrl , reactor , test )
} ,
} ,
2016-05-17 12:55:23 +00:00
}
2018-02-05 14:40:25 +00:00
runSyncTests ( t , tests , [ ] * storage . StorageClass { } , [ ] * v1 . Pod { } )
2016-05-17 12:55:23 +00: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 TestDeleteMultiSync ( t * testing . T ) {
tests := [ ] controllerTest {
{
// delete failure - delete returns error. The controller should
// try again.
"9-1 - delete returns error" ,
2017-03-02 09:23:56 +00:00
newVolumeArray ( "volume9-1" , "1Gi" , "uid9-1" , "claim9-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
2016-05-17 12:55:23 +00:00
novolumes ,
noclaims ,
noclaims ,
2016-05-17 12:55:28 +00:00
[ ] string { "Warning VolumeFailedDelete" } , noerrors ,
2016-08-18 08:36:49 +00:00
wrapTestWithReclaimCalls ( operationDelete , [ ] error { errors . New ( "Mock delete error" ) , nil } , testSyncVolume ) ,
2016-05-17 12:55:23 +00:00
} ,
}
2016-09-01 15:29:26 +00:00
runMultisyncTests ( t , tests , [ ] * storage . StorageClass { } , "" )
2016-05-17 12:55:23 +00:00
}