<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

// To enable debug output when testing, use "go test -debug"

package parse

import (
	"encoding/json"
	"github.com/demizer/go-elog"
	"reflect"
	"strings"
	"testing"
)

var lexParseTests LexTests

func TestSectionLevelsAdd(t *testing.T) {
	var p sectionLevels
	lvl := p.Add('=', true, 5)
	if lvl != 1 {
		t.Errorf("Improper level on first add, Got level: %d, expected: %d", lvl, 1)
	}
}

func TestSectionLevelsString(t *testing.T) {
	var p sectionLevels
	p.Add('=', true, 5)
	p.Add('-', true, 8)
	p.Add('~', false, 6)
	out := p.String()
	expect := "level: 1, rune: '=', overline: true, length: 5\nlevel: 2, rune: '-', " +
		"overline: true, length: 8\nlevel: 3, rune: '~', overline: false, length: 6\n"
	if out != expect {
		t.Errorf("String output mismatch!\nExpect:\n\n\t%q,\nGot:\n\n\t%q\n", expect, out)
	}
}

func TestSectionLevelsFind(t *testing.T) {
	var p sectionLevels
	p.Add('=', true, 5)
	p.Add('-', true, 8)
	p.Add('~', false, 6)
	lvl := p.Find('-')
	if lvl == -1 {
		t.Errorf("Level not found!\nExpect:\n\n\t%d\nGot:\n\n\t%t\n", 2, lvl)
	}
	if lvl != 2 {
		t.Errorf("Level not correct!\nExpect:\n\n\t%d\nGot:\n\n\t%d\n", 2, lvl)
	}
}

func TestSectionLevelsFindNoResult(t *testing.T) {
	var p sectionLevels
	lvl := p.Find('-')
	if lvl > 0 {
		t.Errorf("Should not find any levels!\nExpect:\n\n\t%d\nGot:\n\n\t%d\n", -1, lvl)
	}
}

func TestSectionLevelsLevelEmpty(t *testing.T) {
	var p sectionLevels
	lvl := p.Level()
	expect := 0
	if lvl != expect {
		t.Errorf("Empty sectionLevels should return \"%d\"!\nExpect:\t%d\nGot:\t%d\n",
			expect, expect, lvl)
	}

}

func TestSectionLevelsLevel(t *testing.T) {
	var p sectionLevels
	p.Add('=', true, 5)
	p.Add('-', true, 8)
	p.Add('~', false, 6)
	lvl := p.Level()
	if lvl != 3 {
		t.Errorf("Level() returned incorrect level!\nExpect:\n\n\t%d\nGot:\n\n\t%d\n", 3, lvl)
	}
}

func parseTest(t *testing.T, testName string) (tree *Tree, err error) {
	if lexParseTests == nil {
		lexParseTests, err = ParseTestData("../testdata/test_lex_sections.dat")
		if err != nil {
			t.Fatal(err)
		}
	}
	test := lexParseTests.SearchByName(testName)
	if test != nil {
		log.Debugf("Test Name: \t%s\n", test.name)
		log.Debugf("Description: \t%s\n", test.description)
		log.Debugf("Test Input:\n-----------\n%s\n----------\n", test.data)
		tree, err = Parse(test.name, test.data)
		if err != nil {
			t.Fatal(err)
		}
	}
	return
}

type checkNode struct {
	t          *testing.T
	testName   string
	pNodeName  string
	pFieldName string
	pFieldVal  interface{}
	pFieldType reflect.Type
	eFieldName string
	eFieldVal  interface{}
	eFieldType reflect.Type
	id         int
}

func (c *checkNode) error(args ...interface{}) {
	c.t.Error(args...)
}

func (c *checkNode) errorf(format string, args ...interface{}) {
	c.t.Errorf(format, args...)
}

func (c *checkNode) dError() {
	if c.pFieldName == "Rune" {
		c.t.Errorf("Got: %s.%s = %#v (%v) (%v) (Id: %d),\n\tExpect: %s.%s = %#v (%v)\n",
			c.pNodeName, c.pFieldName, c.pFieldVal, string(c.pFieldVal.(int32)),
			c.pFieldType, c.id, c.testName, c.eFieldName, c.eFieldVal, c.eFieldType)
		return
	}
	c.t.Errorf("Got: %s.%s = %#v (%v) (Id: %d),\n\tExpect: %s.%s = %#v (%v)\n",
		c.pNodeName, c.pFieldName, c.pFieldVal, c.pFieldType, c.id, c.testName,
		c.eFieldName, c.eFieldVal, c.eFieldType)
}

func (c *checkNode) updateState(pVal reflect.Value, eVal interface{}, field int) bool {
	// Actual parsed metadata
	c.pNodeName = pVal.Type().Name()
	c.pFieldName = pVal.Type().Field(field).Name
	c.pFieldVal = pVal.Field(field).Interface()
	c.pFieldType = pVal.Type().Field(field).Type
	c.id = pVal.FieldByName("Id").Interface().(int)

	// Expected parser metadata
	c.eFieldName = strings.ToLower(string(c.pFieldName[0])) + c.pFieldName[1:]
	c.eFieldVal = eVal.(map[string]interface{})[c.eFieldName]
	c.eFieldType = reflect.TypeOf(c.eFieldVal)

	if c.eFieldVal == nil && c.eFieldName != "overLine" {
		c.dError()
		return false
	}

	return true
}

func (c *checkNode) checkFields(pNode Node, expect interface{}) {
	pVal := reflect.ValueOf(pNode).Elem()
	for i := 0; i < pVal.NumField(); i++ {

		if c.updateState(pVal, expect, i) == false {
			continue
		}

		switch c.pFieldName {
		case "Type":
			if c.pFieldVal.(NodeType).String() != c.eFieldVal {
				c.dError()
			}
		case "Id", "Level", "Length":
			if float64(c.pFieldVal.(int)) != c.eFieldVal {
				c.dError()
			}
		case "Line":
			if float64(c.pFieldVal.(Line)) != c.eFieldVal {
				c.dError()
			}
		case "StartPosition":
			if float64(c.pFieldVal.(StartPosition)) != c.eFieldVal {
				c.dError()
			}
		case "OverLine", "UnderLine":
			// c.checkAdornmentNode(c.pFieldVal.(*AdornmentNode), c.eFieldVal, c.testName)
			c.error("Overline/Underline not implemented!")
		case "NodeList":
			c.error("NodeList not implemented!")
		default:
			if c.pFieldVal != c.eFieldVal {
				c.dError()
			}
		}
	}

}

// checkParseNodes is a recursive function that compares the resulting nodes (pNodes) from the
// parser with the expected output from the testdata (eNodes).
func checkParseNodes(t *testing.T, pNodes *NodeList, eNodes []interface{}, testName string) (errors []error) {
	state := &checkNode{t: t, testName: testName}
	for pNum, pNode := range *pNodes {
		state.checkFields(pNode, eNodes[pNum])
	}
	return
}

func TestParseSectionTitlePara(t *testing.T) {
	testName := "SectionTitlePara"
	tree, err := parseTest(t, testName)
	if err != nil {
		t.Error(err)
	}
	test := lexParseTests.SearchByName(testName)
	var nodeList []interface{}
	err = json.Unmarshal([]byte(test.expectTree), &nodeList)
	if err != nil {
		t.Error(err)
	}
	errors := checkParseNodes(t, tree.Nodes, nodeList, testName)
	if errors != nil {
		for _, err := range errors {
			t.Error(err)
		}
	}
}
<commit_msg>parse_test.go: Fix interface compare to nil<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

// To enable debug output when testing, use "go test -debug"

package parse

import (
	"encoding/json"
	"github.com/demizer/go-elog"
	"reflect"
	"strings"
	"testing"
)

var lexParseTests LexTests

func TestSectionLevelsAdd(t *testing.T) {
	var p sectionLevels
	lvl := p.Add('=', true, 5)
	if lvl != 1 {
		t.Errorf("Improper level on first add, Got level: %d, expected: %d", lvl, 1)
	}
}

func TestSectionLevelsString(t *testing.T) {
	var p sectionLevels
	p.Add('=', true, 5)
	p.Add('-', true, 8)
	p.Add('~', false, 6)
	out := p.String()
	expect := "level: 1, rune: '=', overline: true, length: 5\nlevel: 2, rune: '-', " +
		"overline: true, length: 8\nlevel: 3, rune: '~', overline: false, length: 6\n"
	if out != expect {
		t.Errorf("String output mismatch!\nExpect:\n\n\t%q,\nGot:\n\n\t%q\n", expect, out)
	}
}

func TestSectionLevelsFind(t *testing.T) {
	var p sectionLevels
	p.Add('=', true, 5)
	p.Add('-', true, 8)
	p.Add('~', false, 6)
	lvl := p.Find('-')
	if lvl == -1 {
		t.Errorf("Level not found!\nExpect:\n\n\t%d\nGot:\n\n\t%t\n", 2, lvl)
	}
	if lvl != 2 {
		t.Errorf("Level not correct!\nExpect:\n\n\t%d\nGot:\n\n\t%d\n", 2, lvl)
	}
}

func TestSectionLevelsFindNoResult(t *testing.T) {
	var p sectionLevels
	lvl := p.Find('-')
	if lvl > 0 {
		t.Errorf("Should not find any levels!\nExpect:\n\n\t%d\nGot:\n\n\t%d\n", -1, lvl)
	}
}

func TestSectionLevelsLevelEmpty(t *testing.T) {
	var p sectionLevels
	lvl := p.Level()
	expect := 0
	if lvl != expect {
		t.Errorf("Empty sectionLevels should return \"%d\"!\nExpect:\t%d\nGot:\t%d\n",
			expect, expect, lvl)
	}

}

func TestSectionLevelsLevel(t *testing.T) {
	var p sectionLevels
	p.Add('=', true, 5)
	p.Add('-', true, 8)
	p.Add('~', false, 6)
	lvl := p.Level()
	if lvl != 3 {
		t.Errorf("Level() returned incorrect level!\nExpect:\n\n\t%d\nGot:\n\n\t%d\n", 3, lvl)
	}
}

func parseTest(t *testing.T, testName string) (tree *Tree, err error) {
	if lexParseTests == nil {
		lexParseTests, err = ParseTestData("../testdata/test_lex_sections.dat")
		if err != nil {
			t.Fatal(err)
		}
	}
	test := lexParseTests.SearchByName(testName)
	if test != nil {
		log.Debugf("Test Name: \t%s\n", test.name)
		log.Debugf("Description: \t%s\n", test.description)
		log.Debugf("Test Input:\n-----------\n%s\n----------\n", test.data)
		tree, err = Parse(test.name, test.data)
		if err != nil {
			t.Fatal(err)
		}
	}
	return
}

type checkNode struct {
	t          *testing.T
	testName   string
	pNodeName  string
	pFieldName string
	pFieldVal  interface{}
	pFieldType reflect.Type
	eFieldName string
	eFieldVal  interface{}
	eFieldType reflect.Type
	id         int
}

func (c *checkNode) error(args ...interface{}) {
	c.t.Error(args...)
}

func (c *checkNode) errorf(format string, args ...interface{}) {
	c.t.Errorf(format, args...)
}

func (c *checkNode) dError() {
	if c.pFieldName == "Rune" {
		c.t.Errorf("Got: %s.%s = %#v (%v) (%v) (Id: %d),\n\tExpect: %s.%s = %#v (%v)\n",
			c.pNodeName, c.pFieldName, c.pFieldVal, string(c.pFieldVal.(int32)),
			c.pFieldType, c.id, c.testName, c.eFieldName, c.eFieldVal, c.eFieldType)
		return
	}
	c.t.Errorf("Got: %s.%s = %#v (%v) (Id: %d),\n\tExpect: %s.%s = %#v (%v)\n",
		c.pNodeName, c.pFieldName, c.pFieldVal, c.pFieldType, c.id, c.testName,
		c.eFieldName, c.eFieldVal, c.eFieldType)
}

func (c *checkNode) updateState(pVal reflect.Value, eVal interface{}, field int) bool {
	// Actual parsed metadata
	c.pNodeName = pVal.Type().Name()
	c.pFieldName = pVal.Type().Field(field).Name
	c.pFieldVal = pVal.Field(field).Interface()
	c.pFieldType = pVal.Type().Field(field).Type
	c.id = pVal.FieldByName("Id").Interface().(int)

	// Expected parser metadata
	c.eFieldName = strings.ToLower(string(c.pFieldName[0])) + c.pFieldName[1:]
	c.eFieldVal = eVal.(map[string]interface{})[c.eFieldName]
	c.eFieldType = reflect.TypeOf(c.eFieldVal)

	pField := pVal.Field(field)
	if pField.Kind() == reflect.Ptr && pField.IsNil() {
		// Overline adornment nodes can be null
		if c.pFieldName == "OverLine" {
			return false
		} else {
			c.dError()
			return false
		}
	} else if c.pFieldVal == nil {
		c.dError()
		return false
	}

	return true
}

func (c *checkNode) checkFields(pNode Node, expect interface{}) {
	pVal := reflect.ValueOf(pNode).Elem()
	for i := 0; i < pVal.NumField(); i++ {

		if c.updateState(pVal, expect, i) == false {
			continue
		}

		switch c.pFieldName {
		case "Type":
			if c.pFieldVal.(NodeType).String() != c.eFieldVal {
				c.dError()
			}
		case "Id", "Level", "Length":
			if float64(c.pFieldVal.(int)) != c.eFieldVal {
				c.dError()
			}
		case "Line":
			if float64(c.pFieldVal.(Line)) != c.eFieldVal {
				c.dError()
			}
		case "StartPosition":
			if float64(c.pFieldVal.(StartPosition)) != c.eFieldVal {
				c.dError()
			}
		case "OverLine", "UnderLine":
			// c.checkAdornmentNode(c.pFieldVal.(*AdornmentNode), c.eFieldVal, c.testName)
			c.error("Overline/Underline not implemented!")
		case "NodeList":
			c.error("NodeList not implemented!")
		default:
			if c.pFieldVal != c.eFieldVal {
				c.dError()
			}
		}
	}

}

