<commit_before>package gofigure

import (
	"github.com/droundy/goopt"
	"os"
)

// Config contains the configuration options that may be set by
// command line flags and environment variables.
type Config struct {
	Description			string
	DisableCommandLine	bool
	Version				string
	EnvPrefix			string
	options				map[string]*Option
	flags				map[string]*string
	values				map[string]*string
}

// Returns a new Config instance.
func New() *Config {
	return &Config{
		DisableCommandLine:	false,
		options:			make(map[string]*Option),
		flags:				make(map[string]*string),
		values:				make(map[string]*string),
	}
}

// Adds a configuration option, returns an Option instance for
// easily setting the corresponding environment variable, default
// value, and description.
func (c *Config) Add(name string) *Option {
	c.options[name] = &Option{
		envVar: "",
		def:    "",
		desc:   "",
	}
	return c.options[name]
}

// Returns a configuration option by flag name.
func (c *Config) Get(name string) *string {
	return c.values[name]
}

// Parses the configuration options into defined flags, sets the value
// accordingly. Options are read first from command line flags, then
// from environment variables, and falls back to the default value if
// neither are set.
//
// See https://github.com/rakyll/globalconf/blob/master/globalconf.go
func (c *Config) Parse() {
	goopt.Description = func() string {
		return c.Description
	}

	goopt.Version = c.Version

	// Sets the flags from the configuration options.
	for name, o := range c.options {
		cmdline := []string{}
		if o.shortOpt != "" {
			cmdline = append(cmdline, "-" + o.shortOpt)
		}
		cmdline = append(cmdline, "--"+name)
		c.flags[name] = goopt.String(cmdline, "", o.desc)
		defcopy := o.def
		c.values[name] = &defcopy
	}

	passed := make(map[string]bool)

	if !c.DisableCommandLine {
		goopt.Parse(nil)

		// Gather the options passed through command line.
		for name, f := range c.flags {
			if *f != "" {
				passed[name] = true
				*c.values[name] = *f
			}
		}
	}

	for name, f := range c.options {

		// Skip flags passed through the command line as the option is
		// already set and takes precedence over environment variables.
		if passed[name] {
			return
		}

		// Some options shouldn't be set via environment variables.
		if f.envVar == "" {
			return
		}

		// If the configuration option was not passed via the command line,
		// check the corresponding environment variable.
		envVar := c.EnvPrefix + f.envVar
		if val := os.Getenv(envVar); val != "" {
			*c.values[name] = val
		}
	}
}

// Option contains the details of a configuration options,
// e.g. corresponding environment variable, default value,
// description.
type Option struct {
	envVar, shortOpt, def, desc string
}

func (o *Option) ShortOpt(opt string) *Option {
	o.shortOpt = opt
	return o
}

// Sets the configuration option's default value.
func (o *Option) Default(def string) *Option {
	o.def = def
	return o
}

// Sets the configuration option's corresponding environment variable.
func (o *Option) EnvVar(envVar string) *Option {
	o.envVar = envVar
	return o
}

// Sets the configuration options long description.
func (o *Option) Description(desc string) *Option {
	o.desc = desc
	return o
}
<commit_msg>fixing an error source<commit_after>package gofigure

import (
	"github.com/droundy/goopt"
	"os"
)

// Config contains the configuration options that may be set by
// command line flags and environment variables.
type Config struct {
	Description			string
	DisableCommandLine	bool
	Version				string
	EnvPrefix			string
	options				map[string]*Option
	flags				map[string]*string
	values				map[string]*string
}

// Returns a new Config instance.
func New() *Config {
	return &Config{
		DisableCommandLine:	false,
		options:			make(map[string]*Option),
		flags:				make(map[string]*string),
		values:				make(map[string]*string),
	}
}

// Adds a configuration option, returns an Option instance for
// easily setting the corresponding environment variable, default
// value, and description.
func (c *Config) Add(name string) *Option {
	c.options[name] = &Option{
		envVar: "",
		def:    "",
		desc:   "",
	}
	return c.options[name]
}

// Returns a configuration option by flag name.
func (c *Config) Get(name string) *string {
	return c.values[name]
}

// Parses the configuration options into defined flags, sets the value
// accordingly. Options are read first from command line flags, then
// from environment variables, and falls back to the default value if
// neither are set.
//
// See https://github.com/rakyll/globalconf/blob/master/globalconf.go
func (c *Config) Parse() {
	goopt.Description = func() string {
		return c.Description
	}

	goopt.Version = c.Version

	// Sets the flags from the configuration options.
	for name, o := range c.options {
		cmdline := []string{}
		if o.shortOpt != "" {
			cmdline = append(cmdline, "-" + o.shortOpt)
		}
		cmdline = append(cmdline, "--"+name)
		c.flags[name] = goopt.String(cmdline, "", o.desc)
		defcopy := o.def
		c.values[name] = &defcopy
	}

	passed := make(map[string]bool)

	if !c.DisableCommandLine {
		goopt.Parse(nil)

		// Gather the options passed through command line.
		for name, f := range c.flags {
			if *f != "" {
				passed[name] = true
				*c.values[name] = *f
			}
		}
	}

	for name, f := range c.options {

		// Skip flags passed through the command line as the option is
		// already set and takes precedence over environment variables.
		if passed[name] {
			continue
		}

		// Some options shouldn't be set via environment variables.
		if f.envVar == "" {
			continue
		}

		// If the configuration option was not passed via the command line,
		// check the corresponding environment variable.
		envVar := c.EnvPrefix + f.envVar
		if val := os.Getenv(envVar); val != "" {
			*c.values[name] = val
		}
	}
}

// Option contains the details of a configuration options,
// e.g. corresponding environment variable, default value,
// description.
type Option struct {
	envVar, shortOpt, def, desc string
}

func (o *Option) ShortOpt(opt string) *Option {
	o.shortOpt = opt
	return o
}

// Sets the configuration option's default value.
func (o *Option) Default(def string) *Option {
	o.def = def
	return o
}

// Sets the configuration option's corresponding environment variable.
func (o *Option) EnvVar(envVar string) *Option {
	o.envVar = envVar
	return o
}

// Sets the configuration options long description.
func (o *Option) Description(desc string) *Option {
	o.desc = desc
	return o
}
<|endoftext|>


<commit_before>/*
  Go adaptation of Colorize lib for Node.JS: https://github.com/mattpat/colorize
*/

package golorize

import (
  "regexp"
  "strings"
)

var ansicodes map[string]string = map[string]string{
  "reset": "\033[0m",
  "bold": "\033[1m",
  "italic": "\033[3m",
  "underline": "\033[4m",
  "blink": "\033[5m",
  "black": "\033[30m",
  "red": "\033[31m",
  "green": "\033[32m",
  "yellow": "\033[33m",
  "blue": "\033[34m",
  "magenta": "\033[35m",
  "cyan": "\033[36m",
  "white": "\033[37m",
}

var tag *regexp.Regexp
var Enabled bool = true

func Ansify(str string) string {
  cstack := make([]string, 3)

  for tag.MatchString(str) {
    matches := tag.FindStringSubmatch(str)
    orig := matches[0]

    if Enabled {
      if orig == "]" {
        cstack = cstack[:len(cstack)-2]
      } else {
        name := matches[1]
        if code, exists := ansicodes[name]; exists {
          cstack = append(cstack, code)
        }

      }
      //str = str.replace(orig, this.ansicodes.reset + cstack.join(''));
      str = strings.Replace(str, orig, ansicodes["reset"] + strings.Join(cstack, ""), -1)
    } else {
      str = strings.Replace(str, orig, "", -1)
    }
  } //for
  return str
}

func init() {
  tag = regexp.MustCompile(`#([a-z]+)\[|\]`)
}<commit_msg>removed read code<commit_after>/*
  Go adaptation of Colorize lib for Node.JS: https://github.com/mattpat/colorize
*/

package golorize

import (
  "regexp"
  "strings"
)

var ansicodes map[string]string = map[string]string{
  "reset": "\033[0m",
  "bold": "\033[1m",
  "italic": "\033[3m",
  "underline": "\033[4m",
  "blink": "\033[5m",
  "black": "\033[30m",
  "red": "\033[31m",
  "green": "\033[32m",
  "yellow": "\033[33m",
  "blue": "\033[34m",
  "magenta": "\033[35m",
  "cyan": "\033[36m",
  "white": "\033[37m",
}

var tag *regexp.Regexp
var Enabled bool = true

func Ansify(str string) string {
  cstack := make([]string, 3)

  for tag.MatchString(str) {
    matches := tag.FindStringSubmatch(str)
    orig := matches[0]

    if Enabled {
      if orig == "]" {
        cstack = cstack[:len(cstack)-2]
      } else {
        name := matches[1]
        if code, exists := ansicodes[name]; exists {
          cstack = append(cstack, code)
        }

      }
      str = strings.Replace(str, orig, ansicodes["reset"] + strings.Join(cstack, ""), -1)
    } else {
      str = strings.Replace(str, orig, "", -1)
    }
  } //for
  return str
}

func init() {
  tag = regexp.MustCompile(`#([a-z]+)\[|\]`)
}
<|endoftext|>


<commit_before>// Package gostruct provides a simple API to populate structs from webpages
// using CSS selectors.
package gostruct

import (
	"fmt"
	"reflect"
	"strconv"
	"time"

	"github.com/PuerkitoBio/goquery"
)

// some parts of this code are stolen^Winspired from
//   https://github.com/vrischmann/envconfig

// Fetch fetches a document from an URL and populates the given target, which
// must be a pointer on a struct. See Populate for the details.
func Fetch(target interface{}, url string) error {
	doc, err := goquery.NewDocument(url)
	if err != nil {
		return err
	}
	return Populate(target, doc)
}

// Populate fills a struct using the given goquery document. The target must be
// a pointer on a struct.
// Types are parsed as follow:
//
//     - uint, int, float, duration, and string values are parsed from the first
//       element which match the selector
//     - bool values are true if the text from the selection is not empty
//     - slice values are parsed with one slice element per element in the
//       selection.
func Populate(target interface{}, doc *goquery.Document) error {
	value := reflect.ValueOf(target)

	if value.Kind() != reflect.Ptr {
		return fmt.Errorf("value '%s' is not a pointer", target)
	}

	elem := value.Elem()

	switch elem.Kind() {
	case reflect.Ptr:
		elem.Set(reflect.New(elem.Type().Elem()))
		return populateStruct(elem.Elem(), doc.Selection)
	case reflect.Struct:
		return populateStruct(elem, doc.Selection)
	default:
		return fmt.Errorf("value '%s' must be a pointer on struct", target)
	}
}

