github.com/jrossiter/goscpwrap@v0.0.0-20160212105001-e15fae0c2306/src/goscp/goscp_test.go (about)

     1  package goscp
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"log"
    10  	"os"
    11  	"path/filepath"
    12  	"reflect"
    13  	"regexp"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  var (
    19  	// Items created during testing
    20  	created []string
    21  )
    22  
    23  func TestMain(m *testing.M) {
    24  	setUp()
    25  
    26  	code := m.Run()
    27  
    28  	tearDown()
    29  
    30  	os.Exit(code)
    31  }
    32  
    33  func setUp() {
    34  	err := os.Chdir(os.TempDir())
    35  	if err != nil {
    36  		log.Fatal(err)
    37  	}
    38  
    39  	log.Println("Running tests in:", os.TempDir())
    40  }
    41  
    42  func tearDown() {
    43  	for _, v := range created {
    44  		os.Remove(v)
    45  	}
    46  }
    47  
    48  func expectedError(t *testing.T, received, expected interface{}) {
    49  	t.Errorf("received: %q, expected: %q", received, expected)
    50  }
    51  
    52  func TestUpDirectory(t *testing.T) {
    53  	tests := []struct {
    54  		Input    []string
    55  		Expected []string
    56  	}{
    57  		{
    58  			// Up one directory
    59  			Input:    []string{"one", "two", "three"},
    60  			Expected: []string{"one", "two"},
    61  		},
    62  		{
    63  			// Up one directory
    64  			Input:    []string{"one"},
    65  			Expected: []string{},
    66  		},
    67  		{
    68  			// Current directory
    69  			Input:    []string{},
    70  			Expected: []string{},
    71  		},
    72  	}
    73  
    74  	c := Client{}
    75  	for _, v := range tests {
    76  		c.DestinationPath = v.Input
    77  		c.upDirectory()
    78  
    79  		// Check paths match
    80  		if !reflect.DeepEqual(c.DestinationPath, v.Expected) {
    81  			expectedError(t, c.DestinationPath, v.Expected)
    82  		}
    83  	}
    84  }
    85  
    86  func TestParseMessage(t *testing.T) {
    87  	tests := []struct {
    88  		Input         string
    89  		Regex         *regexp.Regexp
    90  		Expected      map[string]string
    91  		ExpectedError string
    92  	}{
    93  		{
    94  			// Create file message
    95  			Input: "C0644 25 helloworld.txt",
    96  			Regex: fileCopyRx,
    97  			Expected: map[string]string{
    98  				"":         "C0644 25 helloworld.txt",
    99  				"mode":     "0644",
   100  				"length":   "25",
   101  				"filename": "helloworld.txt",
   102  			},
   103  		},
   104  		{
   105  			// Create directory message
   106  			Input: "D0755 0 mydir",
   107  			Regex: dirCopyRx,
   108  			Expected: map[string]string{
   109  				"":        "D0755 0 mydir",
   110  				"mode":    "0755",
   111  				"length":  "0",
   112  				"dirname": "mydir",
   113  			},
   114  		},
   115  		{
   116  			// Timestamp message
   117  			Input: "T1234567890 0 9876543210 0",
   118  			Regex: timestampRx,
   119  			Expected: map[string]string{
   120  				"":      "T1234567890 0 9876543210 0",
   121  				"mtime": "1234567890",
   122  				"atime": "9876543210",
   123  			},
   124  		},
   125  		{
   126  			// Invalid message
   127  			Input:         "Invalid msg",
   128  			Regex:         fileCopyRx,
   129  			ExpectedError: "Could not parse protocol message: Invalid msg",
   130  		},
   131  	}
   132  
   133  	c := Client{}
   134  	for _, v := range tests {
   135  		output, err := c.parseMessage(v.Input, v.Regex)
   136  		if err != nil {
   137  			if err.Error() != v.ExpectedError {
   138  				expectedError(t, err, v.ExpectedError)
   139  			}
   140  			continue
   141  		}
   142  
   143  		// Check parts match
   144  		if !reflect.DeepEqual(output, v.Expected) {
   145  			expectedError(t, output, v.Expected)
   146  		}
   147  	}
   148  }
   149  
   150  func TestDirectory(t *testing.T) {
   151  	uts := time.Now().Unix()
   152  	dirName := fmt.Sprintf("%s-%v", "goscp-mydir", uts)
   153  
   154  	tests := []struct {
   155  		StartPath               string
   156  		InputPath               string
   157  		ExpectedPath            string
   158  		ExpectedDestinationPath []string
   159  	}{
   160  		{
   161  			// Directory message
   162  			StartPath:               ".",
   163  			InputPath:               fmt.Sprintf("D0755 0 %s", dirName),
   164  			ExpectedPath:            dirName,
   165  			ExpectedDestinationPath: []string{".", dirName},
   166  		},
   167  	}
   168  
   169  	for _, v := range tests {
   170  		c := Client{}
   171  		c.SetDestinationPath(v.StartPath)
   172  		c.directory(v.InputPath)
   173  
   174  		// Check dir was created
   175  		path := filepath.Join(c.DestinationPath...)
   176  		if _, err := os.Stat(path); os.IsNotExist(err) {
   177  			expectedError(t, err, path)
   178  			continue
   179  		}
   180  		created = append(created, path)
   181  
   182  		// Check destination paths match
   183  		if !reflect.DeepEqual(c.DestinationPath, v.ExpectedDestinationPath) {
   184  			expectedError(t, c.DestinationPath, v.ExpectedDestinationPath)
   185  		}
   186  	}
   187  }
   188  
   189  func TestFile(t *testing.T) {
   190  	uts := time.Now().Unix()
   191  	fileName := fmt.Sprintf("%s-%v", "goscp-test-file", uts)
   192  	fileContent := "hello world"
   193  
   194  	tests := []struct {
   195  		StartPath    string
   196  		InputPath    string
   197  		FileContent  string
   198  		ExpectedPath string
   199  	}{
   200  		{
   201  			// File message
   202  			StartPath:    ".",
   203  			InputPath:    fmt.Sprintf("C0755 %d %s", len(fileContent), fileName),
   204  			FileContent:  fileContent,
   205  			ExpectedPath: fileName,
   206  		},
   207  		{
   208  			// Empty file message
   209  			StartPath:    ".",
   210  			InputPath:    fmt.Sprintf("C0755 %d %s", 0, fileName),
   211  			FileContent:  "",
   212  			ExpectedPath: fileName,
   213  		},
   214  	}
   215  
   216  	for _, v := range tests {
   217  		c := Client{}
   218  		c.SetDestinationPath(v.StartPath)
   219  
   220  		dummy := bytes.NewBuffer([]byte(v.FileContent))
   221  		rdr := &readCanceller{Reader: bufio.NewReader(dummy)}
   222  		c.scpStdoutPipe = rdr
   223  
   224  		c.file(v.InputPath)
   225  
   226  		// Check file was created
   227  		if _, err := os.Stat(v.ExpectedPath); os.IsNotExist(err) {
   228  			expectedError(t, err, v.ExpectedPath)
   229  			continue
   230  		}
   231  
   232  		// Check file content
   233  		bytes, _ := ioutil.ReadFile(v.ExpectedPath)
   234  		if string(bytes) != v.FileContent {
   235  			expectedError(t, string(bytes), v.FileContent)
   236  		}
   237  
   238  		os.Remove(v.ExpectedPath)
   239  	}
   240  }
   241  
   242  func TestHandleItem(t *testing.T) {
   243  	tests := []struct {
   244  		Type                    string
   245  		Name                    string
   246  		Content                 []byte
   247  		ExpectedMessages        []string
   248  		DestinationPath         []string
   249  		ExpectedDestinationPath []string
   250  	}{
   251  		{
   252  			// File creation
   253  			Type:    "file",
   254  			Name:    "goscp-test-content.txt",
   255  			Content: []byte("hello-world test text\n"),
   256  			ExpectedMessages: []string{
   257  				"C0644 22 goscp-test-content.txt\n",
   258  				"hello-world test text\n",
   259  				"\x00\n",
   260  			},
   261  		},
   262  		{
   263  			// Empty file creation
   264  			Type:    "file",
   265  			Name:    "goscp-test-content.txt",
   266  			Content: []byte(""),
   267  			ExpectedMessages: []string{
   268  				"C0644 0 goscp-test-content.txt\n",
   269  				"\x00\n",
   270  			},
   271  		},
   272  
   273  		{
   274  			// Directory creation and traversing upward
   275  			Type: "directory",
   276  			Name: "goscp-test-dir/two",
   277  			ExpectedMessages: []string{
   278  				"E\n",
   279  				"E\n",
   280  				"D0644 0 two\n",
   281  			},
   282  			DestinationPath:         []string{"goscp-test-dir", "hello", "one"},
   283  			ExpectedDestinationPath: []string{"goscp-test-dir/two"},
   284  		},
   285  		{
   286  			// Directory creation in same level
   287  			Type: "directory",
   288  			Name: "goscp-test-dir/one",
   289  			ExpectedMessages: []string{
   290  				"E\n",
   291  				"D0644 0 one\n",
   292  			},
   293  			DestinationPath:         []string{"goscp-test-dir", "two"},
   294  			ExpectedDestinationPath: []string{"goscp-test-dir/one"},
   295  		},
   296  		{
   297  			// Directory creation in traversing downward
   298  			Type: "directory",
   299  			Name: "goscp-test-dir/one/two",
   300  			ExpectedMessages: []string{
   301  				"D0644 0 two\n",
   302  			},
   303  			DestinationPath:         []string{"goscp-test-dir", "one"},
   304  			ExpectedDestinationPath: []string{"goscp-test-dir/one/two"},
   305  		},
   306  		{
   307  			// Directory creation
   308  			Type: "directory",
   309  			Name: "goscp-test-dir",
   310  			ExpectedMessages: []string{
   311  				"E\n",
   312  				"D0644 0 goscp-test-dir\n",
   313  			},
   314  			DestinationPath:         []string{"."},
   315  			ExpectedDestinationPath: []string{"goscp-test-dir"},
   316  		},
   317  	}
   318  
   319  	for _, v := range tests {
   320  		r, w := io.Pipe()
   321  		c := Client{
   322  			scpStdinPipe:    w,
   323  			ShowProgressBar: false,
   324  		}
   325  
   326  		filePath := v.Name
   327  		var stats os.FileInfo
   328  		if v.Type == "file" {
   329  			f, err := os.Create(filePath)
   330  			if err != nil {
   331  				t.Error("Unexpected error:", err)
   332  			}
   333  
   334  			f.Write(v.Content)
   335  			f.Close()
   336  		} else if v.Type == "directory" {
   337  			err := os.MkdirAll(filePath, 0755)
   338  			if err != nil {
   339  				t.Error("Unexpected error:", err)
   340  			}
   341  
   342  			c.DestinationPath = v.DestinationPath
   343  		}
   344  
   345  		created = append(created, filePath)
   346  		stats, _ = os.Stat(filePath)
   347  
   348  		go func() {
   349  			br := bufio.NewReader(r)
   350  
   351  			msgCounter := 0
   352  			for {
   353  				msg, err := br.ReadString('\n')
   354  				if err != nil {
   355  					t.Error("Unexpected error:", err)
   356  					break
   357  				}
   358  
   359  				if msg != v.ExpectedMessages[msgCounter] {
   360  					expectedError(t, msg, v.ExpectedMessages[msgCounter])
   361  				}
   362  
   363  				msgCounter++
   364  			}
   365  		}()
   366  
   367  		err := c.handleItem(filePath, stats, nil)
   368  		if err != nil {
   369  			t.Error("Unexpected error:", err)
   370  		}
   371  
   372  		if v.Type == "file" {
   373  			// Output one more newline for convenience in reading from the pipe
   374  			fmt.Fprintf(c.scpStdinPipe, "\n")
   375  		} else if v.Type == "directory" {
   376  			if !reflect.DeepEqual(c.DestinationPath, v.ExpectedDestinationPath) {
   377  				expectedError(t, c.DestinationPath, v.ExpectedDestinationPath)
   378  			}
   379  		}
   380  
   381  		os.Remove(filePath)
   382  	}
   383  }
   384  
   385  func TestCancel(t *testing.T) {
   386  	// Send creation message
   387  	// Cancel
   388  	// Send another creation message
   389  	testsMessages := []string{
   390  		"C0644 15 goscp-cancel.txt",
   391  		"Cancel incoming\x00",
   392  		"C0644 15 goscp-cancel.txt",
   393  		"Transfer cancelled",
   394  		"io: read/write on closed pipe",
   395  	}
   396  
   397  	r, w := io.Pipe()
   398  	c := Client{
   399  		scpStdinPipe:    w,
   400  		ShowProgressBar: false,
   401  	}
   402  
   403  	filePath := "goscp-cancel.txt"
   404  	f, err := os.Create(filePath)
   405  	if err != nil {
   406  		t.Error("Unexpected error:", err)
   407  	}
   408  
   409  	f.Write([]byte("Cancel incoming"))
   410  	f.Close()
   411  
   412  	created = append(created, filePath)
   413  	stats, _ := os.Stat(filePath)
   414  	msgCounter := 0
   415  
   416  	go func() {
   417  		c.scpStdoutPipe = &readCanceller{
   418  			Reader: bufio.NewReader(r),
   419  			cancel: make(chan struct{}, 1),
   420  		}
   421  
   422  		scanner := bufio.NewScanner(c.scpStdoutPipe)
   423  
   424  		for scanner.Scan() {
   425  			txt := scanner.Text()
   426  
   427  			if txt != testsMessages[msgCounter] {
   428  				expectedError(t, txt, testsMessages[msgCounter])
   429  			}
   430  			msgCounter++
   431  		}
   432  
   433  		err := scanner.Err()
   434  		if err != nil {
   435  			if err.Error() != testsMessages[msgCounter] {
   436  				expectedError(t, err.Error(), testsMessages[msgCounter])
   437  			}
   438  			msgCounter++
   439  		}
   440  		c.scpStdinPipe.Close()
   441  	}()
   442  
   443  	err = c.handleItem(filePath, stats, nil)
   444  	if err != nil {
   445  		t.Error("Unexpected error:", err)
   446  	}
   447  
   448  	// Output one more newline for convenience in reading from the pipe
   449  	fmt.Fprintf(c.scpStdinPipe, "\n")
   450  
   451  	go c.Cancel()
   452  
   453  	time.Sleep(time.Millisecond * 100)
   454  
   455  	err = c.handleItem(filePath, stats, nil)
   456  	if err != nil {
   457  		if err.Error() != testsMessages[msgCounter] {
   458  			expectedError(t, err.Error(), testsMessages[msgCounter])
   459  		}
   460  		msgCounter++
   461  	}
   462  
   463  	// Output one more newline for convenience in reading from the pipe
   464  	fmt.Fprintf(c.scpStdinPipe, "\n")
   465  }