Skip to content

Commit beba033

Browse files
authored
Merge pull request #1493 from umagnus/add_azcopy_mock
[test] add mock for azcopy ut
2 parents effa1d0 + 7b6279f commit beba033

12 files changed

+571
-195
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
Copyright 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+
*/
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// /*
2+
// Copyright 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+
// */

hack/boilerplate/boilerplate.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ def get_refs():
6565

6666
return refs
6767

68+
def is_generated_file(filename, data, regexs):
69+
for d in skipped_ungenerated_files:
70+
if d in filename:
71+
return False
72+
73+
p = regexs["generated"]
74+
return p.search(data)
75+
6876
def file_passes(filename, refs, regexs):
6977
try:
7078
f = open(filename, 'r')
@@ -75,15 +83,21 @@ def file_passes(filename, refs, regexs):
7583
data = f.read()
7684
f.close()
7785

86+
# determine if the file is automatically generated
87+
generated = is_generated_file(filename, data, regexs)
88+
7889
basename = os.path.basename(filename)
7990
extension = file_extension(filename)
91+
if generated:
92+
if extension == "go":
93+
extension = "gomock"
8094
if extension != "":
8195
ref = refs[extension]
8296
else:
8397
ref = refs[basename]
8498

8599
# remove build tags from the top of Go files
86-
if extension == "go":
100+
if extension == "go" or extension == "gomock":
87101
p = regexs["go_build_constraints"]
88102
(data, found) = p.subn("", data, 1)
89103

@@ -136,6 +150,10 @@ def file_extension(filename):
136150
'cluster/env.sh', 'vendor', 'test/e2e/generated/bindata.go',
137151
'repo-infra/verify/boilerplate/test', '.glide']
138152

153+
# list all the files contain 'DO NOT EDIT', but are not generated
154+
skipped_ungenerated_files = [
155+
'hack/boilerplate/boilerplate.py']
156+
139157
def normalize_files(files):
140158
newfiles = []
141159
for pathname in files:
@@ -183,6 +201,8 @@ def get_regexs():
183201
regexs["go_build_constraints"] = re.compile(r"^(//(go:build| \+build).*\n)+\n", re.MULTILINE)
184202
# strip #!.* from shell scripts
185203
regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE)
204+
# Search for generated files
205+
regexs["generated"] = re.compile('DO NOT EDIT')
186206
return regexs
187207

188208

hack/update-mock.sh

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
3+
# Copyright 2020 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
set -euo pipefail
18+
19+
REPO_ROOT=$(realpath $(dirname ${BASH_SOURCE})/..)
20+
COPYRIGHT_FILE="${REPO_ROOT}/hack/boilerplate/boilerplate.generatego.txt"
21+
22+
if ! type mockgen &> /dev/null; then
23+
echo "mockgen not exist, install it"
24+
go install github.com/golang/mock/[email protected]
25+
fi
26+
27+
echo "Updating mocks for util.go"
28+
mockgen -copyright_file=$COPYRIGHT_FILE -source=pkg/util/util.go -package=util -destination=pkg/util/util_mock.go

pkg/azurefile/azurefile.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646

4747
csicommon "sigs.k8s.io/azurefile-csi-driver/pkg/csi-common"
4848
"sigs.k8s.io/azurefile-csi-driver/pkg/mounter"
49+
fileutil "sigs.k8s.io/azurefile-csi-driver/pkg/util"
4950
"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/fileclient"
5051
azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
5152
azure "sigs.k8s.io/cloud-provider-azure/pkg/provider"
@@ -269,6 +270,8 @@ type Driver struct {
269270
volStatsCache azcache.Resource
270271
// sas expiry time for azcopy in volume clone
271272
sasTokenExpirationMinutes int
273+
// azcopy for provide exec mock for ut
274+
azcopy *fileutil.Azcopy
272275
}
273276