func populateStruct(target reflect.Value, doc *goquery.Selection) (err error) {
	fieldsCount := target.NumField()
	targetType := target.Type()

	for i := 0; i < fieldsCount; i++ {
		field := target.Field(i)
		sel := targetType.Field(i).Tag.Get("gostruct")
		if sel == "" || sel == "-" {
			continue
		}

		subdoc := doc.Find(sel)

	doPopulate:
		switch field.Kind() {
		case reflect.Ptr:
			field.Set(reflect.New(field.Type().Elem()))
			field = field.Elem()
			goto doPopulate
		default:
			err = setField(field, subdoc)
		}

		if err != nil {
			break
		}
	}

	return
}

var (
	durationType  = reflect.TypeOf(new(time.Duration)).Elem()
	byteSliceType = reflect.TypeOf([]byte(nil))
)

func isDurationField(t reflect.Type) bool {
	return t.AssignableTo(durationType)
}

func setField(field reflect.Value, doc *goquery.Selection) error {
	if !field.CanSet() {
		// unexported field: don't do anything
		return nil
	}

	ftype := field.Type()
	kind := ftype.Kind()

	// types which take the whole selection
	switch kind {
	case reflect.Struct:
		return populateStruct(field, doc)
	case reflect.Slice:
		if ftype == byteSliceType {
			return setByteSliceValue(field, doc)
		}
		return setSliceValue(field, doc)
	case reflect.Bool:
		return setBoolValue(field, doc)
	}

	text := doc.First().Text()

	// types which take only the first element's text

	if isDurationField(ftype) {
		return setDurationValue(field, text)
	}

	switch kind {
	case reflect.String:
		return setStringValue(field, text)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return setIntValue(field, text)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return setUintValue(field, text)
	case reflect.Float32, reflect.Float64:
		return setFloatValue(field, text)
	default:
		return fmt.Errorf("Unsupported field type: '%v'", ftype)
	}
}

func setStringValue(field reflect.Value, s string) error {
	field.SetString(s)
	return nil
}

func setBoolValue(field reflect.Value, sel *goquery.Selection) error {
	// this one is tricky because there are multiple possible interpretations:
	// - set to true only if there are elements matching the selector
	// - set to true if the selection's text is not empty (this is what we're
	//   doing here)
	// - set to the resulting value of `strconf.ParseBool` called on the
	//   selection's text
	field.SetBool(sel.Text() != "")
	return nil
}

func setIntValue(field reflect.Value, s string) error {
	if s == "" {
		field.SetInt(0)
		return nil
	}

	val, err := strconv.ParseInt(s, 10, 64)
	if err == nil {
		field.SetInt(val)
	}

	return err
}

func setUintValue(field reflect.Value, s string) error {
	if s == "" {
		field.SetUint(0)
		return nil
	}

	val, err := strconv.ParseUint(s, 10, 64)
	if err == nil {
		field.SetUint(val)
	}

	return err
}

func setFloatValue(field reflect.Value, s string) error {
	if s == "" {
		field.SetFloat(0)
		return nil
	}

	val, err := strconv.ParseFloat(s, 64)
	if err == nil {
		field.SetFloat(val)
	}

	return err
}

func setDurationValue(field reflect.Value, s string) error {
	val, err := time.ParseDuration(s)
	if err == nil {
		field.SetInt(int64(val))
	}

	return err
}

// this one is like setStringValue except that we convert the string in a byte
// slice
func setByteSliceValue(field reflect.Value, sel *goquery.Selection) error {
	field.SetBytes([]byte(sel.Text()))
	return nil
}

func setSliceValue(field reflect.Value, sel *goquery.Selection) error {
	count := sel.Length()

	eltype := field.Type().Elem()
	capacity := field.Cap()

	if count > capacity {
		capacity = count
	}

	slice := reflect.MakeSlice(field.Type(), 0, capacity)

	var err error

	sel.EachWithBreak(func(i int, subSel *goquery.Selection) bool {
		el := reflect.New(eltype).Elem()

		if err = setField(el, subSel); err != nil {
			return false
		}

		slice = reflect.Append(slice, el)

		return true
	})

	if err != nil {
		return err
	}

	field.Set(slice)

	return nil
}
<commit_msg>PopulateFromResponse shortcut added<commit_after>// Package gostruct provides a simple API to populate structs from webpages
// using CSS selectors.
package gostruct

import (
	"fmt"
	"net/http"
	"reflect"
	"strconv"
	"time"

	"github.com/PuerkitoBio/goquery"
)

// some parts of this code are stolen^Winspired from
//   https://github.com/vrischmann/envconfig

// Fetch fetches a document from an URL and populates the given target, which
// must be a pointer on a struct. See Populate for the details.
func Fetch(target interface{}, url string) error {
	doc, err := goquery.NewDocument(url)
	if err != nil {
		return err
	}
	return Populate(target, doc)
}

// PopulateFromResponse fills a struct using the given HTTP response. See
// Populate for the details.
func PopulateFromResponse(target interface{}, res *http.Response) error {
	doc, err := goquery.NewDocumentFromResponse(res)
	if err != nil {
		return err
	}
	return Populate(target, doc)
}

// Populate fills a struct using the given goquery document. The target must be
// a pointer on a struct.
// Types are parsed as follow:
//
//     - uint, int, float, duration, and string values are parsed from the first
//       element which match the selector
//     - bool values are true if the text from the selection is not empty
//     - slice values are parsed with one slice element per element in the
//       selection.
func Populate(target interface{}, doc *goquery.Document) error {
	value := reflect.ValueOf(target)

	if value.Kind() != reflect.Ptr {
		return fmt.Errorf("value '%s' is not a pointer", target)
	}

	elem := value.Elem()

	switch elem.Kind() {
	case reflect.Ptr:
		elem.Set(reflect.New(elem.Type().Elem()))
		return populateStruct(elem.Elem(), doc.Selection)
	case reflect.Struct:
		return populateStruct(elem, doc.Selection)
	default:
		return fmt.Errorf("value '%s' must be a pointer on struct", target)
	}
}

func populateStruct(target reflect.Value, doc *goquery.Selection) (err error) {
	fieldsCount := target.NumField()
	targetType := target.Type()

	for i := 0; i < fieldsCount; i++ {
		field := target.Field(i)
		sel := targetType.Field(i).Tag.Get("gostruct")
		if sel == "" || sel == "-" {
			continue
		}

		subdoc := doc.Find(sel)

	doPopulate:
		switch field.Kind() {
		case reflect.Ptr:
			field.Set(reflect.New(field.Type().Elem()))
			field = field.Elem()
			goto doPopulate
		default:
			err = setField(field, subdoc)
		}

		if err != nil {
			break
		}
	}

	return
}

var (
	durationType  = reflect.TypeOf(new(time.Duration)).Elem()
	byteSliceType = reflect.TypeOf([]byte(nil))
)

func isDurationField(t reflect.Type) bool {
	return t.AssignableTo(durationType)
}

func setField(field reflect.Value, doc *goquery.Selection) error {
	if !field.CanSet() {
		// unexported field: don't do anything
		return nil
	}

	ftype := field.Type()
	kind := ftype.Kind()

	// types which take the whole selection
	switch kind {
	case reflect.Struct:
		return populateStruct(field, doc)
	case reflect.Slice:
		if ftype == byteSliceType {
			return setByteSliceValue(field, doc)
		}
		return setSliceValue(field, doc)
	case reflect.Bool:
		return setBoolValue(field, doc)
	}

	text := doc.First().Text()

	// types which take only the first element's text

	if isDurationField(ftype) {
		return setDurationValue(field, text)
	}

	switch kind {
	case reflect.String:
		return setStringValue(field, text)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return setIntValue(field, text)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return setUintValue(field, text)
	case reflect.Float32, reflect.Float64:
		return setFloatValue(field, text)
	default:
		return fmt.Errorf("Unsupported field type: '%v'", ftype)
	}
}

func setStringValue(field reflect.Value, s string) error {
	field.SetString(s)
	return nil
}

func setBoolValue(field reflect.Value, sel *goquery.Selection) error {
	// this one is tricky because there are multiple possible interpretations:
	// - set to true only if there are elements matching the selector
	// - set to true if the selection's text is not empty (this is what we're
	//   doing here)
	// - set to the resulting value of `strconf.ParseBool` called on the
	//   selection's text
	field.SetBool(sel.Text() != "")
	return nil
}

func setIntValue(field reflect.Value, s string) error {
	if s == "" {
		field.SetInt(0)
		return nil
	}

	val, err := strconv.ParseInt(s, 10, 64)
	if err == nil {
		field.SetInt(val)
	}

	return err
}

func setUintValue(field reflect.Value, s string) error {
	if s == "" {
		field.SetUint(0)
		return nil
	}

	val, err := strconv.ParseUint(s, 10, 64)
	if err == nil {
		field.SetUint(val)
	}

	return err
}

func setFloatValue(field reflect.Value, s string) error {
	if s == "" {
		field.SetFloat(0)
		return nil
	}

	val, err := strconv.ParseFloat(s, 64)
	if err == nil {
		field.SetFloat(val)
	}

	return err
}

func setDurationValue(field reflect.Value, s string) error {
	val, err := time.ParseDuration(s)
	if err == nil {
		field.SetInt(int64(val))
	}

	return err
}

// this one is like setStringValue except that we convert the string in a byte
// slice
func setByteSliceValue(field reflect.Value, sel *goquery.Selection) error {
	field.SetBytes([]byte(sel.Text()))
	return nil
}

func setSliceValue(field reflect.Value, sel *goquery.Selection) error {
	count := sel.Length()

	eltype := field.Type().Elem()
	capacity := field.Cap()

	if count > capacity {
		capacity = count
	}

	slice := reflect.MakeSlice(field.Type(), 0, capacity)

	var err error

	sel.EachWithBreak(func(i int, subSel *goquery.Selection) bool {
		el := reflect.New(eltype).Elem()

		if err = setField(el, subSel); err != nil {
			return false
		}

		slice = reflect.Append(slice, el)

		return true
	})

	if err != nil {
		return err
	}

	field.Set(slice)

	return nil
}
<|endoftext|>


<commit_before>package language

import (
	"io/ioutil"
	"log"
	"path/filepath"
	"sort"

	"github.com/bazelbuild/bazel-gazelle/config"
	"github.com/bazelbuild/bazel-gazelle/language"
	"github.com/bazelbuild/bazel-gazelle/rule"

	"go.skia.org/infra/bazel/gazelle/cpp/common"
	"go.skia.org/infra/bazel/gazelle/cpp/configurer"
	"go.skia.org/infra/bazel/gazelle/cpp/parsers"
	"go.skia.org/infra/bazel/gazelle/cpp/resolver"
)