// checkParseNodes is a recursive function that compares the resulting nodes (pNodes) from the
// parser with the expected output from the testdata (eNodes).
func checkParseNodes(t *testing.T, pNodes *NodeList, eNodes []interface{}, testName string) (errors []error) {
	state := &checkNode{t: t, testName: testName}
	for pNum, pNode := range *pNodes {
		state.checkFields(pNode, eNodes[pNum])
	}
	return
}

func TestParseSectionTitlePara(t *testing.T) {
	testName := "SectionTitlePara"
	tree, err := parseTest(t, testName)
	if err != nil {
		t.Error(err)
	}
	test := lexParseTests.SearchByName(testName)
	var nodeList []interface{}
	err = json.Unmarshal([]byte(test.expectTree), &nodeList)
	if err != nil {
		t.Error(err)
	}
	errors := checkParseNodes(t, tree.Nodes, nodeList, testName)
	if errors != nil {
		for _, err := range errors {
			t.Error(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	lib "github.com/haklop/bazooka/commons"
)

type Generator struct {
	Config       *lib.Config
	OutputFolder string
	Index        string
}

func (g *Generator) GenerateDockerfile() error {
	err := os.MkdirAll(fmt.Sprintf("%s/%s", g.OutputFolder, g.Index), 0755)
	if err != nil {
		return err
	}

	var buffer bytes.Buffer

	buffer.WriteString(fmt.Sprintf("FROM %s\n\n", g.Config.FromImage))

	envMap := getEnvMap(g.Config)
	buffer.WriteString(fmt.Sprintf("ADD . %s\n\n", envMap["BZK_BUILD_DIR"][0]))
	buffer.WriteString(fmt.Sprintf("RUN chmod +x %s/bazooka_run.sh\n\n", envMap["BZK_BUILD_DIR"][0]))

	type buildPhase struct {
		name      string
		commands  []string
		beforeCmd []string
		runCmd    []string
	}

	phases := []*buildPhase{
		&buildPhase{
			name:      "setup",
			commands:  g.Config.Setup,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_setup.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "before_install",
			commands:  g.Config.BeforeInstall,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "install",
			commands:  g.Config.Install,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "before_script",
			commands:  g.Config.BeforeScript,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_script.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "script",
			commands:  g.Config.Script,
			beforeCmd: []string{"set -v"},
			runCmd:    g.getScriptRunCmd(),
		},
		&buildPhase{
			name:      "after_success",
			commands:  g.Config.AfterSuccess,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_failure",
			commands:  g.Config.AfterFailure,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_script",
			commands:  g.Config.AfterScript,
			beforeCmd: []string{"set -v"},
		},
	}

	var bufferRun bytes.Buffer
	bufferRun.WriteString("#!/bin/bash\n")
	for _, phase := range phases {
		if len(phase.commands) != 0 {
			var buffer bytes.Buffer
			buffer.WriteString("#!/bin/bash\n\n")
			for _, action := range phase.beforeCmd {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			for _, action := range phase.commands {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			err = ioutil.WriteFile(fmt.Sprintf("%s/%s/bazooka_%s.sh", g.OutputFolder, g.Index, phase.name), buffer.Bytes(), 0644)
			if err != nil {
				return fmt.Errorf("Phase [%d/%s]: writing file failed: %v", g.Index, phase.name, err)
			}
			if phase.runCmd == nil {
				bufferRun.WriteString(fmt.Sprintf("./bazooka_%s.sh\n", phase.name))
			} else {
				for _, action := range phase.runCmd {
					bufferRun.WriteString(fmt.Sprintf("%s\n", action))
				}
			}
		}
	}

	err = ioutil.WriteFile(fmt.Sprintf("%s/%s/bazooka_run.sh", g.OutputFolder, g.Index), bufferRun.Bytes(), 0644)
	if err != nil {
		return fmt.Errorf("Phase [%d/run]: writing file failed: %v", g.Index, err)
	}

	for _, phase := range phases {
		if len(phase.commands) != 0 {
			buffer.WriteString(fmt.Sprintf("RUN chmod +x %s/bazooka_%s.sh\n\n", envMap["BZK_BUILD_DIR"][0], phase.name))
		}
	}

	for _, env := range g.Config.Env {
		envSplit := strings.Split(env, "=")
		buffer.WriteString(fmt.Sprintf("ENV %s %s\n", envSplit[0], envSplit[1]))
	}

	buffer.WriteString(fmt.Sprintf("WORKDIR %s\n\n", envMap["BZK_BUILD_DIR"][0]))

	buffer.WriteString("CMD ./bazooka_run.sh\n")

	err = ioutil.WriteFile(fmt.Sprintf("%s/%s/Dockerfile", g.OutputFolder, g.Index), buffer.Bytes(), 0644)
	if err != nil {
		return fmt.Errorf("Phase [%d/docker]: writing file failed: %v", g.Index, err)
	}

	if len(g.Config.Services) > 0 {
		var servicesBuffer bytes.Buffer
		for _, service := range g.Config.Services {
			servicesBuffer.WriteString(fmt.Sprintf("%s\n", service))
		}
		err = ioutil.WriteFile(fmt.Sprintf("%s/%s/services", g.OutputFolder, g.Index), servicesBuffer.Bytes(), 0644)
		if err != nil {
			return fmt.Errorf("Phase [%d/services]: writing file failed: %v", g.Index, err)
		}
	}
	return nil
}

func (g *Generator) getScriptRunCmd() []string {
	switch {
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"else",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) == 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? == 0 ]] ; then",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) == 0:
		return nil
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"fi",
		}
	default:
		return nil
	}
}
<commit_msg>fix compilation failure<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	lib "github.com/haklop/bazooka/commons"
)

type Generator struct {
	Config       *lib.Config
	OutputFolder string
	Index        string
}

func (g *Generator) GenerateDockerfile() error {
	err := os.MkdirAll(fmt.Sprintf("%s/%s", g.OutputFolder, g.Index), 0755)
	if err != nil {
		return err
	}

	var buffer bytes.Buffer

	buffer.WriteString(fmt.Sprintf("FROM %s\n\n", g.Config.FromImage))

	envMap := lib.GetEnvMap(g.Config.Env)
	buffer.WriteString(fmt.Sprintf("ADD . %s\n\n", envMap["BZK_BUILD_DIR"][0]))
	buffer.WriteString(fmt.Sprintf("RUN chmod +x %s/bazooka_run.sh\n\n", envMap["BZK_BUILD_DIR"][0]))

	type buildPhase struct {
		name      string
		commands  []string
		beforeCmd []string
		runCmd    []string
	}

	phases := []*buildPhase{
		&buildPhase{
			name:      "setup",
			commands:  g.Config.Setup,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_setup.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "before_install",
			commands:  g.Config.BeforeInstall,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "install",
			commands:  g.Config.Install,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "before_script",
			commands:  g.Config.BeforeScript,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_script.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit 42",
				"fi",
			},
		},
		&buildPhase{
			name:      "script",
			commands:  g.Config.Script,
			beforeCmd: []string{"set -v"},
			runCmd:    g.getScriptRunCmd(),
		},
		&buildPhase{
			name:      "after_success",
			commands:  g.Config.AfterSuccess,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_failure",
			commands:  g.Config.AfterFailure,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_script",
			commands:  g.Config.AfterScript,
			beforeCmd: []string{"set -v"},
		},
	}

	var bufferRun bytes.Buffer
	bufferRun.WriteString("#!/bin/bash\n")
	for _, phase := range phases {
		if len(phase.commands) != 0 {
			var buffer bytes.Buffer
			buffer.WriteString("#!/bin/bash\n\n")
			for _, action := range phase.beforeCmd {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			for _, action := range phase.commands {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			err = ioutil.WriteFile(fmt.Sprintf("%s/%s/bazooka_%s.sh", g.OutputFolder, g.Index, phase.name), buffer.Bytes(), 0644)
			if err != nil {
				return fmt.Errorf("Phase [%d/%s]: writing file failed: %v", g.Index, phase.name, err)
			}
			if phase.runCmd == nil {
				bufferRun.WriteString(fmt.Sprintf("./bazooka_%s.sh\n", phase.name))
			} else {
				for _, action := range phase.runCmd {
					bufferRun.WriteString(fmt.Sprintf("%s\n", action))
				}
			}
		}
	}

	err = ioutil.WriteFile(fmt.Sprintf("%s/%s/bazooka_run.sh", g.OutputFolder, g.Index), bufferRun.Bytes(), 0644)
	if err != nil {
		return fmt.Errorf("Phase [%d/run]: writing file failed: %v", g.Index, err)
	}

	for _, phase := range phases {
		if len(phase.commands) != 0 {
			buffer.WriteString(fmt.Sprintf("RUN chmod +x %s/bazooka_%s.sh\n\n", envMap["BZK_BUILD_DIR"][0], phase.name))
		}
	}

	for _, env := range g.Config.Env {
		envSplit := strings.Split(env, "=")
		buffer.WriteString(fmt.Sprintf("ENV %s %s\n", envSplit[0], envSplit[1]))
	}

	buffer.WriteString(fmt.Sprintf("WORKDIR %s\n\n", envMap["BZK_BUILD_DIR"][0]))

	buffer.WriteString("CMD ./bazooka_run.sh\n")

	err = ioutil.WriteFile(fmt.Sprintf("%s/%s/Dockerfile", g.OutputFolder, g.Index), buffer.Bytes(), 0644)
	if err != nil {
		return fmt.Errorf("Phase [%d/docker]: writing file failed: %v", g.Index, err)
	}

	if len(g.Config.Services) > 0 {
		var servicesBuffer bytes.Buffer
		for _, service := range g.Config.Services {
			servicesBuffer.WriteString(fmt.Sprintf("%s\n", service))
		}
		err = ioutil.WriteFile(fmt.Sprintf("%s/%s/services", g.OutputFolder, g.Index), servicesBuffer.Bytes(), 0644)
		if err != nil {
			return fmt.Errorf("Phase [%d/services]: writing file failed: %v", g.Index, err)
		}
	}
	return nil
}

func (g *Generator) getScriptRunCmd() []string {
	switch {
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"else",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) == 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? == 0 ]] ; then",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) == 0:
		return nil
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"fi",
		}
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>package board

import (
	"color"
	"errors"
	"fmt"
	"matrix"
	"piece"
	"point"
)

type Board struct {
	matrix matrix.Matrix
	first  [8][8]bool
}

func NewBoard() *Board {
	board := new(Board)
	board.matrix = matrix.Starting()
	for i := 0; i < 8; i++ {
		board.first[0][i] = true
		board.first[1][i] = true
		board.first[6][i] = true
		board.first[7][i] = true
	}
	return board
}

func (board *Board) Print() {
	fmt.Print(" ")
	for i := 0; i < 8; i++ {
		fmt.Printf(" %c", 'a'+i)
	}
	fmt.Println()

	for i := 0; i < 8; i++ {
		fmt.Print(" +")
		for j := 0; j < 8; j++ {
			fmt.Print("-+")
		}
		fmt.Println()
		fmt.Printf("%d|", 8-i)
		for j := 0; j < 8; j++ {
			fmt.Printf("%c|", board.matrix[i][j])
		}
		fmt.Println(8 - i)
	}
	fmt.Print(" +")
	for i := 0; i < 8; i++ {
		fmt.Print("-+")
	}
	fmt.Println()

	fmt.Print(" ")
	for i := 0; i < 8; i++ {
		fmt.Printf(" %c", 'a'+i)
	}
	fmt.Println()
}

func (board *Board) CanCastling(from, to point.Point) bool {
	diff := from.Diff(to)
	rfrom := from
	rto := to

	if diff.X == 2 {
		rfrom.X = 7
		rto.X = to.X - 1
	} else {
		rfrom.X = 0
		rto.X = to.X + 1
	}
	fsymbol := board.matrix[rfrom.Y][rfrom.X]
	if piece.Rook.IsSymbol(fsymbol) == false {
		return false
	} else if board.first[rfrom.Y][rfrom.X] == false {
		return false
	} else if board.matrix.ExistBarrier(rfrom, rto) {
		return false
	}
	return true
}

func (board *Board) Castling(from, to point.Point) {
	diff := from.Diff(to)
	rfrom := from
	rto := to
	if diff.X == 2 {
		rfrom.X = 7
		rto.X = to.X - 1
	} else {
		rfrom.X = 0
		rto.X = to.X + 1
	}

	board.matrix[to.Y][to.X] = board.matrix[from.Y][from.X]
	board.matrix[from.Y][from.X] = ' '
	board.first[from.Y][from.X] = false
	board.first[to.Y][to.X] = false
	board.matrix[rto.Y][rto.X] = board.matrix[rfrom.Y][rfrom.X]
	board.matrix[rfrom.Y][rfrom.X] = ' '
	board.first[rfrom.Y][rfrom.X] = false
	board.first[rto.Y][rto.X] = false
}

