Some enhancements (#30)

- Cleanup if `cleanup.on == Always` and error happens in `setup` step.
- Fail `setup` step if there is command fail in the `steps.command`.
- Retry per case instead of all cases in `verify` step.
- Delete unused function `Which`.
diff --git a/commands/run/run.go b/commands/run/run.go
index b35da3e..53280a9 100644
--- a/commands/run/run.go
+++ b/commands/run/run.go
@@ -47,6 +47,12 @@
 		return config.GlobalConfig.Error
 	}
 
+	// If cleanup.on == Always and there is error in setup step, we should defer cleanup step right now.
+	cleanupOnCondition := config.GlobalConfig.E2EConfig.Cleanup.On
+	if cleanupOnCondition == constant.CleanUpAlways {
+		defer doCleanup()
+	}
+
 	// setup part
 	err := setup.DoSetupAccordingE2E()
 	if err != nil {
@@ -54,36 +60,19 @@
 	}
 	logger.Log.Infof("setup part finished successfully")
 
-	// cleanup part
-	defer func() {
-		clean := true
+	if cleanupOnCondition != constant.CleanUpAlways {
+		defer func() {
+			shouldCleanup := (cleanupOnCondition == constant.CleanUpOnSuccess && err == nil) ||
+				(cleanupOnCondition == constant.CleanUpOnFailure && err != nil)
 
-		switch config.GlobalConfig.E2EConfig.Cleanup.On {
-		case constant.CleanUpNever:
-			clean = false
-		case constant.CleanUpOnSuccess:
-			// failed
-			if err != nil {
-				clean = false
+			if !shouldCleanup {
+				logger.Log.Infof("don't cleanup according to config")
+				return
 			}
-		case constant.CleanUpOnFailure:
-			// success
-			if err == nil {
-				clean = false
-			}
-		}
 
-		if !clean {
-			logger.Log.Infof("cleanup passed according to config")
-			return
-		}
-
-		err = cleanup.DoCleanupAccordingE2E()
-		if err != nil {
-			logger.Log.Errorf("cleanup part error: %s", err)
-		}
-		logger.Log.Infof("cleanup part finished successfully")
-	}()
+			doCleanup()
+		}()
+	}
 
 	// trigger part
 	err = trigger.DoActionAccordingE2E()
@@ -101,3 +90,11 @@
 
 	return nil
 }
+
+func doCleanup() {
+	if err := cleanup.DoCleanupAccordingE2E(); err != nil {
+		logger.Log.Errorf("cleanup part error: %s", err)
+	} else {
+		logger.Log.Infof("cleanup part finished successfully")
+	}
+}
diff --git a/commands/verify/verify.go b/commands/verify/verify.go
index 3f5146a..e979b41 100644
--- a/commands/verify/verify.go
+++ b/commands/verify/verify.go
@@ -101,25 +101,21 @@
 		retryInterval = 1000
 	}
 
-	var err error
-	for current := 1; current <= retryCount; current++ {
-		for _, v := range e2eConfig.Verify.Cases {
-			if v.GetExpected() != "" {
-				if err = verifySingleCase(v.GetExpected(), v.GetActual(), v.Query); err != nil {
-					break
-				}
-			} else {
-				return fmt.Errorf("the expected data file is not specified")
-			}
+	for idx, v := range e2eConfig.Verify.Cases {
+		if v.GetExpected() == "" {
+			return fmt.Errorf("the expected data file for case[%v] is not specified", idx)
 		}
-
-		if err != nil && current != retryCount {
-			logger.Log.Warnf("verify case failure, will continue retry, %v", err)
-			time.Sleep(time.Duration(retryInterval) * time.Millisecond)
-		} else if err == nil {
-			return nil
+		for current := 1; current <= retryCount; current++ {
+			if err := verifySingleCase(v.GetExpected(), v.GetActual(), v.Query); err == nil {
+				break
+			} else if current != retryCount {
+				logger.Log.Warnf("verify case failure, will continue retry, %v", err)
+				time.Sleep(time.Duration(retryInterval) * time.Millisecond)
+			} else {
+				return err
+			}
 		}
 	}
 
-	return err
+	return nil
 }
diff --git a/internal/util/utils.go b/internal/util/utils.go
index 495586c..1e84ea1 100644
--- a/internal/util/utils.go
+++ b/internal/util/utils.go
@@ -26,13 +26,6 @@
 	"os/exec"
 )
 
-// Which checks if binary is present in PATH.
-func Which(binary string) error {
-	_, err := exec.LookPath(binary)
-
-	return err
-}
-
 // PathExist checks if a file/directory is exist.
 func PathExist(_path string) bool {
 	_, err := os.Stat(_path)
@@ -56,7 +49,7 @@
 
 // ExecuteCommand executes the given command and returns the result.
 func ExecuteCommand(cmd string) (string, error) {
-	command := exec.Command("bash", "-c", cmd)
+	command := exec.Command("bash", "-ec", cmd)
 	outinfo := bytes.Buffer{}
 	command.Stdout = &outinfo