// CppLanguage implements the language.CppLanguage interface.
type CppLanguage struct {
	configurer.CppConfigurer
	resolver.CppResolver
}

// Kinds implements the language.CppLanguage interface.
//
// Interface documentation:
//
// Kinds returns a map of maps rule names (kinds) and information on how to
// match and merge attributes that may be found in rules of those kinds. All
// kinds of rules generated for this language may be found here.
func (l *CppLanguage) Kinds() map[string]rule.KindInfo {
	return map[string]rule.KindInfo{
		common.GeneratedCCAtomRule: {
			// This extension only really cares about resolving deps looking at #includes, so
			// we specify that attribute here.
			ResolveAttrs: map[string]bool{"deps": true},
			// NonEmptyAttrs must be non-nil, otherwise no rules will get deleted.
			// We don't have any fields that should prevent a rule from being deleted if the
			// underlying source file or header file is missing, so an empty map suffices.
			NonEmptyAttrs: map[string]bool{},
		},
	}
}

// Loads implements the language.CppLanguage interface.
//
// Interface documentation:
//
// Loads returns .bzl files and symbols they define. Every rule generated by
// GenerateRules, now or in the past, should be loadable from one of these
// files.
func (l *CppLanguage) Loads() []rule.LoadInfo {
	return []rule.LoadInfo{
		{
			Name: "//bazel:macros.bzl",
			Symbols: []string{
				common.GeneratedCCAtomRule,
			},
		},
	}
}

// GenerateRules implements the language.CppLanguage interface.
//
// GenerateRules generates build rules for source files in a directory. GenerateRules is called in
// each directory where an update is requested in depth-first order.
//
// This method does not populate the deps argument of any generate rules. Dependencies are resolved
// in CppResolver.Resolve(), which happens after GenerateRules is called in each directory where an
// update is requested.
func (l *CppLanguage) GenerateRules(args language.GenerateArgs) language.GenerateResult {
	allFiles := append(args.RegularFiles, args.GenFiles...)
	log.Printf("All files %s", allFiles)
	rules := makeRulesFromFiles(allFiles)
	imports := getImportsFromRules(rules, args.Dir, l.ThirdPartyFileMap)

	var existingRules []*rule.Rule
	if args.File != nil {
		existingRules = args.File.Rules
	}

	return language.GenerateResult{
		Gen:     rules,
		Imports: imports,
		Empty:   findEmptyRules(existingRules, rules),
	}
}

// findEmptyRules returns any generated_cc_atom rules which were in the rules from BUILD.bazel,
// but did not show up when we recreated all the rules from the source files. This means the
// underlying source files have been deleted or moved and the rules should as well.
func findEmptyRules(previous, new []*rule.Rule) []*rule.Rule {
	ruleCache := map[string]bool{}
	for _, r := range new {
		if r.Kind() != common.GeneratedCCAtomRule {
			continue
		}
		ruleCache[r.Name()] = true
	}

	var empty []*rule.Rule
	for _, r := range previous {
		if r.Kind() != common.GeneratedCCAtomRule {
			continue
		}
		if _, ok := ruleCache[r.Name()]; !ok {
			empty = append(empty, rule.NewRule(common.GeneratedCCAtomRule, r.Name()))
		}
	}
	return empty
}

// makeRulesFromFiles returns a single rule per file. Header rules will have the _hdr suffix and
// source rules will have the _src suffix so as to distinguish them, but have them be named
// in a predictable way.
func makeRulesFromFiles(names []string) []*rule.Rule {
	var rv []*rule.Rule
	for _, name := range names {
		var r *rule.Rule
		if common.IsCppHeader(name) {
			r = rule.NewRule(common.GeneratedCCAtomRule, common.TrimCSuffix(name)+"_hdr")
			r.SetAttr("hdrs", []string{name})
		} else if common.IsCppSource(name) {
			r = rule.NewRule(common.GeneratedCCAtomRule, common.TrimCSuffix(name)+"_src")
			r.SetAttr("srcs", []string{name})
		} else {
			continue
		}
		r.SetAttr("visibility", []string{"//:__subpackages__"})
		rv = append(rv, r)
	}
	// Sort for determinism
	sort.Slice(rv, func(i, j int) bool {
		return rv[i].Name() < rv[j].Name()
	})
	return rv
}

// getImportsFromRules returns a list of common.ImportsParsedFromRuleSources, one per rule, that
// relate to the files that were listed via #include.
func getImportsFromRules(rules []*rule.Rule, dir string, thirdPartyMap map[string]string) []interface{} {
	var rv []interface{}
	for _, r := range rules {
		var repoHeaders, systemHeaders []string
		hdr := r.AttrStrings("hdrs")
		if len(hdr) == 1 {
			rh, sh := extractImportsFromCFile(filepath.Join(dir, hdr[0]))
			repoHeaders = append(repoHeaders, rh...)
			systemHeaders = append(systemHeaders, sh...)
		}
		src := r.AttrStrings("srcs")
		if len(src) == 1 {
			rh, sh := extractImportsFromCFile(filepath.Join(dir, src[0]))
			repoHeaders = append(repoHeaders, rh...)
			systemHeaders = append(systemHeaders, sh...)
		}
		rv = append(rv, common.NewImports(repoHeaders, systemHeaders, thirdPartyMap))
	}
	return rv
}

// extractImportsFromCFile opens ups the given file and parses the contents.
func extractImportsFromCFile(path string) ([]string, []string) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		log.Panicf("Error reading file %q: %v", path, err)
	}
	return parsers.ParseCIncludes(string(b[:]))
}

// Fix implements the language.CppLanguage interface.
func (l *CppLanguage) Fix(*config.Config, *rule.File) {}

var _ language.Language = &CppLanguage{}
<commit_msg>[bazel] Remove extraneous log<commit_after>package language

import (
	"io/ioutil"
	"log"
	"path/filepath"
	"sort"

	"github.com/bazelbuild/bazel-gazelle/config"
	"github.com/bazelbuild/bazel-gazelle/language"
	"github.com/bazelbuild/bazel-gazelle/rule"

	"go.skia.org/infra/bazel/gazelle/cpp/common"
	"go.skia.org/infra/bazel/gazelle/cpp/configurer"
	"go.skia.org/infra/bazel/gazelle/cpp/parsers"
	"go.skia.org/infra/bazel/gazelle/cpp/resolver"
)

// CppLanguage implements the language.CppLanguage interface.
type CppLanguage struct {
	configurer.CppConfigurer
	resolver.CppResolver
}

// Kinds implements the language.CppLanguage interface.
//
// Interface documentation:
//
// Kinds returns a map of maps rule names (kinds) and information on how to
// match and merge attributes that may be found in rules of those kinds. All
// kinds of rules generated for this language may be found here.
func (l *CppLanguage) Kinds() map[string]rule.KindInfo {
	return map[string]rule.KindInfo{
		common.GeneratedCCAtomRule: {
			// This extension only really cares about resolving deps looking at #includes, so
			// we specify that attribute here.
			ResolveAttrs: map[string]bool{"deps": true},
			// NonEmptyAttrs must be non-nil, otherwise no rules will get deleted.
			// We don't have any fields that should prevent a rule from being deleted if the
			// underlying source file or header file is missing, so an empty map suffices.
			NonEmptyAttrs: map[string]bool{},
		},
	}
}

// Loads implements the language.CppLanguage interface.
//
// Interface documentation:
//
// Loads returns .bzl files and symbols they define. Every rule generated by
// GenerateRules, now or in the past, should be loadable from one of these
// files.
func (l *CppLanguage) Loads() []rule.LoadInfo {
	return []rule.LoadInfo{
		{
			Name: "//bazel:macros.bzl",
			Symbols: []string{
				common.GeneratedCCAtomRule,
			},
		},
	}
}

// GenerateRules implements the language.CppLanguage interface.
//
// GenerateRules generates build rules for source files in a directory. GenerateRules is called in
// each directory where an update is requested in depth-first order.
//
// This method does not populate the deps argument of any generate rules. Dependencies are resolved
// in CppResolver.Resolve(), which happens after GenerateRules is called in each directory where an
// update is requested.
func (l *CppLanguage) GenerateRules(args language.GenerateArgs) language.GenerateResult {
	allFiles := append(args.RegularFiles, args.GenFiles...)
	rules := makeRulesFromFiles(allFiles)
	imports := getImportsFromRules(rules, args.Dir, l.ThirdPartyFileMap)

	var existingRules []*rule.Rule
	if args.File != nil {
		existingRules = args.File.Rules
	}

	return language.GenerateResult{
		Gen:     rules,
		Imports: imports,
		Empty:   findEmptyRules(existingRules, rules),
	}
}

// findEmptyRules returns any generated_cc_atom rules which were in the rules from BUILD.bazel,
// but did not show up when we recreated all the rules from the source files. This means the
// underlying source files have been deleted or moved and the rules should as well.
func findEmptyRules(previous, new []*rule.Rule) []*rule.Rule {
	ruleCache := map[string]bool{}
	for _, r := range new {
		if r.Kind() != common.GeneratedCCAtomRule {
			continue
		}
		ruleCache[r.Name()] = true
	}

	var empty []*rule.Rule
	for _, r := range previous {
		if r.Kind() != common.GeneratedCCAtomRule {
			continue
		}
		if _, ok := ruleCache[r.Name()]; !ok {
			empty = append(empty, rule.NewRule(common.GeneratedCCAtomRule, r.Name()))
		}
	}
	return empty
}

// makeRulesFromFiles returns a single rule per file. Header rules will have the _hdr suffix and
// source rules will have the _src suffix so as to distinguish them, but have them be named
// in a predictable way.
func makeRulesFromFiles(names []string) []*rule.Rule {
	var rv []*rule.Rule
	for _, name := range names {
		var r *rule.Rule
		if common.IsCppHeader(name) {
			r = rule.NewRule(common.GeneratedCCAtomRule, common.TrimCSuffix(name)+"_hdr")
			r.SetAttr("hdrs", []string{name})
		} else if common.IsCppSource(name) {
			r = rule.NewRule(common.GeneratedCCAtomRule, common.TrimCSuffix(name)+"_src")
			r.SetAttr("srcs", []string{name})
		} else {
			continue
		}
		r.SetAttr("visibility", []string{"//:__subpackages__"})
		rv = append(rv, r)
	}
	// Sort for determinism
	sort.Slice(rv, func(i, j int) bool {
		return rv[i].Name() < rv[j].Name()
	})
	return rv
}