func (board *Board) Move(from, to point.Point, c color.Color) error {
	if matrix.InMatrix(from) == false || matrix.InMatrix(to) == false {
		return errors.New("out of board")
	}

	fsymbol := board.matrix[from.Y][from.X]
	// tsymbol := board.matrix[to.Y][to.X]

	fcolor := color.WhichColor(board.matrix[from.Y][from.X])
	tcolor := color.WhichColor(board.matrix[to.Y][to.X])
	diff := point.Point{0, 0}
	if fcolor == color.White {
		diff = from.Diff(to)
	} else if fcolor == color.Black {
		diff = to.Diff(from)
	}
	if fcolor != c || tcolor == c {
		return errors.New("cannot move this piece")
	}

	fpiece := piece.WhichPiece(fsymbol)
	toEnemy := color.WhichColor(board.matrix[to.Y][to.X]) == c.Enemy()
	canMove := fpiece.CanMove(diff, board.first[from.Y][from.X], toEnemy)
	existBarrier := board.matrix.ExistBarrier(from, to)
	if canMove == false || (existBarrier && piece.Knight.IsSymbol(fsymbol) == false) {
		return errors.New("cannot move this piece to that point")
	}

	isCastling := piece.King.IsSymbol(fsymbol) && (diff.X == -2 || diff.X == 2)
	canCastling := isCastling && board.CanCastling(from, to)
	if isCastling && canCastling == false {
		return errors.New("cannot move this piece to that point")
	} else if canCastling == true {
		board.Castling(from, to)
	} else {
		board.matrix[to.Y][to.X] = board.matrix[from.Y][from.X]
		board.matrix[from.Y][from.X] = ' '
		board.first[from.Y][from.X] = false
		board.first[to.Y][to.X] = false
	}

	return nil
}
<commit_msg>Implement a function checks king is checked<commit_after>package board

import (
	"color"
	"errors"
	"fmt"
	"matrix"
	"piece"
	"point"
)

type Board struct {
	matrix matrix.Matrix
	first  [8][8]bool
}

func NewBoard() *Board {
	board := new(Board)
	board.matrix = matrix.Starting()
	for i := 0; i < 8; i++ {
		board.first[0][i] = true
		board.first[1][i] = true
		board.first[6][i] = true
		board.first[7][i] = true
	}
	return board
}

func (board *Board) Print() {
	fmt.Print(" ")
	for i := 0; i < 8; i++ {
		fmt.Printf(" %c", 'a'+i)
	}
	fmt.Println()

	for i := 0; i < 8; i++ {
		fmt.Print(" +")
		for j := 0; j < 8; j++ {
			fmt.Print("-+")
		}
		fmt.Println()
		fmt.Printf("%d|", 8-i)
		for j := 0; j < 8; j++ {
			fmt.Printf("%c|", board.matrix[i][j])
		}
		fmt.Println(8 - i)
	}
	fmt.Print(" +")
	for i := 0; i < 8; i++ {
		fmt.Print("-+")
	}
	fmt.Println()

	fmt.Print(" ")
	for i := 0; i < 8; i++ {
		fmt.Printf(" %c", 'a'+i)
	}
	fmt.Println()
}

func (board Board) IsChecked(c Color) bool {
	var king point.Point
	for i := 0; i < 8; i++ {
		for j := 0; j < 8; j++ {
			symbol := board.matrix[i][j]
			if piece.King.IsSymbol(symbol) && color.WhichColor(symbol) == c {
				king := Point{i, j}
				break
			}
		}
	}
	enemy := c.Enemy()
	for i := 0; i < 8; i++ {
		for j := 0; j < 8; j++ {
			symbol := board.matrix[i][j]
			piece := piece.WhichPiece(symbol)
			first := board.first[i][j]
			diff := point.Point{i, j}.Diff(king)
			if color.WhichColor(symbol) == enemy && piece.CanMove(diff, first, true) {
				return true
			}
		}
	}
	return false
}

func (board *Board) CanCastling(from, to point.Point) bool {
	diff := from.Diff(to)
	rfrom := from
	rto := to

	if diff.X == 2 {
		rfrom.X = 7
		rto.X = to.X - 1
	} else {
		rfrom.X = 0
		rto.X = to.X + 1
	}
	fsymbol := board.matrix[rfrom.Y][rfrom.X]
	if piece.Rook.IsSymbol(fsymbol) == false {
		return false
	} else if board.first[rfrom.Y][rfrom.X] == false {
		return false
	} else if board.matrix.ExistBarrier(rfrom, rto) {
		return false
	}
	return true
}

func (board *Board) Castling(from, to point.Point) {
	diff := from.Diff(to)
	rfrom := from
	rto := to
	if diff.X == 2 {
		rfrom.X = 7
		rto.X = to.X - 1
	} else {
		rfrom.X = 0
		rto.X = to.X + 1
	}

	board.matrix[to.Y][to.X] = board.matrix[from.Y][from.X]
	board.matrix[from.Y][from.X] = ' '
	board.first[from.Y][from.X] = false
	board.first[to.Y][to.X] = false
	board.matrix[rto.Y][rto.X] = board.matrix[rfrom.Y][rfrom.X]
	board.matrix[rfrom.Y][rfrom.X] = ' '
	board.first[rfrom.Y][rfrom.X] = false
	board.first[rto.Y][rto.X] = false
}

func (board *Board) Move(from, to point.Point, c color.Color) error {
	if matrix.InMatrix(from) == false || matrix.InMatrix(to) == false {
		return errors.New("out of board")
	}

	fsymbol := board.matrix[from.Y][from.X]
	// tsymbol := board.matrix[to.Y][to.X]

	fcolor := color.WhichColor(board.matrix[from.Y][from.X])
	tcolor := color.WhichColor(board.matrix[to.Y][to.X])
	diff := point.Point{0, 0}
	if fcolor == color.White {
		diff = from.Diff(to)
	} else if fcolor == color.Black {
		diff = to.Diff(from)
	}
	if fcolor != c || tcolor == c {
		return errors.New("cannot move this piece")
	}

	fpiece := piece.WhichPiece(fsymbol)
	toEnemy := color.WhichColor(board.matrix[to.Y][to.X]) == c.Enemy()
	canMove := fpiece.CanMove(diff, board.first[from.Y][from.X], toEnemy)
	existBarrier := board.matrix.ExistBarrier(from, to)
	if canMove == false || (existBarrier && piece.Knight.IsSymbol(fsymbol) == false) {
		return errors.New("cannot move this piece to that point")
	}

	isCastling := piece.King.IsSymbol(fsymbol) && (diff.X == -2 || diff.X == 2)
	canCastling := isCastling && board.CanCastling(from, to)
	if isCastling && canCastling == false {
		return errors.New("cannot move this piece to that point")
	} else if canCastling == true {
		board.Castling(from, to)
	} else {
		board.matrix[to.Y][to.X] = board.matrix[from.Y][from.X]
		board.matrix[from.Y][from.X] = ' '
		board.first[from.Y][from.X] = false
		board.first[to.Y][to.X] = false
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/ncw/gpython/parser"
)

var (
	lex        = flag.Bool("l", false, "Lex the file only")
	debugLevel = flag.Int("d", 0, "Debug level 0-4")
)

func main() {
	flag.Parse()
	parser.SetDebug(*debugLevel)
	for _, path := range flag.Args() {
		if *lex {
			fmt.Printf("Lexing %q\n", path)
		} else {
			fmt.Printf("Parsing %q\n", path)
		}
		in, err := os.Open(path)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("-----------------\n")
		if *lex {
			_, err = parser.Lex(in)
		} else {
			err = parser.Parse(in)
		}
		fmt.Printf("-----------------\n")
		in.Close()
		if err != nil {
			log.Fatalf("Failed on %q: %v", path, err)
		}
	}
}
<commit_msg>Fix testparser after API changes<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/ncw/gpython/parser"
)

var (
	lex        = flag.Bool("l", false, "Lex the file only")
	debugLevel = flag.Int("d", 0, "Debug level 0-4")
)

func main() {
	flag.Parse()
	parser.SetDebug(*debugLevel)
	for _, path := range flag.Args() {
		if *lex {
			fmt.Printf("Lexing %q\n", path)
		} else {
			fmt.Printf("Parsing %q\n", path)
		}
		in, err := os.Open(path)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("-----------------\n")
		if *lex {
			_, err = parser.Lex(in, "exec")
		} else {
			_, err = parser.Parse(in, "exec")
		}
		fmt.Printf("-----------------\n")
		in.Close()
		if err != nil {
			log.Fatalf("Failed on %q: %v", path, err)
		}
	}
}
<|endoftext|>


<commit_before>package philarios

import (
  "github.com/lib/pq"
  "database/sql"
  "time"
)

const (
  DatabaseDriverName = "postgres"
  DatabaseDataSourceName = "user=philarios dbnamephilarios sslmode=verify-full"
)

type Publication struct {
  Title string
  Author string
  Editor string
  Date time.Time
  SourceURL string
  Encoding string
  Text string
  Categories []Category
}

type Category struct {
  Name string
}

/*
QueryForWord returns SQL rows of paragraphs containing the query word given as
an argument. These are returned from the database.
*/
func QueryForWord(word string) (*sql.Rows, error) {
  db, err := sql.Open(DatabaseDriverName, DatabaseDataSourceName)
  if err != nil {
    return nil, err
  }

  rows, err := performWordQuery(word, db)

  if err != nil {
    return nil, err
  }

  if err = rows.Err(); err != nil {
    return nil, err
  }

  return rows, nil
}

func performWordQuery(word string, db *sql.DB) (*sql.Rows, error) {
  return db.Query(`SELECT body FROM paragraphs
    WHERE to_tsvector(body) @@ to_tsquery(?)`, word)
}

func AddPublication(publication Publication) (error) {
  db, err := sql.Open(DatabaseDriverName, DatabaseDataSourceName)
  if err != nil {
    return err
  }

  txn, err := db.Begin()
  if err != nil {
    return err
  }

  publicationStmt, err := txn.Prepare(pq.CopyIn("publications", "title", "author", "date"))
  publicationResult, err = publicationStmt.Exec(publication.Title, publication.Author, publication.Date)
  if err != nil {
    return err
  }
  publicationId := publicationResult.LastInsertId()

  paragraphStmt, err := txn.Prepare(pq.CopyIn("paragraphs", "publication", "body"))
  paragraphs := strings.Split(publication.Text, "\n")
  for _, paragraph := range paragraphs {
    _, err = paragraphStmt.Exec(publicationId, paragraph)
    if err != nil {
      return err
    }
  }

  categoryStmt, err := txn.Prepare(pq.CopyIn("categories", "publication", "category"))
  for _, category := range publication.Categories {
    _, err = categoryStmt.Exec(publicationId, category.Name)
    if err != nil {
      return err
    }
  }

  _, err = stmt.Exec()
  if err != nil {
    return err
  }

  _, err = stmt.Close()
  if err != nil {
    return err
  }

  err = txn.Commit()
  if err != nil {
    return err
  }

  return nil
}
<commit_msg>Full spec for publication insertions into the DB.<commit_after>package philarios

import (
  "github.com/lib/pq"
  "database/sql"
  "time"
)

const (
  DatabaseDriverName = "postgres"
  DatabaseDataSourceName = "user=philarios dbnamephilarios sslmode=verify-full"
)

/*
Publication is a structure which represents any type of publication (such as
books or articles) which contains text.
*/
type Publication struct {
  Title string
  Author string
  Editor string
  Date time.Time
  SourceURL string
  Encoding string
  Type string
  Text string
  Categories []Category
}

/*
Category is a stuct which represents a category type for a publication.
*/
type Category struct {
  Name string
}

/*
QueryForWord returns SQL rows of paragraphs containing the query word given as
an argument. These are returned from the database.
*/
func QueryForWord(word string) (*sql.Rows, error) {
  db, err := sql.Open(DatabaseDriverName, DatabaseDataSourceName)
  if err != nil {
    return nil, err
  }

  rows, err := performWordQuery(word, db)

  if err != nil {
    return nil, err
  }

  if err = rows.Err(); err != nil {
    return nil, err
  }

  return rows, nil
}

func performWordQuery(word string, db *sql.DB) (*sql.Rows, error) {
  return db.Query(`SELECT body FROM paragraphs
    WHERE to_tsvector(body) @@ to_tsquery(?)`, word)
}

/*
AddPublication adds a new publication to the database, adding data to the
publications, categories, and paragraphs tables.
*/
func AddPublication(publication Publication) (error) {
  db, err := sql.Open(DatabaseDriverName, DatabaseDataSourceName)
  if err != nil {
    return err
  }

  txn, err := db.Begin()
  if err != nil {
    return err
  }

  publicationStmt, err := txn.Prepare(pq.CopyIn(
    "publications",
    "title",
    "author",
    "editor",
    "date",
    "source_url",
    "type",
    "encoding"))
  publicationResult, err = publicationStmt.Exec(
    publication.Title,
    publication.Author,
    publication.Editor,
    publication.Date.Unix(),
    publication.SourceURL,
    publication.Type,
    publication.Encoding)
  if err != nil {
    return err
  }
  publicationId := publicationResult.LastInsertId()

  paragraphStmt, err := txn.Prepare(pq.CopyIn("paragraphs", "publication", "body"))
  paragraphs := strings.Split(publication.Text, "\n")
  for _, paragraph := range paragraphs {
    _, err = paragraphStmt.Exec(publicationId, paragraph)
    if err != nil {
      return err
    }
  }

  categoryStmt, err := txn.Prepare(pq.CopyIn("categories", "publication", "category"))
  for _, category := range publication.Categories {
    _, err = categoryStmt.Exec(publicationId, category.Name)
    if err != nil {
      return err
    }
  }

  _, err = stmt.Exec()
  if err != nil {
    return err
  }

  _, err = stmt.Close()
  if err != nil {
    return err
  }

  err = txn.Commit()
  if err != nil {
    return err
  }

  return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"os/exec"

	"github.com/herman-rogers/gogeta/config"
	"github.com/herman-rogers/gogeta/logger"
	git "github.com/libgit2/git2go"
	uuid "github.com/satori/go.uuid"
)

const UP_TO_DATE = "UP_TO_DATE"
const NORMAL_MERGE = "NORMAL_MERGE"
const FAST_FORWARD = "FAST_FORWARD"

func GitProcessSQSMessages(data scmServiceRequest) error {
	if data.Usr == "" || data.Project == "" || data.Repo == "" {
		message := "Missing git data"
		SendRawMessage(
			data.Id,
			data.Buildcount,
			message,
			message)
		return errors.New("Missing Git Service Properties")
	}
	switch data.Type {
	case "GOGETA_CLONE":
		go GitShallowClone(data)
	case "GOGETA_NEW_BUILD":
		go RunNewGitBuild(data)
	}
	return nil
}

