github.com/mmatczuk/gohan@v0.0.0-20170206152520-30e45d9bdb69/extension/framework/framework.go (about)

     1  // Copyright (C) 2015 NTT Innovation Institute, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package framework
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"path/filepath"
    23  	"regexp"
    24  	"sync"
    25  	"sync/atomic"
    26  
    27  	"github.com/cloudwan/gohan/extension/framework/runner"
    28  	l "github.com/cloudwan/gohan/log"
    29  	"github.com/cloudwan/gohan/schema"
    30  	"github.com/cloudwan/gohan/util"
    31  	"github.com/codegangsta/cli"
    32  )
    33  
    34  var (
    35  	logWriter io.Writer = os.Stderr
    36  	log                 = l.NewLoggerForModule("extest")
    37  )
    38  
    39  // TestExtensions runs extension tests when invoked from Gohan CLI
    40  func TestExtensions(c *cli.Context) {
    41  	l.SetUpBasicLogging(logWriter, l.DefaultFormat, "", l.DEBUG)
    42  
    43  	var config *util.Config
    44  	configFilePath := c.String("config-file")
    45  
    46  	if configFilePath != "" && !c.Bool("verbose") {
    47  		config = util.GetConfig()
    48  		err := config.ReadConfig(configFilePath)
    49  		if err != nil {
    50  			log.Error(fmt.Sprintf("Failed to read config from path %s: %v", configFilePath, err))
    51  			os.Exit(1)
    52  		}
    53  
    54  		err = l.SetUpLogging(config)
    55  		if err != nil {
    56  			log.Error(fmt.Sprintf("Failed to set up logging: %v", err))
    57  			os.Exit(1)
    58  		}
    59  	}
    60  
    61  	testFiles := getTestFiles(c.Args())
    62  
    63  	//logging from config is a limited printAllLogs option
    64  	returnCode := RunTests(testFiles, c.Bool("verbose") || config != nil, c.String("run-test"), c.Int("parallel"))
    65  	os.Exit(returnCode)
    66  }
    67  
    68  // RunTests runs extension tests for CLI.
    69  func RunTests(testFiles []string, printAllLogs bool, testFilter string, workers int) (returnCode int) {
    70  	if !printAllLogs {
    71  		l.SetUpBasicLogging(l.BufWritter{}, l.DefaultFormat, "", l.DEBUG)
    72  	}
    73  
    74  	if workers <= 0 {
    75  		panic("Workers must be greater than 0")
    76  	}
    77  
    78  	if len(testFiles) < workers {
    79  		workers = len(testFiles)
    80  	}
    81  
    82  	var (
    83  		maxIdx         = int64(len(testFiles) - 1)
    84  		idx      int64 = -1
    85  		errors         = make(map[string]runner.TestRunnerErrors)
    86  		errorsMu sync.Mutex
    87  		wg       sync.WaitGroup
    88  	)
    89  
    90  	worker := func() {
    91  		for {
    92  			i := atomic.AddInt64(&idx, 1)
    93  			if i > maxIdx {
    94  				break
    95  			}
    96  
    97  			fileName := testFiles[i]
    98  			testErr := runner.NewTestRunner(fileName, printAllLogs, testFilter).Run()
    99  
   100  			errorsMu.Lock()
   101  			errors[fileName] = testErr
   102  			errorsMu.Unlock()
   103  
   104  			if err, ok := testErr[runner.GeneralError]; ok {
   105  				log.Error(fmt.Sprintf("\t ERROR (%s): %v", fileName, err))
   106  			}
   107  		}
   108  		wg.Done()
   109  	}
   110  
   111  	// force goroutine local manager
   112  	schema.SetManagerScope(schema.ScopeGLSSingleton)
   113  
   114  	for workers > 0 {
   115  		wg.Add(1)
   116  		go worker()
   117  		workers -= 1
   118  	}
   119  	wg.Wait()
   120  
   121  	summary := makeSummary(errors)
   122  	printSummary(summary, printAllLogs)
   123  
   124  	for _, err := range summary {
   125  		if err != nil {
   126  			return 1
   127  		}
   128  	}
   129  	return 0
   130  }
   131  
   132  func makeSummary(errors map[string]runner.TestRunnerErrors) (summary map[string]error) {
   133  	summary = map[string]error{}
   134  	for testFile, errors := range errors {
   135  		if err, ok := errors[runner.GeneralError]; ok {
   136  			summary[testFile] = err
   137  			continue
   138  		}
   139  
   140  		failed := 0
   141  		for _, err := range errors {
   142  			if err != nil {
   143  				failed++
   144  			}
   145  		}
   146  		summary[testFile] = nil
   147  		if failed > 0 {
   148  			summary[testFile] = fmt.Errorf("%d/%d tests failed", failed, len(errors))
   149  		}
   150  	}
   151  	return
   152  }
   153  
   154  func printSummary(summary map[string]error, printAllLogs bool) {
   155  	l.SetUpBasicLogging(logWriter, l.DefaultFormat, "", l.DEBUG)
   156  
   157  	log.Info("Run %d test files.", len(summary))
   158  
   159  	allPassed := true
   160  	for testFile, err := range summary {
   161  		if err != nil {
   162  			log.Error(fmt.Sprintf("\tFAIL\t%s: %s", testFile, err.Error()))
   163  			allPassed = false
   164  		} else if printAllLogs {
   165  			log.Notice("\tOK\t%s", testFile)
   166  		}
   167  	}
   168  	if allPassed {
   169  		log.Notice("All tests have passed.")
   170  	}
   171  }
   172  
   173  func getTestFiles(args cli.Args) []string {
   174  	paths := args
   175  	if len(paths) == 0 {
   176  		paths = append(paths, ".")
   177  	}
   178  
   179  	pattern := regexp.MustCompile(`^test_.*\.js$`)
   180  	seen := map[string]bool{}
   181  	testFiles := []string{}
   182  	for _, path := range paths {
   183  		filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error {
   184  			if err != nil {
   185  				log.Error(fmt.Sprintf("Failed to process '%s': %s", filePath, err.Error()))
   186  				return nil
   187  			}
   188  
   189  			if info.IsDir() {
   190  				return nil
   191  			}
   192  
   193  			if !pattern.MatchString(info.Name()) {
   194  				return nil
   195  			}
   196  
   197  			filePath = filepath.Clean(filePath)
   198  
   199  			if !seen[filePath] {
   200  				testFiles = append(testFiles, filePath)
   201  				seen[filePath] = true
   202  			}
   203  
   204  			return nil
   205  		})
   206  	}
   207  
   208  	return testFiles
   209  }