// getImportsFromRules returns a list of common.ImportsParsedFromRuleSources, one per rule, that
// relate to the files that were listed via #include.
func getImportsFromRules(rules []*rule.Rule, dir string, thirdPartyMap map[string]string) []interface{} {
	var rv []interface{}
	for _, r := range rules {
		var repoHeaders, systemHeaders []string
		hdr := r.AttrStrings("hdrs")
		if len(hdr) == 1 {
			rh, sh := extractImportsFromCFile(filepath.Join(dir, hdr[0]))
			repoHeaders = append(repoHeaders, rh...)
			systemHeaders = append(systemHeaders, sh...)
		}
		src := r.AttrStrings("srcs")
		if len(src) == 1 {
			rh, sh := extractImportsFromCFile(filepath.Join(dir, src[0]))
			repoHeaders = append(repoHeaders, rh...)
			systemHeaders = append(systemHeaders, sh...)
		}
		rv = append(rv, common.NewImports(repoHeaders, systemHeaders, thirdPartyMap))
	}
	return rv
}

// extractImportsFromCFile opens ups the given file and parses the contents.
func extractImportsFromCFile(path string) ([]string, []string) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		log.Panicf("Error reading file %q: %v", path, err)
	}
	return parsers.ParseCIncludes(string(b[:]))
}

// Fix implements the language.CppLanguage interface.
func (l *CppLanguage) Fix(*config.Config, *rule.File) {}

var _ language.Language = &CppLanguage{}
<|endoftext|>


<commit_before>// Copyright 2017 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package integration

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"testing"
	"time"

	"go.uber.org/zap"

	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	"github.com/coreos/etcd/integration"
	"github.com/coreos/etcd/lease"
	"github.com/coreos/etcd/mvcc"
	"github.com/coreos/etcd/mvcc/backend"
	"github.com/coreos/etcd/pkg/testutil"
)

func TestMaintenanceHashKV(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	for i := 0; i < 3; i++ {
		if _, err := clus.RandClient().Put(context.Background(), "foo", "bar"); err != nil {
			t.Fatal(err)
		}
	}

	var hv uint32
	for i := 0; i < 3; i++ {
		cli := clus.Client(i)
		// ensure writes are replicated
		if _, err := cli.Get(context.TODO(), "foo"); err != nil {
			t.Fatal(err)
		}
		hresp, err := cli.HashKV(context.Background(), clus.Members[i].GRPCAddr(), 0)
		if err != nil {
			t.Fatal(err)
		}
		if hv == 0 {
			hv = hresp.Hash
			continue
		}
		if hv != hresp.Hash {
			t.Fatalf("#%d: hash expected %d, got %d", i, hv, hresp.Hash)
		}
	}
}

func TestMaintenanceMoveLeader(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	oldLeadIdx := clus.WaitLeader(t)
	targetIdx := (oldLeadIdx + 1) % 3
	target := uint64(clus.Members[targetIdx].ID())

	cli := clus.Client(targetIdx)
	_, err := cli.MoveLeader(context.Background(), target)
	if err != rpctypes.ErrNotLeader {
		t.Fatalf("error expected %v, got %v", rpctypes.ErrNotLeader, err)
	}

	cli = clus.Client(oldLeadIdx)
	_, err = cli.MoveLeader(context.Background(), target)
	if err != nil {
		t.Fatal(err)
	}

	leadIdx := clus.WaitLeader(t)
	lead := uint64(clus.Members[leadIdx].ID())
	if target != lead {
		t.Fatalf("new leader expected %d, got %d", target, lead)
	}
}

// TestMaintenanceSnapshotError ensures that context cancel/timeout
// before snapshot reading returns corresponding context errors.
func TestMaintenanceSnapshotError(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	// reading snapshot with canceled context should error out
	ctx, cancel := context.WithCancel(context.Background())
	rc1, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc1.Close()

	cancel()
	_, err = io.Copy(ioutil.Discard, rc1)
	if err != context.Canceled {
		t.Errorf("expected %v, got %v", context.Canceled, err)
	}

	// reading snapshot with deadline exceeded should error out
	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	rc2, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc2.Close()

	time.Sleep(2 * time.Second)

	_, err = io.Copy(ioutil.Discard, rc2)
	if err != nil && err != context.DeadlineExceeded {
		t.Errorf("expected %v, got %v", context.DeadlineExceeded, err)
	}
}

// TestMaintenanceSnapshotErrorInflight ensures that inflight context cancel/timeout
// fails snapshot reading with corresponding context errors.
func TestMaintenanceSnapshotErrorInflight(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	// take about 1-second to read snapshot
	clus.Members[0].Stop(t)
	dpath := filepath.Join(clus.Members[0].DataDir, "member", "snap", "db")
	b := backend.NewDefaultBackend(dpath)
	s := mvcc.NewStore(zap.NewExample(), b, &lease.FakeLessor{}, nil)
	rev := 100000
	for i := 2; i <= rev; i++ {
		s.Put([]byte(fmt.Sprintf("%10d", i)), bytes.Repeat([]byte("a"), 1024), lease.NoLease)
	}
	s.Close()
	b.Close()
	clus.Members[0].Restart(t)

	// reading snapshot with canceled context should error out
	ctx, cancel := context.WithCancel(context.Background())
	rc1, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc1.Close()

	donec := make(chan struct{})
	go func() {
		time.Sleep(300 * time.Millisecond)
		cancel()
		close(donec)
	}()
	_, err = io.Copy(ioutil.Discard, rc1)
	if err != nil && err != context.Canceled {
		t.Errorf("expected %v, got %v", context.Canceled, err)
	}
	<-donec

	// reading snapshot with deadline exceeded should error out
	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	rc2, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc2.Close()

	// 300ms left and expect timeout while snapshot reading is in progress
	time.Sleep(700 * time.Millisecond)
	_, err = io.Copy(ioutil.Discard, rc2)
	if err != nil && err != context.DeadlineExceeded {
		t.Errorf("expected %v, got %v", context.DeadlineExceeded, err)
	}
}
<commit_msg>clientv3/integration: fix "TestMaintenanceSnapshotErrorInflight"<commit_after>// Copyright 2017 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package integration

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"go.uber.org/zap"

	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	"github.com/coreos/etcd/integration"
	"github.com/coreos/etcd/lease"
	"github.com/coreos/etcd/mvcc"
	"github.com/coreos/etcd/mvcc/backend"
	"github.com/coreos/etcd/pkg/testutil"
)

func TestMaintenanceHashKV(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	for i := 0; i < 3; i++ {
		if _, err := clus.RandClient().Put(context.Background(), "foo", "bar"); err != nil {
			t.Fatal(err)
		}
	}

	var hv uint32
	for i := 0; i < 3; i++ {
		cli := clus.Client(i)
		// ensure writes are replicated
		if _, err := cli.Get(context.TODO(), "foo"); err != nil {
			t.Fatal(err)
		}
		hresp, err := cli.HashKV(context.Background(), clus.Members[i].GRPCAddr(), 0)
		if err != nil {
			t.Fatal(err)
		}
		if hv == 0 {
			hv = hresp.Hash
			continue
		}
		if hv != hresp.Hash {
			t.Fatalf("#%d: hash expected %d, got %d", i, hv, hresp.Hash)
		}
	}
}

func TestMaintenanceMoveLeader(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	oldLeadIdx := clus.WaitLeader(t)
	targetIdx := (oldLeadIdx + 1) % 3
	target := uint64(clus.Members[targetIdx].ID())

	cli := clus.Client(targetIdx)
	_, err := cli.MoveLeader(context.Background(), target)
	if err != rpctypes.ErrNotLeader {
		t.Fatalf("error expected %v, got %v", rpctypes.ErrNotLeader, err)
	}

	cli = clus.Client(oldLeadIdx)
	_, err = cli.MoveLeader(context.Background(), target)
	if err != nil {
		t.Fatal(err)
	}

	leadIdx := clus.WaitLeader(t)
	lead := uint64(clus.Members[leadIdx].ID())
	if target != lead {
		t.Fatalf("new leader expected %d, got %d", target, lead)
	}
}

// TestMaintenanceSnapshotError ensures that context cancel/timeout
// before snapshot reading returns corresponding context errors.
func TestMaintenanceSnapshotError(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	// reading snapshot with canceled context should error out
	ctx, cancel := context.WithCancel(context.Background())
	rc1, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc1.Close()

	cancel()
	_, err = io.Copy(ioutil.Discard, rc1)
	if err != context.Canceled {
		t.Errorf("expected %v, got %v", context.Canceled, err)
	}

	// reading snapshot with deadline exceeded should error out
	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	rc2, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc2.Close()

	time.Sleep(2 * time.Second)

	_, err = io.Copy(ioutil.Discard, rc2)
	if err != nil && err != context.DeadlineExceeded {
		t.Errorf("expected %v, got %v", context.DeadlineExceeded, err)
	}
}