func GitShallowClone(data scmServiceRequest) {
	repoPath, relativePath := GetRepoPath(data.Project)
	cmd := exec.Command("git", "clone", "--depth", "2", data.Repo, repoPath)

	cloneMsgDev := "git clone --depth 2 " + data.Repo + " " + repoPath
	SendRawMessage(
		data.Id,
		data.Buildcount,
		"git clone started",
		cloneMsgDev)

	logfile := logger.GetLogFile()
	defer logfile.Close()

	cmd.Stdout = logfile
	cmd.Stderr = logfile

	commandErr := cmd.Start()
	logger.LogError(commandErr, "Git Clone")
	if commandErr != nil {
		SendRawMessage(
			data.Id,
			data.Buildcount,
			"git clone failed",
			commandErr.Error())
	}

	cloneErr := cmd.Wait()
	logger.LogError(cloneErr, "Git Clone")
	if cloneErr != nil {
		SendRawMessage(
			data.Id,
			data.Buildcount,
			"git clone failed",
			cloneErr.Error())
	}
	if cloneErr == nil {
		cloneSuccess := "git clone succeded"
		SendRawMessage(
			data.Id,
			data.Buildcount,
			cloneSuccess,
			cloneSuccess)
		gitData := &GogetaRepo{
			data.Id,
			data.Usr,
			data.Repo,
			relativePath,
			data.SCMType,
			data.Engine,
			data.Platform,
			data.Buildcount,
		}
		CreateGitCredentials(repoPath)
		go SaveRepo(*gitData)
		go TriggerMrRobotBuild(*gitData)
	}
}

func RunNewGitBuild(data scmServiceRequest) {
	gitData := FindRepo(data.Usr, data.Id)
	gitData.BuildCount = data.Buildcount + 1
	// put raw message in new build
	SendRawMessage(
		data.Id,
		data.Buildcount,
		"new build started",
		"new build started")
	go TriggerMrRobotBuild(gitData)
	go UpdateRepo(gitData)
}

func UpdateGitRepositories() {
	repos := FindAllRepos()
	for i := 0; i < len(repos); i++ {
		folder := config.File.RepoPath + repos[i].Folder
		repo, err := git.OpenRepository(folder)
		if err != nil {
			logger.Error(err.Error())
			continue
		}
		if repo.IsBare() {
			return
		}
		go GitPull(repos[i], repo)
	}
}

func GetRepoPath(project string) (string, string) {
	var uuid uuid.UUID = uuid.NewV4()
	relativePath := project + "_" + uuid.String()
	repoPath := config.File.RepoPath + relativePath
	return repoPath, relativePath
}

func CreateGitCredentials(repo string) {
	openRepo, err := git.OpenRepository(repo)
	if err != nil {
		logger.LogError(err, "Git Create Credentials")
	}
	config, configErr := openRepo.Config()
	if configErr != nil {
		logger.LogError(configErr, "Git Config Set")
	}
	configNameErr := config.SetString("user.name", "gamebuildr")
	if configNameErr != nil {
		logger.LogError(configNameErr, "Git Config Name")
	}
	configEmailErr := config.SetString("user.email", "contact@gamebuildr.io")
	if configEmailErr != nil {
		logger.LogError(configEmailErr, "Git Config Email")
	}
}

func GitPull(gitData GogetaRepo, repo *git.Repository) {
	FetchLatestsUpdates(gitData)
	remoteBranch := GetRemoteBranch(repo)
	remoteBranchID := remoteBranch.Target()

	analysis, err := AnalyzeLatestUpdates(repo, remoteBranch)
	if err != nil {
		logger.Error(err.Error())
	}
	mergeType := CheckMergeAnalysis(analysis)
	msg := "Git Merge " + mergeType

	switch mergeType {
	case UP_TO_DATE:
		break
	case NORMAL_MERGE:
		err := MergeNormal(repo, remoteBranch, remoteBranchID)
		gitData.BuildCount = gitData.BuildCount + 1
		//put raw message in new build
		SendRawMessage(
			gitData.BuildrId,
			gitData.BuildCount,
			"new code changes detected",
			"git merge origin master")
		BuildAfterMerge(err, msg, gitData)
		go UpdateRepo(gitData)
		break
	case FAST_FORWARD:
		err := MergeFastForward(repo, remoteBranchID)
		gitData.BuildCount = gitData.BuildCount + 1
		//put raw message in new build
		SendRawMessage(
			gitData.BuildrId,
			gitData.BuildCount,
			"new code changes detected",
			"git merge fast forward")
		BuildAfterMerge(err, msg, gitData)
		go UpdateRepo(gitData)
		break
	}
}

func SendRawMessage(dataId string, dataCount int, message string, devMessage string) {
	gitMessage := GamebuildrMessage{
		dataId,
		dataCount,
		message,
		devMessage,
		"BUILDR_MESSAGE",
	}
	SendGamebuildrMessage(gitMessage)
}

func GetRemoteBranch(repo *git.Repository) *git.Reference {
	remoteBranch, err := repo.References.Lookup("refs/remotes/origin/master")
	logger.LogError(err, "Git Remote Branch")
	return remoteBranch
}

func FetchLatestsUpdates(data GogetaRepo) {
	cmd := exec.Command("git", "fetch", "--depth", "1", "origin", "master")
	cmd.Dir = config.File.RepoPath + data.Folder

	commandErr := cmd.Start()
	logger.LogError(commandErr, "Git Fetch")

	fetchErr := cmd.Wait()
	logger.LogError(fetchErr, "Git Fetch")
}

func AnalyzeLatestUpdates(repo *git.Repository, remoteBranch *git.Reference) (git.MergeAnalysis, error) {
	annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)
	if err != nil {
		var nullAnalysis git.MergeAnalysis
		return nullAnalysis, err
	}
	mergeHeads := make([]*git.AnnotatedCommit, 1)
	mergeHeads[0] = annotatedCommit
	analysis, _, err := repo.MergeAnalysis(mergeHeads)
	logger.LogError(err, "Git Merge Analysis")
	return analysis, nil
}

func CheckMergeAnalysis(analysis git.MergeAnalysis) string {
	if analysis&git.MergeAnalysisUpToDate != 0 {
		return UP_TO_DATE
	}
	if analysis&git.MergeAnalysisNormal != 0 {
		return NORMAL_MERGE
	}
	return FAST_FORWARD
}

func MergeNormal(repo *git.Repository, remoteBranch *git.Reference, remoteBranchID *git.Oid) error {
	head, err := repo.Head()
	if err != nil {
		return err
	}
	annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)
	if err != nil {
		return err
	}
	if err := repo.Merge([]*git.AnnotatedCommit{annotatedCommit}, nil, nil); err != nil {
		return err
	}
	index, err := repo.Index()
	if err != nil {
		return err
	}
	if index.HasConflicts() {
		return errors.New("Conflicts encountered, Please Resolve Them")
	}
	sig, err := repo.DefaultSignature()
	if err != nil {
		return err
	}
	treeId, err := index.WriteTree()
	if err != nil {
		return err
	}
	tree, err := repo.LookupTree(treeId)
	if err != nil {
		return err
	}
	localCommit, err := repo.LookupCommit(head.Target())
	if err != nil {
		return err
	}
	remoteCommit, err := repo.LookupCommit(remoteBranchID)
	if err != nil {
		return err
	}
	repo.CreateCommit("HEAD", sig, sig, "", tree, localCommit, remoteCommit)
	repo.StateCleanup()
	return nil
}

func MergeFastForward(repo *git.Repository, remoteBranchID *git.Oid) error {
	head, err := repo.Head()
	if err != nil {
		return err
	}
	remoteTree, err := repo.LookupTree(remoteBranchID)
	if err != nil {
		return err
	}
	if err := repo.CheckoutTree(remoteTree, nil); err != nil {
		return err
	}
	branchRef, err := repo.References.Lookup("refs/heads/master")
	if err != nil {
		return err
	}
	branchRef.SetTarget(remoteBranchID, "")
	if _, err := head.SetTarget(remoteBranchID, ""); err != nil {
		return err
	}
	return nil
}
<commit_msg>Change buildr message id<commit_after>package main

import (
	"errors"
	"os/exec"

	"github.com/herman-rogers/gogeta/config"
	"github.com/herman-rogers/gogeta/logger"
	git "github.com/libgit2/git2go"
	uuid "github.com/satori/go.uuid"
)

const UP_TO_DATE = "UP_TO_DATE"
const NORMAL_MERGE = "NORMAL_MERGE"
const FAST_FORWARD = "FAST_FORWARD"

func GitProcessSQSMessages(data scmServiceRequest) error {
	if data.Usr == "" || data.Project == "" || data.Repo == "" {
		message := "Missing git data"
		SendRawMessage(
			data.Id,
			data.Buildcount,
			message,
			message)
		return errors.New("Missing Git Service Properties")
	}
	switch data.Type {
	case "GOGETA_CLONE":
		go GitShallowClone(data)
	case "GOGETA_NEW_BUILD":
		go RunNewGitBuild(data)
	}
	return nil
}

func GitShallowClone(data scmServiceRequest) {
	repoPath, relativePath := GetRepoPath(data.Project)
	cmd := exec.Command("git", "clone", "--depth", "2", data.Repo, repoPath)

	cloneMsgDev := "git clone --depth 2 " + data.Repo + " " + repoPath
	SendRawMessage(
		data.Id,
		data.Buildcount,
		"git clone started",
		cloneMsgDev)

	logfile := logger.GetLogFile()
	defer logfile.Close()

	cmd.Stdout = logfile
	cmd.Stderr = logfile

	commandErr := cmd.Start()
	logger.LogError(commandErr, "Git Clone")
	if commandErr != nil {
		SendRawMessage(
			data.Id,
			data.Buildcount,
			"git clone failed",
			commandErr.Error())
	}

	cloneErr := cmd.Wait()
	logger.LogError(cloneErr, "Git Clone")
	if cloneErr != nil {
		SendRawMessage(
			data.Id,
			data.Buildcount,
			"git clone failed",
			cloneErr.Error())
	}
	if cloneErr == nil {
		cloneSuccess := "git clone succeded"
		SendRawMessage(
			data.Id,
			data.Buildcount,
			cloneSuccess,
			cloneSuccess)
		gitData := &GogetaRepo{
			data.Id,
			data.Usr,
			data.Repo,
			relativePath,
			data.SCMType,
			data.Engine,
			data.Platform,
			data.Buildcount,
		}
		CreateGitCredentials(repoPath)
		go SaveRepo(*gitData)
		go TriggerMrRobotBuild(*gitData)
	}
}

func RunNewGitBuild(data scmServiceRequest) {
	gitData := FindRepo(data.Usr, data.Id)
	gitData.BuildCount = data.Buildcount + 1
	// put raw message in new build
	SendRawMessage(
		gitData.BuildrId,
		gitData.BuildCount,
		"new build started",
		"new build started")
	go TriggerMrRobotBuild(gitData)
	go UpdateRepo(gitData)
}

func UpdateGitRepositories() {
	repos := FindAllRepos()
	for i := 0; i < len(repos); i++ {
		folder := config.File.RepoPath + repos[i].Folder
		repo, err := git.OpenRepository(folder)
		if err != nil {
			logger.Error(err.Error())
			continue
		}
		if repo.IsBare() {
			return
		}
		go GitPull(repos[i], repo)
	}
}

func GetRepoPath(project string) (string, string) {
	var uuid uuid.UUID = uuid.NewV4()
	relativePath := project + "_" + uuid.String()
	repoPath := config.File.RepoPath + relativePath
	return repoPath, relativePath
}

func CreateGitCredentials(repo string) {
	openRepo, err := git.OpenRepository(repo)
	if err != nil {
		logger.LogError(err, "Git Create Credentials")
	}
	config, configErr := openRepo.Config()
	if configErr != nil {
		logger.LogError(configErr, "Git Config Set")
	}
	configNameErr := config.SetString("user.name", "gamebuildr")
	if configNameErr != nil {
		logger.LogError(configNameErr, "Git Config Name")
	}
	configEmailErr := config.SetString("user.email", "contact@gamebuildr.io")
	if configEmailErr != nil {
		logger.LogError(configEmailErr, "Git Config Email")
	}
}

func GitPull(gitData GogetaRepo, repo *git.Repository) {
	FetchLatestsUpdates(gitData)
	remoteBranch := GetRemoteBranch(repo)
	remoteBranchID := remoteBranch.Target()

	analysis, err := AnalyzeLatestUpdates(repo, remoteBranch)
	if err != nil {
		logger.Error(err.Error())
	}
	mergeType := CheckMergeAnalysis(analysis)
	msg := "Git Merge " + mergeType

	switch mergeType {
	case UP_TO_DATE:
		break
	case NORMAL_MERGE:
		err := MergeNormal(repo, remoteBranch, remoteBranchID)
		gitData.BuildCount = gitData.BuildCount + 1
		//put raw message in new build
		SendRawMessage(
			gitData.BuildrId,
			gitData.BuildCount,
			"new code changes detected",
			"git merge origin master")
		BuildAfterMerge(err, msg, gitData)
		go UpdateRepo(gitData)
		break
	case FAST_FORWARD:
		err := MergeFastForward(repo, remoteBranchID)
		gitData.BuildCount = gitData.BuildCount + 1
		//put raw message in new build
		SendRawMessage(
			gitData.BuildrId,
			gitData.BuildCount,
			"new code changes detected",
			"git merge fast forward")
		BuildAfterMerge(err, msg, gitData)
		go UpdateRepo(gitData)
		break
	}
}

func SendRawMessage(dataId string, dataCount int, message string, devMessage string) {
	gitMessage := GamebuildrMessage{
		dataId,
		dataCount,
		message,
		devMessage,
		"BUILDR_MESSAGE",
	}
	SendGamebuildrMessage(gitMessage)
}

