Skip to content

Commit

Permalink
Add test for TestDataCentrallyAvailable (#26)
Browse files Browse the repository at this point in the history
* Add test for TestDataCentrallyAvailable

* Check if SSH is installed. Add more tests

* Rename TestDataCentrallyAvailable to CheckDataCentrallyAvailable

* change file names of TestDataCentrallyAvailable to CheckDataCentrallyAvailable
  • Loading branch information
kavir1698 authored Apr 4, 2024
1 parent ed05baf commit 9efbc26
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 22 deletions.
7 changes: 4 additions & 3 deletions cmd/datasetIngestor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ import (
"net/http"
"os"
"path/filepath"
"github.com/paulscherrerinstitute/scicat/datasetIngestor"
"github.com/paulscherrerinstitute/scicat/datasetUtils"
"strings"
"time"

"github.com/paulscherrerinstitute/scicat/datasetIngestor"
"github.com/paulscherrerinstitute/scicat/datasetUtils"

"github.com/fatih/color"
)

Expand Down Expand Up @@ -299,7 +300,7 @@ func main() {
// and unless copy flag defined via command line
if !*copyFlag && !*nocopyFlag {
if !beamlineAccount {
err := datasetIngestor.TestDataCentrallyAvailable(user["username"], RSYNCServer, sourceFolder)
err := datasetIngestor.CheckDataCentrallyAvailable(user["username"], RSYNCServer, sourceFolder)
if err != nil {
color.Set(color.FgYellow)
log.Printf("The source folder %v is not centrally available (decentral use case).\nThe data must first be copied to a rsync cache server.\n ", sourceFolder)
Expand Down
47 changes: 47 additions & 0 deletions datasetIngestor/checkDataCentrallyAvailable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package datasetIngestor

import (
"errors"
"log"
"os"
"os/exec"
"runtime"
)

// execCommand is a variable that points to exec.Command, allowing it to be replaced in tests.
var execCommand = exec.Command

// CheckDataCentrallyAvailable checks if a specific directory (sourceFolder) is available on a remote server (ARCHIVEServer)
// using the provided username for SSH connection. It returns an error if the directory is not available or if there's an issue with the SSH connection.
func CheckDataCentrallyAvailable(username string, ARCHIVEServer string, sourceFolder string) (err error) {
var cmd *exec.Cmd

// Check the operating system
switch os := runtime.GOOS; os {
case "linux", "windows", "darwin":
// Check if ssh exists
_, err := exec.LookPath("ssh") // locate a program in the user's path
if err != nil {
log.Println("SSH is not installed. Please install OpenSSH client.")
return err
}

// Create a new exec.Command to run the SSH command. The command checks if the directory exists on the remote server.
// The "-q" option suppresses all warnings, "-l" specifies the login name on the remote server.
cmd = execCommand("ssh", "-q", "-l", username, ARCHIVEServer, "test", "-d", sourceFolder)
default:
log.Printf("%s is not supported.\n", os)
return errors.New("unsupported operating system")
}

// Redirect the command's standard error to the process's standard error.
// This means that any error messages from the command will be displayed in the terminal.
cmd.Stderr = os.Stderr

// Log the command that is being run for debugging purposes.
log.Printf("Running %v.\n", cmd.Args)

// Run the command and return any error that occurs.
err = cmd.Run()
return err
}
102 changes: 102 additions & 0 deletions datasetIngestor/checkDataCentrallyAvailable_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package datasetIngestor

import (
"errors"
"fmt"
"os"
"os/exec"
"reflect"
"strconv"
"testing"
)

// Mock for exec.Command
type execCommandMock struct {
expectedArgs []string
returnError error
}

func (m *execCommandMock) Command(name string, arg ...string) *exec.Cmd {
if !reflect.DeepEqual(arg, m.expectedArgs) {
panic(fmt.Sprintf("unexpected arguments: got %v, want %v", arg, m.expectedArgs))
}

cs := []string{"-test.run=TestHelperProcess", "--", name}
cs = append(cs, arg...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}

if m.returnError != nil {
cmd.Env = append(cmd.Env, "EXIT_STATUS=1")
} else {
cmd.Env = append(cmd.Env, "EXIT_STATUS=0")
}

return cmd
}

// TestHelperProcess isn't a real test. It's used as a helper process
func TestHelperProcess(t *testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
fmt.Fprintf(os.Stdout, "output")
fmt.Fprintf(os.Stderr, "error")
exitStatus, _ := strconv.Atoi(os.Getenv("EXIT_STATUS"))
os.Exit(exitStatus)
}

func TestCheckDataCentrallyAvailable(t *testing.T) {
tests := []struct {
name string
username string
archiveServer string
sourceFolder string
wantErr bool
errMsg string
}{
{
name: "test data centrally available",
username: "testuser",
archiveServer: "testserver",
sourceFolder: "/test/folder",
wantErr: false,
},
{
name: "test data not available",
username: "testuser",
archiveServer: "testserver",
sourceFolder: "/nonexistent/folder",
wantErr: true,
errMsg: "exit status 1",
},
// Add more test cases here.
}

for _, tt := range tests {
expectedArgs := []string{"-q", "-l", tt.username, tt.archiveServer, "test", "-d", tt.sourceFolder}

var returnError error
if tt.wantErr {
returnError = errors.New(tt.errMsg)
}

// Replace exec.Command with a mock
oldExecCommand := execCommand
execCommand = (&execCommandMock{
expectedArgs: expectedArgs,
returnError: returnError,
}).Command
defer func() { execCommand = oldExecCommand }()

t.Run(tt.name, func(t *testing.T) {
err := CheckDataCentrallyAvailable(tt.username, tt.archiveServer, tt.sourceFolder)
if (err != nil) != tt.wantErr {
t.Errorf("CheckDataCentrallyAvailable() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil && tt.wantErr && err.Error() != tt.errMsg {
t.Errorf("CheckDataCentrallyAvailable() errMsg = %v, wantErrMsg %v", err.Error(), tt.errMsg)
}
})
}
}
19 changes: 0 additions & 19 deletions datasetIngestor/testDataCentrallyAvailable.go

This file was deleted.

0 comments on commit 9efbc26

Please sign in to comment.