diff --git a/go.mod b/go.mod
index 144026f24..bafa6048d 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/harvester/harvester-installer
go 1.22.5
require (
+ github.com/dell/goiscsi v1.9.0
github.com/harvester/go-common v0.0.0-20230718010724-11313421a8f5
github.com/imdario/mergo v0.3.16
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac
@@ -71,4 +72,5 @@ replace (
k8s.io/api => k8s.io/api v0.24.10
k8s.io/apimachinery => k8s.io/apimachinery v0.24.10
k8s.io/client-go => k8s.io/client-go v0.24.10
+ k8s.io/kubelet => k8s.io/kubelet v0.24.10
)
diff --git a/go.sum b/go.sum
index c85528b12..0b5b0db8c 100644
--- a/go.sum
+++ b/go.sum
@@ -121,6 +121,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
+github.com/dell/goiscsi v1.9.0 h1:VvMHbAO4vk80oc/TAbQPYlxysscCqVBW78GyPoUxgik=
+github.com/dell/goiscsi v1.9.0/go.mod h1:NI/W/0O1UrMW2zVdMxy4z395Jn0r7utH6RQDFSZiFyQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/cli v20.10.20+incompatible h1:lWQbHSHUFs7KraSN2jOJK7zbMS2jNCHI4mt4xUFUVQ4=
diff --git a/package/harvester-os/files/etc/cos/bootargs.cfg b/package/harvester-os/files/etc/cos/bootargs.cfg
index 45e829f45..9a9a605ae 100644
--- a/package/harvester-os/files/etc/cos/bootargs.cfg
+++ b/package/harvester-os/files/etc/cos/bootargs.cfg
@@ -4,7 +4,7 @@ set crash_kernel_params="crashkernel=219M,high crashkernel=72M,low"
if [ "${img}" == "/cOS/recovery.img" ]; then
set kernelcmd="$console_params root=LABEL=$recovery_label cos-img/filename=$img rd.neednet=1 rd.cos.oemlabel=$oem_label rd.cos.mount=LABEL=$oem_label:/oem rd.cos.oemtimeout=120"
else
- set kernelcmd="$console_params root=LABEL=$state_label cos-img/filename=$img panic=0 net.ifnames=1 rd.cos.oemlabel=$oem_label rd.cos.mount=LABEL=$oem_label:/oem rd.cos.mount=LABEL=$persistent_label:/usr/local rd.cos.oemtimeout=120 audit=1 audit_backlog_limit=8192 intel_iommu=on amd_iommu=on iommu=pt"
+ set kernelcmd="$console_params root=LABEL=$state_label cos-img/filename=$img panic=0 net.ifnames=1 rd.cos.oemlabel=$oem_label rd.cos.mount=LABEL=$oem_label:/oem rd.cos.mount=LABEL=$persistent_label:/usr/local rd.cos.oemtimeout=120 audit=1 audit_backlog_limit=8192 intel_iommu=on amd_iommu=on iommu=pt $third_party_kernel_args"
fi
set initramfs=/boot/initrd
diff --git a/package/harvester-os/files/usr/sbin/harv-install b/package/harvester-os/files/usr/sbin/harv-install
index 705175ec9..e04e0158e 100755
--- a/package/harvester-os/files/usr/sbin/harv-install
+++ b/package/harvester-os/files/usr/sbin/harv-install
@@ -435,6 +435,14 @@ update_grub_settings()
if ! [ -f ${TARGET_FILE} ]; then
touch ${TARGET_FILE}
fi
+ # /etc/cos/bootargs.cfg appends a new variable $third_party_kernel_args
+ # if harvester config has os.externalStorageConfig.additionalKernelArguments specified
+ # then these will be mapped to HARVESTER_ADDITIONAL_KERNEL_ARGUMENTS
+ # and will be added to /oem/grubenv file
+ TARGET_FILE="${oem_dir}/grubenv"
+ if [ -n "${HARVESTER_ADDITIONAL_KERNEL_ARGUMENTS}" ]; then
+ grub2-editenv ${TARGET_FILE} set third_party_kernel_args="${HARVESTER_ADDITIONAL_KERNEL_ARGUMENTS}"
+ fi
add_debug_grub_entry
}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 2bb16b3ad..1086ac99d 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -204,7 +204,19 @@ type OS struct {
Labels map[string]string `json:"labels,omitempty"`
SSHD SSHDConfig `json:"sshd,omitempty"`
- PersistentStatePaths []string `json:"persistentStatePaths,omitempty"`
+ PersistentStatePaths []string `json:"persistentStatePaths,omitempty"`
+ ExternalStorage ExternalStorageConfig `json:"externalStorageConfig,omitempty"`
+ AdditionalKernelArguments string `json:"additionalKernelArguments,omitempty"`
+}
+
+type ExternalStorageConfig struct {
+ Enabled bool `json:"enabled,omitempty"`
+ MultiPathConfig []DiskConfig `json:"multiPathConfig,omitempty"`
+}
+
+type DiskConfig struct {
+ Vendor string `json:"vendor"`
+ Product string `json:"product"`
}
// SSHDConfig is the SSHD configuration for the node
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index e9c4ffa4d..2ed1e3833 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)
@@ -539,3 +540,48 @@ func TestCalculateCPUReservedInMilliCPU(t *testing.T) {
assert.Equal(t, tc.reservedMilliCores, calculateCPUReservedInMilliCPU(tc.coreNum, tc.maxPods))
}
}
+func Test_MultipathConfig(t *testing.T) {
+ assert := require.New(t)
+ config := NewHarvesterConfig()
+ config.OS.ExternalStorage = ExternalStorageConfig{
+ Enabled: true,
+ MultiPathConfig: []DiskConfig{
+ {
+ Vendor: "DELL",
+ Product: "DISK1",
+ },
+ {
+ Vendor: "HPE",
+ Product: "DISK2",
+ },
+ },
+ }
+
+ content, err := render("multipath.conf.tmpl", config)
+ assert.NoError(err, "expected no error while rending multipath config")
+ t.Log("rendered multipath config:")
+ t.Log(content)
+}
+
+func Test_ToCosInstallEnv(t *testing.T) {
+ hvConfig := NewHarvesterConfig()
+ hvConfig.OS.ExternalStorage = ExternalStorageConfig{
+ Enabled: true,
+ MultiPathConfig: []DiskConfig{
+ {
+ Vendor: "DELL",
+ Product: "DISK1",
+ },
+ {
+ Vendor: "HPE",
+ Product: "DISK2",
+ },
+ },
+ }
+ hvConfig.OS.AdditionalKernelArguments = "rd.iscsi.firmware rd.iscsi.ibft"
+ assert := require.New(t)
+ env, err := hvConfig.ToCosInstallEnv()
+ assert.NoError(err)
+ t.Log(env)
+
+}
diff --git a/pkg/config/cos.go b/pkg/config/cos.go
index ea1c0466e..4b1a1b948 100644
--- a/pkg/config/cos.go
+++ b/pkg/config/cos.go
@@ -175,6 +175,11 @@ func ConvertToCOS(config *HarvesterConfig) (*yipSchema.YipConfig, error) {
})
}
+ // enable multipathd for external storage support
+ if err := setupExternalStorage(config, &initramfs); err != nil {
+ return nil, err
+ }
+
// TOP
if cfg.Mode != ModeInstall {
if err := initRancherdStage(config, &initramfs); err != nil {
@@ -840,3 +845,24 @@ func CreateRootPartitioningLayout(elementalConfig *ElementalConfig, hvstConfig *
return elementalConfig, nil
}
+
+// setupExternalStorage is needed to support boot of external disks
+// this involves enable multipath service and configuring it to blacklist
+// all devices except the ones listed in the config.OS.ExternalStorage.MultiPathConfig
+
+func setupExternalStorage(config *HarvesterConfig, stage *yipSchema.Stage) error {
+ if !config.OS.ExternalStorage.Enabled {
+ return nil
+ }
+ stage.Systemctl.Enable = append(stage.Systemctl.Enable, "multipathd")
+ content, err := render("multipath.conf.tmpl", config)
+ if err != nil {
+ return fmt.Errorf("error rending multipath.conf template: %v", err)
+ }
+ stage.Files = append(stage.Files, yipSchema.File{
+ Path: "/etc/multipath.conf",
+ Content: content,
+ Permissions: 0755,
+ })
+ return nil
+}
diff --git a/pkg/config/templates/multipath.conf.tmpl b/pkg/config/templates/multipath.conf.tmpl
new file mode 100644
index 000000000..fc7b40c71
--- /dev/null
+++ b/pkg/config/templates/multipath.conf.tmpl
@@ -0,0 +1,8 @@
+blacklist {
+{{ range $val := .ExternalStorage.MultiPathConfig }}
+ device {
+ vendor "!{{ $val.Vendor }}"
+ product "!{{ $val.Product }}"
+ }
+{{ end }}
+}
\ No newline at end of file
diff --git a/pkg/console/install_panels.go b/pkg/console/install_panels.go
index efa11dd70..57100635b 100644
--- a/pkg/console/install_panels.go
+++ b/pkg/console/install_panels.go
@@ -289,11 +289,13 @@ func getDataDiskOptions(hvstConfig *config.HarvesterConfig) ([]widgets.Option, e
}
func getDiskOptions() ([]widgets.Option, error) {
- output, err := exec.Command("/bin/sh", "-c", `lsblk -r -o NAME,SIZE,TYPE | grep -w disk | cut -d ' ' -f 1,2`).CombinedOutput()
+ output, err := exec.Command("/bin/sh", "-c", `lsblk -J -o NAME,SIZE,TYPE,WWN,SERIAL`).CombinedOutput()
if err != nil {
return nil, err
}
- lines := strings.Split(strings.TrimSuffix(string(output), "\n"), "\n")
+
+ lines, err := identifyUniqueDisks(output)
+
var options []widgets.Option
for _, line := range lines {
splits := strings.SplitN(line, " ", 2)
diff --git a/pkg/console/network.go b/pkg/console/network.go
index 7e1888e5a..68bf2090e 100644
--- a/pkg/console/network.go
+++ b/pkg/console/network.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
+ "net"
"os"
"os/exec"
"syscall"
@@ -14,6 +15,8 @@ import (
"golang.org/x/sys/unix"
"gopkg.in/yaml.v3"
+ "github.com/dell/goiscsi"
+
"github.com/harvester/harvester-installer/pkg/config"
)
@@ -137,7 +140,7 @@ func getNICs() ([]netlink.Link, error) {
}
}
- return nics, nil
+ return filterISCSIInterfaces(nics)
}
func getNICState(name string) int {
@@ -190,3 +193,47 @@ func getManagementInterfaceName(mgmtInterface config.Network) string {
}
return mgmtName
}
+
+// filterISCSIInterfaces will query the host to identify iscsi sessions, and skip interfaces
+// used by the existing iscsi session.
+func filterISCSIInterfaces(links []netlink.Link) ([]netlink.Link, error) {
+ iscsi := goiscsi.NewLinuxISCSI(nil)
+ sessions, err := iscsi.GetSessions()
+ if err != nil {
+ return nil, fmt.Errorf("error querying iscsi sessions: %v", err)
+ }
+
+ var returnLinks []netlink.Link
+ for _, link := range links {
+ var inuse bool
+ if getNICState(link.Attrs().Name) == NICStateUP {
+ iface, err := net.InterfaceByName(link.Attrs().Name)
+ if err != nil {
+ return nil, fmt.Errorf("error fetching interface details: %v", err)
+ }
+
+ addresses, err := iface.Addrs()
+ if err != nil {
+ return nil, fmt.Errorf("error fetching addresses from interface: %v", err)
+ }
+
+ for _, address := range addresses {
+ // interface addresses are in cidr format, and need to be converted before comparison
+ // since iscsi session contains just the ip address
+ ipAddress, _, err := net.ParseCIDR(address.String())
+ if err != nil {
+ return nil, fmt.Errorf("error parsing ip address: %v", err)
+ }
+ for _, session := range sessions {
+ if session.IfaceIPaddress == ipAddress.String() {
+ inuse = true
+ }
+ }
+ }
+ }
+ if !inuse {
+ returnLinks = append(returnLinks, link)
+ }
+ }
+ return returnLinks, nil
+}
diff --git a/pkg/console/util.go b/pkg/console/util.go
index 789d0c9cf..a00937553 100644
--- a/pkg/console/util.go
+++ b/pkg/console/util.go
@@ -504,6 +504,10 @@ func doInstall(g *gocui.Gui, hvstConfig *config.HarvesterConfig, webhooks Render
env = append(env, fmt.Sprintf("HARVESTER_DATA_DISK=%s", hvstConfig.DataDisk))
}
+ if hvstConfig.OS.AdditionalKernelArguments != "" {
+ env = append(env, fmt.Sprintf("HARVESTER_ADDITIONAL_KERNEL_ARGUMENTS=%s", hvstConfig.OS.AdditionalKernelArguments))
+ }
+
elementalConfigDir, elementalConfigFile, err := saveElementalConfig(elementalConfig)
if err != nil {
return nil
@@ -982,3 +986,78 @@ func generateEnvAndConfig(g *gocui.Gui, hvstConfig *config.HarvesterConfig) ([]s
env = append(env, fmt.Sprintf("HARVESTER_STREAMDISK_CLOUDINIT_URL=%s", userDataURL))
return env, elementalConfig, nil
}
+
+// internal objects to parse lsblk output
+type BlockDevices struct {
+ Disks []Device `json:"blockdevices"`
+}
+
+type Device struct {
+ Name string `json:"name"`
+ Size string `json:"size"`
+ DiskType string `json:"type"`
+ WWN string `json:"wwn,omitempty"`
+ Serial string `json:"serial,omitempty"`
+ Children []Device `json:"children,omitempty"`
+}
+
+func generateDiskEntry(d Device) string {
+ return fmt.Sprintf("%s %s", d.Name, d.Size)
+}
+
+const (
+ diskType = "disk"
+)
+
+// identifyUniqueDisks parses the json output of lsblk and identifies
+// unique disks by comparing their serial number info and wwn details
+func identifyUniqueDisks(output []byte) ([]string, error) {
+ var returnDisks []string
+ disks := &BlockDevices{}
+ err := json.Unmarshal(output, disks)
+ if err != nil {
+ return nil, fmt.Errorf("error unmarshalling lsblk json output: %v", err)
+ }
+
+ // identify devices which may be unique
+ dedupMap := make(map[string]Device)
+ for _, disk := range disks.Disks {
+ if disk.DiskType == diskType {
+ // no serial or wwn info present
+ // add to list of disks
+ if disk.WWN == "" && disk.Serial == "" {
+ returnDisks = append(returnDisks, generateDiskEntry(disk))
+ continue
+ }
+
+ if disk.Serial != "" {
+ _, ok := dedupMap[disk.Serial]
+ if !ok {
+ dedupMap[disk.Serial] = disk
+ }
+ continue
+ }
+
+ if disk.WWN != "" {
+ _, ok := dedupMap[disk.WWN]
+ if !ok {
+ dedupMap[disk.WWN] = disk
+ }
+ continue
+ }
+ }
+ }
+ // devices may appear twice in the map when both serial number and wwn info is present
+ // we need to ensure only unique names are shown in the console
+ resultMap := make(map[string]Device)
+ for _, v := range dedupMap {
+ resultMap[v.Name] = v
+ }
+
+ // generate list of disks
+ for _, v := range resultMap {
+ returnDisks = append(returnDisks, generateDiskEntry(v))
+ }
+
+ return returnDisks, nil
+}
diff --git a/pkg/console/util_test.go b/pkg/console/util_test.go
index b212c5039..443611879 100644
--- a/pkg/console/util_test.go
+++ b/pkg/console/util_test.go
@@ -9,6 +9,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"github.com/harvester/harvester-installer/pkg/util"
)
@@ -231,3 +232,380 @@ func startMockNTPServers(quit chan interface{}) ([]string, error) {
}
return ntpServers, nil
}
+
+const (
+ sampleSerialDiskOutput = `
+{
+ "blockdevices": [
+ {
+ "name": "loop0",
+ "size": "768.1M",
+ "type": "loop",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda",
+ "size": "250G",
+ "type": "disk",
+ "wwn": null,
+ "serial": "serial-1",
+ "children": [
+ {
+ "name": "0QEMU_QEMU_HARDDISK_serial-1",
+ "size": "250G",
+ "type": "mpath",
+ "wwn": null,
+ "serial": null
+ }
+ ]
+ },{
+ "name": "sdb",
+ "size": "250G",
+ "type": "disk",
+ "wwn": null,
+ "serial": "serial-1",
+ "children": [
+ {
+ "name": "0QEMU_QEMU_HARDDISK_serial-1",
+ "size": "250G",
+ "type": "mpath",
+ "wwn": null,
+ "serial": null
+ }
+ ]
+ },{
+ "name": "sr0",
+ "size": "5.8G",
+ "type": "rom",
+ "wwn": null,
+ "serial": "QM00001"
+ }
+ ]
+}
+`
+
+ reinstallDisks = `
+{
+ "blockdevices": [
+ {
+ "name": "loop0",
+ "size": "3G",
+ "type": "loop",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "loop1",
+ "size": "10G",
+ "type": "loop",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda",
+ "size": "10G",
+ "type": "disk",
+ "wwn": "0x60000000000000000e00000000010001",
+ "serial": "beaf11",
+ "children": [
+ {
+ "name": "sda1",
+ "size": "2.5G",
+ "type": "part",
+ "wwn": "0x60000000000000000e00000000010001",
+ "serial": null
+ },{
+ "name": "sda14",
+ "size": "4M",
+ "type": "part",
+ "wwn": "0x60000000000000000e00000000010001",
+ "serial": null
+ },{
+ "name": "sda15",
+ "size": "106M",
+ "type": "part",
+ "wwn": "0x60000000000000000e00000000010001",
+ "serial": null
+ },{
+ "name": "sda16",
+ "size": "913M",
+ "type": "part",
+ "wwn": "0x60000000000000000e00000000010001",
+ "serial": null
+ }
+ ]
+ },{
+ "name": "sr0",
+ "size": "364K",
+ "type": "rom",
+ "wwn": null,
+ "serial": "QM00001"
+ },{
+ "name": "vda",
+ "size": "250G",
+ "type": "disk",
+ "wwn": null,
+ "serial": null,
+ "children": [
+ {
+ "name": "vda1",
+ "size": "1M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "vda2",
+ "size": "50M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "vda3",
+ "size": "8G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "vda4",
+ "size": "15G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "vda5",
+ "size": "150G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "vda6",
+ "size": "76.9G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ }
+ ]
+ }
+ ]
+}
+`
+
+ preInstalledMultiPath = `
+{
+ "blockdevices": [
+ {
+ "name": "loop0",
+ "size": "768.4M",
+ "type": "loop",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda",
+ "size": "250G",
+ "type": "disk",
+ "wwn": null,
+ "serial": "disk1",
+ "children": [
+ {
+ "name": "sda1",
+ "size": "1M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda2",
+ "size": "50M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda3",
+ "size": "8G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda4",
+ "size": "15G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda5",
+ "size": "150G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sda6",
+ "size": "76.9G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1",
+ "size": "250G",
+ "type": "mpath",
+ "wwn": null,
+ "serial": null,
+ "children": [
+ {
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part1",
+ "size": "1M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part2",
+ "size": "50M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part3",
+ "size": "8G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part4",
+ "size": "15G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part5",
+ "size": "150G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part6",
+ "size": "76.9G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ }
+ ]
+ }
+ ]
+ },{
+ "name": "sdb",
+ "size": "250G",
+ "type": "disk",
+ "wwn": null,
+ "serial": "disk1",
+ "children": [
+ {
+ "name": "sdb1",
+ "size": "1M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sdb2",
+ "size": "50M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sdb3",
+ "size": "8G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sdb4",
+ "size": "15G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sdb5",
+ "size": "150G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "sdb6",
+ "size": "76.9G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1",
+ "size": "250G",
+ "type": "mpath",
+ "wwn": null,
+ "serial": null,
+ "children": [
+ {
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part1",
+ "size": "1M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part2",
+ "size": "50M",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part3",
+ "size": "8G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part4",
+ "size": "15G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part5",
+ "size": "150G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ },{
+ "name": "0QEMU_QEMU_HARDDISK_disk1-part6",
+ "size": "76.9G",
+ "type": "part",
+ "wwn": null,
+ "serial": null
+ }
+ ]
+ }
+ ]
+ },{
+ "name": "sr0",
+ "size": "5.8G",
+ "type": "rom",
+ "wwn": null,
+ "serial": "QM00001"
+ }
+ ]
+}
+`
+)
+
+func Test_identifyUniqueDisksWithSerialNumber(t *testing.T) {
+ assert := require.New(t)
+ result, err := identifyUniqueDisks([]byte(sampleSerialDiskOutput))
+ assert.NoError(err, "expected no error while parsing disk data")
+ assert.Len(result, 1, "expected to find 1 disk only")
+}
+
+func Test_identifyUniqueDisksWithExistingData(t *testing.T) {
+ assert := require.New(t)
+ result, err := identifyUniqueDisks([]byte(reinstallDisks))
+ assert.NoError(err, "expected no error while parsing disk data")
+ assert.Len(result, 2, "expected to find 2 disks only")
+}
+
+func Test_identifyUniqueDisksOnExistingInstalls(t *testing.T) {
+ assert := require.New(t)
+ result, err := identifyUniqueDisks([]byte(preInstalledMultiPath))
+ assert.NoError(err, "expected no error while parsing disk data")
+ assert.Len(result, 1, "expected to find 1 disk only")
+}
diff --git a/vendor/github.com/dell/goiscsi/.gitignore b/vendor/github.com/dell/goiscsi/.gitignore
new file mode 100644
index 000000000..e0a065ca3
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/.gitignore
@@ -0,0 +1,3 @@
+c.out
+.idea
+.vscode
diff --git a/vendor/github.com/dell/goiscsi/.golangci.yaml b/vendor/github.com/dell/goiscsi/.golangci.yaml
new file mode 100644
index 000000000..56f533245
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/.golangci.yaml
@@ -0,0 +1,30 @@
+run:
+ timeout: 20m
+ issue-exit-code: 0 # we will change this later
+ tests: true
+ skip-dirs-use-default: true
+ modules-download-mode: readonly
+
+issues:
+ max-issues-per-linter: 0
+ max-same-issues: 0
+ new: false
+
+output:
+ print-linter-name: true
+ sort-results: true
+ uniq-by-line: false
+ print-issued-lines: true
+
+linters:
+ disable-all: true
+ fast: false
+ enable:
+ # A stricter replacement for gofmt.
+ - gofumpt
+ # Inspects source code for security problems.
+ - gosec
+ # Check for correctness of programs.
+ - govet
+ # Drop-in replacement of golint.
+ - revive
diff --git a/vendor/github.com/dell/goiscsi/LICENSE b/vendor/github.com/dell/goiscsi/LICENSE
new file mode 100644
index 000000000..23636b946
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright © 2019 Dell Inc. or its subsidiaries. All Rights Reserved.
+
+ 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.
diff --git a/vendor/github.com/dell/goiscsi/Makefile b/vendor/github.com/dell/goiscsi/Makefile
new file mode 100644
index 000000000..baa8fab96
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+#
+# 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.
+#
+#
+# These values should be set for running the entire test suite
+# all must be valid
+Portal="1.1.1.1"
+Target="iqn.1992-04.com.emc:600009700bcbb70e3287017400000000"
+
+
+all:check int-test
+
+mock-test:
+ go clean -cache
+ go test -v -coverprofile=c.out --run=TestMock
+
+int-test:
+ GOISCSI_PORTAL=$(Portal) GOISCSI_TARGET=$(Target) \
+ go test -v -timeout 20m -coverprofile=c.out -coverpkg ./...
+
+gocover:
+ go tool cover -html=c.out
+
+check:
+ gofmt -d .
+ golint -set_exit_status
+ go vet
diff --git a/vendor/github.com/dell/goiscsi/README.md b/vendor/github.com/dell/goiscsi/README.md
new file mode 100644
index 000000000..2c7d37b1a
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/README.md
@@ -0,0 +1,114 @@
+# goiscsi
+A portable Go module for iscsi related operations such as discovery and login
+
+## Features
+The following features are supported:
+* Discover iSCSI targets provided by a specific portal, optionally log into each target
+* Discover the iSCSI Initiators defined on the local system
+* Log into a specific portal/target
+* Log out of a specific portal/target
+* Rescan all connected iSCSI sessions
+
+## Implementation options
+Two implementations of the `goiscsi.ISCSIinterface` exist; one is for Linux based systems and one is a mock
+implementation. When instantiating an implementation of the `goiscsi.ISCSIinterface` interface, the factories
+accept a `map[string]string` option that allows the user to set specific key/values within the implementation.
+
+The `goiscsi.ISCSIinterface` is defined as:
+```go
+type ISCSIinterface interface {
+ // Discover the targets exposed via a given portal
+ // returns an array of ISCSITarget instances
+ DiscoverTargets(address string, login bool) ([]ISCSITarget, error)
+
+ // Get a list of iSCSI initiators defined in a specified file
+ // To use the system default file of "/etc/iscsi/initiatorname.iscsi", provide a filename of ""
+ GetInitiators(filename string) ([]string, error)
+
+ // Log into a specified target
+ PerformLogin(target ISCSITarget) error
+
+ // Log out of a specified target
+ PerformLogout(target ISCSITarget) error
+
+ // Rescan current iSCSI sessions
+ PerformRescan() error
+
+ // generic implementations
+ isMock() bool
+ getOptions() map[string]string
+}
+```
+
+Many operations deal with iSCSI Targets via a type of `goiscsi.ISCSITarget`, defined as:
+```go
+type ISCSITarget struct {
+ Portal string
+ GroupTag string
+ Target string
+}
+```
+
+#### LinuxISCSI
+When instantiating a Linux implementation via `goiscsi.NewLinuxISCSI` the following options are available
+
+| Key | Meaning |
+|--------------------|-----------------------------------------------------------------------------------------|
+| chrootDirectory | Run `iscsiadm` in a chrooted environment with the root set to this value. |
+| | Default is to not chroot |
+
+#### MockISCSI
+When instantiating a mock implementation via `goiscsi.NewMockISCSI`, the follwoing options are available:
+
+| Key | Meaning |
+|--------------------|-----------------------------------------------------------------------------------------------------------|
+| numberOfInitiators | Defines the number of initiators that will be returned via the `GetInitiators` method.
Default is "1" |
+| numberOfTargets | Defines the number of targets that will be returned via the `DiscoverTargets` method.
Default is "1" |
+
+## Usage examples
+The following example will instantiate a Linux based iSCSI client and Discover the targets exposed via the portal at `address`
+
+```go
+import (
+ "errors"
+
+ "github.com/dell/goiscsi"
+)
+
+func printTargets(address string) {
+ var c goiscsi.ISCSIinterface
+ c := goiscsi.NewLinuxISCSI(map[string]string{})
+ targets, err := c.DiscoverTargets(address, false)
+ if err != nil {
+ return
+ }
+ for _, t := range targets {
+ fmt.Printf("Found target: %s", tgt.Target)
+ }
+}
+```
+
+The following example will instantiate a Mock iSCSI client, set the number of targets to 3, and Discover the mocked targets
+
+```go
+import (
+ "errors"
+
+ "github.com/dell/goiscsi"
+)
+
+func printTargets(address string) {
+ var c goiscsi.ISCSIinterface
+ opts := make(map[string]string, 0)
+ opts[goiscsi.MockNumberOfTargets] = "3"
+ c := goiscsi.NewMockISCSI(opts)
+ targets, err := c.DiscoverTargets(address, false)
+ if err != nil {
+ return
+ }
+ for _, t := range targets {
+ fmt.Printf("Found target: %s", tgt.Target)
+ }
+}
+```
+
diff --git a/vendor/github.com/dell/goiscsi/goiscsi.go b/vendor/github.com/dell/goiscsi/goiscsi.go
new file mode 100644
index 000000000..c5e782831
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/goiscsi.go
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+ *
+ * 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 goiscsi
+
+import (
+ "errors"
+)
+
+// ISCSIinterface is the interface that provides the iSCSI client functionality
+type ISCSIinterface interface {
+ // Discover the targets exposed via a given portal
+ // returns an array of ISCSITarget instances
+ DiscoverTargets(address string, login bool) ([]ISCSITarget, error)
+
+ // Get a list of iSCSI initiators defined in a specified file
+ // To use the system default file of "/etc/iscsi/initiatorname.iscsi", provide a filename of ""
+ GetInitiators(filename string) ([]string, error)
+
+ // Log into a specified target
+ PerformLogin(target ISCSITarget) error
+
+ // Log out of a specified target
+ PerformLogout(target ISCSITarget) error
+
+ // Rescan current iSCSI sessions
+ PerformRescan() error
+
+ // Query information about sessions
+ GetSessions() ([]ISCSISession, error)
+
+ // Query information about nodes
+ GetNodes() ([]ISCSINode, error)
+
+ // Set CHAP credentials for a target (creates/updates node database)
+ SetCHAPCredentials(target ISCSITarget, username, password string) error
+
+ // CreateOrUpdateNode creates new or update existing iSCSI node in iscsid database
+ CreateOrUpdateNode(target ISCSITarget, options map[string]string) error
+
+ // DeleteNode delete iSCSI node from iscsid database
+ DeleteNode(target ISCSITarget) error
+
+ // generic implementations
+ isMock() bool
+ getOptions() map[string]string
+}
+
+// ISCSIType is the base structre for each platform implementation
+type ISCSIType struct {
+ mock bool
+ options map[string]string
+}
+
+var (
+ // ErrIscsiNotInstalled is returned when the iscsi utilities are not
+ // found on a system
+ ErrIscsiNotInstalled = errors.New("iSCSI utilities are not installed")
+ // ErrNotImplemented is returned when a platform does not implement
+ ErrNotImplemented = errors.New("not implemented")
+)
+
+func (i *ISCSIType) isMock() bool {
+ return i.mock
+}
+
+func (i *ISCSIType) getOptions() map[string]string {
+ return i.options
+}
diff --git a/vendor/github.com/dell/goiscsi/goiscsi_iscsi.go b/vendor/github.com/dell/goiscsi/goiscsi_iscsi.go
new file mode 100644
index 000000000..a8d23eda7
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/goiscsi_iscsi.go
@@ -0,0 +1,422 @@
+/*
+ *
+ * Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+ *
+ * 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 goiscsi
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "syscall"
+ "time"
+)
+
+const (
+ // ChrootDirectory allows the iscsiadm commands to be run within a chrooted path, helpful for containerized services
+ ChrootDirectory = "chrootDirectory"
+ // DefaultInitiatorNameFile is the default file which contains the initiator names
+ DefaultInitiatorNameFile = "/etc/iscsi/initiatorname.iscsi"
+
+ // ISCSINoObjsFoundExitCode exit code indicates that no records/targets/sessions/portals
+ // found to execute operation on
+ iSCSINoObjsFoundExitCode = 21
+ // Timeout for iscsiadm command to execute
+ Timeout = 30
+)
+
+// LinuxISCSI provides many iSCSI-specific functions.
+type LinuxISCSI struct {
+ ISCSIType
+ sessionParser iSCSISessionParser
+ nodeParser iSCSINodeParser
+}
+
+// NewLinuxISCSI returns an LinuxISCSI client
+func NewLinuxISCSI(opts map[string]string) *LinuxISCSI {
+ iscsi := LinuxISCSI{
+ ISCSIType: ISCSIType{
+ mock: false,
+ options: opts,
+ },
+ }
+ iscsi.sessionParser = &sessionParser{}
+ iscsi.nodeParser = &nodeParser{}
+
+ return &iscsi
+}
+
+func (iscsi *LinuxISCSI) getChrootDirectory() string {
+ s := iscsi.options[ChrootDirectory]
+ if s == "" {
+ s = "/"
+ }
+ return s
+}
+
+func (iscsi *LinuxISCSI) buildISCSICommand(cmd []string) []string {
+ if iscsi.getChrootDirectory() == "/" {
+ return cmd
+ }
+ command := []string{"chroot", iscsi.getChrootDirectory()}
+ command = append(command, cmd...)
+ return command
+}
+
+// DiscoverTargets runs an iSCSI discovery and returns a list of targets.
+func (iscsi *LinuxISCSI) DiscoverTargets(address string, login bool) ([]ISCSITarget, error) {
+ return iscsi.discoverTargets(address, login)
+}
+
+func (iscsi *LinuxISCSI) discoverTargets(address string, login bool) ([]ISCSITarget, error) {
+ // iSCSI discovery is done via the iscsiadm cli
+ // iscsiadm -m discovery -t st --portal
+
+ // validate for valid address
+ err := validateIPAddress(address)
+ if err != nil {
+ fmt.Printf("\nError invalid address %s: %v", address, err)
+ return []ISCSITarget{}, err
+ }
+ exe := iscsi.buildISCSICommand([]string{"iscsiadm", "-m", "discovery", "-t", "st", "--portal", address})
+ ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Timeout)*time.Second)
+ defer cancel()
+
+ cmd := exec.CommandContext(ctx, exe[0], exe[1:]...) // #nosec G204
+
+ out, err := cmd.Output()
+ if err != nil {
+ fmt.Printf("\nError discovering %s: %v", address, err)
+ return []ISCSITarget{}, err
+ }
+
+ targets := make([]ISCSITarget, 0)
+
+ for _, line := range strings.Split(string(out), "\n") {
+ // one line of the output should look like:
+ // 1.1.1.1:3260,0 iqn.1992-04.com.emc:600009700bcbb70e3287017400000001
+ // Portal,GroupTag Target
+ tokens := strings.Split(line, " ")
+ // make sure we got two tokens
+ if len(tokens) == 2 {
+ addrtag := strings.Split(line, " ")[0]
+ tgt := strings.Split(line, " ")[1]
+ targets = append(targets,
+ ISCSITarget{
+ Portal: strings.Split(addrtag, ",")[0],
+ GroupTag: strings.Split(addrtag, ",")[1],
+ Target: tgt,
+ })
+ }
+ }
+ // log into the target if asked
+ if login {
+ for _, t := range targets {
+ _ = iscsi.PerformLogin(t)
+ }
+ }
+
+ return targets, nil
+}
+
+// GetInitiators returns a list of initiators on the local system.
+func (iscsi *LinuxISCSI) GetInitiators(filename string) ([]string, error) {
+ return iscsi.getInitiators(filename)
+}
+
+func (iscsi *LinuxISCSI) getInitiators(filename string) ([]string, error) {
+ // a slice of filename, which might exist and define the iSCSI initiators
+ initiatorConfig := []string{}
+ iqns := []string{}
+
+ if filename == "" {
+ // add default filename(s) here
+ // /etc/iscsi/initiatorname.iscsi is the proper file for CentOS, RedHat, Debian, Ubuntu
+ if iscsi.getChrootDirectory() != "/" {
+ initiatorConfig = append(initiatorConfig, iscsi.getChrootDirectory()+"/"+DefaultInitiatorNameFile)
+ } else {
+ initiatorConfig = append(initiatorConfig, DefaultInitiatorNameFile)
+ }
+ } else {
+ initiatorConfig = append(initiatorConfig, filename)
+ }
+
+ // for each initiatior config file
+ for _, init := range initiatorConfig {
+ // make sure the file exists
+ _, err := os.Stat(init)
+ if err != nil {
+ return []string{}, err
+ }
+
+ // get the contents of the initiator config file
+ cmd, err := os.ReadFile(filepath.Clean(init))
+ if err != nil {
+ fmt.Printf("Error gathering initiator names: %v", err)
+ return nil, err
+ }
+ lines := strings.Split(string(cmd), "\n")
+ for _, l := range lines {
+ // remove all whitespace to catch different formatting
+ l = strings.Join(strings.Fields(l), "")
+ if strings.HasPrefix(l, "InitiatorName=") {
+ iqns = append(iqns, strings.Split(l, "=")[1])
+ }
+ }
+ }
+
+ return iqns, nil
+}
+
+// PerformLogin will attempt to log into an iSCSI target
+func (iscsi *LinuxISCSI) PerformLogin(target ISCSITarget) error {
+ return iscsi.performLogin(target)
+}
+
+func (iscsi *LinuxISCSI) performLogin(target ISCSITarget) error {
+ // iSCSI login is done via the iscsiadm cli
+ // iscsiadm -m node -T --portal -l
+
+ err := validateIPAddress(target.Portal)
+ if err != nil {
+ fmt.Printf("\nError invalid portal address %s: %v", target.Portal, err)
+ return err
+ }
+
+ err = validateIQN(target.Target)
+ if err != nil {
+ fmt.Printf("\nError invalid IQN Target %s: %v", target.Target, err)
+ return err
+ }
+
+ exe := iscsi.buildISCSICommand([]string{"iscsiadm", "-m", "node", "-T", target.Target, "--portal", target.Portal, "-l"})
+ ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Timeout)*time.Second)
+ defer cancel()
+
+ cmd := exec.CommandContext(ctx, exe[0], exe[1:]...) // #nosec G204
+
+ _, err = cmd.Output()
+ if err != nil {
+ if exiterr, ok := err.(*exec.ExitError); ok {
+ // iscsiadm exited with an exit code != 0
+ iscsiResult := -1
+ if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
+ iscsiResult = status.ExitStatus()
+ }
+ if iscsiResult == 15 {
+ // session already exists
+ // do not treat this as a failure
+ err = nil
+ } else {
+ fmt.Printf("\niscsiadm login failure: %v", err)
+ }
+ } else {
+ fmt.Printf("\nError logging %s at %s: %v", target.Target, target.Portal, err)
+ }
+
+ if err != nil {
+ fmt.Printf("\nError logging %s at %s: %v", target.Target, target.Portal, err)
+ return err
+ }
+ }
+
+ return nil
+}
+
+// PerformLogout will attempt to log out of an iSCSI target
+func (iscsi *LinuxISCSI) PerformLogout(target ISCSITarget) error {
+ return iscsi.performLogout(target)
+}
+
+func (iscsi *LinuxISCSI) performLogout(target ISCSITarget) error {
+ // iSCSI login is done via the iscsiadm cli
+ // iscsiadm -m node -T --portal -l
+ err := validateIPAddress(target.Portal)
+ if err != nil {
+ fmt.Printf("\nError invalid portal address %s: %v", target.Portal, err)
+ return err
+ }
+
+ err = validateIQN(target.Target)
+ if err != nil {
+ fmt.Printf("\nError invalid IQN Target %s: %v", target.Target, err)
+ return err
+ }
+
+ exe := iscsi.buildISCSICommand([]string{"iscsiadm", "-m", "node", "-T", target.Target, "--portal", target.Portal, "--logout"})
+ cmd := exec.Command(exe[0], exe[1:]...) // #nosec G204
+
+ _, err = cmd.Output()
+ if err != nil {
+ if exiterr, ok := err.(*exec.ExitError); ok {
+ // iscsiadm exited with an exit code != 0
+ iscsiResult := -1
+ if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
+ iscsiResult = status.ExitStatus()
+ }
+ if iscsiResult == 15 {
+ // session already exists
+ // do not treat this as a failure
+ err = nil
+ } else {
+ fmt.Printf("iscsiadm login failure: %v", err)
+ }
+ } else {
+ fmt.Printf("Error logging %s at %s: %v", target.Target, target.Portal, err)
+ }
+
+ if err != nil {
+ fmt.Printf("Error logging %s at %s: %v", target.Target, target.Portal, err)
+ return err
+ }
+ }
+
+ return nil
+}
+
+// PerformRescan will rescan targets known to current sessions
+func (iscsi *LinuxISCSI) PerformRescan() error {
+ return iscsi.performRescan()
+}
+
+func (iscsi *LinuxISCSI) performRescan() error {
+ exe := iscsi.buildISCSICommand([]string{"iscsiadm", "-m", "node", "--rescan"})
+ cmd := exec.Command(exe[0], exe[1:]...) // #nosec G204
+
+ _, err := cmd.Output()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// GetSessions will query information about sessions
+func (iscsi *LinuxISCSI) GetSessions() ([]ISCSISession, error) {
+ exe := iscsi.buildISCSICommand([]string{"iscsiadm", "-m", "session", "-P", "2", "-S"})
+ cmd := exec.Command(exe[0], exe[1:]...) // #nosec G204
+ output, err := cmd.Output()
+ if err != nil {
+ if isNoObjsExitCode(err) {
+ return []ISCSISession{}, nil
+ }
+ return []ISCSISession{}, err
+ }
+ return iscsi.sessionParser.Parse(output), nil
+}
+
+// GetNodes will query information about nodes
+func (iscsi *LinuxISCSI) GetNodes() ([]ISCSINode, error) {
+ exe := iscsi.buildISCSICommand([]string{"iscsiadm", "-m", "node", "-o", "show"})
+ cmd := exec.Command(exe[0], exe[1:]...) // #nosec G204
+ output, err := cmd.Output()
+ if err != nil {
+ if isNoObjsExitCode(err) {
+ return []ISCSINode{}, nil
+ }
+ return []ISCSINode{}, err
+ }
+ return iscsi.nodeParser.Parse(output), nil
+}
+
+// SetCHAPCredentials will set CHAP credentials
+func (iscsi *LinuxISCSI) SetCHAPCredentials(target ISCSITarget, username, password string) error {
+ options := make(map[string]string)
+ options["node.session.auth.authmethod"] = "CHAP"
+ options["node.session.auth.username"] = username
+ options["node.session.auth.password"] = password
+ return iscsi.CreateOrUpdateNode(target, options)
+}
+
+// CreateOrUpdateNode creates new or update existing iSCSI node in iscsid dm
+func (iscsi *LinuxISCSI) CreateOrUpdateNode(target ISCSITarget, options map[string]string) error {
+ err := validateIPAddress(target.Portal)
+ if err != nil {
+ fmt.Printf("\nError invalid portal address %s: %v", target.Portal, err)
+ return err
+ }
+
+ err = validateIQN(target.Target)
+ if err != nil {
+ fmt.Printf("\nError invalid IQN Target %s: %v", target.Target, err)
+ return err
+ }
+ baseCmd := iscsi.buildISCSICommand(
+ []string{"iscsiadm", "-m", "node", "-p", target.Portal, "-T", target.Target})
+
+ var commands [][]string
+
+ cmd := exec.Command(baseCmd[0], baseCmd[1:]...) // #nosec G204
+ _, err = cmd.Output()
+ if err != nil {
+ if !isNoObjsExitCode(err) {
+ return err
+ }
+ c := append(append([]string{}, baseCmd...), "-o", "new")
+ commands = append(commands, c)
+ }
+
+ for k, v := range options {
+ c := append(append([]string{}, baseCmd...), "-o", "update", "-n", k, "-v", v)
+ commands = append(commands, c)
+ }
+ for _, command := range commands {
+ cmd := exec.Command(command[0], command[1:]...) // #nosec G204
+ _, err := cmd.Output()
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// DeleteNode delete iSCSI node from iscsid database
+func (iscsi *LinuxISCSI) DeleteNode(target ISCSITarget) error {
+ err := validateIPAddress(target.Portal)
+ if err != nil {
+ fmt.Printf("\nError invalid portal address %s: %v", target.Portal, err)
+ return err
+ }
+
+ err = validateIQN(target.Target)
+ if err != nil {
+ fmt.Printf("\nError invalid IQN Target %s: %v", target.Target, err)
+ return err
+ }
+ exe := iscsi.buildISCSICommand(
+ []string{"iscsiadm", "-m", "node", "-p", target.Portal, "-T", target.Target, "-o", "delete"})
+ cmd := exec.Command(exe[0], exe[1:]...) // #nosec G204
+ _, err = cmd.Output()
+ if err != nil {
+ if isNoObjsExitCode(err) {
+ return nil
+ }
+ return err
+ }
+ return nil
+}
+
+func isNoObjsExitCode(err error) bool {
+ if err != nil {
+ if exitError, ok := err.(*exec.ExitError); ok {
+ return exitError.ExitCode() == iSCSINoObjsFoundExitCode
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/dell/goiscsi/goiscsi_mock.go b/vendor/github.com/dell/goiscsi/goiscsi_mock.go
new file mode 100644
index 000000000..6f7400cf1
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/goiscsi_mock.go
@@ -0,0 +1,259 @@
+/*
+ *
+ * Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+ *
+ * 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 goiscsi
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+)
+
+const (
+ // MockNumberOfInitiators controls the number of initiators found in mock mode
+ MockNumberOfInitiators = "numberOfInitiators"
+ // MockNumberOfTargets controls the number of targets found in mock mode
+ MockNumberOfTargets = "numberOfTargets"
+ // MockNumberOfSessions controls the number of iSCIS sessions found in mock mode
+ MockNumberOfSessions = "numberOfSession"
+ // MockNumberOfNodes controls the number of iSCIS sessions found in mock mode
+ MockNumberOfNodes = "numberOfNode"
+)
+
+// GOISCSIMock is a struct controlling induced errors
+var GOISCSIMock struct {
+ InduceDiscoveryError bool
+ InduceInitiatorError bool
+ InduceLoginError bool
+ InduceLogoutError bool
+ InduceRescanError bool
+ InduceGetSessionsError bool
+ InduceGetNodesError bool
+ InduceCreateOrUpdateNodeError bool
+ InduceDeleteNodeError bool
+ InduceSetCHAPError bool
+}
+
+// MockISCSI provides a mock implementation of an iscsi client
+type MockISCSI struct {
+ ISCSIType
+}
+
+// NewMockISCSI returns an mock ISCSI client
+func NewMockISCSI(opts map[string]string) *MockISCSI {
+ iscsi := MockISCSI{
+ ISCSIType: ISCSIType{
+ mock: true,
+ options: opts,
+ },
+ }
+
+ return &iscsi
+}
+
+func getOptionAsInt(opts map[string]string, key string) int64 {
+ v, _ := strconv.ParseInt(opts[key], 10, 64)
+ return v
+}
+
+func (iscsi *MockISCSI) discoverTargets(address string, _ bool) ([]ISCSITarget, error) {
+ if GOISCSIMock.InduceDiscoveryError {
+ return []ISCSITarget{}, errors.New("discoverTargets induced error")
+ }
+ mockedTargets := make([]ISCSITarget, 0)
+ count := getOptionAsInt(iscsi.options, MockNumberOfTargets)
+ if count == 0 {
+ count = 1
+ }
+
+ for idx := 0; idx < int(count); idx++ {
+ tgt := fmt.Sprintf("%05d", idx)
+ mockedTargets = append(mockedTargets,
+ ISCSITarget{
+ Portal: address + ":3260",
+ GroupTag: "0",
+ Target: "iqn.1992-04.com.mock:600009700bcbb70e32870174000" + tgt,
+ })
+ }
+
+ // send back a slice of targets
+ return mockedTargets, nil
+}
+
+func (iscsi *MockISCSI) getInitiators(_ string) ([]string, error) {
+ if GOISCSIMock.InduceInitiatorError {
+ return []string{}, errors.New("getInitiators induced error")
+ }
+
+ mockedInitiators := make([]string, 0)
+ count := getOptionAsInt(iscsi.options, MockNumberOfInitiators)
+ if count == 0 {
+ count = 1
+ }
+
+ for idx := 0; idx < int(count); idx++ {
+ init := fmt.Sprintf("%05d", idx)
+ mockedInitiators = append(mockedInitiators,
+ "iqn.1993-08.com.mock:01:00000000"+init)
+ }
+ return mockedInitiators, nil
+}
+
+func (iscsi *MockISCSI) performLogin(_ ISCSITarget) error {
+ if GOISCSIMock.InduceLoginError {
+ return errors.New("iSCSI Login induced error")
+ }
+
+ return nil
+}
+
+func (iscsi *MockISCSI) performLogout(_ ISCSITarget) error {
+ if GOISCSIMock.InduceLogoutError {
+ return errors.New("iSCSI Logout induced error")
+ }
+
+ return nil
+}
+
+func (iscsi *MockISCSI) performRescan() error {
+ if GOISCSIMock.InduceRescanError {
+ return errors.New("iSCSI Rescan induced error")
+ }
+
+ return nil
+}
+
+func (iscsi *MockISCSI) getSessions() ([]ISCSISession, error) {
+ if GOISCSIMock.InduceGetSessionsError {
+ return []ISCSISession{}, errors.New("getSessions induced error")
+ }
+
+ var sessions []ISCSISession
+ count := getOptionAsInt(iscsi.options, MockNumberOfSessions)
+ if count == 0 {
+ count = 1
+ }
+ for idx := 0; idx < int(count); idx++ {
+ init := fmt.Sprintf("%05d", idx)
+ session := ISCSISession{}
+ session.Target = fmt.Sprintf("iqn.2015-10.com.dell:dellemc-foobar-123-a-7ceb34a%d", idx)
+ session.Portal = fmt.Sprintf("192.168.1.%d", idx)
+ session.IfaceInitiatorname = "iqn.1993-08.com.mock:01:00000000" + init
+ session.IfaceTransport = ISCSITransportNameTCP
+ session.ISCSIConnectionState = ISCSIConnectionStateINLOGIN
+ session.ISCSISessionState = ISCSISessionStateLOGGEDIN
+ session.IfaceIPaddress = "192.168.1.10"
+ sessions = append(sessions, session)
+ }
+ return sessions, nil
+}
+
+func (iscsi *MockISCSI) getNodes() ([]ISCSINode, error) {
+ if GOISCSIMock.InduceGetNodesError {
+ return []ISCSINode{}, errors.New("getSessions induced error")
+ }
+
+ var nodes []ISCSINode
+ count := getOptionAsInt(iscsi.options, MockNumberOfNodes)
+ if count == 0 {
+ count = 1
+ }
+ for idx := 0; idx < int(count); idx++ {
+ node := ISCSINode{}
+ node.Target = fmt.Sprintf("iqn.2015-10.com.dell:dellemc-foobar-123-a-7ceb34a%d", idx)
+ node.Portal = fmt.Sprintf("192.168.1.%d", idx)
+ node.Fields = make(map[string]string)
+ node.Fields["node.session.scan"] = "auto"
+ nodes = append(nodes, node)
+ }
+ return nodes, nil
+}
+
+func (iscsi *MockISCSI) newNode(_ ISCSITarget, _ map[string]string) error {
+ if GOISCSIMock.InduceCreateOrUpdateNodeError {
+ return errors.New("newNode induced error")
+ }
+ if GOISCSIMock.InduceSetCHAPError {
+ return errors.New("set CHAP induced error")
+ }
+ return nil
+}
+
+func (iscsi *MockISCSI) deleteNode(_ ISCSITarget) error {
+ if GOISCSIMock.InduceDeleteNodeError {
+ return errors.New("newNode induced error")
+ }
+ return nil
+}
+
+// ====================================================================
+// Architecture agnostic code for the mock implementation
+
+// DiscoverTargets runs an iSCSI discovery and returns a list of targets.
+func (iscsi *MockISCSI) DiscoverTargets(address string, login bool) ([]ISCSITarget, error) {
+ return iscsi.discoverTargets(address, login)
+}
+
+// GetInitiators returns a list of initiators on the local system.
+func (iscsi *MockISCSI) GetInitiators(filename string) ([]string, error) {
+ return iscsi.getInitiators(filename)
+}
+
+// PerformLogin will attempt to log into an iSCSI target
+func (iscsi *MockISCSI) PerformLogin(target ISCSITarget) error {
+ return iscsi.performLogin(target)
+}
+
+// PerformLogout will attempt to log out of an iSCSI target
+func (iscsi *MockISCSI) PerformLogout(target ISCSITarget) error {
+ return iscsi.performLogout(target)
+}
+
+// PerformRescan will will rescan targets known to current sessions
+func (iscsi *MockISCSI) PerformRescan() error {
+ return iscsi.performRescan()
+}
+
+// GetSessions will query iSCSI session info
+func (iscsi *MockISCSI) GetSessions() ([]ISCSISession, error) {
+ return iscsi.getSessions()
+}
+
+// GetNodes will query iSCSI session info
+func (iscsi *MockISCSI) GetNodes() ([]ISCSINode, error) {
+ return iscsi.getNodes()
+}
+
+// CreateOrUpdateNode creates new or update existing iSCSI node in iscsid database
+func (iscsi *MockISCSI) CreateOrUpdateNode(target ISCSITarget, options map[string]string) error {
+ return iscsi.newNode(target, options)
+}
+
+// DeleteNode delete iSCSI node from iscsid database
+func (iscsi *MockISCSI) DeleteNode(target ISCSITarget) error {
+ return iscsi.deleteNode(target)
+}
+
+// SetCHAPCredentials will set CHAP credentials
+func (iscsi *MockISCSI) SetCHAPCredentials(target ISCSITarget, username, password string) error {
+ options := make(map[string]string)
+ options["node.session.auth.authmethod"] = "CHAP"
+ options["node.session.auth.username"] = username
+ options["node.session.auth.password"] = password
+ return iscsi.newNode(target, options)
+}
diff --git a/vendor/github.com/dell/goiscsi/goiscsi_types.go b/vendor/github.com/dell/goiscsi/goiscsi_types.go
new file mode 100644
index 000000000..486eb58c3
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/goiscsi_types.go
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+ *
+ * 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 goiscsi
+
+// ISCSITarget defines an iSCSI target
+type ISCSITarget struct {
+ Portal string
+ GroupTag string
+ Target string
+}
+
+// ISCSISessionState holds iscsi session state
+type ISCSISessionState string
+
+// ISCSIConnectionState holds iscsi connection state
+type ISCSIConnectionState string
+
+// ISCSITransportName holds iscsi transport name
+type ISCSITransportName string
+
+// ISCSI session and connection states
+const (
+ ISCSISessionStateLOGGEDIN ISCSISessionState = "LOGGED_IN"
+ ISCSISessionStateFAILED ISCSISessionState = "FAILED"
+ ISCSISessionStateFREE ISCSISessionState = "FREE"
+
+ ISCSIConnectionStateFREE ISCSIConnectionState = "FREE"
+ ISCSIConnectionStateTRANSPORTWAIT ISCSIConnectionState = "TRANSPORT WAIT"
+ ISCSIConnectionStateINLOGIN ISCSIConnectionState = "IN LOGIN"
+ ISCSIConnectionStateLOGGEDIN ISCSIConnectionState = "LOGGED IN"
+ ISCSIConnectionStateINLOGOUT ISCSIConnectionState = "IN LOGOUT"
+ ISCSIConnectionStateLOGOUTREQUESTED ISCSIConnectionState = "LOGOUT REQUESTED"
+ ISCSIConnectionStateCLEANUPWAIT ISCSIConnectionState = "CLEANUP WAIT"
+
+ ISCSITransportNameTCP ISCSITransportName = "tcp"
+ ISCSITransportNameISER ISCSITransportName = "iser"
+)
+
+// ISCSISession defines an iSCSI session info
+type ISCSISession struct {
+ Target string
+ Portal string
+ SID string
+ IfaceTransport ISCSITransportName
+ IfaceInitiatorname string
+ IfaceIPaddress string
+ ISCSISessionState ISCSISessionState
+ ISCSIConnectionState ISCSIConnectionState
+ Username string
+ Password string
+ UsernameIn string
+ PasswordIn string
+}
+
+// ISCSINode defines an iSCSI node info
+type ISCSINode struct {
+ Target string
+ Portal string
+ Fields map[string]string
+}
+
+type iSCSISessionParser interface {
+ Parse([]byte) []ISCSISession
+}
+
+type iSCSINodeParser interface {
+ Parse([]byte) []ISCSINode
+}
diff --git a/vendor/github.com/dell/goiscsi/goiscsi_utils.go b/vendor/github.com/dell/goiscsi/goiscsi_utils.go
new file mode 100644
index 000000000..949e089ea
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/goiscsi_utils.go
@@ -0,0 +1,147 @@
+/*
+ *
+ * Copyright © 2020-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+ *
+ * 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 goiscsi
+
+import (
+ "fmt"
+ "strings"
+)
+
+type sessionParser struct{}
+
+func (sp *sessionParser) Parse(data []byte) []ISCSISession {
+ str := string(data)
+ lines := strings.Split(str, "\n")
+
+ var result []ISCSISession
+ var curSession *ISCSISession
+ for _, line := range lines {
+ line = strings.TrimSpace(line)
+ switch {
+ case strings.HasPrefix(line, "Target:"):
+ session := ISCSISession{}
+ session.Target = strings.Fields(line)[1]
+ if curSession != nil {
+ result = append(result, *curSession)
+ }
+ curSession = &session
+ case curSession == nil:
+ case strings.HasPrefix(line, "Current Portal:"):
+ curSession.Portal = strings.Split(sessionFieldValue(line), ",")[0]
+ case strings.HasPrefix(line, "Iface Transport:"):
+ curSession.IfaceTransport = ISCSITransportName(sessionFieldValue(line))
+ case strings.HasPrefix(line, "Iface Initiatorname:"):
+ curSession.IfaceInitiatorname = sessionFieldValue(line)
+ case strings.HasPrefix(line, "Iface IPaddress:"):
+ curSession.IfaceIPaddress = sessionFieldValue(line)
+ case strings.HasPrefix(line, "SID:"):
+ curSession.SID = sessionFieldValue(line)
+ case strings.HasPrefix(line, "iSCSI Connection State:"):
+ curSession.ISCSIConnectionState = ISCSIConnectionState(sessionFieldValue(line))
+ case strings.HasPrefix(line, "iSCSI Session State:"):
+ curSession.ISCSISessionState = ISCSISessionState(sessionFieldValue(line))
+ case strings.HasPrefix(line, "username:"):
+ curSession.Username = sessionFieldValue(line)
+ case strings.HasPrefix(line, "password:"):
+ curSession.Password = sessionFieldValue(line)
+ case strings.HasPrefix(line, "username_in:"):
+ curSession.UsernameIn = sessionFieldValue(line)
+ case strings.HasPrefix(line, "password_in:"):
+ curSession.PasswordIn = sessionFieldValue(line)
+ }
+ }
+ if curSession != nil {
+ result = append(result, *curSession)
+ }
+ return result
+}
+
+func sessionFieldValue(s string) string {
+ _, value := fieldKeyValue(s, ":")
+ return value
+}
+
+func nodeFieldKeyValue(s string) (string, string) {
+ return fieldKeyValue(s, "=")
+}
+
+func fieldKeyValue(s string, sep string) (string, string) {
+ var key, value string
+ splitted := strings.SplitN(s, sep, 2)
+ if len(splitted) > 0 {
+ key = strings.Trim(strings.TrimSpace(splitted[0]), sep)
+ }
+ if len(splitted) > 1 {
+ value = replaceEmpty(strings.TrimSpace(splitted[1]))
+ }
+ return key, value
+}
+
+func replaceEmpty(s string) string {
+ if s == "" {
+ return ""
+ }
+ return s
+}
+
+type nodeParser struct{}
+
+func (np *nodeParser) Parse(data []byte) []ISCSINode {
+ str := string(data)
+ lines := strings.Split(str, "\n")
+ var result []ISCSINode
+ var curNode *ISCSINode
+ for _, line := range lines {
+ line = strings.TrimSpace(line)
+ switch {
+ case strings.HasPrefix(line, "# BEGIN RECORD"):
+ if curNode != nil {
+ result = append(result, *curNode)
+ }
+ curNode = &ISCSINode{Fields: make(map[string]string)}
+ case strings.HasPrefix(line, "# END RECORD"):
+ if curNode != nil {
+ result = append(result, *curNode)
+ }
+ curNode = nil
+ case curNode == nil:
+ case strings.HasPrefix(line, "node.name ="):
+ key, value := nodeFieldKeyValue(line)
+ curNode.Target = value
+ curNode.Fields[key] = value
+ case strings.HasPrefix(line, "node.conn[0].address ="):
+ key, value := nodeFieldKeyValue(line)
+ curNode.Portal = value
+ curNode.Fields[key] = value
+ case strings.HasPrefix(line, "node.conn[0].port ="):
+ key, value := nodeFieldKeyValue(line)
+ if curNode.Portal != "" {
+ curNode.Portal = fmt.Sprintf("%s:%s", curNode.Portal, value)
+ }
+ curNode.Fields[key] = value
+ default:
+ key, value := nodeFieldKeyValue(line)
+ curNode.Fields[key] = value
+ }
+ }
+ if curNode != nil {
+ result = append(result, *curNode)
+ }
+ return result
+}
diff --git a/vendor/github.com/dell/goiscsi/utils.go b/vendor/github.com/dell/goiscsi/utils.go
new file mode 100644
index 000000000..1691cc4a5
--- /dev/null
+++ b/vendor/github.com/dell/goiscsi/utils.go
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright © 2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+ *
+ * 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 goiscsi
+
+import (
+ "errors"
+ "net"
+ "regexp"
+)
+
+func validateIPAddress(ip string) error {
+ isValidIP := true
+ isValidPortal := true
+
+ // validtes only IP
+ if net.ParseIP(ip) == nil {
+ isValidIP = false
+ }
+
+ // Regex to validate IPV4 with port - for portal validation Ex: 10.0.0.0:1111
+ const exp = `^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+$`
+ r := regexp.MustCompile(exp)
+ if !r.MatchString(ip) {
+ isValidPortal = false
+ }
+ // Either valid IP/portal address should be given
+ if !isValidIP && !isValidPortal {
+ return errors.New("error invalid IP or portal address")
+ }
+ return nil
+}
+
+func validateIQN(iqn string) error {
+ const exp = `iqn\.\d{4}-\d{2}\.([[:alnum:]-.]+)(:[^,;*&$|\s]+)$`
+ r := regexp.MustCompile(exp)
+ if !r.MatchString(iqn) {
+ return errors.New("error invalid IQN")
+ }
+ return nil
+}
diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go
new file mode 100644
index 000000000..968434724
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/doc.go
@@ -0,0 +1,29 @@
+// Package require implements the same assertions as the `assert` package but
+// stops test execution when a test fails.
+//
+// # Example Usage
+//
+// The following is a complete example using require in a standard test function:
+//
+// import (
+// "testing"
+// "github.com/stretchr/testify/require"
+// )
+//
+// func TestSomething(t *testing.T) {
+//
+// var a string = "Hello"
+// var b string = "Hello"
+//
+// require.Equal(t, a, b, "The two words should be the same.")
+//
+// }
+//
+// # Assertions
+//
+// The `require` package have same global functions as in the `assert` package,
+// but instead of returning a boolean result they call `t.FailNow()`.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package require
diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go
new file mode 100644
index 000000000..1dcb2338c
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go
@@ -0,0 +1,16 @@
+package require
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+ t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+ return &Assertions{
+ t: t,
+ }
+}
+
+//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs"
diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go
new file mode 100644
index 000000000..506a82f80
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go
@@ -0,0 +1,2060 @@
+// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
+
+package require
+
+import (
+ assert "github.com/stretchr/testify/assert"
+ http "net/http"
+ url "net/url"
+ time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Condition(t, comp, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Conditionf(t, comp, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// assert.Contains(t, "Hello World", "World")
+// assert.Contains(t, ["Hello", "World"], "World")
+// assert.Contains(t, {"Hello": "World"}, "Hello")
+func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Contains(t, s, contains, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
+// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
+// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
+func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Containsf(t, s, contains, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.DirExists(t, path, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.DirExistsf(t, path, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
+func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ElementsMatch(t, listA, listB, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ElementsMatchf(t, listA, listB, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// assert.Empty(t, obj)
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Empty(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// assert.Emptyf(t, obj, "error message %s", "formatted")
+func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Emptyf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Equal asserts that two objects are equal.
+//
+// assert.Equal(t, 123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Equal(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// assert.EqualError(t, err, expectedErrorString)
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EqualError(t, theError, errString, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
+func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EqualErrorf(t, theError, errString, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EqualExportedValues asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+// type S struct {
+// Exported int
+// notExported int
+// }
+// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
+// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
+func EqualExportedValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EqualExportedValues(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EqualExportedValuesf asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+// type S struct {
+// Exported int
+// notExported int
+// }
+// assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
+// assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
+func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EqualExportedValuesf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EqualValues asserts that two objects are equal or convertible to the same types
+// and equal.
+//
+// assert.EqualValues(t, uint32(123), int32(123))
+func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EqualValues(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EqualValuesf asserts that two objects are equal or convertible to the same types
+// and equal.
+//
+// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
+func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EqualValuesf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Equalf asserts that two objects are equal.
+//
+// assert.Equalf(t, 123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Equalf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.Error(t, err) {
+// assert.Equal(t, expectedError, err)
+// }
+func Error(t TestingT, err error, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Error(t, err, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ErrorAs(t, err, target, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ErrorAsf(t, err, target, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ErrorContains asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+// actualObj, err := SomeFunction()
+// assert.ErrorContains(t, err, expectedErrorSubString)
+func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ErrorContains(t, theError, contains, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+// actualObj, err := SomeFunction()
+// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted")
+func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ErrorContainsf(t, theError, contains, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ErrorIs asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ErrorIs(t, err, target, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// ErrorIsf asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.ErrorIsf(t, err, target, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.Errorf(t, err, "error message %s", "formatted") {
+// assert.Equal(t, expectedErrorf, err)
+// }
+func Errorf(t TestingT, err error, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Errorf(t, err, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EventuallyWithT asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+// externalValue := false
+// go func() {
+// time.Sleep(8*time.Second)
+// externalValue = true
+// }()
+// assert.EventuallyWithT(t, func(c *assert.CollectT) {
+// // add assertions as needed; any assertion failure will fail the current tick
+// assert.True(c, externalValue, "expected 'externalValue' to be true")
+// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
+func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// EventuallyWithTf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+// externalValue := false
+// go func() {
+// time.Sleep(8*time.Second)
+// externalValue = true
+// }()
+// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
+// // add assertions as needed; any assertion failure will fail the current tick
+// assert.True(c, externalValue, "expected 'externalValue' to be true")
+// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
+func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.EventuallyWithTf(t, condition, waitFor, tick, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+// assert.Exactly(t, int32(123), int64(123))
+func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Exactly(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
+func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Exactlyf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Fail(t, failureMessage, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.FailNow(t, failureMessage, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// FailNowf fails test
+func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.FailNowf(t, failureMessage, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Failf reports a failure through
+func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Failf(t, failureMessage, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// False asserts that the specified value is false.
+//
+// assert.False(t, myBool)
+func False(t TestingT, value bool, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.False(t, value, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Falsef asserts that the specified value is false.
+//
+// assert.Falsef(t, myBool, "error message %s", "formatted")
+func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Falsef(t, value, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.FileExists(t, path, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.FileExistsf(t, path, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Greater asserts that the first element is greater than the second
+//
+// assert.Greater(t, 2, 1)
+// assert.Greater(t, float64(2), float64(1))
+// assert.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Greater(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqual(t, 2, 1)
+// assert.GreaterOrEqual(t, 2, 2)
+// assert.GreaterOrEqual(t, "b", "a")
+// assert.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.GreaterOrEqualf(t, e1, e2, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
+// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
+// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Greaterf(t, e1, e2, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPStatusCode asserts that a specified handler returns a specified status code.
+//
+// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPStatusCodef asserts that a specified handler returns a specified status code.
+//
+// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Implements(t, interfaceObject, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Implementsf(t, interfaceObject, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// assert.InDelta(t, math.Pi, 22/7.0, 0.01)
+func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
+func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InDeltaf(t, expected, actual, delta, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsDecreasing asserts that the collection is decreasing
+//
+// assert.IsDecreasing(t, []int{2, 1, 0})
+// assert.IsDecreasing(t, []float{2, 1})
+// assert.IsDecreasing(t, []string{"b", "a"})
+func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsDecreasing(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsDecreasingf asserts that the collection is decreasing
+//
+// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted")
+// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted")
+// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
+func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsDecreasingf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsIncreasing asserts that the collection is increasing
+//
+// assert.IsIncreasing(t, []int{1, 2, 3})
+// assert.IsIncreasing(t, []float{1, 2})
+// assert.IsIncreasing(t, []string{"a", "b"})
+func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsIncreasing(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsIncreasingf asserts that the collection is increasing
+//
+// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted")
+// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted")
+// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
+func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsIncreasingf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsNonDecreasing asserts that the collection is not decreasing
+//
+// assert.IsNonDecreasing(t, []int{1, 1, 2})
+// assert.IsNonDecreasing(t, []float{1, 2})
+// assert.IsNonDecreasing(t, []string{"a", "b"})
+func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsNonDecreasing(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsNonDecreasingf asserts that the collection is not decreasing
+//
+// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted")
+// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted")
+// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
+func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsNonDecreasingf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsNonIncreasing asserts that the collection is not increasing
+//
+// assert.IsNonIncreasing(t, []int{2, 1, 1})
+// assert.IsNonIncreasing(t, []float{2, 1})
+// assert.IsNonIncreasing(t, []string{"b", "a"})
+func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsNonIncreasing(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsNonIncreasingf asserts that the collection is not increasing
+//
+// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted")
+// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted")
+// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
+func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsNonIncreasingf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsType(t, expectedType, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.IsTypef(t, expectedType, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.JSONEq(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.JSONEqf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+// assert.Len(t, mySlice, 3)
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Len(t, object, length, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
+func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Lenf(t, object, length, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Less asserts that the first element is less than the second
+//
+// assert.Less(t, 1, 2)
+// assert.Less(t, float64(1), float64(2))
+// assert.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Less(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqual(t, 1, 2)
+// assert.LessOrEqual(t, 2, 2)
+// assert.LessOrEqual(t, "a", "b")
+// assert.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.LessOrEqual(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.LessOrEqualf(t, e1, e2, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Lessf asserts that the first element is less than the second
+//
+// assert.Lessf(t, 1, 2, "error message %s", "formatted")
+// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
+// assert.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Lessf(t, e1, e2, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Negative asserts that the specified element is negative
+//
+// assert.Negative(t, -1)
+// assert.Negative(t, -1.23)
+func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Negative(t, e, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Negativef asserts that the specified element is negative
+//
+// assert.Negativef(t, -1, "error message %s", "formatted")
+// assert.Negativef(t, -1.23, "error message %s", "formatted")
+func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Negativef(t, e, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
+func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Never(t, condition, waitFor, tick, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Neverf(t, condition, waitFor, tick, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Nil asserts that the specified object is nil.
+//
+// assert.Nil(t, err)
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Nil(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Nilf asserts that the specified object is nil.
+//
+// assert.Nilf(t, err, "error message %s", "formatted")
+func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Nilf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NoDirExists checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NoDirExists(t, path, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NoDirExistsf checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NoDirExistsf(t, path, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.NoError(t, err) {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NoError(t, err, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.NoErrorf(t, err, "error message %s", "formatted") {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NoErrorf(t, err, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NoFileExists checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NoFileExists(t, path, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NoFileExistsf checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NoFileExistsf(t, path, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// assert.NotContains(t, "Hello World", "Earth")
+// assert.NotContains(t, ["Hello", "World"], "Earth")
+// assert.NotContains(t, {"Hello": "World"}, "Earth")
+func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotContains(t, s, contains, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
+// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
+// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
+func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotContainsf(t, s, contains, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if assert.NotEmpty(t, obj) {
+// assert.Equal(t, "two", obj[1])
+// }
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotEmpty(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
+// assert.Equal(t, "two", obj[1])
+// }
+func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotEmptyf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+// assert.NotEqual(t, obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotEqual(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotEqualValues asserts that two objects are not equal even when converted to the same type
+//
+// assert.NotEqualValues(t, obj1, obj2)
+func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotEqualValues(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
+//
+// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
+func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotEqualValuesf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotEqualf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotErrorIs asserts that at none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotErrorIs(t, err, target, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotErrorIsf asserts that at none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotErrorIsf(t, err, target, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotImplements asserts that an object does not implement the specified interface.
+//
+// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject))
+func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotImplements(t, interfaceObject, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotImplementsf asserts that an object does not implement the specified interface.
+//
+// assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotImplementsf(t, interfaceObject, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+// assert.NotNil(t, err)
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotNil(t, object, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+// assert.NotNilf(t, err, "error message %s", "formatted")
+func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotNilf(t, object, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// assert.NotPanics(t, func(){ RemainCalm() })
+func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotPanics(t, f, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
+func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotPanicsf(t, f, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+// assert.NotRegexp(t, "^start", "it's not starting")
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotRegexp(t, rx, str, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
+// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
+func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotRegexpf(t, rx, str, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotSame asserts that two pointers do not reference the same object.
+//
+// assert.NotSame(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotSame(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotSamef asserts that two pointers do not reference the same object.
+//
+// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotSamef(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotSubset asserts that the specified list(array, slice...) or map does NOT
+// contain all elements given in the specified subset list(array, slice...) or
+// map.
+//
+// assert.NotSubset(t, [1, 3, 4], [1, 2])
+// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
+func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotSubset(t, list, subset, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
+// contain all elements given in the specified subset list(array, slice...) or
+// map.
+//
+// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
+// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
+func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotSubsetf(t, list, subset, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotZero(t, i, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.NotZerof(t, i, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+// assert.Panics(t, func(){ GoCrazy() })
+func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Panics(t, f, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// PanicsWithError asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.PanicsWithError(t, errString, f, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.PanicsWithErrorf(t, errString, f, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.PanicsWithValue(t, expected, f, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.PanicsWithValuef(t, expected, f, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
+func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Panicsf(t, f, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Positive asserts that the specified element is positive
+//
+// assert.Positive(t, 1)
+// assert.Positive(t, 1.23)
+func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Positive(t, e, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Positivef asserts that the specified element is positive
+//
+// assert.Positivef(t, 1, "error message %s", "formatted")
+// assert.Positivef(t, 1.23, "error message %s", "formatted")
+func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Positivef(t, e, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+// assert.Regexp(t, "start...$", "it's not starting")
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Regexp(t, rx, str, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
+// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
+func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Regexpf(t, rx, str, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Same asserts that two pointers reference the same object.
+//
+// assert.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Same(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Samef(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Subset asserts that the specified list(array, slice...) or map contains all
+// elements given in the specified subset list(array, slice...) or map.
+//
+// assert.Subset(t, [1, 2, 3], [1, 2])
+// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})
+func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Subset(t, list, subset, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Subsetf asserts that the specified list(array, slice...) or map contains all
+// elements given in the specified subset list(array, slice...) or map.
+//
+// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
+// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
+func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Subsetf(t, list, subset, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// True asserts that the specified value is true.
+//
+// assert.True(t, myBool)
+func True(t TestingT, value bool, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.True(t, value, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Truef asserts that the specified value is true.
+//
+// assert.Truef(t, myBool, "error message %s", "formatted")
+func Truef(t TestingT, value bool, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Truef(t, value, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
+func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.WithinDurationf(t, expected, actual, delta, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// WithinRange asserts that a time is within a time range (inclusive).
+//
+// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
+func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.WithinRange(t, actual, start, end, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// WithinRangef asserts that a time is within a time range (inclusive).
+//
+// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
+func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.WithinRangef(t, actual, start, end, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.YAMLEqf(t, expected, actual, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Zero asserts that i is the zero value for its type.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Zero(t, i, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Zerof asserts that i is the zero value for its type.
+func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Zerof(t, i, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl
new file mode 100644
index 000000000..55e42ddeb
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl
@@ -0,0 +1,6 @@
+{{.Comment}}
+func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
+ if h, ok := t.(tHelper); ok { h.Helper() }
+ if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
+ t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go
new file mode 100644
index 000000000..eee8310a5
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go
@@ -0,0 +1,1622 @@
+// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
+
+package require
+
+import (
+ assert "github.com/stretchr/testify/assert"
+ http "net/http"
+ url "net/url"
+ time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Condition(a.t, comp, msgAndArgs...)
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Conditionf(a.t, comp, msg, args...)
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// a.Contains("Hello World", "World")
+// a.Contains(["Hello", "World"], "World")
+// a.Contains({"Hello": "World"}, "Hello")
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// a.Containsf("Hello World", "World", "error message %s", "formatted")
+// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
+// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
+func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Containsf(a.t, s, contains, msg, args...)
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ DirExists(a.t, path, msgAndArgs...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ DirExistsf(a.t, path, msg, args...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
+func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// a.Empty(obj)
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Empty(a.t, object, msgAndArgs...)
+}
+
+// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// a.Emptyf(obj, "error message %s", "formatted")
+func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Emptyf(a.t, object, msg, args...)
+}
+
+// Equal asserts that two objects are equal.
+//
+// a.Equal(123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// a.EqualError(err, expectedErrorString)
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
+func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EqualErrorf(a.t, theError, errString, msg, args...)
+}
+
+// EqualExportedValues asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+// type S struct {
+// Exported int
+// notExported int
+// }
+// a.EqualExportedValues(S{1, 2}, S{1, 3}) => true
+// a.EqualExportedValues(S{1, 2}, S{2, 3}) => false
+func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EqualExportedValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualExportedValuesf asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+// type S struct {
+// Exported int
+// notExported int
+// }
+// a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
+// a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
+func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EqualExportedValuesf(a.t, expected, actual, msg, args...)
+}
+
+// EqualValues asserts that two objects are equal or convertible to the same types
+// and equal.
+//
+// a.EqualValues(uint32(123), int32(123))
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertible to the same types
+// and equal.
+//
+// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
+func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+// a.Equalf(123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Equalf(a.t, expected, actual, msg, args...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.Error(err) {
+// assert.Equal(t, expectedError, err)
+// }
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Error(a.t, err, msgAndArgs...)
+}
+
+// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ErrorAs(a.t, err, target, msgAndArgs...)
+}
+
+// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ErrorAsf(a.t, err, target, msg, args...)
+}
+
+// ErrorContains asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+// actualObj, err := SomeFunction()
+// a.ErrorContains(err, expectedErrorSubString)
+func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ErrorContains(a.t, theError, contains, msgAndArgs...)
+}
+
+// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+// actualObj, err := SomeFunction()
+// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted")
+func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ErrorContainsf(a.t, theError, contains, msg, args...)
+}
+
+// ErrorIs asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ErrorIs(a.t, err, target, msgAndArgs...)
+}
+
+// ErrorIsf asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ ErrorIsf(a.t, err, target, msg, args...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.Errorf(err, "error message %s", "formatted") {
+// assert.Equal(t, expectedErrorf, err)
+// }
+func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Errorf(a.t, err, msg, args...)
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// EventuallyWithT asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+// externalValue := false
+// go func() {
+// time.Sleep(8*time.Second)
+// externalValue = true
+// }()
+// a.EventuallyWithT(func(c *assert.CollectT) {
+// // add assertions as needed; any assertion failure will fail the current tick
+// assert.True(c, externalValue, "expected 'externalValue' to be true")
+// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
+func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// EventuallyWithTf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+// externalValue := false
+// go func() {
+// time.Sleep(8*time.Second)
+// externalValue = true
+// }()
+// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
+// // add assertions as needed; any assertion failure will fail the current tick
+// assert.True(c, externalValue, "expected 'externalValue' to be true")
+// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
+func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+// a.Exactly(int32(123), int64(123))
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted")
+func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Exactlyf(a.t, expected, actual, msg, args...)
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNowf fails test
+func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ FailNowf(a.t, failureMessage, msg, args...)
+}
+
+// Failf reports a failure through
+func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Failf(a.t, failureMessage, msg, args...)
+}
+
+// False asserts that the specified value is false.
+//
+// a.False(myBool)
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ False(a.t, value, msgAndArgs...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+// a.Falsef(myBool, "error message %s", "formatted")
+func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Falsef(a.t, value, msg, args...)
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ FileExists(a.t, path, msgAndArgs...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ FileExistsf(a.t, path, msg, args...)
+}
+
+// Greater asserts that the first element is greater than the second
+//
+// a.Greater(2, 1)
+// a.Greater(float64(2), float64(1))
+// a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqual(2, 1)
+// a.GreaterOrEqual(2, 2)
+// a.GreaterOrEqual("b", "a")
+// a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+// a.Greaterf(2, 1, "error message %s", "formatted")
+// a.Greaterf(float64(2), float64(1), "error message %s", "formatted")
+// a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Greaterf(a.t, e1, e2, msg, args...)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPError(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPErrorf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPStatusCode asserts that a specified handler returns a specified status code.
+//
+// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...)
+}
+
+// HTTPStatusCodef asserts that a specified handler returns a specified status code.
+//
+// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...)
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+// a.Implements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Implementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// a.InDelta(math.Pi, 22/7.0, 0.01)
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
+func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InDeltaf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// IsDecreasing asserts that the collection is decreasing
+//
+// a.IsDecreasing([]int{2, 1, 0})
+// a.IsDecreasing([]float{2, 1})
+// a.IsDecreasing([]string{"b", "a"})
+func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsDecreasing(a.t, object, msgAndArgs...)
+}
+
+// IsDecreasingf asserts that the collection is decreasing
+//
+// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted")
+// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted")
+// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted")
+func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsDecreasingf(a.t, object, msg, args...)
+}
+
+// IsIncreasing asserts that the collection is increasing
+//
+// a.IsIncreasing([]int{1, 2, 3})
+// a.IsIncreasing([]float{1, 2})
+// a.IsIncreasing([]string{"a", "b"})
+func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsIncreasing(a.t, object, msgAndArgs...)
+}
+
+// IsIncreasingf asserts that the collection is increasing
+//
+// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted")
+// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted")
+// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted")
+func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsIncreasingf(a.t, object, msg, args...)
+}
+
+// IsNonDecreasing asserts that the collection is not decreasing
+//
+// a.IsNonDecreasing([]int{1, 1, 2})
+// a.IsNonDecreasing([]float{1, 2})
+// a.IsNonDecreasing([]string{"a", "b"})
+func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsNonDecreasing(a.t, object, msgAndArgs...)
+}
+
+// IsNonDecreasingf asserts that the collection is not decreasing
+//
+// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted")
+// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted")
+// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted")
+func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsNonDecreasingf(a.t, object, msg, args...)
+}
+
+// IsNonIncreasing asserts that the collection is not increasing
+//
+// a.IsNonIncreasing([]int{2, 1, 1})
+// a.IsNonIncreasing([]float{2, 1})
+// a.IsNonIncreasing([]string{"b", "a"})
+func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsNonIncreasing(a.t, object, msgAndArgs...)
+}
+
+// IsNonIncreasingf asserts that the collection is not increasing
+//
+// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted")
+// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted")
+// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted")
+func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsNonIncreasingf(a.t, object, msg, args...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ IsTypef(a.t, expectedType, object, msg, args...)
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ JSONEqf(a.t, expected, actual, msg, args...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+// a.Len(mySlice, 3)
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Len(a.t, object, length, msgAndArgs...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+// a.Lenf(mySlice, 3, "error message %s", "formatted")
+func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Lenf(a.t, object, length, msg, args...)
+}
+
+// Less asserts that the first element is less than the second
+//
+// a.Less(1, 2)
+// a.Less(float64(1), float64(2))
+// a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqual(1, 2)
+// a.LessOrEqual(2, 2)
+// a.LessOrEqual("a", "b")
+// a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqualf(1, 2, "error message %s", "formatted")
+// a.LessOrEqualf(2, 2, "error message %s", "formatted")
+// a.LessOrEqualf("a", "b", "error message %s", "formatted")
+// a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+// a.Lessf(1, 2, "error message %s", "formatted")
+// a.Lessf(float64(1), float64(2), "error message %s", "formatted")
+// a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Lessf(a.t, e1, e2, msg, args...)
+}
+
+// Negative asserts that the specified element is negative
+//
+// a.Negative(-1)
+// a.Negative(-1.23)
+func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Negative(a.t, e, msgAndArgs...)
+}
+
+// Negativef asserts that the specified element is negative
+//
+// a.Negativef(-1, "error message %s", "formatted")
+// a.Negativef(-1.23, "error message %s", "formatted")
+func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Negativef(a.t, e, msg, args...)
+}
+
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Never(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Neverf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+// a.Nil(err)
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Nil(a.t, object, msgAndArgs...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+// a.Nilf(err, "error message %s", "formatted")
+func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Nilf(a.t, object, msg, args...)
+}
+
+// NoDirExists checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NoDirExists(a.t, path, msgAndArgs...)
+}
+
+// NoDirExistsf checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NoDirExistsf(a.t, path, msg, args...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.NoError(err) {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NoError(a.t, err, msgAndArgs...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.NoErrorf(err, "error message %s", "formatted") {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NoErrorf(a.t, err, msg, args...)
+}
+
+// NoFileExists checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NoFileExists(a.t, path, msgAndArgs...)
+}
+
+// NoFileExistsf checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NoFileExistsf(a.t, path, msg, args...)
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// a.NotContains("Hello World", "Earth")
+// a.NotContains(["Hello", "World"], "Earth")
+// a.NotContains({"Hello": "World"}, "Earth")
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
+// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
+// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
+func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotContainsf(a.t, s, contains, msg, args...)
+}
+
+// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if a.NotEmpty(obj) {
+// assert.Equal(t, "two", obj[1])
+// }
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if a.NotEmptyf(obj, "error message %s", "formatted") {
+// assert.Equal(t, "two", obj[1])
+// }
+func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotEmptyf(a.t, object, msg, args...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+// a.NotEqual(obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualValues asserts that two objects are not equal even when converted to the same type
+//
+// a.NotEqualValues(obj1, obj2)
+func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotEqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
+//
+// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted")
+func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotEqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+// a.NotEqualf(obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotEqualf(a.t, expected, actual, msg, args...)
+}
+
+// NotErrorIs asserts that at none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotErrorIs(a.t, err, target, msgAndArgs...)
+}
+
+// NotErrorIsf asserts that at none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotErrorIsf(a.t, err, target, msg, args...)
+}
+
+// NotImplements asserts that an object does not implement the specified interface.
+//
+// a.NotImplements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotImplements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// NotImplementsf asserts that an object does not implement the specified interface.
+//
+// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotImplementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+// a.NotNil(err)
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotNil(a.t, object, msgAndArgs...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+// a.NotNilf(err, "error message %s", "formatted")
+func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotNilf(a.t, object, msg, args...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// a.NotPanics(func(){ RemainCalm() })
+func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotPanics(a.t, f, msgAndArgs...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
+func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotPanicsf(a.t, f, msg, args...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+// a.NotRegexp("^start", "it's not starting")
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
+// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotRegexpf(a.t, rx, str, msg, args...)
+}
+
+// NotSame asserts that two pointers do not reference the same object.
+//
+// a.NotSame(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotSame(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotSamef asserts that two pointers do not reference the same object.
+//
+// a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotSamef(a.t, expected, actual, msg, args...)
+}
+
+// NotSubset asserts that the specified list(array, slice...) or map does NOT
+// contain all elements given in the specified subset list(array, slice...) or
+// map.
+//
+// a.NotSubset([1, 3, 4], [1, 2])
+// a.NotSubset({"x": 1, "y": 2}, {"z": 3})
+func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotSubset(a.t, list, subset, msgAndArgs...)
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
+// contain all elements given in the specified subset list(array, slice...) or
+// map.
+//
+// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
+// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
+func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotSubsetf(a.t, list, subset, msg, args...)
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotZero(a.t, i, msgAndArgs...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ NotZerof(a.t, i, msg, args...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+// a.Panics(func(){ GoCrazy() })
+func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Panics(a.t, f, msgAndArgs...)
+}
+
+// PanicsWithError asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+// a.PanicsWithError("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ PanicsWithError(a.t, errString, f, msgAndArgs...)
+}
+
+// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ PanicsWithErrorf(a.t, errString, f, msg, args...)
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ PanicsWithValue(a.t, expected, f, msgAndArgs...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ PanicsWithValuef(a.t, expected, f, msg, args...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Panicsf(a.t, f, msg, args...)
+}
+
+// Positive asserts that the specified element is positive
+//
+// a.Positive(1)
+// a.Positive(1.23)
+func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Positive(a.t, e, msgAndArgs...)
+}
+
+// Positivef asserts that the specified element is positive
+//
+// a.Positivef(1, "error message %s", "formatted")
+// a.Positivef(1.23, "error message %s", "formatted")
+func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Positivef(a.t, e, msg, args...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+// a.Regexp(regexp.MustCompile("start"), "it's starting")
+// a.Regexp("start...$", "it's not starting")
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
+// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Regexpf(a.t, rx, str, msg, args...)
+}
+
+// Same asserts that two pointers reference the same object.
+//
+// a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+// a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Samef(a.t, expected, actual, msg, args...)
+}
+
+// Subset asserts that the specified list(array, slice...) or map contains all
+// elements given in the specified subset list(array, slice...) or map.
+//
+// a.Subset([1, 2, 3], [1, 2])
+// a.Subset({"x": 1, "y": 2}, {"x": 1})
+func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Subset(a.t, list, subset, msgAndArgs...)
+}
+
+// Subsetf asserts that the specified list(array, slice...) or map contains all
+// elements given in the specified subset list(array, slice...) or map.
+//
+// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
+// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
+func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Subsetf(a.t, list, subset, msg, args...)
+}
+
+// True asserts that the specified value is true.
+//
+// a.True(myBool)
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ True(a.t, value, msgAndArgs...)
+}
+
+// Truef asserts that the specified value is true.
+//
+// a.Truef(myBool, "error message %s", "formatted")
+func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Truef(a.t, value, msg, args...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ WithinDurationf(a.t, expected, actual, delta, msg, args...)
+}
+
+// WithinRange asserts that a time is within a time range (inclusive).
+//
+// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
+func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ WithinRange(a.t, actual, start, end, msgAndArgs...)
+}
+
+// WithinRangef asserts that a time is within a time range (inclusive).
+//
+// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
+func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ WithinRangef(a.t, actual, start, end, msg, args...)
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
+// Zero asserts that i is the zero value for its type.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Zero(a.t, i, msgAndArgs...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Zerof(a.t, i, msg, args...)
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
new file mode 100644
index 000000000..54124df1d
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
+ if h, ok := a.t.(tHelper); ok { h.Helper() }
+ {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go
new file mode 100644
index 000000000..91772dfeb
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/requirements.go
@@ -0,0 +1,29 @@
+package require
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+ Errorf(format string, args ...interface{})
+ FailNow()
+}
+
+type tHelper interface {
+ Helper()
+}
+
+// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
+// for table driven tests.
+type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
+
+// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
+// for table driven tests.
+type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
+
+// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
+// for table driven tests.
+type BoolAssertionFunc func(TestingT, bool, ...interface{})
+
+// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
+// for table driven tests.
+type ErrorAssertionFunc func(TestingT, error, ...interface{})
+
+//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs"
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 72a238a37..77d067e5e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -4,6 +4,9 @@ github.com/coreos/go-systemd/v22/dbus
# github.com/davecgh/go-spew v1.1.1
## explicit
github.com/davecgh/go-spew/spew
+# github.com/dell/goiscsi v1.9.0
+## explicit; go 1.22
+github.com/dell/goiscsi
# github.com/docker/cli v20.10.20+incompatible
## explicit
github.com/docker/cli/cli/config
@@ -154,6 +157,7 @@ github.com/sirupsen/logrus
# github.com/stretchr/testify v1.9.0
## explicit; go 1.17
github.com/stretchr/testify/assert
+github.com/stretchr/testify/require
# github.com/tredoe/osutil v1.5.0
## explicit; go 1.16
github.com/tredoe/osutil/user/crypt
@@ -237,3 +241,4 @@ k8s.io/utils/net
# k8s.io/api => k8s.io/api v0.24.10
# k8s.io/apimachinery => k8s.io/apimachinery v0.24.10
# k8s.io/client-go => k8s.io/client-go v0.24.10
+# k8s.io/kubelet => k8s.io/kubelet v0.24.10