// TestMaintenanceSnapshotErrorInflight ensures that inflight context cancel/timeout
// fails snapshot reading with corresponding context errors.
func TestMaintenanceSnapshotErrorInflight(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	// take about 1-second to read snapshot
	clus.Members[0].Stop(t)
	dpath := filepath.Join(clus.Members[0].DataDir, "member", "snap", "db")
	b := backend.NewDefaultBackend(dpath)
	s := mvcc.NewStore(zap.NewExample(), b, &lease.FakeLessor{}, nil)
	rev := 100000
	for i := 2; i <= rev; i++ {
		s.Put([]byte(fmt.Sprintf("%10d", i)), bytes.Repeat([]byte("a"), 1024), lease.NoLease)
	}
	s.Close()
	b.Close()
	clus.Members[0].Restart(t)

	// reading snapshot with canceled context should error out
	ctx, cancel := context.WithCancel(context.Background())
	rc1, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc1.Close()

	donec := make(chan struct{})
	go func() {
		time.Sleep(300 * time.Millisecond)
		cancel()
		close(donec)
	}()
	_, err = io.Copy(ioutil.Discard, rc1)
	if err != nil && err != context.Canceled {
		t.Errorf("expected %v, got %v", context.Canceled, err)
	}
	<-donec

	// reading snapshot with deadline exceeded should error out
	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	rc2, err := clus.RandClient().Snapshot(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer rc2.Close()

	// 300ms left and expect timeout while snapshot reading is in progress
	time.Sleep(700 * time.Millisecond)
	_, err = io.Copy(ioutil.Discard, rc2)
	if err != nil && !strings.Contains(err.Error(), context.DeadlineExceeded.Error()) {
		t.Errorf("expected %v from gRPC, got %v", context.DeadlineExceeded, err)
	}
}
<|endoftext|>


<commit_before>package integration_test

import (
	"encoding/json"
	"io/ioutil"
	"os"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/concourse/s3-resource"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
)

func TestIntegration(t *testing.T) {
	RegisterFailHandler(Fail)
}

var accessKeyID = os.Getenv("S3_TESTING_ACCESS_KEY_ID")
var secretAccessKey = os.Getenv("S3_TESTING_SECRET_ACCESS_KEY")
var versionedBucketName = os.Getenv("S3_VERSIONED_TESTING_BUCKET")
var bucketName = os.Getenv("S3_TESTING_BUCKET")
var regionName = os.Getenv("S3_TESTING_REGION")
var endpoint = os.Getenv("S3_ENDPOINT")
var v2signing = os.Getenv("S3_V2_SIGNING")
var s3client s3resource.S3Client
var s3Service *s3.S3

var checkPath string
var inPath string
var outPath string

type suiteData struct {
	CheckPath string
	InPath    string
	OutPath   string
}

var _ = SynchronizedBeforeSuite(func() []byte {
	cp, err := gexec.Build("github.com/concourse/s3-resource/cmd/check")
	Ω(err).ShouldNot(HaveOccurred())
	ip, err := gexec.Build("github.com/concourse/s3-resource/cmd/in")
	Ω(err).ShouldNot(HaveOccurred())
	op, err := gexec.Build("github.com/concourse/s3-resource/cmd/out")
	Ω(err).ShouldNot(HaveOccurred())

	data, err := json.Marshal(suiteData{
		CheckPath: cp,
		InPath:    ip,
		OutPath:   op,
	})

	Ω(err).ShouldNot(HaveOccurred())

	return data
}, func(data []byte) {
	var sd suiteData
	err := json.Unmarshal(data, &sd)
	Ω(err).ShouldNot(HaveOccurred())

	checkPath = sd.CheckPath
	inPath = sd.InPath
	outPath = sd.OutPath

	Ω(accessKeyID).ShouldNot(BeEmpty(), "must specify $S3_TESTING_ACCESS_KEY_ID")
	Ω(secretAccessKey).ShouldNot(BeEmpty(), "must specify $S3_TESTING_SECRET_ACCESS_KEY")
	Ω(versionedBucketName).ShouldNot(BeEmpty(), "must specify $S3_VERSIONED_TESTING_BUCKET")
	Ω(bucketName).ShouldNot(BeEmpty(), "must specify $S3_TESTING_BUCKET")
	Ω(regionName).ShouldNot(BeEmpty(), "must specify $S3_TESTING_REGION")

	awsConfig := s3resource.NewAwsConfig(
		accessKeyID,
		secretAccessKey,
		regionName,
		endpoint,
		false,
	)

	s3Service = s3.New(session.New(awsConfig), awsConfig)

	s3client = s3resource.NewS3Client(ioutil.Discard, awsConfig, v2signing == "true")
})

var _ = SynchronizedAfterSuite(func() {}, func() {
	gexec.CleanupBuildArtifacts()
})

func TestIn(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Integration Suite")
}

func buildEndpoint(bucket string, endpoint string) string {
	if endpoint == "" {
		return "https://s3.amazonaws.com/" + bucket
	} else {
		return endpoint + "/" + bucket
	}
}
<commit_msg>Check S3_ENDPOINT before integration test run<commit_after>package integration_test

import (
	"encoding/json"
	"io/ioutil"
	"os"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/concourse/s3-resource"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
)

func TestIntegration(t *testing.T) {
	RegisterFailHandler(Fail)
}

var accessKeyID = os.Getenv("S3_TESTING_ACCESS_KEY_ID")
var secretAccessKey = os.Getenv("S3_TESTING_SECRET_ACCESS_KEY")
var versionedBucketName = os.Getenv("S3_VERSIONED_TESTING_BUCKET")
var bucketName = os.Getenv("S3_TESTING_BUCKET")
var regionName = os.Getenv("S3_TESTING_REGION")
var endpoint = os.Getenv("S3_ENDPOINT")
var v2signing = os.Getenv("S3_V2_SIGNING")
var s3client s3resource.S3Client
var s3Service *s3.S3

var checkPath string
var inPath string
var outPath string

type suiteData struct {
	CheckPath string
	InPath    string
	OutPath   string
}

var _ = SynchronizedBeforeSuite(func() []byte {
	cp, err := gexec.Build("github.com/concourse/s3-resource/cmd/check")
	Ω(err).ShouldNot(HaveOccurred())
	ip, err := gexec.Build("github.com/concourse/s3-resource/cmd/in")
	Ω(err).ShouldNot(HaveOccurred())
	op, err := gexec.Build("github.com/concourse/s3-resource/cmd/out")
	Ω(err).ShouldNot(HaveOccurred())

	data, err := json.Marshal(suiteData{
		CheckPath: cp,
		InPath:    ip,
		OutPath:   op,
	})

	Ω(err).ShouldNot(HaveOccurred())

	return data
}, func(data []byte) {
	var sd suiteData
	err := json.Unmarshal(data, &sd)
	Ω(err).ShouldNot(HaveOccurred())

	checkPath = sd.CheckPath
	inPath = sd.InPath
	outPath = sd.OutPath

	Ω(accessKeyID).ShouldNot(BeEmpty(), "must specify $S3_TESTING_ACCESS_KEY_ID")
	Ω(secretAccessKey).ShouldNot(BeEmpty(), "must specify $S3_TESTING_SECRET_ACCESS_KEY")
	Ω(versionedBucketName).ShouldNot(BeEmpty(), "must specify $S3_VERSIONED_TESTING_BUCKET")
	Ω(bucketName).ShouldNot(BeEmpty(), "must specify $S3_TESTING_BUCKET")
	Ω(regionName).ShouldNot(BeEmpty(), "must specify $S3_TESTING_REGION")
	Ω(endpoint).ShouldNot(BeEmpty(), "must specify $S3_ENDPOINT")

	awsConfig := s3resource.NewAwsConfig(
		accessKeyID,
		secretAccessKey,
		regionName,
		endpoint,
		false,
	)

	s3Service = s3.New(session.New(awsConfig), awsConfig)

	s3client = s3resource.NewS3Client(ioutil.Discard, awsConfig, v2signing == "true")
})

var _ = SynchronizedAfterSuite(func() {}, func() {
	gexec.CleanupBuildArtifacts()
})

func TestIn(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Integration Suite")
}

func buildEndpoint(bucket string, endpoint string) string {
	if endpoint == "" {
		return "https://s3.amazonaws.com/" + bucket
	} else {
		return endpoint + "/" + bucket
	}
}
<|endoftext|>


<commit_before>package provider

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceInteger() *schema.Resource {
	return &schema.Resource{
		Description: "The resource `random_integer` generates random values from a given range, described " +
			"by the `min` and `max` attributes of a given resource.\n" +
			"\n" +
			"This resource can be used in conjunction with resources that have the `create_before_destroy` " +
			"lifecycle flag set, to avoid conflicts with unique names during the brief period where both the " +
			"old and new resources exist concurrently.",
		Create: CreateInteger,
		Read:   schema.Noop,
		Delete: schema.RemoveFromState,
		Importer: &schema.ResourceImporter{
			State: ImportInteger,
		},

		Schema: map[string]*schema.Schema{
			"keepers": {
				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
					"resource. See [the main provider documentation](../index.html) for more information.",
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},

			"min": {
				Description: "The minimum inclusive value of the range.",
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
			},

			"max": {
				Description: "The maximum inclusive value of the range.",
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
			},

			"seed": {
				Description: "A custom seed to always produce the same value.",
				Type:        schema.TypeString,
				Optional:    true,
				ForceNew:    true,
			},

			"result": {
				Description: "The random integer result.",
				Type:        schema.TypeInt,
				Computed:    true,
			},

			"id": {
				Description: "The string representation of the integer result.",
				Type:        schema.TypeString,
				Computed:    true,
			},
		},
		UseJSONNumber: true,
	}
}

func CreateInteger(d *schema.ResourceData, meta interface{}) error {
	min := d.Get("min").(int)
	max := d.Get("max").(int)
	seed := d.Get("seed").(string)

	if max <= min {
		return fmt.Errorf("Minimum value needs to be smaller than maximum value")
	}
	rand := NewRand(seed)
	number := rand.Intn((max+1)-min) + min

	d.Set("result", number)
	d.SetId(strconv.Itoa(number))

	return nil
}

func ImportInteger(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	parts := strings.Split(d.Id(), ",")
	if len(parts) != 3 && len(parts) != 4 {
		return nil, fmt.Errorf("Invalid import usage: expecting {result},{min},{max} or {result},{min},{max},{seed}")
	}

	result, err := strconv.Atoi(parts[0])
	if err != nil {
		return nil, errwrap.Wrapf("Error parsing \"result\": {{err}}", err)
	}
	d.Set("result", result)

	min, err := strconv.Atoi(parts[1])
	if err != nil {
		return nil, errwrap.Wrapf("Error parsing \"min\": {{err}}", err)
	}
	d.Set("min", min)

	max, err := strconv.Atoi(parts[2])
	if err != nil {
		return nil, errwrap.Wrapf("Error parsing \"max\": {{err}}", err)
	}
	d.Set("max", max)

	if len(parts) == 4 {
		d.Set("seed", parts[3])
	}
	d.SetId(parts[0])

	return []*schema.ResourceData{d}, nil
}
<commit_msg>Replace usage of Create field with CreateContext in resource_integer (#230)<commit_after>package provider

import (
	"context"
	"fmt"
	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
	"strconv"
	"strings"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceInteger() *schema.Resource {
	return &schema.Resource{
		Description: "The resource `random_integer` generates random values from a given range, described " +
			"by the `min` and `max` attributes of a given resource.\n" +
			"\n" +
			"This resource can be used in conjunction with resources that have the `create_before_destroy` " +
			"lifecycle flag set, to avoid conflicts with unique names during the brief period where both the " +
			"old and new resources exist concurrently.",
		CreateContext: CreateInteger,
		Read:          schema.Noop,
		Delete:        schema.RemoveFromState,
		Importer: &schema.ResourceImporter{
			State: ImportInteger,
		},

		Schema: map[string]*schema.Schema{
			"keepers": {
				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
					"resource. See [the main provider documentation](../index.html) for more information.",
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},

			"min": {
				Description: "The minimum inclusive value of the range.",
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
			},

			"max": {
				Description: "The maximum inclusive value of the range.",
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
			},

			"seed": {
				Description: "A custom seed to always produce the same value.",
				Type:        schema.TypeString,
				Optional:    true,
				ForceNew:    true,
			},

			"result": {
				Description: "The random integer result.",
				Type:        schema.TypeInt,
				Computed:    true,
			},

			"id": {
				Description: "The string representation of the integer result.",
				Type:        schema.TypeString,
				Computed:    true,
			},
		},
		UseJSONNumber: true,
	}
}

func CreateInteger(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
	var diags diag.Diagnostics
	min := d.Get("min").(int)
	max := d.Get("max").(int)
	seed := d.Get("seed").(string)

	if max <= min {
		return append(diags, diag.Diagnostic{
			Severity: diag.Error,
			Summary:  "minimum value needs to be smaller than maximum value",
		})
	}
	rand := NewRand(seed)
	number := rand.Intn((max+1)-min) + min

	d.Set("result", number)
	d.SetId(strconv.Itoa(number))

	return nil
}

func ImportInteger(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	parts := strings.Split(d.Id(), ",")
	if len(parts) != 3 && len(parts) != 4 {
		return nil, fmt.Errorf("Invalid import usage: expecting {result},{min},{max} or {result},{min},{max},{seed}")
	}

	result, err := strconv.Atoi(parts[0])
	if err != nil {
		return nil, errwrap.Wrapf("Error parsing \"result\": {{err}}", err)
	}
	d.Set("result", result)

	min, err := strconv.Atoi(parts[1])
	if err != nil {
		return nil, errwrap.Wrapf("Error parsing \"min\": {{err}}", err)
	}
	d.Set("min", min)

	max, err := strconv.Atoi(parts[2])
	if err != nil {
		return nil, errwrap.Wrapf("Error parsing \"max\": {{err}}", err)
	}
	d.Set("max", max)

	if len(parts) == 4 {
		d.Set("seed", parts[3])
	}
	d.SetId(parts[0])

	return []*schema.ResourceData{d}, nil
}
<|endoftext|>


<commit_before>package admin_test

import (
	"strconv"
	"strings"
	"testing"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/commands/admin"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/testutil"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/mocks"
	"github.com/cheekybits/is"
)

func TestAdminShowVLANsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	vlans := []brain.VLAN{getFixtureVLAN()}
	c.When("GetVLANs").Return(&vlans, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show vlans", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowVLANCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	vlanNum := 1
	vlan := getFixtureVLAN()
	c.When("GetVLAN", vlanNum).Return(&vlan, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show vlan 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowIPRangesCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	ipRanges := []brain.IPRange{getFixtureIPRange()}
	c.When("GetIPRanges").Return(&ipRanges, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show ip ranges", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowIPRangeCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	ipRangeID := "1"
	ipRange := getFixtureIPRange()
	c.When("GetIPRange", ipRangeID).Return(&ipRange, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show ip range 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowIPRangeWithIPRangeCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	rangeString := "192.168.33.0/24"
	ipRange := getFixtureIPRange()
	c.When("GetIPRange", rangeString).Return(&ipRange, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show ip range 192.168.33.0/24", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowHeadsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	heads := []brain.Head{getFixtureHead()}
	c.When("GetHeads").Return(&heads, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show heads", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowHeadCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	headID := "1"
	head := getFixtureHead()
	c.When("GetHead", headID).Return(&head, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show head 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowTailsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	tails := []brain.Tail{getFixtureTail()}
	c.When("GetTails").Return(&tails, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show tails", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowTailCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	tailID := "1"
	tail := getFixtureTail()
	c.When("GetTail", tailID).Return(&tail, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show tail 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowStoragePoolsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	storagePool := []brain.StoragePool{getFixtureStoragePool()}
	c.When("GetStoragePools").Return(&storagePool, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show storage pools", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowStoragePoolCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	storagePoolID := "1"
	storagePool := getFixtureStoragePool()
	c.When("GetStoragePool", storagePoolID).Return(&storagePool, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show storage pool 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowMigratingDiscsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	discs := brain.Discs{{ID: 134, StorageGrade: "sata", Size: 25600}}
	c.When("GetMigratingDiscs").Return(discs, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show migrating discs", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowMigrations(t *testing.T) {
	tests := []struct {
		name string
		mjs  brain.MigrationJobs
	}{
		{
			name: "NoJobs",
			mjs:  brain.MigrationJobs{},
		},
		{
			name: "OneJob",
			mjs: brain.MigrationJobs{
				{ID: 123},
			},
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			is := is.New(t)
			_, client, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)
			client.When("BuildRequest", "GET", lib.BrainEndpoint, "/admin/migration_jobs?unfinished=1%s", []string{""}).Return(&mocks.Request{
				T:              t,
				StatusCode:     200,
				ResponseObject: test.mjs,
			}).Times(1)
			err := app.Run(strings.Split("bytemark --admin show migrations", " "))
			is.Nil(err)
			if ok, err := client.Verify(); !ok {
				t.Fatal(err)
			}
		})
	}
}

func TestAdminShowMigration(t *testing.T) {
	tests := []struct {
		name      string
		id        int
		shouldErr bool
	}{
		{
			name:      "MissingID",
			shouldErr: true,
		},
		{
			name: "Successful",
			id:   123,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			_, client, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)
			args := []string{"bytemark", "--admin", "show", "migration"}
			if test.id > 0 {
				client.When("BuildRequest", "GET", lib.BrainEndpoint, "/admin/migration_jobs/%s", []string{strconv.Itoa(test.id)}).Return(&mocks.Request{
					T:              t,
					StatusCode:     200,
					ResponseObject: brain.MigrationJob{ID: test.id},
				}).Times(1)
				client.When("BuildRequest", "GET", lib.BrainEndpoint, "/admin/migration_jobs/%s/migrations", []string{strconv.Itoa(test.id)}).Return(&mocks.Request{
					T:              t,
					StatusCode:     200,
					ResponseObject: brain.Migrations{},
				}).Times(1)
				args = append(args, "--id", strconv.Itoa(test.id))
			}
			err := app.Run(args)
			if !test.shouldErr && err != nil {
				t.Errorf("shouldn't err, but did: %T{%s}", err, err.Error())
			} else if test.shouldErr && err == nil {
				t.Errorf("should err, but didn't")
			}
			if !test.shouldErr {
				if ok, err := client.Verify(); !ok {
					t.Fatal(err)
				}
			}
		})
	}
}

func TestAdminShowDiscByIDCommand(t *testing.T) {
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	discID := 132
	disc := getFixtureDisc()
	c.When("GetDiscByID", discID).Return(&disc, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show disc by id 132", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}
<commit_msg>add test for AdminShowDependantServers<commit_after>package admin_test

import (
	"strconv"
	"strings"
	"testing"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/commands/admin"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/testutil"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/mocks"
	"github.com/cheekybits/is"
)

func TestAdminShowVLANsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	vlans := []brain.VLAN{getFixtureVLAN()}
	c.When("GetVLANs").Return(&vlans, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show vlans", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowVLANCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	vlanNum := 1
	vlan := getFixtureVLAN()
	c.When("GetVLAN", vlanNum).Return(&vlan, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show vlan 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowIPRangesCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	ipRanges := []brain.IPRange{getFixtureIPRange()}
	c.When("GetIPRanges").Return(&ipRanges, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show ip ranges", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowIPRangeCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	ipRangeID := "1"
	ipRange := getFixtureIPRange()
	c.When("GetIPRange", ipRangeID).Return(&ipRange, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show ip range 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowIPRangeWithIPRangeCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	rangeString := "192.168.33.0/24"
	ipRange := getFixtureIPRange()
	c.When("GetIPRange", rangeString).Return(&ipRange, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show ip range 192.168.33.0/24", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowHeadsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	heads := []brain.Head{getFixtureHead()}
	c.When("GetHeads").Return(&heads, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show heads", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowHeadCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	headID := "1"
	head := getFixtureHead()
	c.When("GetHead", headID).Return(&head, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show head 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowTailsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	tails := []brain.Tail{getFixtureTail()}
	c.When("GetTails").Return(&tails, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show tails", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowTailCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	tailID := "1"
	tail := getFixtureTail()
	c.When("GetTail", tailID).Return(&tail, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show tail 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowStoragePoolsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	storagePool := []brain.StoragePool{getFixtureStoragePool()}
	c.When("GetStoragePools").Return(&storagePool, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show storage pools", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowStoragePoolCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	storagePoolID := "1"
	storagePool := getFixtureStoragePool()
	c.When("GetStoragePool", storagePoolID).Return(&storagePool, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show storage pool 1", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowMigratingDiscsCommand(t *testing.T) {
	// TODO(telyn): make table-driven
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	discs := brain.Discs{{ID: 134, StorageGrade: "sata", Size: 25600}}
	c.When("GetMigratingDiscs").Return(discs, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show migrating discs", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowMigrations(t *testing.T) {
	tests := []struct {
		name string
		mjs  brain.MigrationJobs
	}{
		{
			name: "NoJobs",
			mjs:  brain.MigrationJobs{},
		},
		{
			name: "OneJob",
			mjs: brain.MigrationJobs{
				{ID: 123},
			},
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			is := is.New(t)
			_, client, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)
			client.When("BuildRequest", "GET", lib.BrainEndpoint, "/admin/migration_jobs?unfinished=1%s", []string{""}).Return(&mocks.Request{
				T:              t,
				StatusCode:     200,
				ResponseObject: test.mjs,
			}).Times(1)
			err := app.Run(strings.Split("bytemark --admin show migrations", " "))
			is.Nil(err)
			if ok, err := client.Verify(); !ok {
				t.Fatal(err)
			}
		})
	}
}

func TestAdminShowMigration(t *testing.T) {
	tests := []struct {
		name      string
		id        int
		shouldErr bool
	}{
		{
			name:      "MissingID",
			shouldErr: true,
		},
		{
			name: "Successful",
			id:   123,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			_, client, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)
			args := []string{"bytemark", "--admin", "show", "migration"}
			if test.id > 0 {
				client.When("BuildRequest", "GET", lib.BrainEndpoint, "/admin/migration_jobs/%s", []string{strconv.Itoa(test.id)}).Return(&mocks.Request{
					T:              t,
					StatusCode:     200,
					ResponseObject: brain.MigrationJob{ID: test.id},
				}).Times(1)
				client.When("BuildRequest", "GET", lib.BrainEndpoint, "/admin/migration_jobs/%s/migrations", []string{strconv.Itoa(test.id)}).Return(&mocks.Request{
					T:              t,
					StatusCode:     200,
					ResponseObject: brain.Migrations{},
				}).Times(1)
				args = append(args, "--id", strconv.Itoa(test.id))
			}
			err := app.Run(args)
			if !test.shouldErr && err != nil {
				t.Errorf("shouldn't err, but did: %T{%s}", err, err.Error())
			} else if test.shouldErr && err == nil {
				t.Errorf("should err, but didn't")
			}
			if !test.shouldErr {
				if ok, err := client.Verify(); !ok {
					t.Fatal(err)
				}
			}
		})
	}
}

func TestAdminShowDiscByIDCommand(t *testing.T) {
	is := is.New(t)
	_, c, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

	discID := 132
	disc := getFixtureDisc()
	c.When("GetDiscByID", discID).Return(&disc, nil).Times(1)

	err := app.Run(strings.Split("bytemark --admin show disc by id 132", " "))
	is.Nil(err)

	if ok, err := c.Verify(); !ok {
		t.Fatal(err)
	}
}

func TestAdminShowDependantServers(t *testing.T) {
	tests := []struct {
		name	string
		url		string
		args 	[]string
	}{
		{
			name: "head",
			url: "/admin/heads/%s/virtual_machines",
			args: []string{"--head", "123"},
		},
		{
			name: "tail",
			url: "/admin/tails/%s/virtual_machines",
			args: []string{"--tail", "123"},
		},
		{
			name: "storage pool",
			url: "/admin/storage_pools/%s/virtual_machines",
			args: []string{"--storage-pool", "123"},
		},
	}

	baseArgs := []string{"bytemark", "--admin", "show", "dependant", "servers"}
	servers := mocks.Request{
		T:              t,
		StatusCode:     200,
		ResponseObject: []brain.VirtualMachine{
			{ID: 1, Name: "Test1"},
			{ID: 2, Name: "Test2"},
		},
	}

	is := is.New(t)

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			_, client, app := testutil.BaseTestAuthSetup(t, true, admin.Commands)

			client.When("BuildRequest", "GET", lib.BrainEndpoint, test.url, []string{"123"}).Return(&servers).Times(1)

			err := app.Run(append(baseArgs, test.args...))
			is.Nil(err)
			if ok, err := client.Verify(); !ok {
				t.Fatal(err)
			}
		})
	}
}
<|endoftext|>


<commit_before>package collectors

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"time"

	"bosun.org/_third_party/github.com/stackexchange/mof"
	"bosun.org/metadata"
	"bosun.org/opentsdb"
	"bosun.org/util"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_dsc_mof, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_dsc_status, Interval: time.Minute * 5})
}

const (
	dscLCM    = "dsc.lcm."
	dscMof    = "dsc.mof."
	dscStatus = "dsc.status."
)

var (
	dscpath     = os.ExpandEnv(`${SYSTEMROOT}\system32\Configuration\`)
	mapMofFiles = map[string]string{
		"MetaConfig.mof":       "Meta_Config",
		"Current.mof":          "Current_Config",
		"backup.mof":           "Backup_Config",
		"pending.mof":          "Pending_Config",
		"DSCStatusHistory.mof": "DSC_History",
		"DSCEngineCache.mof":   "DSC_Cache",
	}
)

// c_dsc_mof monitors the size and last modified time of each mof file.
// These out of band metrics can be used to verify the DSC WMI Status metrics.
func c_dsc_mof() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	c := 0
	if _, err := os.Stat(dscpath + "MetaConfig.mof"); os.IsNotExist(err) {
		c = 1
	}
	Add(&md, dscLCM+"configured", c, nil, metadata.Gauge, metadata.StatusCode, descDSCLCMConfigured)
	if c == 1 {
		return md, nil
	}
	for filename, filetype := range mapMofFiles {
		tags := opentsdb.TagSet{"type": filetype}
		s := int64(-1)
		l := int64(-1)
		if fi, fierr := os.Stat(dscpath + filename); fierr == nil {
			s = fi.Size()
			l = time.Now().Unix() - fi.ModTime().Unix()
		}
		Add(&md, dscMof+"size", s, tags, metadata.Gauge, metadata.Bytes, descDSCMofSize)
		Add(&md, dscMof+"last_modified", l, tags, metadata.Gauge, metadata.Second, descDSCMofModified)
	}
	return md, nil
}

const (
	descDSCLCMConfigured = "Indicates if DSC Local Configuration Manager is configured: 0=configured, 1=not configured. If the LCM is not configured then the rest of the dsc.* metrics will be skipped on that server."
	descDSCMofSize       = "Size of the mof file in bytes or -1 if file does not exist."
	descDSCMofModified   = "Number of seconds since the mof file was last modified or -1 if file does not exist."
)

func c_dsc_status() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	if _, err := os.Stat(dscpath + "MetaConfig.mof"); os.IsNotExist(err) {
		return md, nil
	}
	var dst MSFT_DSCConfigurationStatus
	dscstatusmof, err := util.Command(time.Minute, nil, "wmic",
		`/namespace:\\ROOT\Microsoft\Windows\DesiredStateConfiguration`, "class",
		"MSFT_DSCLocalConfigurationManager", "call", "GetConfigurationStatus")
	if err != nil {
		return nil, err
	}
	dscstatusbuffer := new(bytes.Buffer)
	_, err = dscstatusbuffer.ReadFrom(dscstatusmof)
	if err != nil {
		return nil, err
	}
	err = mof.Unmarshal(dscstatusbuffer.Bytes(), &dst)
	if err != nil {
		return nil, err
	}
	if dst.ReturnValue != 0 {
		return nil, fmt.Errorf("GetConfigurationStatus ReturnValue %v", dst.ReturnValue)
	}
	for _, v := range dst.MSFT_DSCConfigurationStatus {
		Add(&md, dscLCM+"auto_reboot", v.MetaConfiguration.RebootNodeIfNeeded, nil, metadata.Gauge, metadata.Bool, descWinDSCAutoReboot)
		Add(&md, dscLCM+"frequency_config", v.MetaConfiguration.ConfigurationModeFrequencyMins, nil, metadata.Gauge, metadata.Count, descWinDSCFreqConfig)
		Add(&md, dscLCM+"frequency_refresh", v.MetaConfiguration.RefreshFrequencyMins, nil, metadata.Gauge, metadata.Count, descWinDSCFreqRefresh)
		Add(&md, dscLCM+"refresh_mode", dscModeToStatusCode(v.Mode), nil, metadata.Gauge, metadata.StatusCode, descWinDSCMode)
		Add(&md, dscLCM+"state", dscStateToStatusCode(v.MetaConfiguration.LCMState), nil, metadata.Gauge, metadata.StatusCode, descWinDSCState)
		Add(&md, dscStatus+"reboot_requested", v.RebootRequested, nil, metadata.Gauge, metadata.Bool, descWinDSCRebootRequested)
		Add(&md, dscStatus+"resources_total", v.NumberOfResources, nil, metadata.Gauge, metadata.Count, descWinDSCNumberOfResources)
		Add(&md, dscStatus+"run_age", dscStartDateToAge(v.StartDate), nil, metadata.Gauge, metadata.Second, descWinDSCAge)
		Add(&md, dscStatus+"run_duration", v.DurationInSeconds, nil, metadata.Gauge, metadata.Second, descWinDSCDurationInSeconds)
		Add(&md, dscStatus+"run_success", v.Status == "Success", nil, metadata.Gauge, metadata.Bool, descWinDSCStatus)
		Add(&md, dscStatus+"run_type", dscTypeToStatusCode(v.Type), nil, metadata.Gauge, metadata.Count, descWinDSCType)
		configurations := make(map[string]dscResourceCount)
		for _, r := range v.ResourcesInDesiredState {
			c := configurations[r.ConfigurationName]
			c.Success++
			c.Duration += r.DurationInSeconds
			configurations[r.ConfigurationName] = c
		}
		for _, r := range v.ResourcesNotInDesiredState {
			c := configurations[r.ConfigurationName]
			c.Failed++
			c.Duration += r.DurationInSeconds
			configurations[r.ConfigurationName] = c
		}
		for key, value := range configurations {
			Add(&md, dscStatus+"resources", value.Success, opentsdb.TagSet{"state": "Success", "configuration": key}, metadata.Gauge, metadata.Count, descWinDSCResourceState)
			Add(&md, dscStatus+"resources", value.Failed, opentsdb.TagSet{"state": "Failed", "configuration": key}, metadata.Gauge, metadata.Count, descWinDSCResourceState)
			Add(&md, dscStatus+"config_duration", value.Duration, opentsdb.TagSet{"configuration": key}, metadata.Gauge, metadata.Second, descWinDSCConfigSeconds)
		}
	}
	return md, nil
}

const (
	descWinDSCAge               = "Seconds since the last DSC run."
	descWinDSCAutoReboot        = "Bool for if the LCM can automatically reboot the system when needed."
	descWinDSCDurationInSeconds = "Seconds taken to process entire configuration."
	descWinDSCConfigSeconds     = "Seconds taken to process each configuration."
	descWinDSCFreqConfig        = "Specifies how often (in minutes) LCM ensures that the configuration is in the desired state."
	descWinDSCFreqRefresh       = "Specifies how often (in minutes) LCM attempts to obtain the configuration from the pull server. If configuration on the pull server differs from the current one on the target node, it is copied to the pending store and applied."
	descWinDSCMode              = "Refresh mode of configuration. 0=Pull, 1=Push, 2=Disabled, -1=Unknown."
	descWinDSCNumberOfResources = "Total number of resources in configuration."
	descWinDSCRebootRequested   = "Reboot was requested during configuration run."
	descWinDSCResourceState     = "Count of resources from each named configuration that were successful or failed."
	descWinDSCStartDate         = "Date and time when the configuration was started."
	descWinDSCState             = "Current LCM Statue. 0=Idle, 1=PendingConfiguration, 2=Ready, 3=Busy, 4=PendingReboot, -1=Unknown."
	descWinDSCStatus            = "Status of configuration."
	descWinDSCType              = "Type of configuration run. 0=Reboot, 1=Initial, 2=Consistency, 3=ReadOnly, -1=Unknown."
)

type MSFT_DSCConfigurationStatus struct {
	MSFT_DSCConfigurationStatus []struct {
		DurationInSeconds int
		MetaConfiguration struct {
			ConfigurationModeFrequencyMins int
			LCMState                       string
			RebootNodeIfNeeded             bool
			RefreshFrequencyMins           int
		}
		Mode                    string
		NumberOfResources       int
		RebootRequested         bool
		ResourcesInDesiredState []struct {
			ConfigurationName string
			DurationInSeconds float64
		}
		ResourcesNotInDesiredState []struct {
			ConfigurationName string
			DurationInSeconds float64
		}
		StartDate string
		Status    string
		Type      string
	}
	ReturnValue int
}

type dscResourceCount struct {
	Success  int
	Failed   int
	Duration float64
}

func dscModeToStatusCode(mode string) int64 {
	switch strings.ToUpper(mode) {
	case "PULL":
		return 0
	case "PUSH":
		return 1
	case "DISABLED":
		return 2
	default:
		return -1
	}
}

func dscTypeToStatusCode(t string) int64 {
	switch strings.ToUpper(t) {
	case "REBOOT":
		return 0
	case "INITIAL":
		return 1
	case "CONSISTENCY":
		return 2
	case "READONLY":
		return 3
	default:
		return -1
	}
}

func dscStateToStatusCode(t string) int64 {
	switch strings.ToUpper(t) {
	case "IDLE":
		return 0
	case "PENDINGCONFIGURATION":
		return 1
	case "READY":
		return 2
	case "BUSY":
		return 3
	case "PENDINGREBOOT":
		return 4
	default:
		return -1
	}
}

func dscStartDateToAge(startdate string) float64 {
	t, err := time.Parse("2006/01/02 15:04:05", startdate)
	if err != nil {
		return -1
	}
	return time.Now().Sub(t).Seconds()
}
<commit_msg>Fixing case of import statement for windows build<commit_after>package collectors

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"time"

	"bosun.org/_third_party/github.com/StackExchange/mof"
	"bosun.org/metadata"
	"bosun.org/opentsdb"
	"bosun.org/util"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_dsc_mof, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_dsc_status, Interval: time.Minute * 5})
}

const (
	dscLCM    = "dsc.lcm."
	dscMof    = "dsc.mof."
	dscStatus = "dsc.status."
)

var (
	dscpath     = os.ExpandEnv(`${SYSTEMROOT}\system32\Configuration\`)
	mapMofFiles = map[string]string{
		"MetaConfig.mof":       "Meta_Config",
		"Current.mof":          "Current_Config",
		"backup.mof":           "Backup_Config",
		"pending.mof":          "Pending_Config",
		"DSCStatusHistory.mof": "DSC_History",
		"DSCEngineCache.mof":   "DSC_Cache",
	}
)

// c_dsc_mof monitors the size and last modified time of each mof file.
// These out of band metrics can be used to verify the DSC WMI Status metrics.
func c_dsc_mof() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	c := 0
	if _, err := os.Stat(dscpath + "MetaConfig.mof"); os.IsNotExist(err) {
		c = 1
	}
	Add(&md, dscLCM+"configured", c, nil, metadata.Gauge, metadata.StatusCode, descDSCLCMConfigured)
	if c == 1 {
		return md, nil
	}
	for filename, filetype := range mapMofFiles {
		tags := opentsdb.TagSet{"type": filetype}
		s := int64(-1)
		l := int64(-1)
		if fi, fierr := os.Stat(dscpath + filename); fierr == nil {
			s = fi.Size()
			l = time.Now().Unix() - fi.ModTime().Unix()
		}
		Add(&md, dscMof+"size", s, tags, metadata.Gauge, metadata.Bytes, descDSCMofSize)
		Add(&md, dscMof+"last_modified", l, tags, metadata.Gauge, metadata.Second, descDSCMofModified)
	}
	return md, nil
}

const (
	descDSCLCMConfigured = "Indicates if DSC Local Configuration Manager is configured: 0=configured, 1=not configured. If the LCM is not configured then the rest of the dsc.* metrics will be skipped on that server."
	descDSCMofSize       = "Size of the mof file in bytes or -1 if file does not exist."
	descDSCMofModified   = "Number of seconds since the mof file was last modified or -1 if file does not exist."
)

func c_dsc_status() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	if _, err := os.Stat(dscpath + "MetaConfig.mof"); os.IsNotExist(err) {
		return md, nil
	}
	var dst MSFT_DSCConfigurationStatus
	dscstatusmof, err := util.Command(time.Minute, nil, "wmic",
		`/namespace:\\ROOT\Microsoft\Windows\DesiredStateConfiguration`, "class",
		"MSFT_DSCLocalConfigurationManager", "call", "GetConfigurationStatus")
	if err != nil {
		return nil, err
	}
	dscstatusbuffer := new(bytes.Buffer)
	_, err = dscstatusbuffer.ReadFrom(dscstatusmof)
	if err != nil {
		return nil, err
	}
	err = mof.Unmarshal(dscstatusbuffer.Bytes(), &dst)
	if err != nil {
		return nil, err
	}
	if dst.ReturnValue != 0 {
		return nil, fmt.Errorf("GetConfigurationStatus ReturnValue %v", dst.ReturnValue)
	}
	for _, v := range dst.MSFT_DSCConfigurationStatus {
		Add(&md, dscLCM+"auto_reboot", v.MetaConfiguration.RebootNodeIfNeeded, nil, metadata.Gauge, metadata.Bool, descWinDSCAutoReboot)
		Add(&md, dscLCM+"frequency_config", v.MetaConfiguration.ConfigurationModeFrequencyMins, nil, metadata.Gauge, metadata.Count, descWinDSCFreqConfig)
		Add(&md, dscLCM+"frequency_refresh", v.MetaConfiguration.RefreshFrequencyMins, nil, metadata.Gauge, metadata.Count, descWinDSCFreqRefresh)
		Add(&md, dscLCM+"refresh_mode", dscModeToStatusCode(v.Mode), nil, metadata.Gauge, metadata.StatusCode, descWinDSCMode)
		Add(&md, dscLCM+"state", dscStateToStatusCode(v.MetaConfiguration.LCMState), nil, metadata.Gauge, metadata.StatusCode, descWinDSCState)
		Add(&md, dscStatus+"reboot_requested", v.RebootRequested, nil, metadata.Gauge, metadata.Bool, descWinDSCRebootRequested)
		Add(&md, dscStatus+"resources_total", v.NumberOfResources, nil, metadata.Gauge, metadata.Count, descWinDSCNumberOfResources)
		Add(&md, dscStatus+"run_age", dscStartDateToAge(v.StartDate), nil, metadata.Gauge, metadata.Second, descWinDSCAge)
		Add(&md, dscStatus+"run_duration", v.DurationInSeconds, nil, metadata.Gauge, metadata.Second, descWinDSCDurationInSeconds)
		Add(&md, dscStatus+"run_success", v.Status == "Success", nil, metadata.Gauge, metadata.Bool, descWinDSCStatus)
		Add(&md, dscStatus+"run_type", dscTypeToStatusCode(v.Type), nil, metadata.Gauge, metadata.Count, descWinDSCType)
		configurations := make(map[string]dscResourceCount)
		for _, r := range v.ResourcesInDesiredState {
			c := configurations[r.ConfigurationName]
			c.Success++
			c.Duration += r.DurationInSeconds
			configurations[r.ConfigurationName] = c
		}
		for _, r := range v.ResourcesNotInDesiredState {
			c := configurations[r.ConfigurationName]
			c.Failed++
			c.Duration += r.DurationInSeconds
			configurations[r.ConfigurationName] = c
		}
		for key, value := range configurations {
			Add(&md, dscStatus+"resources", value.Success, opentsdb.TagSet{"state": "Success", "configuration": key}, metadata.Gauge, metadata.Count, descWinDSCResourceState)
			Add(&md, dscStatus+"resources", value.Failed, opentsdb.TagSet{"state": "Failed", "configuration": key}, metadata.Gauge, metadata.Count, descWinDSCResourceState)
			Add(&md, dscStatus+"config_duration", value.Duration, opentsdb.TagSet{"configuration": key}, metadata.Gauge, metadata.Second, descWinDSCConfigSeconds)
		}
	}
	return md, nil
}

const (
	descWinDSCAge               = "Seconds since the last DSC run."
	descWinDSCAutoReboot        = "Bool for if the LCM can automatically reboot the system when needed."
	descWinDSCDurationInSeconds = "Seconds taken to process entire configuration."
	descWinDSCConfigSeconds     = "Seconds taken to process each configuration."
	descWinDSCFreqConfig        = "Specifies how often (in minutes) LCM ensures that the configuration is in the desired state."
	descWinDSCFreqRefresh       = "Specifies how often (in minutes) LCM attempts to obtain the configuration from the pull server. If configuration on the pull server differs from the current one on the target node, it is copied to the pending store and applied."
	descWinDSCMode              = "Refresh mode of configuration. 0=Pull, 1=Push, 2=Disabled, -1=Unknown."
	descWinDSCNumberOfResources = "Total number of resources in configuration."
	descWinDSCRebootRequested   = "Reboot was requested during configuration run."
	descWinDSCResourceState     = "Count of resources from each named configuration that were successful or failed."
	descWinDSCStartDate         = "Date and time when the configuration was started."
	descWinDSCState             = "Current LCM Statue. 0=Idle, 1=PendingConfiguration, 2=Ready, 3=Busy, 4=PendingReboot, -1=Unknown."
	descWinDSCStatus            = "Status of configuration."
	descWinDSCType              = "Type of configuration run. 0=Reboot, 1=Initial, 2=Consistency, 3=ReadOnly, -1=Unknown."
)

type MSFT_DSCConfigurationStatus struct {
	MSFT_DSCConfigurationStatus []struct {
		DurationInSeconds int
		MetaConfiguration struct {
			ConfigurationModeFrequencyMins int
			LCMState                       string
			RebootNodeIfNeeded             bool
			RefreshFrequencyMins           int
		}
		Mode                    string
		NumberOfResources       int
		RebootRequested         bool
		ResourcesInDesiredState []struct {
			ConfigurationName string
			DurationInSeconds float64
		}
		ResourcesNotInDesiredState []struct {
			ConfigurationName string
			DurationInSeconds float64
		}
		StartDate string
		Status    string
		Type      string
	}
	ReturnValue int
}

type dscResourceCount struct {
	Success  int
	Failed   int
	Duration float64
}

func dscModeToStatusCode(mode string) int64 {
	switch strings.ToUpper(mode) {
	case "PULL":
		return 0
	case "PUSH":
		return 1
	case "DISABLED":
		return 2
	default:
		return -1
	}
}

func dscTypeToStatusCode(t string) int64 {
	switch strings.ToUpper(t) {
	case "REBOOT":
		return 0
	case "INITIAL":
		return 1
	case "CONSISTENCY":
		return 2
	case "READONLY":
		return 3
	default:
		return -1
	}
}

func dscStateToStatusCode(t string) int64 {
	switch strings.ToUpper(t) {
	case "IDLE":
		return 0
	case "PENDINGCONFIGURATION":
		return 1
	case "READY":
		return 2
	case "BUSY":
		return 3
	case "PENDINGREBOOT":
		return 4
	default:
		return -1
	}
}

func dscStartDateToAge(startdate string) float64 {
	t, err := time.Parse("2006/01/02 15:04:05", startdate)
	if err != nil {
		return -1
	}
	return time.Now().Sub(t).Seconds()
}
<|endoftext|>