github.com/jkawamoto/roadie-azure@v0.3.5/roadie/script_test.go (about)

     1  //
     2  // roadie/script_test.go
     3  //
     4  // Copyright (c) 2017 Junpei Kawamoto
     5  //
     6  // This file is part of Roadie Azure.
     7  //
     8  // Roadie Azure is free software: you can redistribute it and/or modify
     9  // it under the terms of the GNU General Public License as published by
    10  // the Free Software Foundation, either version 3 of the License, or
    11  // (at your option) any later version.
    12  //
    13  // Roadie Azure is distributed in the hope that it will be useful,
    14  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  // GNU General Public License for more details.
    17  //
    18  // You should have received a copy of the GNU General Public License
    19  // along with Roadie Azure. If not, see <http://www.gnu.org/licenses/>.
    20  //
    21  
    22  package roadie
    23  
    24  import (
    25  	"bytes"
    26  	"context"
    27  	"fmt"
    28  	"io/ioutil"
    29  	"log"
    30  	"os"
    31  	"os/exec"
    32  	"path/filepath"
    33  	"strings"
    34  	"testing"
    35  
    36  	"github.com/jkawamoto/roadie/cloud/azure"
    37  	"github.com/jkawamoto/roadie/cloud/azure/mock"
    38  	"github.com/jkawamoto/roadie/script"
    39  )
    40  
    41  func TestPrepareSourceCode(t *testing.T) {
    42  
    43  	ctx := context.Background()
    44  	output := bytes.NewBuffer(nil)
    45  	s := Script{
    46  		Script: new(script.Script),
    47  		Logger: log.New(output, "", log.LstdFlags),
    48  	}
    49  
    50  	t.Run("empty source", func(t *testing.T) {
    51  		output.Reset()
    52  		err := s.PrepareSourceCode(ctx)
    53  		if err != nil {
    54  			t.Fatalf("PrepareSourceCode returns an error: %v", err)
    55  		}
    56  	})
    57  
    58  	t.Run("git source", func(t *testing.T) {
    59  		output.Reset()
    60  
    61  		temp, err := ioutil.TempDir("", "")
    62  		if err != nil {
    63  			t.Fatalf("cannot create a temporary directory: %v", err)
    64  		}
    65  		defer os.RemoveAll(temp)
    66  		wd, err := os.Getwd()
    67  		if err != nil {
    68  			t.Fatalf("cannot get the working directory: %v", err)
    69  		}
    70  		err = os.Chdir(temp)
    71  		if err != nil {
    72  			t.Fatalf("cannot change the current directory: %v", err)
    73  		}
    74  		defer os.Chdir(wd)
    75  
    76  		err = ioutil.WriteFile("test-file", []byte("aaa"), 0666)
    77  		if err != nil {
    78  			t.Errorf("cannot create a dummy file: %v", err)
    79  		}
    80  
    81  		s.Source = "https://github.com/jkawamoto/roadie-azure.git"
    82  		err = s.PrepareSourceCode(ctx)
    83  		if err != nil {
    84  			t.Fatalf("PrepareSourceCode returns an error: %v", err)
    85  		}
    86  		var matches []string
    87  		matches, err = filepath.Glob("roadie/*")
    88  		if err != nil {
    89  			t.Fatalf("Glob returns an error: %v", err)
    90  		}
    91  		for _, f := range matches {
    92  			_, err = os.Stat(filepath.Join(wd, filepath.Base(f)))
    93  			if err != nil {
    94  				t.Errorf("cloned file %q doesn't exist in %q", filepath.Base(f), wd)
    95  			}
    96  		}
    97  		if t.Failed() {
    98  			data, _ := exec.Command("ls", "-la").Output()
    99  			t.Log(string(data))
   100  		}
   101  	})
   102  
   103  	t.Run("dropbox source", func(t *testing.T) {
   104  		output.Reset()
   105  
   106  		temp, err := ioutil.TempDir("", "")
   107  		if err != nil {
   108  			t.Fatalf("cannot create a temporary directory: %v", err)
   109  		}
   110  		defer os.RemoveAll(temp)
   111  		wd, err := os.Getwd()
   112  		if err != nil {
   113  			t.Fatalf("cannot get the working directory: %v", err)
   114  		}
   115  		err = os.Chdir(temp)
   116  		if err != nil {
   117  			t.Fatalf("cannot change the current directory: %v", err)
   118  		}
   119  		defer os.Chdir(wd)
   120  
   121  		s.Source = "dropbox://sh/hlt9248hw1u54d6/AADLBa5TfbZKAacDzoARfFhqa"
   122  		err = s.PrepareSourceCode(ctx)
   123  		if err != nil {
   124  			t.Fatalf("PrepareSourceCode returns an error: %v", err)
   125  		}
   126  		_, err = os.Stat("aaa")
   127  		if err != nil {
   128  			t.Errorf("download source files don't have executable file %q", "aaa")
   129  		}
   130  		if t.Failed() {
   131  			data, _ := exec.Command("ls", "-la").Output()
   132  			t.Log(string(data))
   133  		}
   134  	})
   135  
   136  	t.Run("archived https source", func(t *testing.T) {
   137  		output.Reset()
   138  
   139  		temp, err := ioutil.TempDir("", "")
   140  		if err != nil {
   141  			t.Fatalf("cannot create a temporary directory: %v", err)
   142  		}
   143  		defer os.RemoveAll(temp)
   144  		wd, err := os.Getwd()
   145  		if err != nil {
   146  			t.Fatalf("cannot get the working directory: %v", err)
   147  		}
   148  		err = os.Chdir(temp)
   149  		if err != nil {
   150  			t.Fatalf("cannot change the current directory: %v", err)
   151  		}
   152  		defer os.Chdir(wd)
   153  
   154  		s.Source = "https://github.com/jkawamoto/roadie-azure/releases/download/v0.3.3/roadie-azure_linux_amd64.tar.gz"
   155  		err = s.PrepareSourceCode(ctx)
   156  		if err != nil {
   157  			t.Fatalf("PrepareSourceCode returns an error: %v", err)
   158  		}
   159  		_, err = os.Stat("roadie-azure_linux_amd64/roadie-azure")
   160  		if err != nil {
   161  			t.Errorf("download source files don't have executable file %q", "roadie-azure_linux_amd64/roadie-azure")
   162  		}
   163  		if t.Failed() {
   164  			data, _ := exec.Command("ls", "-la", "roadie-azure_linux_amd64").Output()
   165  			t.Log(string(data))
   166  		}
   167  	})
   168  
   169  	t.Run("plain https source", func(t *testing.T) {
   170  		output.Reset()
   171  
   172  		temp, err := ioutil.TempDir("", "")
   173  		if err != nil {
   174  			t.Fatalf("cannot create a temporary directory: %v", err)
   175  		}
   176  		defer os.RemoveAll(temp)
   177  		wd, err := os.Getwd()
   178  		if err != nil {
   179  			t.Fatalf("cannot get the working directory: %v", err)
   180  		}
   181  		err = os.Chdir(temp)
   182  		if err != nil {
   183  			t.Fatalf("cannot change the current directory: %v", err)
   184  		}
   185  		defer os.Chdir(wd)
   186  
   187  		s.Source = "https://raw.githubusercontent.com/jkawamoto/roadie-azure/master/README.md"
   188  		err = s.PrepareSourceCode(ctx)
   189  		if err != nil {
   190  			t.Fatalf("PrepareSourceCode returns an error: %v", err)
   191  		}
   192  		_, err = os.Stat("README.md")
   193  		if err != nil {
   194  			t.Errorf("download source files don't have executable file %q", "roadie")
   195  		}
   196  		if t.Failed() {
   197  			data, _ := exec.Command("ls", "-la").Output()
   198  			t.Log(string(data))
   199  		}
   200  	})
   201  
   202  	t.Run("archived file source", func(t *testing.T) {
   203  		output.Reset()
   204  
   205  		temp, err := ioutil.TempDir("", "")
   206  		if err != nil {
   207  			t.Fatalf("cannot create a temporary directory: %v", err)
   208  		}
   209  		defer os.RemoveAll(temp)
   210  		wd, err := os.Getwd()
   211  		if err != nil {
   212  			t.Fatalf("cannot get the working directory: %v", err)
   213  		}
   214  		err = os.Chdir(temp)
   215  		if err != nil {
   216  			t.Fatalf("cannot change the current directory: %v", err)
   217  		}
   218  		defer os.Chdir(wd)
   219  
   220  		s.Source = "file://" + filepath.Join(wd, "archive_test.zip")
   221  		err = s.PrepareSourceCode(ctx)
   222  		if err != nil {
   223  			t.Fatalf("PrepareSourceCode returns an error: %v", err)
   224  		}
   225  		_, err = os.Stat("abc.txt")
   226  		if err != nil {
   227  			t.Errorf("prepared source files don't have file %q", "abc.txt")
   228  		}
   229  		if t.Failed() {
   230  			data, _ := exec.Command("ls", "-la").Output()
   231  			t.Log(string(data))
   232  		}
   233  	})
   234  
   235  	t.Run("plain file source", func(t *testing.T) {
   236  		output.Reset()
   237  
   238  		temp, err := ioutil.TempDir("", "")
   239  		if err != nil {
   240  			t.Fatalf("cannot create a temporary directory: %v", err)
   241  		}
   242  		defer os.RemoveAll(temp)
   243  		wd, err := os.Getwd()
   244  		if err != nil {
   245  			t.Fatalf("cannot get the working directory: %v", err)
   246  		}
   247  		err = os.Chdir(temp)
   248  		if err != nil {
   249  			t.Fatalf("cannot change the current directory: %v", err)
   250  		}
   251  		defer os.Chdir(wd)
   252  
   253  		target := "script_test.go"
   254  		s.Source = "file://" + filepath.Join(wd, target)
   255  		err = s.PrepareSourceCode(ctx)
   256  		if err != nil {
   257  			t.Fatalf("PrepareSourceCode returns an error: %v", err)
   258  		}
   259  		_, err = os.Stat(target)
   260  		if err != nil {
   261  			t.Errorf("prepared source files don't have file %q", target)
   262  		}
   263  		if t.Failed() {
   264  			data, _ := exec.Command("ls", "-la").Output()
   265  			t.Log(string(data))
   266  		}
   267  	})
   268  
   269  }
   270  
   271  func TestDownloadDataFiles(t *testing.T) {
   272  
   273  	dir, err := ioutil.TempDir("", "")
   274  	if err != nil {
   275  		t.Fatalf("cannot create a temporary directory: %v", err)
   276  	}
   277  	defer os.RemoveAll(dir)
   278  
   279  	script := Script{
   280  		Script: &script.Script{
   281  			Data: []string{
   282  				// Archived file from Dropbox with a destination.
   283  				fmt.Sprintf("dropbox://sh/hlt9248hw1u54d6/AADLBa5TfbZKAacDzoARfFhqa:%v/", dir),
   284  				// Archived file from Dropbox with renaming.
   285  				fmt.Sprintf("dropbox://sh/hlt9248hw1u54d6/AADLBa5TfbZKAacDzoARfFhqa:%v/dropbox.dat", dir),
   286  				// Archived file from a HTTP server with a destination.
   287  				fmt.Sprintf("https://github.com/jkawamoto/roadie-azure/releases/download/v0.3.3/roadie-azure_linux_amd64.tar.gz:%v/", dir),
   288  				// Archived file from a HTTP server with renaming.
   289  				fmt.Sprintf("https://github.com/jkawamoto/roadie-azure/releases/download/v0.3.3/roadie-azure_linux_amd64.tar.gz:%v/sample.dat", dir),
   290  				// Plain file from a HTTP server with a destination.
   291  				fmt.Sprintf("https://raw.githubusercontent.com/jkawamoto/roadie-azure/master/README.md:%v/", dir),
   292  				// Plain file from a HTTP server with renaming.
   293  				fmt.Sprintf("https://raw.githubusercontent.com/jkawamoto/roadie-azure/master/README.md:%v", filepath.Join(dir, "README2.md")),
   294  			},
   295  		},
   296  		Logger: log.New(ioutil.Discard, "", log.Lshortfile),
   297  	}
   298  	expectedFiles := []string{
   299  		"aaa",
   300  		"dropbox.dat",
   301  		"roadie-azure_linux_amd64",
   302  		"sample.dat",
   303  		"README.md",
   304  		"README2.md",
   305  	}
   306  
   307  	err = script.DownloadDataFiles(context.Background())
   308  	if err != nil {
   309  		t.Fatalf("DownloadDataFiles returns an error: %v", err)
   310  	}
   311  	for _, f := range expectedFiles {
   312  		_, err = os.Stat(filepath.Join(dir, f))
   313  		if err != nil {
   314  			t.Errorf("downloaded file %q doesn't exist: %v", f, err)
   315  		}
   316  	}
   317  
   318  }
   319  
   320  func TestUploadResults(t *testing.T) {
   321  
   322  	var err error
   323  	tmp, err := ioutil.TempDir("", "")
   324  	if err != nil {
   325  		t.Fatalf("cannot create a temporary directory: %v", err)
   326  	}
   327  	defer os.RemoveAll(tmp)
   328  
   329  	script := Script{
   330  		Script: &script.Script{
   331  			Name: "task-abc",
   332  			Run: []string{
   333  				"cmd1",
   334  				"cmd2",
   335  			},
   336  			Upload: []string{
   337  				filepath.Join(tmp, "*.txt"),
   338  			},
   339  		},
   340  		Logger: log.New(ioutil.Discard, "", log.LstdFlags),
   341  	}
   342  	var expected []string
   343  
   344  	// Create dummy output files.
   345  	for i := range script.Run {
   346  		filename := filepath.Join("/tmp", fmt.Sprintf("stdout%v.txt", i))
   347  		_, err = os.Stat(filename)
   348  		if err != nil {
   349  			err = ioutil.WriteFile(filename, []byte(filename), 0644)
   350  			if err != nil {
   351  				t.Fatalf("cannot create dummy output file %v: %v", filename, err)
   352  			}
   353  			defer os.Remove(filename)
   354  		}
   355  		expected = append(expected, filepath.Base(filename))
   356  	}
   357  
   358  	// Create dummy other outputs.
   359  	for i := 0; i != 10; i++ {
   360  		filename := filepath.Join(tmp, fmt.Sprintf("output-%v.txt", i))
   361  		err = ioutil.WriteFile(filename, []byte(filename), 0644)
   362  		if err != nil {
   363  			t.Fatalf("cannot create dummy output file %v: %v", filename, err)
   364  		}
   365  		expected = append(expected, filepath.Base(filename))
   366  	}
   367  
   368  	server := mock.NewStorageServer()
   369  	defer server.Close()
   370  
   371  	cli, err := server.GetClient()
   372  	if err != nil {
   373  		t.Fatalf("cannot get a client: %v", err)
   374  	}
   375  
   376  	store := azure.StorageService{
   377  		Client: cli.GetBlobService(),
   378  		Logger: log.New(ioutil.Discard, "", log.LstdFlags),
   379  	}
   380  
   381  	err = script.UploadResults(context.Background(), &store)
   382  	if err != nil {
   383  		t.Fatalf("UploadResults returns an error: %v", err)
   384  	}
   385  	c, ok := server.Items["result"]
   386  	if !ok {
   387  		t.Fatalf("container %q doesn't exist", "result")
   388  	}
   389  	for _, f := range expected {
   390  		name := filepath.Join("abc", f)
   391  		_, ok = c[name]
   392  		if !ok {
   393  			t.Errorf("uploaded file %q doesn't exist", name)
   394  		}
   395  	}
   396  	if t.Failed() {
   397  		t.Log("following files are stored in the cloud storage")
   398  		for key, value := range c {
   399  			t.Logf("%v: %v", key, value)
   400  		}
   401  	}
   402  
   403  }
   404  
   405  func TestDockerfile(t *testing.T) {
   406  
   407  	script := Script{
   408  		Script: &script.Script{
   409  			APT: []string{
   410  				"python-numpy",
   411  				"python-scipy",
   412  			},
   413  		},
   414  	}
   415  
   416  	buf, err := script.Dockerfile()
   417  	if err != nil {
   418  		t.Fatalf("cannot create a dockerfile: %v", err)
   419  	}
   420  
   421  	res := string(buf)
   422  	if !strings.Contains(res, "python-numpy") || !strings.Contains(res, "python-scipy") {
   423  		t.Error("Generated Dockerfile is not correct:", res)
   424  	}
   425  
   426  }
   427  
   428  func TestEntrypoint(t *testing.T) {
   429  
   430  	script := Script{
   431  		Script: &script.Script{
   432  			Run: []string{
   433  				"cmd1",
   434  				"cmd2",
   435  			},
   436  		},
   437  	}
   438  
   439  	buf, err := script.Entrypoint()
   440  	if err != nil {
   441  		t.Fatalf("cannot create an entrypoint: %v", err)
   442  	}
   443  
   444  	res := string(buf)
   445  	if !strings.Contains(res, "cmd1") || !strings.Contains(res, "cmd2") {
   446  		t.Error("Generated entrypoint is not correct:", res)
   447  	}
   448  	if !strings.Contains(res, "stdout0.txt") || !strings.Contains(res, "stdout1.txt") {
   449  		t.Error("Generated entrypoint is not correct:", res)
   450  	}
   451  
   452  }