func GetRemoteBranch(repo *git.Repository) *git.Reference {
	remoteBranch, err := repo.References.Lookup("refs/remotes/origin/master")
	logger.LogError(err, "Git Remote Branch")
	return remoteBranch
}

func FetchLatestsUpdates(data GogetaRepo) {
	cmd := exec.Command("git", "fetch", "--depth", "1", "origin", "master")
	cmd.Dir = config.File.RepoPath + data.Folder

	commandErr := cmd.Start()
	logger.LogError(commandErr, "Git Fetch")

	fetchErr := cmd.Wait()
	logger.LogError(fetchErr, "Git Fetch")
}

func AnalyzeLatestUpdates(repo *git.Repository, remoteBranch *git.Reference) (git.MergeAnalysis, error) {
	annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)
	if err != nil {
		var nullAnalysis git.MergeAnalysis
		return nullAnalysis, err
	}
	mergeHeads := make([]*git.AnnotatedCommit, 1)
	mergeHeads[0] = annotatedCommit
	analysis, _, err := repo.MergeAnalysis(mergeHeads)
	logger.LogError(err, "Git Merge Analysis")
	return analysis, nil
}

func CheckMergeAnalysis(analysis git.MergeAnalysis) string {
	if analysis&git.MergeAnalysisUpToDate != 0 {
		return UP_TO_DATE
	}
	if analysis&git.MergeAnalysisNormal != 0 {
		return NORMAL_MERGE
	}
	return FAST_FORWARD
}

func MergeNormal(repo *git.Repository, remoteBranch *git.Reference, remoteBranchID *git.Oid) error {
	head, err := repo.Head()
	if err != nil {
		return err
	}
	annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)
	if err != nil {
		return err
	}
	if err := repo.Merge([]*git.AnnotatedCommit{annotatedCommit}, nil, nil); err != nil {
		return err
	}
	index, err := repo.Index()
	if err != nil {
		return err
	}
	if index.HasConflicts() {
		return errors.New("Conflicts encountered, Please Resolve Them")
	}
	sig, err := repo.DefaultSignature()
	if err != nil {
		return err
	}
	treeId, err := index.WriteTree()
	if err != nil {
		return err
	}
	tree, err := repo.LookupTree(treeId)
	if err != nil {
		return err
	}
	localCommit, err := repo.LookupCommit(head.Target())
	if err != nil {
		return err
	}
	remoteCommit, err := repo.LookupCommit(remoteBranchID)
	if err != nil {
		return err
	}
	repo.CreateCommit("HEAD", sig, sig, "", tree, localCommit, remoteCommit)
	repo.StateCleanup()
	return nil
}

func MergeFastForward(repo *git.Repository, remoteBranchID *git.Oid) error {
	head, err := repo.Head()
	if err != nil {
		return err
	}
	remoteTree, err := repo.LookupTree(remoteBranchID)
	if err != nil {
		return err
	}
	if err := repo.CheckoutTree(remoteTree, nil); err != nil {
		return err
	}
	branchRef, err := repo.References.Lookup("refs/heads/master")
	if err != nil {
		return err
	}
	branchRef.SetTarget(remoteBranchID, "")
	if _, err := head.SetTarget(remoteBranchID, ""); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package path_test

import (
	"math"
	"reflect"
	"testing"

	"github.com/gonum/graph"
	"github.com/gonum/graph/concrete"
	"github.com/gonum/graph/internal"
	"github.com/gonum/graph/path"
	"github.com/gonum/graph/topo"
)

var aStarTests = []struct {
	name string
	g    graph.Graph

	s, t      int
	heuristic path.Heuristic
	wantPath  []int
}{
	{
		name: "simple path",
		g: func() graph.Graph {
			tg, err := internal.NewTileGraphFrom("" +
				"▀  ▀\n" +
				"▀▀ ▀\n" +
				"▀▀ ▀\n" +
				"▀▀ ▀",
			)
			if err != nil {
				panic("bad test graph")
			}
			return tg
		}(),

		s: 1, t: 14,
		wantPath: []int{1, 2, 6, 10, 14},
	},
	{
		name: "small open graph",
		g:    internal.NewTileGraph(3, 3, true),

		s: 0, t: 8,
	},
	{
		name: "large open graph",
		g:    internal.NewTileGraph(1000, 1000, true),

		s: 0, t: 999*1000 + 999,
	},
	{
		name: "no path",
		g: func() graph.Graph {
			tg := internal.NewTileGraph(5, 5, true)

			// Create a complete "wall" across the middle row.
			tg.SetPassability(2, 0, false)
			tg.SetPassability(2, 1, false)
			tg.SetPassability(2, 2, false)
			tg.SetPassability(2, 3, false)
			tg.SetPassability(2, 4, false)

			return tg
		}(),

		s: 2, t: 22,
	},
	{
		name: "partially obstructed",
		g: func() graph.Graph {
			tg := internal.NewTileGraph(10, 10, true)

			// Create a partial "wall" accross the middle
			// row with a gap at the left-hand end.
			tg.SetPassability(4, 1, false)
			tg.SetPassability(4, 2, false)
			tg.SetPassability(4, 3, false)
			tg.SetPassability(4, 4, false)
			tg.SetPassability(4, 5, false)
			tg.SetPassability(4, 6, false)
			tg.SetPassability(4, 7, false)
			tg.SetPassability(4, 8, false)
			tg.SetPassability(4, 9, false)

			return tg
		}(),

		s: 5, t: 9*10 + 9,
	},
	{
		name: "partially obstructed with heuristic",
		g: func() graph.Graph {
			tg := internal.NewTileGraph(10, 10, true)

			// Create a partial "wall" accross the middle
			// row with a gap at the left-hand end.
			tg.SetPassability(4, 1, false)
			tg.SetPassability(4, 2, false)
			tg.SetPassability(4, 3, false)
			tg.SetPassability(4, 4, false)
			tg.SetPassability(4, 5, false)
			tg.SetPassability(4, 6, false)
			tg.SetPassability(4, 7, false)
			tg.SetPassability(4, 8, false)
			tg.SetPassability(4, 9, false)

			return tg
		}(),

		s: 5, t: 9*10 + 9,
		// Manhattan Heuristic
		heuristic: func(u, v graph.Node) float64 {
			uid := u.ID()
			cu := (uid % 10)
			ru := (uid - cu) / 10

			vid := v.ID()
			cv := (vid % 10)
			rv := (vid - cv) / 10

			return math.Abs(float64(ru-rv)) + math.Abs(float64(cu-cv))
		},
	},
}

func TestAStar(t *testing.T) {
	for _, test := range aStarTests {
		pt, _ := path.AStar(concrete.Node(test.s), concrete.Node(test.t), test.g, test.heuristic)

		p, cost := pt.To(concrete.Node(test.t))

		if !topo.IsPathIn(test.g, p) {
			t.Error("got path that is not path in input graph for %q", test.name)
		}

		bfp, ok := path.BellmanFordFrom(concrete.Node(test.s), test.g)
		if !ok {
			t.Fatalf("unexpected negative cycle in %q", test.name)
		}
		if want := bfp.WeightTo(concrete.Node(test.t)); cost != want {
			t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want)
		}

		var got = make([]int, 0, len(p))
		for _, n := range p {
			got = append(got, n.ID())
		}
		if test.wantPath != nil && !reflect.DeepEqual(got, test.wantPath) {
			t.Errorf("unexpected result for %q:\ngot: %v\nwant:%v", test.name, got, test.wantPath)
		}
	}
}

func TestExhaustiveAStar(t *testing.T) {
	g := concrete.NewGraph()
	nodes := []locatedNode{
		1: {id: 1, x: 0, y: 6},
		2: {id: 2, x: 1, y: 0},
		3: {id: 3, x: 8, y: 7},
		4: {id: 4, x: 16, y: 0},
		5: {id: 5, x: 17, y: 6},
		6: {id: 6, x: 9, y: 8},
	}
	for _, n := range nodes[1:] {
		g.AddNode(n)
	}

	edges := []weightedEdge{
		{from: nodes[1], to: nodes[2], cost: 7},
		{from: nodes[1], to: nodes[3], cost: 9},
		{from: nodes[1], to: nodes[6], cost: 14},
		{from: nodes[2], to: nodes[3], cost: 10},
		{from: nodes[2], to: nodes[4], cost: 15},
		{from: nodes[3], to: nodes[4], cost: 11},
		{from: nodes[3], to: nodes[6], cost: 2},
		{from: nodes[4], to: nodes[5], cost: 7},
		{from: nodes[5], to: nodes[6], cost: 9},
	}
	for _, e := range edges {
		g.SetEdge(e, e.cost)
	}

	heuristic := func(u, v graph.Node) float64 {
		lu := u.(locatedNode)
		lv := v.(locatedNode)
		return math.Hypot(lu.x-lv.x, lu.y-lv.y)
	}

	if ok, edge, goal := isMonotonic(g, heuristic); !ok {
		t.Fatalf("non-monotonic heuristic at edge:%v for goal:%v", edge, goal)
	}

	ps := path.DijkstraAllPaths(g)
	for _, start := range g.Nodes() {
		for _, goal := range g.Nodes() {
			pt, _ := path.AStar(start, goal, g, heuristic)
			gotPath, gotWeight := pt.To(goal)
			wantPath, wantWeight, _ := ps.Between(start, goal)
			if gotWeight != wantWeight {
				t.Errorf("unexpected path weight from %v to %v result: got:%s want:%s",
					start, goal, gotWeight, wantWeight)
			}
			if !reflect.DeepEqual(gotPath, wantPath) {
				t.Errorf("unexpected path from %v to %v result:\ngot: %v\nwant:%v",
					start, goal, gotPath, wantPath)
			}
		}
	}
}

type locatedNode struct {
	id   int
	x, y float64
}

func (n locatedNode) ID() int { return n.id }

type weightedEdge struct {
	from, to locatedNode
	cost     float64
}

func (e weightedEdge) From() graph.Node { return e.from }
func (e weightedEdge) To() graph.Node   { return e.to }

type costEdgeListGraph interface {
	graph.Weighter
	path.EdgeListerGraph
}

func isMonotonic(g costEdgeListGraph, h path.Heuristic) (ok bool, at graph.Edge, goal graph.Node) {
	for _, goal := range g.Nodes() {
		for _, edge := range g.Edges() {
			from := edge.From()
			to := edge.To()
			if h(from, goal) > g.Weight(edge)+h(to, goal) {
				return false, edge, goal
			}
		}
	}
	return true, nil, nil
}

func TestAStarNullHeuristic(t *testing.T) {
	for _, test := range shortestPathTests {
		g := test.g()
		for _, e := range test.edges {
			g.SetEdge(e, e.Cost)
		}

		var (
			pt path.Shortest

			panicked bool
		)
		func() {
			defer func() {
				panicked = recover() != nil
			}()
			pt, _ = path.AStar(test.query.From(), test.query.To(), g.(graph.Graph), nil)
		}()
		if panicked || test.negative {
			if !test.negative {
				t.Errorf("%q: unexpected panic", test.name)
			}
			if !panicked {
				t.Errorf("%q: expected panic for negative edge weight", test.name)
			}
			continue
		}

		if pt.From().ID() != test.query.From().ID() {
			t.Fatalf("%q: unexpected from node ID: got:%d want:%d", pt.From().ID(), test.query.From().ID())
		}

		p, weight := pt.To(test.query.To())
		if weight != test.weight {
			t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
				test.name, weight, test.weight)
		}
		if weight := pt.WeightTo(test.query.To()); weight != test.weight {
			t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
				test.name, weight, test.weight)
		}

		var got []int
		for _, n := range p {
			got = append(got, n.ID())
		}
		ok := len(got) == 0 && len(test.want) == 0
		for _, sp := range test.want {
			if reflect.DeepEqual(got, sp) {
				ok = true
				break
			}
		}
		if !ok {
			t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v",
				test.name, p, test.want)
		}

		np, weight := pt.To(test.none.To())
		if pt.From().ID() == test.none.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
			t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
				test.name, np, weight)
		}
	}
}
<commit_msg>path: use Node method to define edge end points<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package path_test

import (
	"math"
	"reflect"
	"testing"

	"github.com/gonum/graph"
	"github.com/gonum/graph/concrete"
	"github.com/gonum/graph/internal"
	"github.com/gonum/graph/path"
	"github.com/gonum/graph/topo"
)

var aStarTests = []struct {
	name string
	g    graph.Graph

	s, t      int
	heuristic path.Heuristic
	wantPath  []int
}{
	{
		name: "simple path",
		g: func() graph.Graph {
			tg, err := internal.NewTileGraphFrom("" +
				"▀  ▀\n" +
				"▀▀ ▀\n" +
				"▀▀ ▀\n" +
				"▀▀ ▀",
			)
			if err != nil {
				panic("bad test graph")
			}
			return tg
		}(),

		s: 1, t: 14,
		wantPath: []int{1, 2, 6, 10, 14},
	},
	{
		name: "small open graph",
		g:    internal.NewTileGraph(3, 3, true),

		s: 0, t: 8,
	},
	{
		name: "large open graph",
		g:    internal.NewTileGraph(1000, 1000, true),

		s: 0, t: 999*1000 + 999,
	},
	{
		name: "no path",
		g: func() graph.Graph {
			tg := internal.NewTileGraph(5, 5, true)

			// Create a complete "wall" across the middle row.
			tg.SetPassability(2, 0, false)
			tg.SetPassability(2, 1, false)
			tg.SetPassability(2, 2, false)
			tg.SetPassability(2, 3, false)
			tg.SetPassability(2, 4, false)

			return tg
		}(),

		s: 2, t: 22,
	},
	{
		name: "partially obstructed",
		g: func() graph.Graph {
			tg := internal.NewTileGraph(10, 10, true)

			// Create a partial "wall" accross the middle
			// row with a gap at the left-hand end.
			tg.SetPassability(4, 1, false)
			tg.SetPassability(4, 2, false)
			tg.SetPassability(4, 3, false)
			tg.SetPassability(4, 4, false)
			tg.SetPassability(4, 5, false)
			tg.SetPassability(4, 6, false)
			tg.SetPassability(4, 7, false)
			tg.SetPassability(4, 8, false)
			tg.SetPassability(4, 9, false)

			return tg
		}(),

		s: 5, t: 9*10 + 9,
	},
	{
		name: "partially obstructed with heuristic",
		g: func() graph.Graph {
			tg := internal.NewTileGraph(10, 10, true)

			// Create a partial "wall" accross the middle
			// row with a gap at the left-hand end.
			tg.SetPassability(4, 1, false)
			tg.SetPassability(4, 2, false)
			tg.SetPassability(4, 3, false)
			tg.SetPassability(4, 4, false)
			tg.SetPassability(4, 5, false)
			tg.SetPassability(4, 6, false)
			tg.SetPassability(4, 7, false)
			tg.SetPassability(4, 8, false)
			tg.SetPassability(4, 9, false)

			return tg
		}(),

		s: 5, t: 9*10 + 9,
		// Manhattan Heuristic
		heuristic: func(u, v graph.Node) float64 {
			uid := u.ID()
			cu := (uid % 10)
			ru := (uid - cu) / 10

			vid := v.ID()
			cv := (vid % 10)
			rv := (vid - cv) / 10

			return math.Abs(float64(ru-rv)) + math.Abs(float64(cu-cv))
		},
	},
}

