github.com/go-graphite/carbonapi@v0.17.0/cmd/mockbackend/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  	"sync"
    10  	"time"
    11  
    12  	"go.uber.org/zap"
    13  	"gopkg.in/yaml.v2"
    14  )
    15  
    16  type MainConfig struct {
    17  	Version   string      `yaml:"version"`
    18  	Test      *TestSchema `yaml:"test"`
    19  	Listeners []Listener  `yaml:"listeners"`
    20  }
    21  
    22  type Listener struct {
    23  	Address        string              `yaml:"address"`
    24  	Code           int                 `yaml:"httpCode"` // global responce code
    25  	ShuffleResults bool                `yaml:"shuffleResults"`
    26  	EmptyBody      bool                `yaml:"emptyBody"`
    27  	Expressions    map[string]Response `yaml:"expressions"`
    28  }
    29  
    30  var cfg = MainConfig{}
    31  
    32  type listener struct {
    33  	Listener
    34  	logger *zap.Logger
    35  }
    36  
    37  func main() {
    38  	config := flag.String("config", "average.yaml", "yaml where it would be possible to get data")
    39  	verbose := flag.Bool("verbose", false, "verbose reporting")
    40  	testonly := flag.Bool("testonly", false, "run only unit test")
    41  	noapp := flag.Bool("noapp", false, "do not run application")
    42  	test := flag.Bool("test", false, "run unit test if present")
    43  	breakOnError := flag.Bool("break", false, "break and wait user response if request failed")
    44  	flag.Parse()
    45  	logger, err := zap.NewProduction()
    46  	if err != nil {
    47  		log.Fatal(err)
    48  	}
    49  
    50  	if *config == "" {
    51  		logger.Fatal("failed to get config, it should be non-null")
    52  	}
    53  
    54  	f, err := os.Open(*config)
    55  	if err != nil {
    56  		logger.Fatal("failed to read config", zap.Error(err))
    57  	}
    58  
    59  	decoder := yaml.NewDecoder(f)
    60  	decoder.SetStrict(true)
    61  	err = decoder.Decode(&cfg)
    62  	if err != nil {
    63  		logger.Fatal("failed to read config", zap.Error(err))
    64  		return
    65  	}
    66  
    67  	logger.Info("starting mockbackend",
    68  		zap.Any("config", cfg),
    69  	)
    70  
    71  	httpServers := make([]*http.Server, 0)
    72  	wg := sync.WaitGroup{}
    73  	wgStart := sync.WaitGroup{}
    74  	if !*testonly {
    75  		for _, c := range cfg.Listeners {
    76  			logger := logger.With(zap.String("listener", c.Address))
    77  			listener := listener{
    78  				Listener: c,
    79  				logger:   logger,
    80  			}
    81  
    82  			if listener.Address == "" {
    83  				listener.Address = ":9070"
    84  			}
    85  
    86  			if listener.Code == 0 {
    87  				listener.Code = http.StatusOK
    88  			}
    89  
    90  			logger.Info("started",
    91  				zap.String("listener", listener.Address),
    92  				zap.Any("config", c),
    93  			)
    94  
    95  			mux := http.NewServeMux()
    96  			mux.HandleFunc("/render", listener.renderHandler)
    97  			mux.HandleFunc("/render/", listener.renderHandler)
    98  			mux.HandleFunc("/metrics/find", listener.findHandler)
    99  			mux.HandleFunc("/metrics/find/", listener.findHandler)
   100  			mux.HandleFunc("/tags/autoComplete/values", listener.tagsValuesHandler)
   101  			mux.HandleFunc("/tags/autoComplete/tags", listener.tagsNamesHandler)
   102  
   103  			wg.Add(1)
   104  			wgStart.Add(1)
   105  			server := &http.Server{
   106  				Addr:    listener.Address,
   107  				Handler: mux,
   108  			}
   109  			go func(h *http.Server) {
   110  				wgStart.Done()
   111  				err = h.ListenAndServe()
   112  				if err != nil && err != http.ErrServerClosed {
   113  					logger.Error("failed to start server",
   114  						zap.Error(err),
   115  					)
   116  				}
   117  				wg.Done()
   118  			}(server)
   119  
   120  			wgStart.Wait()
   121  			httpServers = append(httpServers, server)
   122  		}
   123  		logger.Info("all listeners started")
   124  	}
   125  
   126  	failed := false
   127  	if cfg.Test != nil && (*test || *testonly) {
   128  		failed = e2eTest(logger, *noapp, *breakOnError, *verbose)
   129  	}
   130  
   131  	if !*testonly {
   132  		if *test {
   133  			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   134  			for i := range httpServers {
   135  				// we don't care about error here
   136  				_ = httpServers[i].Shutdown(ctx)
   137  			}
   138  			cancel()
   139  		}
   140  
   141  		wg.Wait()
   142  	}
   143  
   144  	if failed {
   145  		// skipcq: CRT-D0011
   146  		os.Exit(1)
   147  	}
   148  }