github.com/taubyte/tau-cli@v0.1.13-0.20240326000942-487f0d57edfc/tests/utils_monkey_test.go (about)

     1  package tests
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/pterm/pterm"
    13  	"github.com/spf13/afero"
    14  	"github.com/taubyte/go-project-schema/project"
    15  	"github.com/taubyte/tau-cli/common"
    16  	"github.com/taubyte/tau-cli/singletons/session"
    17  	"gotest.tools/v3/assert"
    18  )
    19  
    20  func newMonkey(s *spiderTestContext, tm testMonkey) *monkeyTestContext {
    21  	return &monkeyTestContext{
    22  		spider:     s,
    23  		testMonkey: tm,
    24  	}
    25  }
    26  
    27  func newMonkeyRunContext(tm testMonkey, rr roadRunner, isChild bool) *monkeyRunContext {
    28  	prefix := "Command"
    29  	if isChild {
    30  		prefix = "Child-Command"
    31  	}
    32  
    33  	return &monkeyRunContext{
    34  		prefix:     prefix,
    35  		testMonkey: tm,
    36  		rr:         rr,
    37  		isChild:    isChild,
    38  	}
    39  }
    40  
    41  func (ctx *monkeyRunContext) checkSession(t *testing.T, result *commandResult) {
    42  	if ctx.evaluateSession != nil {
    43  		sessionLock.Lock()
    44  		defer sessionLock.Unlock()
    45  
    46  		err := session.LoadSessionInDir(ctx.rr.sessionFile)
    47  		if err != nil {
    48  			t.Errorf("loading session at `%s` failed with: %s", ctx.rr.sessionFile, err)
    49  			return
    50  		}
    51  
    52  		err = ctx.evaluateSession(session.Get())
    53  		if err != nil {
    54  			result.Error(t, fmt.Sprintf("Session evaluation failed with: %s", err.Error()))
    55  			return
    56  		}
    57  	}
    58  }
    59  
    60  func (ctx *monkeyRunContext) checkProject(t *testing.T) {
    61  	if ctx.confirmProject != nil {
    62  		_project, err := project.Open(project.VirtualFS(afero.NewOsFs(), path.Join(ctx.rr.dir, "test_project/config")))
    63  		if err != nil {
    64  			panic(err)
    65  		}
    66  
    67  		err = ctx.confirmProject(_project)
    68  		if err != nil {
    69  			t.Errorf("\n\nConfirming project failed with error: %s\n\n", err)
    70  			return
    71  		}
    72  	}
    73  }
    74  
    75  func (ctx *monkeyRunContext) Run(t *testing.T) {
    76  	result := &commandResult{
    77  		monkeyRunContext: ctx,
    78  	}
    79  	result.err, result.exitCode, result.out1, result.out2 = ctx.rr.Run(ctx.args...)
    80  	result.printDebugInfo()
    81  
    82  	// confirm error is as expected, either nil or containing string
    83  	result.checkError(t)
    84  
    85  	// confirm wantOut and dontWantOut
    86  	result.checkWantOut(t)
    87  
    88  	// Check exit code, defaults 0
    89  	result.checkExitCode(t)
    90  
    91  	// confirm wantDir and dontWantDir
    92  	result.checkDirectories(t)
    93  
    94  	// Run confirmProject
    95  	ctx.checkProject(t)
    96  
    97  	// Run evaluateSession
    98  	ctx.checkSession(t, result)
    99  }
   100  
   101  func (tm *monkeyTestContext) setParallel(t *testing.T) {
   102  	if tm.spider.parallel {
   103  		t.Parallel()
   104  	}
   105  }
   106  
   107  func (tm *monkeyTestContext) getOrCreateDir() (err error) {
   108  	// Create temp configFile
   109  	if tm.spider.debug {
   110  		tm.dir = "./_fakeroot/debug/" + tm.name
   111  	} else {
   112  		tm.dir, err = os.MkdirTemp("_fakeroot", "tests")
   113  		if err != nil {
   114  			return err
   115  		}
   116  	}
   117  
   118  	// Transform dir to an absolute
   119  	tm.dir, err = filepath.Abs(tm.dir)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	// Define the location of the config file
   125  	// in the temp directory, or named directory if in
   126  	// debug mode
   127  	tm.configLoc, _ = filepath.Abs(tm.dir + "/tau.yaml")
   128  	tm.sessionLoc, _ = filepath.Abs(tm.dir + "/session")
   129  
   130  	return nil
   131  }
   132  
   133  func (tm *monkeyTestContext) refreshTestFiles() error {
   134  	// Remove previous debug files, as they don't get removed
   135  	// when debugging
   136  	if tm.spider.debug {
   137  		os.Remove(tm.configLoc)
   138  		os.Remove(tm.sessionLoc)
   139  		os.RemoveAll(tm.dir)
   140  	}
   141  
   142  	// Create the project config and code directories for testing
   143  	if tm.spider.projectName != "" {
   144  		err := os.MkdirAll(fmt.Sprintf("%s/%s/config", tm.dir, tm.spider.projectName), 0755)
   145  		if err != nil {
   146  			return err
   147  		}
   148  
   149  		err = os.MkdirAll(fmt.Sprintf("%s/%s/code", tm.dir, tm.spider.projectName), 0755)
   150  		if err != nil {
   151  			return err
   152  		}
   153  	} else {
   154  		err := os.MkdirAll(tm.dir, 0755)
   155  		if err != nil {
   156  			return err
   157  		}
   158  	}
   159  
   160  	return nil
   161  }
   162  
   163  func (tm *monkeyTestContext) Run(t *testing.T) {
   164  	defer func() {
   165  		if tm.cleanUp != nil {
   166  			assert.NilError(t, tm.cleanUp())
   167  		}
   168  		pterm.Info.Printfln("%s is done.", tm.name)
   169  	}()
   170  
   171  	tm.setParallel(t)
   172  
   173  	// Call a function to clear vars and lock
   174  	// TODO do this better, as of 1.20 we can test coverage with a binary rather than this hack
   175  	deferment := takeCover()
   176  	defer deferment()
   177  
   178  	err := tm.getOrCreateDir()
   179  	assert.NilError(t, err)
   180  
   181  	// Remove old test files, create the new directories, and test tm values for relative directories
   182  	err = tm.refreshTestFiles()
   183  	assert.NilError(t, err)
   184  
   185  	// Write the test config based on a spider supplied config method
   186  	err = tm.spider.writeConfig(tm.dir, tm.configLoc)
   187  	assert.NilError(t, err)
   188  
   189  	// Write the session dir for tests in which values will not be set, but seer still needs to open
   190  	err = os.Mkdir(tm.sessionLoc, common.DefaultDirPermission)
   191  	assert.NilError(t, err)
   192  
   193  	// Set selected project in the session
   194  	err = tm.setSessionProject()
   195  	assert.NilError(t, err)
   196  
   197  	// Call a provided method to write files to the temp directory
   198  	if tm.writeFilesInDir != nil {
   199  		tm.writeFilesInDir(tm.dir)
   200  	}
   201  
   202  	// Make sure env is not nil
   203  	if tm.env == nil {
   204  		tm.env = make(map[string]string, 0)
   205  	}
   206  
   207  	// Set the default wait time if none is set
   208  	if tm.waitTime == 0 {
   209  		tm.waitTime = 30 * time.Second
   210  	}
   211  
   212  	// Start the mock server and get the url
   213  	if tm.mock {
   214  		// TODO dreamland
   215  
   216  		// // get a random port 1024 to 65353 and start it
   217  		port := fmt.Sprintf("%v", random.Intn(64329)+1024)
   218  		tm.authUrl = "http://localhost:" + port
   219  		mockServerStop := startMockOnPort(port)
   220  
   221  		// wait for mock server to start
   222  		// TODO, check ping the port
   223  		time.Sleep(1500 * time.Millisecond)
   224  
   225  		if tm.debug {
   226  			fmt.Println("Started mock on", tm.authUrl)
   227  		}
   228  		defer func() {
   229  			mockServerStop()
   230  			// Give the server a moment to shut down
   231  			time.Sleep(500 * time.Millisecond)
   232  		}()
   233  	} else {
   234  		tm.authUrl = "https://auth.tau.sandbox.taubyte.com"
   235  	}
   236  
   237  	rr := roadRunner{
   238  		configFile:  tm.configLoc,
   239  		sessionFile: tm.sessionLoc,
   240  		authUrl:     tm.authUrl,
   241  		waitTime:    tm.waitTime,
   242  		env:         tm.env,
   243  		dir:         tm.dir,
   244  	}
   245  
   246  	// run preRun commands
   247  	tm.runPreRun(t, rr)
   248  
   249  	tm.runBabyMonkeys(t, rr)
   250  
   251  	// run main command
   252  	newMonkeyRunContext(tm.testMonkey, rr, false).Run(t)
   253  
   254  	// Cleanup
   255  	if !tm.spider.debug {
   256  		os.Remove(tm.configLoc)
   257  		os.RemoveAll(tm.dir)
   258  	}
   259  }
   260  
   261  func (tm *monkeyTestContext) setSessionProject() error {
   262  	projectName := tm.spider.projectName
   263  
   264  	if projectName == "" {
   265  		return nil
   266  	}
   267  	sessionLock.Lock()
   268  	defer sessionLock.Unlock()
   269  
   270  	err := session.LoadSessionInDir(tm.sessionLoc)
   271  	if err != nil {
   272  		return fmt.Errorf("loading session at `%s` failed with: %s", tm.sessionLoc, err)
   273  	}
   274  
   275  	err = session.Set().SelectedProject(projectName)
   276  	if err != nil {
   277  		return fmt.Errorf("setting selected project to `%s` failed with: %s", projectName, err)
   278  	}
   279  
   280  	return nil
   281  }
   282  
   283  func (tm *monkeyTestContext) runPreRun(t *testing.T, rr roadRunner) {
   284  	runBefore := tm.spider.getBeforeEach(tm.testMonkey)
   285  
   286  	if tm.preRun != nil {
   287  		runBefore = append(runBefore, tm.preRun...)
   288  	}
   289  	for _, _args := range runBefore {
   290  		err, exitCode, out1, out2 := rr.Run(_args...)
   291  		if err != nil {
   292  			t.Errorf("RunBefore(%s) failed with error: %s \nOut1 %s:\n %s\nOut2:%s \n(%s)", _args, err, rr.dir, out1, out2, tm.name)
   293  			return
   294  		}
   295  
   296  		if tm.debug {
   297  			pterm.FgLightYellow.Println("RunBefore args:")
   298  			fmt.Print(cleanArgs(_args), "\n\n")
   299  
   300  			pterm.FgLightYellow.Print("RunBefore exitCode: ")
   301  			fmt.Print(exitCode, "\n\n")
   302  
   303  			pterm.FgLightYellow.Println("RunBefore Out:")
   304  			fmt.Println(out1)
   305  
   306  			pterm.FgLightYellow.Println("RunBefore Error:")
   307  			fmt.Println(out2)
   308  
   309  			fmt.Print(strings.Repeat("-", 50), "\n\n")
   310  		}
   311  	}
   312  }