func TestAStar(t *testing.T) {
	for _, test := range aStarTests {
		pt, _ := path.AStar(concrete.Node(test.s), concrete.Node(test.t), test.g, test.heuristic)

		p, cost := pt.To(concrete.Node(test.t))

		if !topo.IsPathIn(test.g, p) {
			t.Error("got path that is not path in input graph for %q", test.name)
		}

		bfp, ok := path.BellmanFordFrom(concrete.Node(test.s), test.g)
		if !ok {
			t.Fatalf("unexpected negative cycle in %q", test.name)
		}
		if want := bfp.WeightTo(concrete.Node(test.t)); cost != want {
			t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want)
		}

		var got = make([]int, 0, len(p))
		for _, n := range p {
			got = append(got, n.ID())
		}
		if test.wantPath != nil && !reflect.DeepEqual(got, test.wantPath) {
			t.Errorf("unexpected result for %q:\ngot: %v\nwant:%v", test.name, got, test.wantPath)
		}
	}
}

func TestExhaustiveAStar(t *testing.T) {
	g := concrete.NewGraph()
	nodes := []locatedNode{
		{id: 1, x: 0, y: 6},
		{id: 2, x: 1, y: 0},
		{id: 3, x: 8, y: 7},
		{id: 4, x: 16, y: 0},
		{id: 5, x: 17, y: 6},
		{id: 6, x: 9, y: 8},
	}
	for _, n := range nodes {
		g.AddNode(n)
	}

	edges := []weightedEdge{
		{from: g.Node(1), to: g.Node(2), cost: 7},
		{from: g.Node(1), to: g.Node(3), cost: 9},
		{from: g.Node(1), to: g.Node(6), cost: 14},
		{from: g.Node(2), to: g.Node(3), cost: 10},
		{from: g.Node(2), to: g.Node(4), cost: 15},
		{from: g.Node(3), to: g.Node(4), cost: 11},
		{from: g.Node(3), to: g.Node(6), cost: 2},
		{from: g.Node(4), to: g.Node(5), cost: 7},
		{from: g.Node(5), to: g.Node(6), cost: 9},
	}
	for _, e := range edges {
		g.SetEdge(e, e.cost)
	}

	heuristic := func(u, v graph.Node) float64 {
		lu := u.(locatedNode)
		lv := v.(locatedNode)
		return math.Hypot(lu.x-lv.x, lu.y-lv.y)
	}

	if ok, edge, goal := isMonotonic(g, heuristic); !ok {
		t.Fatalf("non-monotonic heuristic at edge:%v for goal:%v", edge, goal)
	}

	ps := path.DijkstraAllPaths(g)
	for _, start := range g.Nodes() {
		for _, goal := range g.Nodes() {
			pt, _ := path.AStar(start, goal, g, heuristic)
			gotPath, gotWeight := pt.To(goal)
			wantPath, wantWeight, _ := ps.Between(start, goal)
			if gotWeight != wantWeight {
				t.Errorf("unexpected path weight from %v to %v result: got:%s want:%s",
					start, goal, gotWeight, wantWeight)
			}
			if !reflect.DeepEqual(gotPath, wantPath) {
				t.Errorf("unexpected path from %v to %v result:\ngot: %v\nwant:%v",
					start, goal, gotPath, wantPath)
			}
		}
	}
}

type locatedNode struct {
	id   int
	x, y float64
}

func (n locatedNode) ID() int { return n.id }

type weightedEdge struct {
	from, to graph.Node
	cost     float64
}

func (e weightedEdge) From() graph.Node { return e.from }
func (e weightedEdge) To() graph.Node   { return e.to }

type costEdgeListGraph interface {
	graph.Weighter
	path.EdgeListerGraph
}

func isMonotonic(g costEdgeListGraph, h path.Heuristic) (ok bool, at graph.Edge, goal graph.Node) {
	for _, goal := range g.Nodes() {
		for _, edge := range g.Edges() {
			from := edge.From()
			to := edge.To()
			if h(from, goal) > g.Weight(edge)+h(to, goal) {
				return false, edge, goal
			}
		}
	}
	return true, nil, nil
}

func TestAStarNullHeuristic(t *testing.T) {
	for _, test := range shortestPathTests {
		g := test.g()
		for _, e := range test.edges {
			g.SetEdge(e, e.Cost)
		}

		var (
			pt path.Shortest

			panicked bool
		)
		func() {
			defer func() {
				panicked = recover() != nil
			}()
			pt, _ = path.AStar(test.query.From(), test.query.To(), g.(graph.Graph), nil)
		}()
		if panicked || test.negative {
			if !test.negative {
				t.Errorf("%q: unexpected panic", test.name)
			}
			if !panicked {
				t.Errorf("%q: expected panic for negative edge weight", test.name)
			}
			continue
		}

		if pt.From().ID() != test.query.From().ID() {
			t.Fatalf("%q: unexpected from node ID: got:%d want:%d", pt.From().ID(), test.query.From().ID())
		}

		p, weight := pt.To(test.query.To())
		if weight != test.weight {
			t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
				test.name, weight, test.weight)
		}
		if weight := pt.WeightTo(test.query.To()); weight != test.weight {
			t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
				test.name, weight, test.weight)
		}

		var got []int
		for _, n := range p {
			got = append(got, n.ID())
		}
		ok := len(got) == 0 && len(test.want) == 0
		for _, sp := range test.want {
			if reflect.DeepEqual(got, sp) {
				ok = true
				break
			}
		}
		if !ok {
			t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v",
				test.name, p, test.want)
		}

		np, weight := pt.To(test.none.To())
		if pt.From().ID() == test.none.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
			t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
				test.name, np, weight)
		}
	}
}
<|endoftext|>


<commit_before>package pgproto

import (
	"bytes"
	"femebe"
	"fmt"
)

func encodeValText(buf *bytes.Buffer,
	val interface{}, format string) {
	result := fmt.Sprintf(format, val)
	femebe.WriteInt32(buf, int32(len([]byte(result))))
	buf.WriteString(result)
}

func BinEncodeInt16(buff *bytes.Buffer, val int16) {
	femebe.WriteInt32(buff, 2)
	femebe.WriteInt16(buff, val)
}

func TextEncodeInt16(buff *bytes.Buffer, val int16) {
	encodeValText(buff, val, "%d")
}

func TextEncodeInt32(buff *bytes.Buffer, val int32) {
	encodeValText(buff, val, "%d")
}

func TextEncodeInt64(buff *bytes.Buffer, val int64) {
	encodeValText(buff, val, "%d")
}

func TextEncodeFloat32(buff *bytes.Buffer, val float32) {
	encodeValText(buff, val, "%e")
}

func TextEncodeFloat64(buff *bytes.Buffer, val float64) {
	encodeValText(buff, val, "%e")
}

func TextEncodeString(buff *bytes.Buffer, val string) {
	encodeValText(buff, val, "%s")
}

func TextEncodeBool(buff *bytes.Buffer, val bool) {
	encodeValText(buff, val, "%t")
}
<commit_msg>Add some decoding utility methods<commit_after>package pgproto

import (
	"bytes"
	"encoding/hex"
	"femebe"
	"fmt"
	"log"
	"strconv"
	"time"
)

func encodeValText(buf *bytes.Buffer,
	val interface{}, format string) {
	result := fmt.Sprintf(format, val)
	femebe.WriteInt32(buf, int32(len([]byte(result))))
	buf.WriteString(result)
}

func BinEncodeInt16(buff *bytes.Buffer, val int16) {
	femebe.WriteInt32(buff, 2)
	femebe.WriteInt16(buff, val)
}

func TextEncodeInt16(buff *bytes.Buffer, val int16) {
	encodeValText(buff, val, "%d")
}

func TextEncodeInt32(buff *bytes.Buffer, val int32) {
	encodeValText(buff, val, "%d")
}

func TextEncodeInt64(buff *bytes.Buffer, val int64) {
	encodeValText(buff, val, "%d")
}

func TextEncodeFloat32(buff *bytes.Buffer, val float32) {
	encodeValText(buff, val, "%e")
}

func TextEncodeFloat64(buff *bytes.Buffer, val float64) {
	encodeValText(buff, val, "%e")
}

func TextEncodeString(buff *bytes.Buffer, val string) {
	encodeValText(buff, val, "%s")
}

func TextEncodeBool(buff *bytes.Buffer, val bool) {
	encodeValText(buff, val, "%t")
}

// Decode Postgres (text) encoding into a reasonably corresponding Go
// type (lifted from pq)
func Decode(s []byte, typ Oid) interface{} {
	switch typ {
	case OID_BYTEA:
		s = s[2:] // trim off "\\x"
		d := make([]byte, hex.DecodedLen(len(s)))
		_, err := hex.Decode(d, s)
		if err != nil {
			log.Fatalf("femebe: %s", err)
		}
		return d
	case OID_TIMESTAMP:
		return mustParse("2006-01-02 15:04:05", typ, s)
	case OID_TIMESTAMPTZ:
		return mustParse("2006-01-02 15:04:05-07", typ, s)
	case OID_TIME:
		return mustParse("15:04:05", typ, s)
	case OID_TIMETZ:
		return mustParse("15:04:05-07", typ, s)
	case OID_DATE:
		return mustParse("2006-01-02", typ, s)
	case OID_BOOL:
		return s[0] == 't'
	case OID_INT8, OID_INT4, OID_INT2:
		i, err := strconv.ParseInt(string(s), 10, 64)
		if err != nil {
			log.Fatalf("femebe: %s", err)
		}
		return i
	case OID_FLOAT4, OID_FLOAT8:
		var bits int
		if typ == OID_FLOAT4 {
			bits = 32
		} else {
			bits = 64
		}
		f, err := strconv.ParseFloat(string(s), bits)
		if err != nil {
			log.Fatalf("femebe: %s", err)
		}
		return f
	default:
		return s
	}
}

func mustParse(f string, typ Oid, s []byte) time.Time {
	str := string(s)

	// Special case until time.Parse bug is fixed:
	// http://code.google.com/p/go/issues/detail?id=3487
	if str[len(str)-2] == '.' {
		str += "0"
	}

	// check for a 30-minute-offset timezone
	if (typ == OID_TIMESTAMPTZ || typ == OID_TIMETZ) &&
		str[len(str)-3] == ':' {
		f += ":00"
	}
	t, err := time.Parse(f, str)
	if err != nil {
		log.Fatalf("femebe: decode: %s", err)
	}
	return t
}

