// Return a reverse proxy that forwards requests to the given port. func NewHarness() *Harness { // Get a template loader to render errors. // Prefer the app's views/errors directory, and fall back to the stock error pages. revel.MainTemplateLoader = revel.NewTemplateLoader( []string{path.Join(revel.RevelPath, "templates")}) revel.MainTemplateLoader.Refresh() addr := revel.HttpAddr port := revel.Config.IntDefault("harness.port", 0) if port == 0 { port = getFreePort() } serverUrl, _ := url.ParseRequestURI(fmt.Sprintf("http://%s:%d", addr, port)) harness := &Harness{ port: port, serverHost: serverUrl.String()[len("http://"):], proxy: httputil.NewSingleHostReverseProxy(serverUrl), } return harness }
func testApp(args []string) { var err error if len(args) == 0 { errorf("No import path given.\nRun 'revel help test' for usage.\n") } mode := "dev" if len(args) == 2 { mode = args[1] } // Find and parse app.conf revel.Init(mode, args[0], "") // Ensure that the testrunner is loaded in this mode. testRunnerFound := false for _, module := range revel.Modules { if module.ImportPath == "github.com/pyanfield/revel/modules/testrunner" { testRunnerFound = true break } } if !testRunnerFound { errorf(`Error: The testrunner module is not running. You can add it to a run mode configuration with the following line: module.testrunner = github.com/pyanfield/revel/modules/testrunner `) } // Create a directory to hold the test result files. resultPath := path.Join(revel.BasePath, "test-results") if err = os.RemoveAll(resultPath); err != nil { errorf("Failed to remove test result directory %s: %s", resultPath, err) } if err = os.Mkdir(resultPath, 0777); err != nil { errorf("Failed to create test result directory %s: %s", resultPath, err) } // Direct all the output into a file in the test-results directory. file, err := os.OpenFile(path.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { errorf("Failed to create log file: %s", err) } app, reverr := harness.Build() if reverr != nil { errorf("Error building: %s", reverr) } cmd := app.Cmd() cmd.Stderr = file cmd.Stdout = file // Start the app... cmd.Start() defer cmd.Kill() revel.INFO.Printf("Testing %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode) // Get a list of tests. var testSuites []controllers.TestSuiteDesc baseUrl := fmt.Sprintf("http://127.0.0.1:%d", revel.HttpPort) resp, err := http.Get(baseUrl + "/@tests.list") if err != nil { errorf("Failed to request test list: %s", err) } defer resp.Body.Close() json.NewDecoder(resp.Body).Decode(&testSuites) fmt.Printf("\n%d test suite%s to run.\n", len(testSuites), pluralize(len(testSuites), "", "s")) fmt.Println() // Load the result template, which we execute for each suite. TemplateLoader := revel.NewTemplateLoader(revel.TemplatePaths) if err := TemplateLoader.Refresh(); err != nil { errorf("Failed to compile templates: %s", err) } resultTemplate, err := TemplateLoader.Template("TestRunner/SuiteResult.html") if err != nil { errorf("Failed to load suite result template: %s", err) } // Run each suite. overallSuccess := true for _, suite := range testSuites { // Print the name of the suite we're running. name := suite.Name if len(name) > 22 { name = name[:19] + "..." } fmt.Printf("%-22s", name) // Run every test. startTime := time.Now() suiteResult := controllers.TestSuiteResult{Name: suite.Name, Passed: true} for _, test := range suite.Tests { testUrl := baseUrl + "/@tests/" + suite.Name + "/" + test.Name resp, err := http.Get(testUrl) if err != nil { errorf("Failed to fetch test result at url %s: %s", testUrl, err) } defer resp.Body.Close() var testResult controllers.TestResult json.NewDecoder(resp.Body).Decode(&testResult) if !testResult.Passed { suiteResult.Passed = false } suiteResult.Results = append(suiteResult.Results, testResult) } overallSuccess = overallSuccess && suiteResult.Passed // Print result. (Just PASSED or FAILED, and the time taken) suiteResultStr, suiteAlert := "PASSED", "" if !suiteResult.Passed { suiteResultStr, suiteAlert = "FAILED", "!" } fmt.Printf("%8s%3s%6ds\n", suiteResultStr, suiteAlert, int(time.Since(startTime).Seconds())) // Create the result HTML file. suiteResultFilename := path.Join(resultPath, fmt.Sprintf("%s.%s.html", suite.Name, strings.ToLower(suiteResultStr))) suiteResultFile, err := os.Create(suiteResultFilename) if err != nil { errorf("Failed to create result file %s: %s", suiteResultFilename, err) } if err = resultTemplate.Render(suiteResultFile, suiteResult); err != nil { errorf("Failed to render result template: %s", err) } } fmt.Println() if overallSuccess { writeResultFile(resultPath, "result.passed", "passed") fmt.Println("All Tests Passed.") } else { writeResultFile(resultPath, "result.failed", "failed") errorf("Some tests failed. See file://%s for results.", resultPath) } }