274277
// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
@@ -300,6 +303,7 @@ func NewDriver(options *DriverOptions) *Driver {
300303
driver.volLockMap = newLockMap()
301304
driver.subnetLockMap = newLockMap()
302305
driver.volumeLocks = newVolumeLocks()
306+
driver.azcopy = &fileutil.Azcopy{}
303307

304308
var err error
305309
getter := func(key string) (interface{}, error) { return nil, nil }
@@ -928,21 +932,21 @@ func (d *Driver) copyFileShare(ctx context.Context, req *csi.CreateVolumeRequest
928932
srcPath := fmt.Sprintf("https://%s.file.%s/%s%s", accountName, storageEndpointSuffix, srcFileShareName, accountSasToken)
929933
dstPath := fmt.Sprintf("https://%s.file.%s/%s%s", accountName, storageEndpointSuffix, dstFileShareName, accountSasToken)
930934

931-
jobState, percent, err := getAzcopyJob(dstFileShareName)
935+
jobState, percent, err := d.azcopy.GetAzcopyJob(dstFileShareName)
932936
klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err)
933-
if jobState == AzcopyJobError || jobState == AzcopyJobCompleted {
937+
if jobState == fileutil.AzcopyJobError || jobState == fileutil.AzcopyJobCompleted {
934938
return err
935939
}
936940
klog.V(2).Infof("begin to copy fileshare %s to %s", srcFileShareName, dstFileShareName)
937941
for {
938942
select {
939943
case <-timeTick:
940-
jobState, percent, err := getAzcopyJob(dstFileShareName)
944+
jobState, percent, err := d.azcopy.GetAzcopyJob(dstFileShareName)
941945
klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err)
942946
switch jobState {
943-
case AzcopyJobError, AzcopyJobCompleted:
947+
case fileutil.AzcopyJobError, fileutil.AzcopyJobCompleted:
944948
return err
945-
case AzcopyJobNotFound:
949+
case fileutil.AzcopyJobNotFound:
946950
klog.V(2).Infof("copy fileshare %s to %s", srcFileShareName, dstFileShareName)
947951
out, copyErr := exec.Command("azcopy", "copy", srcPath, dstPath, "--recursive", "--check-length=false").CombinedOutput()
948952
if copyErr != nil {

pkg/azurefile/controllerserver.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
108108
if acquired := d.volumeLocks.TryAcquire(volName); !acquired {
109109
// logging the job status if it's volume cloning
110110
if req.GetVolumeContentSource() != nil {
111-
jobState, percent, err := getAzcopyJob(volName)
111+
jobState, percent, err := d.azcopy.GetAzcopyJob(volName)
112112
klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err)
113113
}
114114
return nil, status.Errorf(codes.Aborted, volumeOperationAlreadyExistsFmt, volName)

pkg/azurefile/controllerserver_test.go

+92-1
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ import (
2323
"net/http"
2424
"net/url"
2525
"reflect"
26-
"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/fileclient"
2726
"strings"
2827
"sync"
2928
"testing"
3029
"time"
3130

31+
"sigs.k8s.io/azurefile-csi-driver/pkg/util"
32+
"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/fileclient"
33+
3234
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
3335
"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient/mocksubnetclient"
3436
azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
@@ -1783,6 +1785,95 @@ func TestCopyVolume(t *testing.T) {
17831785
}
17841786
},
17851787
},
1788+
{
1789+
name: "azcopy job is already completed",
1790+
testFunc: func(t *testing.T) {
1791+
d := NewFakeDriver()
1792+
mp := map[string]string{}
1793+
1794+
volumeSource := &csi.VolumeContentSource_VolumeSource{
1795+
VolumeId: "vol_1#f5713de20cde511e8ba4900#fileshare#",
1796+
}
1797+
volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{
1798+
Volume: volumeSource,
1799+
}
1800+
volumecontensource := csi.VolumeContentSource{
1801+
Type: volumeContentSourceVolumeSource,
1802+
}
1803+
1804+
req := &csi.CreateVolumeRequest{
1805+
Name: "unit-test",
1806+
VolumeCapabilities: stdVolCap,
1807+
Parameters: mp,
1808+
VolumeContentSource: &volumecontensource,
1809+
}
1810+
1811+
ctrl := gomock.NewController(t)
1812+
defer ctrl.Finish()
1813+
1814+
m := util.NewMockEXEC(ctrl)
1815+
listStr := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false"
1816+
m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstFileshare -B 3")).Return(listStr, nil)
1817+
// if test.enableShow {
1818+
// m.EXPECT().RunCommand(gomock.Not("azcopy jobs list | grep dstContainer -B 3")).Return(test.showStr, test.showErr)
1819+
// }
1820+
1821+
d.azcopy.ExecCmd = m
1822+
1823+
ctx := context.Background()
1824+
1825+
var expectedErr error
1826+
err := d.copyVolume(ctx, req, "", &fileclient.ShareOptions{Name: "dstFileshare"}, "core.windows.net")
1827+
if !reflect.DeepEqual(err, expectedErr) {
1828+
t.Errorf("Unexpected error: %v", err)
1829+
}
1830+
},
1831+
},
1832+
{
1833+
name: "azcopy job is first in progress and then be completed",
1834+
testFunc: func(t *testing.T) {
1835+
d := NewFakeDriver()
1836+
mp := map[string]string{}
1837+
1838+
volumeSource := &csi.VolumeContentSource_VolumeSource{
1839+
VolumeId: "vol_1#f5713de20cde511e8ba4900#fileshare#",
1840+
}
1841+
volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{
1842+
Volume: volumeSource,
1843+
}
1844+
volumecontensource := csi.VolumeContentSource{
1845+
Type: volumeContentSourceVolumeSource,
1846+
}
1847+
1848+
req := &csi.CreateVolumeRequest{
1849+
Name: "unit-test",
1850+
VolumeCapabilities: stdVolCap,
1851+
Parameters: mp,
1852+
VolumeContentSource: &volumecontensource,
1853+
}
1854+
1855+
ctrl := gomock.NewController(t)
1856+
defer ctrl.Finish()
1857+
1858+
m := util.NewMockEXEC(ctrl)
1859+
listStr1 := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: InProgress\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false"
1860+
listStr2 := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false"
1861+
o1 := m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstFileshare -B 3")).Return(listStr1, nil).Times(1)
1862+
m.EXPECT().RunCommand(gomock.Not("azcopy jobs list | grep dstFileshare -B 3")).Return("Percent Complete (approx): 50.0", nil)
1863+
o2 := m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstFileshare -B 3")).Return(listStr2, nil)
1864+
gomock.InOrder(o1, o2)
1865+
1866+
d.azcopy.ExecCmd = m
1867+
1868+
ctx := context.Background()
1869+
1870+
var expectedErr error
1871+
err := d.copyVolume(ctx, req, "", &fileclient.ShareOptions{Name: "dstFileshare"}, "core.windows.net")
1872+
if !reflect.DeepEqual(err, expectedErr) {
1873+
t.Errorf("Unexpected error: %v", err)
1874+
}
1875+
},
1876+
},
17861877
}
17871878

17881879
for _, tc := range testCases {

0 commit comments

Comments
 (0)