// Describe which Go type this Postgres OID will map to in the scheme
// above
func DescribeType(typ Oid) string {
	switch typ {
	case OID_BYTEA:
		return "[]byte"
	case OID_TIMESTAMP, OID_TIMESTAMPTZ, OID_TIME, OID_TIMETZ, OID_DATE:
		return "time.Time"
	case OID_BOOL:
		return "boolean"
	case OID_INT8, OID_INT4, OID_INT2:
		return "int64"
	case OID_FLOAT4, OID_FLOAT8:
		return "float64"
	default:
		return "unknown"
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"fmt"
	"go.etcd.io/etcd/client"
	"github.com/samuel/go-zookeeper/zk"
	"path"
	"regexp"
	"time"
)

func ParseHostAndPortFromJdbcConnStr(connStr string) (string, string, error) {
	r := regexp.MustCompile(`postgres://(.*)+:([0-9]+)/`)
	matches := r.FindStringSubmatch(connStr)
	if len(matches) != 3 {
		log.Errorf("Unexpected regex result groups:", matches)
		return "", "", errors.New(fmt.Sprintf("unexpected regex result groups: %v", matches))
	}
	return matches[1], matches[2], nil
}

func EtcdGetClusterMembers(database MonitoredDatabase) ([]PatroniClusterMember, error) {
	var ret []PatroniClusterMember

	if len(database.HostConfig.DcsEndpoints) == 0 {
		return ret, errors.New("Missing ETCD connect info, make sure host config has a 'dcs_endpoints' key")
	}

	cfg := client.Config{
		Endpoints:               database.HostConfig.DcsEndpoints,
		Transport:               client.DefaultTransport,
		HeaderTimeoutPerRequest: time.Second,
	}
	c, err := client.New(cfg)
	if err != nil {
		log.Error("Could not connect to DCS", err)
		return ret, err
	}
	kapi := client.NewKeysAPI(c)

	membersPath := path.Join(database.HostConfig.Namespace, database.HostConfig.Scope, "members")
	resp, err := kapi.Get(context.Background(), membersPath , &client.GetOptions{Recursive:true})
	if err != nil {
		log.Error("Could not read Patroni members from ETCD:", err)
		return ret, err
	}

	for _, node := range resp.Node.Nodes {
		log.Debugf("Found a cluster member from etcd: %+v", node.Value)
		nodeData, err := jsonTextToStringMap(node.Value)
		if err != nil {
			log.Errorf("Could not parse ETCD node data for node \"%s\": %s", node, err)
			continue
		}
		role, _ := nodeData["role"]
		connUrl, _ := nodeData["conn_url"]
		name := path.Base(node.Key)

		ret = append(ret, PatroniClusterMember{Scope: database.HostConfig.Scope, ConnUrl: connUrl, Role: role, Name: name})
	}
	return ret, nil
}

func ZookeeperGetClusterMembers(database MonitoredDatabase) ([]PatroniClusterMember, error) {
	var ret []PatroniClusterMember

	if len(database.HostConfig.DcsEndpoints) == 0 {
		return ret, errors.New("Missing Zookeeper connect info, make sure host config has a 'dcs_endpoints' key")
	}

	c, _, err := zk.Connect(database.HostConfig.DcsEndpoints, time.Second)
	if err != nil {
		log.Error("Could not connect to DCS", err)
		return ret, err
	}
	members, _, err := c.Children(path.Join(database.HostConfig.Namespace, database.HostConfig.Scope, "members"))
	if err != nil {
		log.Error("Could not read Patroni members from Zookeeper:", err)
		return ret, err
	}
	for _, member := range members {
		log.Debugf("Found a cluster member from Zookeeper: %+v", member)
		keyData, _, err := c.Get(path.Join(database.HostConfig.Namespace, database.HostConfig.Scope, "members", member))
		if err != nil {
			log.Errorf("Could not read member (%s) info from Zookeeper:", member, err)
			return ret, err
		}
		nodeData, err := jsonTextToStringMap(string(keyData))
		if err != nil {
			log.Errorf("Could not parse Zookeeper node data for node \"%s\": %s", member, err)
			continue
		}
		role, _ := nodeData["role"]
		connUrl, _ := nodeData["conn_url"]
		name := path.Base(member)

		ret = append(ret, PatroniClusterMember{Scope: database.HostConfig.Scope, ConnUrl: connUrl, Role: role, Name: name})
	}

	return ret, nil
}

func ResolveDatabasesFromPatroni(ce MonitoredDatabase) ([]MonitoredDatabase, error) {
	md := make([]MonitoredDatabase, 0)
	cm := make([]PatroniClusterMember, 0)
	var err error
	var dbUnique string

	log.Error("ce.HostConfig", ce.HostConfig)
	if ce.HostConfig.DcsType == DCS_TYPE_ETCD {
		cm, err = EtcdGetClusterMembers(ce)
	} else if ce.HostConfig.DcsType == DCS_TYPE_ZOOKEEPER{
		cm, err = ZookeeperGetClusterMembers(ce)
	} else {
		log.Error("unknown DCS", ce.HostConfig.DcsType)
		return md, errors.New("unknown DCS")
	}
	if len(cm) == 0 {
		log.Warningf("No Patroni cluster members found for cluster [%s:%s]", ce.DBUniqueName, ce.HostConfig.Scope)
		return md, nil
	}
	log.Infof("Found %d Patroni members for cluster [%s:%s]", len(cm), ce.DBUniqueName, ce.HostConfig.Scope)

	for _, m := range cm {
		log.Infof("Processing Patroni cluster member [%s:%s]", ce.DBUniqueName, m.Name)
		if ce.OnlyIfMaster && m.Role != "master" {
			log.Infof("Skipping over Patroni cluster member [%s:%s] as not a master", ce.DBUniqueName, m.Name)
			continue
		}
		host, port, err := ParseHostAndPortFromJdbcConnStr(m.ConnUrl)
		if err != nil {
			log.Errorf("Could not parse Patroni conn str \"%s\" [%s:%s]: %v", m.ConnUrl, ce.DBUniqueName, m.Scope, err)
			continue
		}
		if ce.OnlyIfMaster {
			dbUnique = ce.DBUniqueName
		} else {
			dbUnique = ce.DBUniqueName + "_" + m.Name
		}
		if ce.DBName != "" {
			md = append(md, MonitoredDatabase{DBUniqueName: dbUnique,
				DBName:            ce.DBName,
				Host:              host,
				Port:              port,
				User:              ce.User,
				Password:          ce.Password,
				PasswordType:      ce.PasswordType,
				SslMode:           ce.SslMode,
				SslRootCAPath:     ce.SslRootCAPath,
				SslClientCertPath: ce.SslClientCertPath,
				SslClientKeyPath:  ce.SslClientKeyPath,
				StmtTimeout:       ce.StmtTimeout,
				Metrics:           ce.Metrics,
				PresetMetrics:     ce.PresetMetrics,
				IsSuperuser:       ce.IsSuperuser,
				CustomTags:        ce.CustomTags,
				HostConfig:	       ce.HostConfig,
				DBType:            "postgres"})
			continue
		} else {
			c, err := GetPostgresDBConnection("", host, port, "template1", ce.User, ce.Password,
				ce.SslMode, ce.SslRootCAPath, ce.SslClientCertPath, ce.SslClientKeyPath)
			if err != nil {
				log.Errorf("Could not contact Patroni member [%s:%s]: %v", ce.DBUniqueName, m.Scope, err)
				continue
			}
			defer c.Close()
			sql := `select datname::text as datname,
					quote_ident(datname)::text as datname_escaped
					from pg_database
					where not datistemplate
					and datallowconn
					and has_database_privilege (datname, 'CONNECT')
					and case when length(trim($1)) > 0 then datname ~ $2 else true end
					and case when length(trim($3)) > 0 then not datname ~ $4 else true end`

			data, err := DBExecRead(c, ce.DBUniqueName, sql, ce.DBNameIncludePattern, ce.DBNameIncludePattern, ce.DBNameExcludePattern, ce.DBNameExcludePattern)
			if err != nil {
				log.Errorf("Could not get DB name listing from Patroni member [%s:%s]: %v", ce.DBUniqueName, m.Scope, err)
				continue
			}

			for _, d := range data {
				md = append(md, MonitoredDatabase{DBUniqueName: dbUnique + "_" + d["datname_escaped"].(string),
					DBName:            d["datname"].(string),
					Host:              host,
					Port:              port,
					User:              ce.User,
					Password:          ce.Password,
					PasswordType:      ce.PasswordType,
					SslMode:           ce.SslMode,
					SslRootCAPath:     ce.SslRootCAPath,
					SslClientCertPath: ce.SslClientCertPath,
					SslClientKeyPath:  ce.SslClientKeyPath,
					StmtTimeout:       ce.StmtTimeout,
					Metrics:           ce.Metrics,
					PresetMetrics:     ce.PresetMetrics,
					IsSuperuser:       ce.IsSuperuser,
					CustomTags:        ce.CustomTags,
					HostConfig:        ce.HostConfig,
					DBType:            "postgres"})
			}
		}

	}

	return md, err
}

<commit_msg>Maintain a cache of last resolved nodes found from DCS<commit_after>package main

import (
	"context"
	"errors"
	"fmt"
	"github.com/samuel/go-zookeeper/zk"
	"go.etcd.io/etcd/client"
	"path"
	"regexp"
	"time"
)

var lastFoundClusterMembers = make(map[string][]PatroniClusterMember)	// needed for cases where DCS is temporarily down
																		// don't want to immediately remove monitoring of DBs

func ParseHostAndPortFromJdbcConnStr(connStr string) (string, string, error) {
	r := regexp.MustCompile(`postgres://(.*)+:([0-9]+)/`)
	matches := r.FindStringSubmatch(connStr)
	if len(matches) != 3 {
		log.Errorf("Unexpected regex result groups:", matches)
		return "", "", errors.New(fmt.Sprintf("unexpected regex result groups: %v", matches))
	}
	return matches[1], matches[2], nil
}

func EtcdGetClusterMembers(database MonitoredDatabase) ([]PatroniClusterMember, error) {
	var ret []PatroniClusterMember

	if len(database.HostConfig.DcsEndpoints) == 0 {
		return ret, errors.New("Missing ETCD connect info, make sure host config has a 'dcs_endpoints' key")
	}

	cfg := client.Config{
		Endpoints:               database.HostConfig.DcsEndpoints,
		Transport:               client.DefaultTransport,
		HeaderTimeoutPerRequest: time.Second,
	}
	c, err := client.New(cfg)
	if err != nil {
		log.Error("Could not connect to ETCD", err)
		return ret, err
	}
	kapi := client.NewKeysAPI(c)

	membersPath := path.Join(database.HostConfig.Namespace, database.HostConfig.Scope, "members")
	resp, err := kapi.Get(context.Background(), membersPath , &client.GetOptions{Recursive:true})
	if err != nil {
		log.Error("Could not read Patroni members from ETCD:", err)
		return ret, err
	}

	for _, node := range resp.Node.Nodes {
		log.Debugf("Found a cluster member from etcd: %+v", node.Value)
		nodeData, err := jsonTextToStringMap(node.Value)
		if err != nil {
			log.Errorf("Could not parse ETCD node data for node \"%s\": %s", node, err)
			continue
		}
		role, _ := nodeData["role"]
		connUrl, _ := nodeData["conn_url"]
		name := path.Base(node.Key)

		ret = append(ret, PatroniClusterMember{Scope: database.HostConfig.Scope, ConnUrl: connUrl, Role: role, Name: name})
	}
	lastFoundClusterMembers[database.DBUniqueName] = ret
	return ret, nil
}

func ZookeeperGetClusterMembers(database MonitoredDatabase) ([]PatroniClusterMember, error) {
	var ret []PatroniClusterMember

	if len(database.HostConfig.DcsEndpoints) == 0 {
		return ret, errors.New("Missing Zookeeper connect info, make sure host config has a 'dcs_endpoints' key")
	}

	c, _, err := zk.Connect(database.HostConfig.DcsEndpoints, time.Second, zk.WithLogInfo(false))
	if err != nil {
		log.Error("Could not connect to Zookeeper", err)
		return ret, err
	}
	defer c.Close()

	members, _, err := c.Children(path.Join(database.HostConfig.Namespace, database.HostConfig.Scope, "members"))
	if err != nil {
		log.Error("Could not read Patroni members from Zookeeper:", err)
		return ret, err
	}

	for _, member := range members {
		log.Debugf("Found a cluster member from Zookeeper: %+v", member)
		keyData, _, err := c.Get(path.Join(database.HostConfig.Namespace, database.HostConfig.Scope, "members", member))
		if err != nil {
			log.Errorf("Could not read member (%s) info from Zookeeper:", member, err)
			continue
		}
		nodeData, err := jsonTextToStringMap(string(keyData))
		if err != nil {
			log.Errorf("Could not parse Zookeeper node data for node \"%s\": %s", member, err)
			continue
		}
		role, _ := nodeData["role"]
		connUrl, _ := nodeData["conn_url"]
		name := path.Base(member)

		ret = append(ret, PatroniClusterMember{Scope: database.HostConfig.Scope, ConnUrl: connUrl, Role: role, Name: name})
	}

	return ret, nil
}

func ResolveDatabasesFromPatroni(ce MonitoredDatabase) ([]MonitoredDatabase, error) {
	md := make([]MonitoredDatabase, 0)
	cm := make([]PatroniClusterMember, 0)
	var err error
	var ok bool
	var dbUnique string

	log.Error("ce.HostConfig", ce.HostConfig)
	if ce.HostConfig.DcsType == DCS_TYPE_ETCD {
		cm, err = EtcdGetClusterMembers(ce)
	} else if ce.HostConfig.DcsType == DCS_TYPE_ZOOKEEPER{
		cm, err = ZookeeperGetClusterMembers(ce)
	} else {
		log.Error("unknown DCS", ce.HostConfig.DcsType)
		return md, errors.New("unknown DCS")
	}
	if err != nil {
		log.Warningf("Failed to get info from DCS for %s, using previous member info if any", ce.DBUniqueName)
		cm, ok = lastFoundClusterMembers[ce.DBUniqueName]
		if ok {	// mask error from main loop not to remove monitored DBs due to "jitter"
			err = nil
		}
	} else {
		lastFoundClusterMembers[ce.DBUniqueName] = cm
	}
	if len(cm) == 0 {
		log.Warningf("No Patroni cluster members found for cluster [%s:%s]", ce.DBUniqueName, ce.HostConfig.Scope)
		return md, nil
	}
	log.Infof("Found %d Patroni members for cluster [%s:%s]", len(cm), ce.DBUniqueName, ce.HostConfig.Scope)

	for _, m := range cm {
		log.Infof("Processing Patroni cluster member [%s:%s]", ce.DBUniqueName, m.Name)
		if ce.OnlyIfMaster && m.Role != "master" {
			log.Infof("Skipping over Patroni cluster member [%s:%s] as not a master", ce.DBUniqueName, m.Name)
			continue
		}
		host, port, err := ParseHostAndPortFromJdbcConnStr(m.ConnUrl)
		if err != nil {
			log.Errorf("Could not parse Patroni conn str \"%s\" [%s:%s]: %v", m.ConnUrl, ce.DBUniqueName, m.Scope, err)
			continue
		}
		if ce.OnlyIfMaster {
			dbUnique = ce.DBUniqueName
		} else {
			dbUnique = ce.DBUniqueName + "_" + m.Name
		}
		if ce.DBName != "" {
			md = append(md, MonitoredDatabase{DBUniqueName: dbUnique,
				DBName:            ce.DBName,
				Host:              host,
				Port:              port,
				User:              ce.User,
				Password:          ce.Password,
				PasswordType:      ce.PasswordType,
				SslMode:           ce.SslMode,
				SslRootCAPath:     ce.SslRootCAPath,
				SslClientCertPath: ce.SslClientCertPath,
				SslClientKeyPath:  ce.SslClientKeyPath,
				StmtTimeout:       ce.StmtTimeout,
				Metrics:           ce.Metrics,
				PresetMetrics:     ce.PresetMetrics,
				IsSuperuser:       ce.IsSuperuser,
				CustomTags:        ce.CustomTags,
				HostConfig:	       ce.HostConfig,
				DBType:            "postgres"})
			continue
		} else {
			c, err := GetPostgresDBConnection("", host, port, "template1", ce.User, ce.Password,
				ce.SslMode, ce.SslRootCAPath, ce.SslClientCertPath, ce.SslClientKeyPath)
			if err != nil {
				log.Errorf("Could not contact Patroni member [%s:%s]: %v", ce.DBUniqueName, m.Scope, err)
				continue
			}
			defer c.Close()
			sql := `select datname::text as datname,
					quote_ident(datname)::text as datname_escaped
					from pg_database
					where not datistemplate
					and datallowconn
					and has_database_privilege (datname, 'CONNECT')
					and case when length(trim($1)) > 0 then datname ~ $2 else true end
					and case when length(trim($3)) > 0 then not datname ~ $4 else true end`

			data, err := DBExecRead(c, ce.DBUniqueName, sql, ce.DBNameIncludePattern, ce.DBNameIncludePattern, ce.DBNameExcludePattern, ce.DBNameExcludePattern)
			if err != nil {
				log.Errorf("Could not get DB name listing from Patroni member [%s:%s]: %v", ce.DBUniqueName, m.Scope, err)
				continue
			}

			for _, d := range data {
				md = append(md, MonitoredDatabase{DBUniqueName: dbUnique + "_" + d["datname_escaped"].(string),
					DBName:            d["datname"].(string),
					Host:              host,
					Port:              port,
					User:              ce.User,
					Password:          ce.Password,
					PasswordType:      ce.PasswordType,
					SslMode:           ce.SslMode,
					SslRootCAPath:     ce.SslRootCAPath,
					SslClientCertPath: ce.SslClientCertPath,
					SslClientKeyPath:  ce.SslClientKeyPath,
					StmtTimeout:       ce.StmtTimeout,
					Metrics:           ce.Metrics,
					PresetMetrics:     ce.PresetMetrics,
					IsSuperuser:       ce.IsSuperuser,
					CustomTags:        ce.CustomTags,
					HostConfig:        ce.HostConfig,
					DBType:            "postgres"})
			}
		}

	}

	return md, err
}

<|endoftext|>


<commit_before>package ph2slack

import (
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestPhabricatorInvalidToken(t *testing.T) {
	ph := &Phabricator{
		Host:  "https://secure.phabricator.com",
		Token: "01234567890123456789012345678901",
	}
	_, err := ph.PhidQuery(os.Getenv("PHABRICATOR_TEST_PHID"))
	assert.Error(t, err)
}

func TestPhabricatorInvalidPhid(t *testing.T) {
	ph := &Phabricator{
		Host:  "https://secure.phabricator.com",
		Token: os.Getenv("PHABRICATOR_TEST_TOKEN"),
	}
	_, err := ph.PhidQuery("invalid")
	assert.Error(t, err)
}

func TestPhabricatorInvalidHost(t *testing.T) {
	ph := &Phabricator{
		Host:  "invalid",
		Token: os.Getenv("PHABRICATOR_TEST_TOKEN"),
	}
	_, err := ph.PhidQuery(os.Getenv("PHABRICATOR_TEST_PHID"))
	assert.Error(t, err)
}

func TestPhabricatorQuery(t *testing.T) {
	ph := &Phabricator{
		Host:  os.Getenv("PHABRICATOR_TEST_HOST"),
		Token: os.Getenv("PHABRICATOR_TEST_TOKEN"),
	}
	_, err := ph.PhidQuery(os.Getenv("PHABRICATOR_TEST_PHID"))
	assert.NoError(t, err)
}
<commit_msg>Test Phabricator query error<commit_after>package ph2slack

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestPhabricatorInvalidToken(t *testing.T) {
	ph := &Phabricator{
		Host:  "https://secure.phabricator.com",
		Token: "01234567890123456789012345678901",
	}
	_, err := ph.PhidQuery(os.Getenv("PHABRICATOR_TEST_PHID"))
	assert.Error(t, err)
}

func TestPhabricatorInvalidPhid(t *testing.T) {
	ph := &Phabricator{
		Host:  "https://secure.phabricator.com",
		Token: os.Getenv("PHABRICATOR_TEST_TOKEN"),
	}
	_, err := ph.PhidQuery("invalid")
	assert.Error(t, err)
}

func TestPhabricatorInvalidHost(t *testing.T) {
	ph := &Phabricator{
		Host:  "invalid",
		Token: os.Getenv("PHABRICATOR_TEST_TOKEN"),
	}
	_, err := ph.PhidQuery(os.Getenv("PHABRICATOR_TEST_PHID"))
	assert.Error(t, err)
}

func TestPhabricatorQuery(t *testing.T) {
	ph := &Phabricator{
		Host:  os.Getenv("PHABRICATOR_TEST_HOST"),
		Token: os.Getenv("PHABRICATOR_TEST_TOKEN"),
	}
	_, err := ph.PhidQuery(os.Getenv("PHABRICATOR_TEST_PHID"))
	assert.NoError(t, err)
}

func TestPhabricatorQueryError(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, `{"error_code": "500", "error_info": "something wrong"}`)
	}))
	defer ts.Close()

	ph := &Phabricator{
		Host: ts.URL,
	}
	_, err := ph.PhidQuery("token")
	assert.EqualError(t, err, "500 something wrong")
}
<|endoftext|>


