Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
7ebcab8c
Commit
7ebcab8c
authored
Dec 28, 2016
by
rkouj
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add unit tests for operation_executor
parent
a8b168a7
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
238 additions
and
59 deletions
+238
-59
BUILD
pkg/volume/util/operationexecutor/BUILD
+2
-1
operation_executor_test.go
pkg/volume/util/operationexecutor/operation_executor_test.go
+236
-58
No files found.
pkg/volume/util/operationexecutor/BUILD
View file @
7ebcab8c
...
@@ -41,6 +41,7 @@ go_test(
...
@@ -41,6 +41,7 @@ go_test(
"//pkg/api/v1:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/types:go_default_library",
"//pkg/types:go_default_library",
"//pkg/util/mount:go_default_library",
"//pkg/util/mount:go_default_library",
"//vendor:k8s.io/client-go/_vendor/github.com/pborman/uuid",
"//pkg/util/uuid:go_default_library",
"//pkg/volume/util/types:go_default_library",
],
],
)
)
pkg/volume/util/operationexecutor/operation_executor_test.go
View file @
7ebcab8c
...
@@ -17,25 +17,32 @@ limitations under the License.
...
@@ -17,25 +17,32 @@ limitations under the License.
package
operationexecutor
package
operationexecutor
import
(
import
(
"k8s.io/client-go/_vendor/github.com/pborman/uuid"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/uuid"
volumetypes
"k8s.io/kubernetes/pkg/volume/util/types"
"strconv"
"strconv"
"testing"
"testing"
"time"
"time"
)
)
const
numVolumesToMount
=
2
const
(
numVolumesToMount
=
2
numAttachableVolumesToUnmount
=
2
numNonAttachableVolumesToUnmount
=
2
numDevicesToUnmount
=
2
numVolumesToAttach
=
2
numVolumesToDetach
=
2
numVolumesToVerifyAttached
=
2
numVolumesToVerifyControllerAttached
=
2
)
var
_
OperationGenerator
=
&
mock
OperationGenerator
{}
var
_
OperationGenerator
=
&
fake
OperationGenerator
{}
func
TestOperationExecutor_MountVolume_
Parallel
MountForNonAttachablePlugins
(
t
*
testing
.
T
)
{
func
TestOperationExecutor_MountVolume_
Concurrent
MountForNonAttachablePlugins
(
t
*
testing
.
T
)
{
// Arrange
// Arrange
ch
,
quit
:=
make
(
chan
interface
{}),
make
(
chan
interface
{})
ch
,
quit
,
oe
:=
setup
()
numMountOperationsStarted
:=
0
mopg
:=
newMockOperationGenerator
(
ch
,
quit
)
oe
:=
NewOperationExecutor
(
mopg
)
volumesToMount
:=
make
([]
VolumeToMount
,
numVolumesToMount
)
volumesToMount
:=
make
([]
VolumeToMount
,
numVolumesToMount
)
secretName
:=
"secret-volume"
secretName
:=
"secret-volume"
volumeName
:=
v1
.
UniqueVolumeName
(
secretName
)
volumeName
:=
v1
.
UniqueVolumeName
(
secretName
)
...
@@ -54,29 +61,15 @@ func TestOperationExecutor_MountVolume_ParallelMountForNonAttachablePlugins(t *t
...
@@ -54,29 +61,15 @@ func TestOperationExecutor_MountVolume_ParallelMountForNonAttachablePlugins(t *t
}
}
// Assert
// Assert
loop
:
if
!
isOperationRunConcurrently
(
ch
,
quit
,
numVolumesToMount
)
{
for
{
t
.
Fatalf
(
"Unable to start mount operations in Concurrent for non-attachable volumes"
)
select
{
case
<-
ch
:
numMountOperationsStarted
++
if
numMountOperationsStarted
==
numVolumesToMount
{
break
loop
}
case
<-
time
.
After
(
5
*
time
.
Second
)
:
t
.
Fatalf
(
"Unable to start mount operations in parallel for non-attachable volumes"
)
break
loop
}
}
}
close
(
quit
)
}
}
func
TestOperationExecutor_MountVolume_
Parallel
MountForAttachablePlugins
(
t
*
testing
.
T
)
{
func
TestOperationExecutor_MountVolume_
Concurrent
MountForAttachablePlugins
(
t
*
testing
.
T
)
{
// Arrange
// Arrange
ch
,
quit
:=
make
(
chan
interface
{}),
make
(
chan
interface
{})
ch
,
quit
,
oe
:=
setup
()
numMountOperationsStarted
:=
0
volumesToMount
:=
make
([]
VolumeToMount
,
numVolumesToAttach
)
mopg
:=
newMockOperationGenerator
(
ch
,
quit
)
oe
:=
NewOperationExecutor
(
mopg
)
volumesToMount
:=
make
([]
VolumeToMount
,
numVolumesToMount
)
pdName
:=
"pd-volume"
pdName
:=
"pd-volume"
volumeName
:=
v1
.
UniqueVolumeName
(
pdName
)
volumeName
:=
v1
.
UniqueVolumeName
(
pdName
)
...
@@ -94,59 +87,196 @@ func TestOperationExecutor_MountVolume_ParallelMountForAttachablePlugins(t *test
...
@@ -94,59 +87,196 @@ func TestOperationExecutor_MountVolume_ParallelMountForAttachablePlugins(t *test
}
}
// Assert
// Assert
loop
:
if
!
isOperationRunSerially
(
ch
,
quit
)
{
for
{
t
.
Fatalf
(
"Mount operations should not start concurrently for attachable volumes"
)
select
{
}
case
<-
ch
:
}
numMountOperationsStarted
++
if
numMountOperationsStarted
>
1
{
func
TestOperationExecutor_UnmountVolume_ConcurrentUnmountForAllPlugins
(
t
*
testing
.
T
)
{
t
.
Fatalf
(
"Mount operations should not start in parallel for attachable volumes"
)
// Arrange
break
loop
ch
,
quit
,
oe
:=
setup
()
volumesToUnmount
:=
make
([]
MountedVolume
,
numAttachableVolumesToUnmount
+
numNonAttachableVolumesToUnmount
)
pdName
:=
"pd-volume"
secretName
:=
"secret-volume"
// Act
for
i
:=
0
;
i
<
numNonAttachableVolumesToUnmount
+
numAttachableVolumesToUnmount
;
i
++
{
podName
:=
"pod-"
+
strconv
.
Itoa
(
i
+
1
)
if
i
<
numNonAttachableVolumesToUnmount
{
pod
:=
getTestPodWithSecret
(
podName
,
secretName
)
volumesToUnmount
[
i
]
=
MountedVolume
{
PodName
:
volumetypes
.
UniquePodName
(
podName
),
VolumeName
:
v1
.
UniqueVolumeName
(
secretName
),
PodUID
:
pod
.
UID
,
}
}
case
<-
time
.
After
(
5
*
time
.
Second
)
:
}
else
{
break
loop
pod
:=
getTestPodWithGCEPD
(
podName
,
pdName
)
volumesToUnmount
[
i
]
=
MountedVolume
{
PodName
:
volumetypes
.
UniquePodName
(
podName
),
VolumeName
:
v1
.
UniqueVolumeName
(
pdName
),
PodUID
:
pod
.
UID
,
}
}
oe
.
UnmountVolume
(
volumesToUnmount
[
i
],
nil
/* actualStateOfWorldMounterUpdater */
)
}
// Assert
if
!
isOperationRunConcurrently
(
ch
,
quit
,
numNonAttachableVolumesToUnmount
+
numAttachableVolumesToUnmount
)
{
t
.
Fatalf
(
"Unable to start unmount operations concurrently for volume plugins"
)
}
}
func
TestOperationExecutor_UnmountDeviceConcurrently
(
t
*
testing
.
T
)
{
// Arrange
ch
,
quit
,
oe
:=
setup
()
attachedVolumes
:=
make
([]
AttachedVolume
,
numDevicesToUnmount
)
pdName
:=
"pd-volume"
// Act
for
i
:=
range
attachedVolumes
{
attachedVolumes
[
i
]
=
AttachedVolume
{
VolumeName
:
v1
.
UniqueVolumeName
(
pdName
),
NodeName
:
"node-name"
,
}
oe
.
UnmountDevice
(
attachedVolumes
[
i
],
nil
/* actualStateOfWorldMounterUpdater */
,
nil
/* mount.Interface */
)
}
// Assert
if
!
isOperationRunSerially
(
ch
,
quit
)
{
t
.
Fatalf
(
"Unmount device operations should not start concurrently"
)
}
}
func
TestOperationExecutor_AttachVolumeConcurrently
(
t
*
testing
.
T
)
{
// Arrange
ch
,
quit
,
oe
:=
setup
()
volumesToAttach
:=
make
([]
VolumeToAttach
,
numVolumesToAttach
)
pdName
:=
"pd-volume"
// Act
for
i
:=
range
volumesToAttach
{
volumesToAttach
[
i
]
=
VolumeToAttach
{
VolumeName
:
v1
.
UniqueVolumeName
(
pdName
),
NodeName
:
"node"
,
}
oe
.
AttachVolume
(
volumesToAttach
[
i
],
nil
/* actualStateOfWorldAttacherUpdater */
)
}
// Assert
if
!
isOperationRunSerially
(
ch
,
quit
)
{
t
.
Fatalf
(
"Attach volume operations should not start concurrently"
)
}
}
func
TestOperationExecutor_DetachVolumeConcurrently
(
t
*
testing
.
T
)
{
// Arrange
ch
,
quit
,
oe
:=
setup
()
attachedVolumes
:=
make
([]
AttachedVolume
,
numVolumesToDetach
)
pdName
:=
"pd-volume"
// Act
for
i
:=
range
attachedVolumes
{
attachedVolumes
[
i
]
=
AttachedVolume
{
VolumeName
:
v1
.
UniqueVolumeName
(
pdName
),
NodeName
:
"node"
,
}
oe
.
DetachVolume
(
attachedVolumes
[
i
],
true
/* verifySafeToDetach */
,
nil
/* actualStateOfWorldAttacherUpdater */
)
}
// Assert
if
!
isOperationRunSerially
(
ch
,
quit
)
{
t
.
Fatalf
(
"DetachVolume operations should not run concurrently"
)
}
}
func
TestOperationExecutor_VerifyVolumesAreAttachedConcurrently
(
t
*
testing
.
T
)
{
// Arrange
ch
,
quit
,
oe
:=
setup
()
// Act
for
i
:=
0
;
i
<
numVolumesToVerifyAttached
;
i
++
{
oe
.
VerifyVolumesAreAttached
(
nil
/* attachedVolumes */
,
"node-name"
,
nil
/* actualStateOfWorldAttacherUpdater */
)
}
// Assert
if
!
isOperationRunConcurrently
(
ch
,
quit
,
numVolumesToVerifyAttached
)
{
t
.
Fatalf
(
"VerifyVolumesAreAttached operation is not being run concurrently"
)
}
}
func
TestOperationExecutor_VerifyControllerAttachedVolumeConcurrently
(
t
*
testing
.
T
)
{
// Arrange
ch
,
quit
,
oe
:=
setup
()
volumesToMount
:=
make
([]
VolumeToMount
,
numVolumesToVerifyControllerAttached
)
pdName
:=
"pd-volume"
// Act
for
i
:=
range
volumesToMount
{
volumesToMount
[
i
]
=
VolumeToMount
{
VolumeName
:
v1
.
UniqueVolumeName
(
pdName
),
}
}
oe
.
VerifyControllerAttachedVolume
(
volumesToMount
[
i
],
types
.
NodeName
(
"node-name"
),
nil
/* actualStateOfWorldMounterUpdater */
)
}
// Assert
if
!
isOperationRunSerially
(
ch
,
quit
)
{
t
.
Fatalf
(
"VerifyControllerAttachedVolume should not run concurrently"
)
}
}
close
(
quit
)
}
}
type
mock
OperationGenerator
struct
{
type
fake
OperationGenerator
struct
{
ch
chan
interface
{}
ch
chan
interface
{}
quit
chan
interface
{}
quit
chan
interface
{}
}
}
func
new
MockOperationGenerator
(
ch
,
quit
chan
interface
{})
OperationGenerator
{
func
new
FakeOperationGenerator
(
ch
chan
interface
{}
,
quit
chan
interface
{})
OperationGenerator
{
return
&
mock
OperationGenerator
{
return
&
fake
OperationGenerator
{
ch
:
ch
,
ch
:
ch
,
quit
:
quit
,
quit
:
quit
,
}
}
}
}
func
(
mopg
*
mock
OperationGenerator
)
GenerateMountVolumeFunc
(
waitForAttachTimeout
time
.
Duration
,
volumeToMount
VolumeToMount
,
actualStateOfWorldMounterUpdater
ActualStateOfWorldMounterUpdater
)
(
func
()
error
,
error
)
{
func
(
fopg
*
fake
OperationGenerator
)
GenerateMountVolumeFunc
(
waitForAttachTimeout
time
.
Duration
,
volumeToMount
VolumeToMount
,
actualStateOfWorldMounterUpdater
ActualStateOfWorldMounterUpdater
)
(
func
()
error
,
error
)
{
return
func
()
error
{
return
func
()
error
{
mopg
.
ch
<-
nil
startOperationAndBlock
(
fopg
.
ch
,
fopg
.
quit
)
// Blocks until the assertion is complete
<-
mopg
.
quit
return
nil
return
nil
},
nil
},
nil
}
}
func
(
mopg
*
mockOperationGenerator
)
GenerateUnmountVolumeFunc
(
volumeToUnmount
MountedVolume
,
actualStateOfWorld
ActualStateOfWorldMounterUpdater
)
(
func
()
error
,
error
)
{
func
(
fopg
*
fakeOperationGenerator
)
GenerateUnmountVolumeFunc
(
volumeToUnmount
MountedVolume
,
actualStateOfWorld
ActualStateOfWorldMounterUpdater
)
(
func
()
error
,
error
)
{
return
func
()
error
{
return
nil
},
nil
return
func
()
error
{
startOperationAndBlock
(
fopg
.
ch
,
fopg
.
quit
)
return
nil
},
nil
}
}
func
(
mopg
*
mockOperationGenerator
)
GenerateAttachVolumeFunc
(
volumeToAttach
VolumeToAttach
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
func
(
fopg
*
fakeOperationGenerator
)
GenerateAttachVolumeFunc
(
volumeToAttach
VolumeToAttach
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
return
func
()
error
{
return
nil
},
nil
return
func
()
error
{
startOperationAndBlock
(
fopg
.
ch
,
fopg
.
quit
)
return
nil
},
nil
}
}
func
(
mopg
*
mockOperationGenerator
)
GenerateDetachVolumeFunc
(
volumeToDetach
AttachedVolume
,
verifySafeToDetach
bool
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
func
(
fopg
*
fakeOperationGenerator
)
GenerateDetachVolumeFunc
(
volumeToDetach
AttachedVolume
,
verifySafeToDetach
bool
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
return
func
()
error
{
return
nil
},
nil
return
func
()
error
{
startOperationAndBlock
(
fopg
.
ch
,
fopg
.
quit
)
return
nil
},
nil
}
}
func
(
mopg
*
mockOperationGenerator
)
GenerateVolumesAreAttachedFunc
(
attachedVolumes
[]
AttachedVolume
,
nodeName
types
.
NodeName
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
func
(
fopg
*
fakeOperationGenerator
)
GenerateVolumesAreAttachedFunc
(
attachedVolumes
[]
AttachedVolume
,
nodeName
types
.
NodeName
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
return
func
()
error
{
return
nil
},
nil
return
func
()
error
{
startOperationAndBlock
(
fopg
.
ch
,
fopg
.
quit
)
return
nil
},
nil
}
}
func
(
mopg
*
mockOperationGenerator
)
GenerateUnmountDeviceFunc
(
deviceToDetach
AttachedVolume
,
actualStateOfWorld
ActualStateOfWorldMounterUpdater
,
mounter
mount
.
Interface
)
(
func
()
error
,
error
)
{
func
(
fopg
*
fakeOperationGenerator
)
GenerateUnmountDeviceFunc
(
deviceToDetach
AttachedVolume
,
actualStateOfWorld
ActualStateOfWorldMounterUpdater
,
mounter
mount
.
Interface
)
(
func
()
error
,
error
)
{
return
func
()
error
{
return
nil
},
nil
return
func
()
error
{
startOperationAndBlock
(
fopg
.
ch
,
fopg
.
quit
)
return
nil
},
nil
}
}
func
(
mopg
*
mockOperationGenerator
)
GenerateVerifyControllerAttachedVolumeFunc
(
volumeToMount
VolumeToMount
,
nodeName
types
.
NodeName
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
func
(
fopg
*
fakeOperationGenerator
)
GenerateVerifyControllerAttachedVolumeFunc
(
volumeToMount
VolumeToMount
,
nodeName
types
.
NodeName
,
actualStateOfWorld
ActualStateOfWorldAttacherUpdater
)
(
func
()
error
,
error
)
{
return
func
()
error
{
return
nil
},
nil
return
func
()
error
{
startOperationAndBlock
(
fopg
.
ch
,
fopg
.
quit
)
return
nil
},
nil
}
}
func
getTestPodWithSecret
(
podName
,
secretName
string
)
*
v1
.
Pod
{
func
getTestPodWithSecret
(
podName
,
secretName
string
)
*
v1
.
Pod
{
...
@@ -190,7 +320,7 @@ func getTestPodWithGCEPD(podName, pdName string) *v1.Pod {
...
@@ -190,7 +320,7 @@ func getTestPodWithGCEPD(podName, pdName string) *v1.Pod {
return
&
v1
.
Pod
{
return
&
v1
.
Pod
{
ObjectMeta
:
v1
.
ObjectMeta
{
ObjectMeta
:
v1
.
ObjectMeta
{
Name
:
podName
,
Name
:
podName
,
UID
:
types
.
UID
(
podName
+
string
(
uuid
.
New
())),
UID
:
types
.
UID
(
podName
+
string
(
uuid
.
New
UUID
())),
},
},
Spec
:
v1
.
PodSpec
{
Spec
:
v1
.
PodSpec
{
Volumes
:
[]
v1
.
Volume
{
Volumes
:
[]
v1
.
Volume
{
...
@@ -224,3 +354,51 @@ func getTestPodWithGCEPD(podName, pdName string) *v1.Pod {
...
@@ -224,3 +354,51 @@ func getTestPodWithGCEPD(podName, pdName string) *v1.Pod {
},
},
}
}
}
}
func
isOperationRunSerially
(
ch
<-
chan
interface
{},
quit
chan
<-
interface
{})
bool
{
defer
close
(
quit
)
numOperationsStarted
:=
0
loop
:
for
{
select
{
case
<-
ch
:
numOperationsStarted
++
if
numOperationsStarted
>
1
{
return
false
}
case
<-
time
.
After
(
5
*
time
.
Second
)
:
break
loop
}
}
return
true
}
func
isOperationRunConcurrently
(
ch
<-
chan
interface
{},
quit
chan
<-
interface
{},
numOperationsToRun
int
)
bool
{
defer
close
(
quit
)
numOperationsStarted
:=
0
loop
:
for
{
select
{
case
<-
ch
:
numOperationsStarted
++
if
numOperationsStarted
==
numOperationsToRun
{
return
true
}
case
<-
time
.
After
(
5
*
time
.
Second
)
:
break
loop
}
}
return
false
}
func
setup
()
(
chan
interface
{},
chan
interface
{},
OperationExecutor
)
{
ch
,
quit
:=
make
(
chan
interface
{}),
make
(
chan
interface
{})
return
ch
,
quit
,
NewOperationExecutor
(
newFakeOperationGenerator
(
ch
,
quit
))
}
// This function starts by writing to ch and blocks on the quit channel
// until it is closed by the currently running test
func
startOperationAndBlock
(
ch
chan
<-
interface
{},
quit
<-
chan
interface
{})
{
ch
<-
nil
<-
quit
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment