unittests: Fixes unit tests for Windows (part 4)

Currently, there are some unit tests that are failing on Windows due to
various reasons:

- paths not properly joined (filepath.Join should be used).
- files not closed, which means that they cannot be removed / renamed.
- time.Now() is not as precise on Windows, which means that 2
  consecutive calls may return the same timestamp.
This commit is contained in:
Claudiu Belu 2022-05-23 16:53:00 +03:00
parent 95bd687a28
commit 4dc7a260ec
7 changed files with 178 additions and 23 deletions

View File

@ -2811,9 +2811,7 @@ func collectAndComparePluginMetrics(t *testing.T, wantExtensionPoint, wantPlugin
if err != nil {
t.Errorf("Failed to get %s value, err: %v", metrics.PluginExecutionDuration.Name, err)
}
if value <= 0 {
t.Errorf("Expect latency to be greater than 0, got: %v", value)
}
checkLatency(t, value)
}
func collectAndCompareFrameworkMetrics(t *testing.T, wantExtensionPoint string, wantStatus framework.Code) {
@ -2831,9 +2829,7 @@ func collectAndCompareFrameworkMetrics(t *testing.T, wantExtensionPoint string,
if err != nil {
t.Errorf("Failed to get %s value, err: %v", metrics.FrameworkExtensionPointDuration.Name, err)
}
if value <= 0 {
t.Errorf("Expect latency to be greater than 0, got: %v", value)
}
checkLatency(t, value)
}
func collectAndComparePermitWaitDuration(t *testing.T, wantRes string) {
@ -2854,9 +2850,7 @@ func collectAndComparePermitWaitDuration(t *testing.T, wantRes string) {
if err != nil {
t.Errorf("Failed to get %s value, err: %v", metrics.PermitWaitDuration.Name, err)
}
if value <= 0 {
t.Errorf("Expect latency to be greater than 0, got: %v", value)
}
checkLatency(t, value)
}
}

View File

@ -0,0 +1,30 @@
//go:build !windows
// +build !windows
/*
Copyright 2022 The Kubernetes Authors.
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 runtime
import (
"testing"
)
func checkLatency(t *testing.T, value float64) {
if value <= 0 {
t.Errorf("Expect latency to be greater than 0, got: %v", value)
}
}

View File

@ -0,0 +1,30 @@
//go:build windows
// +build windows
/*
Copyright 2022 The Kubernetes Authors.
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 runtime
import (
"testing"
)
func checkLatency(t *testing.T, value float64) {
// On Windows, time.Now() is not as precise, 2 consecutive calls may return the same timestamp,
// thus, the latency metric may be 0 (SinceInSeconds will return 0).
// See: https://github.com/golang/go/issues/8687
}

View File

@ -156,15 +156,6 @@ func (fake *fakeDiskManager) MakeGlobalVDPDName(rbd rbd) string {
return makePDNameInternal(rbd.plugin.host, rbd.Pool, rbd.Image)
}
func (fake *fakeDiskManager) AttachDisk(b rbdMounter) (string, error) {
fake.mutex.Lock()
defer fake.mutex.Unlock()
fake.rbdMapIndex++
devicePath := fmt.Sprintf("/dev/rbd%d", fake.rbdMapIndex)
fake.rbdDevices[devicePath] = true
return devicePath, nil
}
func (fake *fakeDiskManager) DetachDisk(r *rbdPlugin, deviceMountPath string, device string) error {
fake.mutex.Lock()
defer fake.mutex.Unlock()
@ -292,7 +283,11 @@ func doTestPlugin(t *testing.T, c *testcase) {
t.Errorf("Attacher.MountDevice() failed: %v", err)
}
}
checkMounterLog(t, fakeMounter, 1, mount.FakeAction{Action: "mount", Target: c.expectedDeviceMountPath, Source: devicePath, FSType: "ext4"})
loggedSource, err := getLoggedSource(devicePath)
if err != nil {
t.Fatal(err)
}
checkMounterLog(t, fakeMounter, 1, mount.FakeAction{Action: "mount", Target: c.expectedDeviceMountPath, Source: loggedSource, FSType: "ext4"})
// mounter
mounter, err := plug.(*rbdPlugin).newMounterInternal(c.spec, c.pod.UID, fdm, "secrets")
@ -317,7 +312,7 @@ func doTestPlugin(t *testing.T, c *testcase) {
t.Errorf("SetUp() failed: %v", err)
}
}
checkMounterLog(t, fakeMounter, 2, mount.FakeAction{Action: "mount", Target: c.expectedPodMountPath, Source: devicePath, FSType: ""})
checkMounterLog(t, fakeMounter, 2, mount.FakeAction{Action: "mount", Target: c.expectedPodMountPath, Source: loggedSource, FSType: ""})
// unmounter
unmounter, err := plug.(*rbdPlugin).newUnmounterInternal(c.spec.Name(), c.pod.UID, fdm)
@ -374,6 +369,12 @@ func TestPlugin(t *testing.T) {
t.Fatal(err)
}
expectedDevicePath := "/dev/rbd1"
if runtime.GOOS == "windows" {
// Windows expects Disk Numbers.
expectedDevicePath = "1"
}
podUID := uuid.NewUUID()
var cases []*testcase
cases = append(cases, &testcase{
@ -396,7 +397,7 @@ func TestPlugin(t *testing.T) {
UID: podUID,
},
},
expectedDevicePath: "/dev/rbd1",
expectedDevicePath: expectedDevicePath,
expectedDeviceMountPath: filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts/pool1-image-image1"),
expectedPodMountPath: filepath.Join(tmpDir, "pods", string(podUID), "volumes/kubernetes.io~rbd/vol1"),
})
@ -425,7 +426,7 @@ func TestPlugin(t *testing.T) {
UID: podUID,
},
},
expectedDevicePath: "/dev/rbd1",
expectedDevicePath: expectedDevicePath,
expectedDeviceMountPath: filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts/pool2-image-image2"),
expectedPodMountPath: filepath.Join(tmpDir, "pods", string(podUID), "volumes/kubernetes.io~rbd/vol2"),
})

View File

@ -0,0 +1,37 @@
//go:build !windows
// +build !windows
/*
Copyright 2022 The Kubernetes Authors.
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 rbd
import (
"fmt"
)
func (fake *fakeDiskManager) AttachDisk(b rbdMounter) (string, error) {
fake.mutex.Lock()
defer fake.mutex.Unlock()
fake.rbdMapIndex++
devicePath := fmt.Sprintf("/dev/rbd%d", fake.rbdMapIndex)
fake.rbdDevices[devicePath] = true
return devicePath, nil
}
func getLoggedSource(devicePath string) (string, error) {
return devicePath, nil
}

View File

@ -0,0 +1,63 @@
//go:build windows
// +build windows
/*
Copyright 2022 The Kubernetes Authors.
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 rbd
import (
"fmt"
"os/exec"
"strconv"
"strings"
)
func (fake *fakeDiskManager) AttachDisk(b rbdMounter) (string, error) {
fake.mutex.Lock()
defer fake.mutex.Unlock()
fake.rbdMapIndex++
// Windows expects Disk Numbers.
volIds, err := listVolumesOnDisk(strconv.Itoa(fake.rbdMapIndex))
if err != nil {
return "", err
}
fake.rbdDevices[volIds[0]] = true
devicePath := strconv.Itoa(fake.rbdMapIndex)
return devicePath, nil
}
// listVolumesOnDisk - returns back list of volumes(volumeIDs) in the disk (requested in diskID) on Windows.
func listVolumesOnDisk(diskID string) (volumeIDs []string, err error) {
cmd := fmt.Sprintf("(Get-Disk -DeviceId %s | Get-Partition | Get-Volume).UniqueId", diskID)
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
if err != nil {
return []string{}, fmt.Errorf("error list volumes on disk. cmd: %s, output: %s, error: %v", cmd, string(output), err)
}
volumeIds := strings.Split(strings.TrimSpace(string(output)), "\r\n")
return volumeIds, nil
}
func getLoggedSource(devicePath string) (string, error) {
// Windows mounter is mounting based on the Disk's Unique ID.
volIds, err := listVolumesOnDisk(devicePath)
if err != nil {
return "", err
}
return volIds[0], nil
}

View File

@ -144,7 +144,7 @@ func TestGetNestedMountpoints(t *testing.T) {
name: "Big Pod",
err: false,
volname: "vol1",
expected: sets.NewString("sub1/sub2/sub3", "sub1/sub2/sub4", "sub1/sub2/sub6", "sub"),
expected: sets.NewString(filepath.Join("sub1", "sub2", "sub3"), filepath.Join("sub1", "sub2", "sub4"), filepath.Join("sub1", "sub2", "sub6"), "sub"),
pod: v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,