<commit_before>// Copyright 2020 The LUCI 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 invocations

import (
	"testing"
	"time"

	"github.com/golang/protobuf/ptypes"
	"github.com/golang/protobuf/ptypes/timestamp"

	"go.chromium.org/luci/common/clock/testclock"
	"go.chromium.org/luci/server/span"

	"go.chromium.org/luci/resultdb/internal/spanutil"
	"go.chromium.org/luci/resultdb/internal/testutil"
	pb "go.chromium.org/luci/resultdb/proto/v1"

	. "github.com/smartystreets/goconvey/convey"
)

// historyAccumulator has a method that can be passed as a callback to ByTimestamp.
type historyAccumulator struct {
	invs []ID
	b    spanutil.Buffer
}

func (ia *historyAccumulator) accumulate(inv ID, ts *timestamp.Timestamp) error {
	// We only need the invocationID in these tests.
	_ = ts
	ia.invs = append(ia.invs, inv)
	return nil
}

func newHistoryAccumulator(capacity int) historyAccumulator {
	return historyAccumulator{
		invs: make([]ID, 0, capacity),
	}
}

func TestByTimestamp(t *testing.T) {
	SkipConvey(`ByTimestamp`, t, func() {
		ctx := testutil.SpannerTestContext(t)
		realm := "testproject:bytimestamprealm"

		start := testclock.TestRecentTimeUTC
		middle := start.Add(time.Hour)
		end := middle.Add(time.Hour)

		// Insert some Invocations.
		testutil.MustApply(ctx,
			insertInvocation("first", map[string]interface{}{
				"CreateTime":  start,
				"HistoryTime": start,
				"Realm":       realm,
			}),
			insertInvocation("second", map[string]interface{}{
				"CreateTime":  middle,
				"HistoryTime": middle,
				"Realm":       realm,
			}),
			insertInvocation("secondWrongRealm", map[string]interface{}{
				"CreateTime":  middle,
				"HistoryTime": middle,
				"Realm":       "testproject:wrongrealm",
			}),
			insertInvocation("secondUnindexed", map[string]interface{}{
				"CreateTime": middle,
				// No HistoryTime.
				"Realm": realm,
			}),
			insertInvocation("third", map[string]interface{}{
				"CreateTime":  end,
				"HistoryTime": end,
				"Realm":       realm,
			}),
		)
		ctx, cancel := span.ReadOnlyTransaction(ctx)
		defer cancel()

		beforePB, _ := ptypes.TimestampProto(start.Add(-1 * time.Hour))
		justBeforePB, _ := ptypes.TimestampProto(start.Add(-1 * time.Second))
		startPB, _ := ptypes.TimestampProto(start)
		middlePB, _ := ptypes.TimestampProto(middle)
		afterPB, _ := ptypes.TimestampProto(end.Add(time.Hour))
		muchLaterPB, _ := ptypes.TimestampProto(end.Add(24 * time.Hour))

		Convey(`all but the most recent`, func() {
			ac := newHistoryAccumulator(2)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: startPB, Latest: middlePB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 2)
			So(string(ac.invs[0]), ShouldEndWith, "second")
			So(string(ac.invs[1]), ShouldEndWith, "first")
		})

		Convey(`all but the oldest`, func() {
			ac := newHistoryAccumulator(2)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: middlePB, Latest: afterPB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 2)
			So(string(ac.invs[0]), ShouldEndWith, "third")
			So(string(ac.invs[1]), ShouldEndWith, "second")
		})

		Convey(`all results`, func() {
			ac := newHistoryAccumulator(2)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: startPB, Latest: afterPB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 3)
			So(string(ac.invs[0]), ShouldEndWith, "third")
			So(string(ac.invs[1]), ShouldEndWith, "second")
			So(string(ac.invs[2]), ShouldEndWith, "first")
		})

		Convey(`before first result`, func() {
			ac := newHistoryAccumulator(1)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: beforePB, Latest: justBeforePB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 0)
		})

		Convey(`after last result`, func() {
			ac := newHistoryAccumulator(1)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: afterPB, Latest: muchLaterPB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 0)
		})
	})
}
<commit_msg>Revert "[resultdb] Disable history test."<commit_after>// Copyright 2020 The LUCI 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 invocations

import (
	"testing"
	"time"

	"github.com/golang/protobuf/ptypes"
	"github.com/golang/protobuf/ptypes/timestamp"

	"go.chromium.org/luci/common/clock/testclock"
	"go.chromium.org/luci/server/span"

	"go.chromium.org/luci/resultdb/internal/spanutil"
	"go.chromium.org/luci/resultdb/internal/testutil"
	pb "go.chromium.org/luci/resultdb/proto/v1"

	. "github.com/smartystreets/goconvey/convey"
)

// historyAccumulator has a method that can be passed as a callback to ByTimestamp.
type historyAccumulator struct {
	invs []ID
	b    spanutil.Buffer
}

func (ia *historyAccumulator) accumulate(inv ID, ts *timestamp.Timestamp) error {
	// We only need the invocationID in these tests.
	_ = ts
	ia.invs = append(ia.invs, inv)
	return nil
}

func newHistoryAccumulator(capacity int) historyAccumulator {
	return historyAccumulator{
		invs: make([]ID, 0, capacity),
	}
}

func TestByTimestamp(t *testing.T) {
	Convey(`ByTimestamp`, t, func() {
		ctx := testutil.SpannerTestContext(t)
		realm := "testproject:bytimestamprealm"

		start := testclock.TestRecentTimeUTC
		middle := start.Add(time.Hour)
		end := middle.Add(time.Hour)

		// Insert some Invocations.
		testutil.MustApply(ctx,
			insertInvocation("first", map[string]interface{}{
				"CreateTime":  start,
				"HistoryTime": start,
				"Realm":       realm,
			}),
			insertInvocation("second", map[string]interface{}{
				"CreateTime":  middle,
				"HistoryTime": middle,
				"Realm":       realm,
			}),
			insertInvocation("secondWrongRealm", map[string]interface{}{
				"CreateTime":  middle,
				"HistoryTime": middle,
				"Realm":       "testproject:wrongrealm",
			}),
			insertInvocation("secondUnindexed", map[string]interface{}{
				"CreateTime": middle,
				// No HistoryTime.
				"Realm": realm,
			}),
			insertInvocation("third", map[string]interface{}{
				"CreateTime":  end,
				"HistoryTime": end,
				"Realm":       realm,
			}),
		)
		ctx, cancel := span.ReadOnlyTransaction(ctx)
		defer cancel()

		beforePB, _ := ptypes.TimestampProto(start.Add(-1 * time.Hour))
		justBeforePB, _ := ptypes.TimestampProto(start.Add(-1 * time.Second))
		startPB, _ := ptypes.TimestampProto(start)
		middlePB, _ := ptypes.TimestampProto(middle)
		afterPB, _ := ptypes.TimestampProto(end.Add(time.Hour))
		muchLaterPB, _ := ptypes.TimestampProto(end.Add(24 * time.Hour))

		Convey(`all but the most recent`, func() {
			ac := newHistoryAccumulator(2)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: startPB, Latest: middlePB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 2)
			So(string(ac.invs[0]), ShouldEndWith, "second")
			So(string(ac.invs[1]), ShouldEndWith, "first")
		})

		Convey(`all but the oldest`, func() {
			ac := newHistoryAccumulator(2)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: middlePB, Latest: afterPB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 2)
			So(string(ac.invs[0]), ShouldEndWith, "third")
			So(string(ac.invs[1]), ShouldEndWith, "second")
		})

		Convey(`all results`, func() {
			ac := newHistoryAccumulator(2)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: startPB, Latest: afterPB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 3)
			So(string(ac.invs[0]), ShouldEndWith, "third")
			So(string(ac.invs[1]), ShouldEndWith, "second")
			So(string(ac.invs[2]), ShouldEndWith, "first")
		})

		Convey(`before first result`, func() {
			ac := newHistoryAccumulator(1)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: beforePB, Latest: justBeforePB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 0)
		})

		Convey(`after last result`, func() {
			ac := newHistoryAccumulator(1)
			err := ByTimestamp(ctx, realm, &pb.TimeRange{Earliest: afterPB, Latest: muchLaterPB}, ac.accumulate)
			So(err, ShouldBeNil)
			So(ac.invs, ShouldHaveLength, 0)
		})
	})
}
<|endoftext|>