<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/agl/xmpp"
	"github.com/jroimartin/gocui"
	"github.com/rakoo/goax"
)

var (
	ratchet *goax.Ratchet

	// The Key Exchange material marshalled as json
	kx string

	xmppClient *xmpp.Conn

	// contact type indexed by jid
	contacts map[string]contact
)

type contact struct {
	jid    string
	status string
}

// Convert a xmpp status ("away", "dnd") into a status, defaulting to
// "available"
func statusFromStatus(xstatus string) string {
	if xstatus == "" {
		return "available"
	}
	return xstatus
}

func main() {
	var err error
	var ourJid string
	xmppClient, ourJid, err = getXmppClient()
	if err != nil {
		log.Fatal(err)
	}
	resp, _, err := xmppClient.RequestRoster()
	if err != nil {
		log.Fatal(err)
	}

	// Create ratchet and kx material
	var priv [32]byte
	io.ReadFull(rand.Reader, priv[:])
	ratchet = goax.New(rand.Reader, &priv)
	kxraw, err := ratchet.GetKeyExchangeMaterial()
	if err != nil {
		log.Fatal(err)
	}

	marshalled, err := json.Marshal(kxraw)
	if err != nil {
		log.Fatal(err)
	}
	kx = string(marshalled)

	// The ui
	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		log.Panicln(err)
	}
	defer g.Close()
	g.SetLayout(layout)
	if err := keybindings(g); err != nil {
		log.Panicln(err)
	}
	g.SelBgColor = gocui.ColorGreen
	g.SelFgColor = gocui.ColorBlack
	g.ShowCursor = true

	go func() {
		roster := <-resp
		switch v := roster.Value.(type) {
		case *xmpp.ClientIQ:
			var roster xmpp.Roster
			err := xml.NewDecoder(bytes.NewReader(v.Query)).Decode(&roster)
			if err != nil {
				debugf(g, "Couldn't decode into a roster: %s\n", err)
			}
			contacts = make(map[string]contact)
			for _, entry := range roster.Item {
				contacts[entry.Jid] = contact{entry.Jid, "unknown"}
			}
			setContacts(g, contacts)
		}
	}()

	go func() {
		for {
			st, err := xmppClient.Next()
			if err != nil {
				debugf(g, "! Error at next stanza: %s\n", err)
				continue
			}

			switch v := st.Value.(type) {
			case *xmpp.ClientPresence:
				bare := xmpp.RemoveResourceFromJid(v.From)
				if bare == ourJid {
					continue
				}
				if len(contacts) == 0 {
					contacts = make(map[string]contact)
				}
				c, ok := contacts[v.From]
				if !ok {
					contacts[v.From] = contact{v.From, statusFromStatus(v.Status)}
					setContacts(g, contacts)
				} else {
					if v.Type == "error" {
						delete(contacts, v.From)
						setContacts(g, contacts)
					} else if c.status != statusFromStatus(v.Status) {
						c.status = statusFromStatus(v.Status)
						setContacts(g, contacts)
					}
				}
			default:
				debugf(g, "! Got stanza: %v\n", st.Name)
			}
		}
	}()

	err = g.MainLoop()
	if err != nil && err != gocui.ErrorQuit {
		log.Panicln(err)
	}
}

type config struct {
	Jid                     string `json:"jid"`
	Password                string `json:"password"`
	ServerCertificateSHA256 string
}

func getXmppClient() (*xmpp.Conn, string, error) {
	// The xmpp connection
	configFile, err := os.Open(filepath.Join(os.Getenv("HOME"), ".config", "goax", "config.json"))
	if err != nil {
		return nil, "", fmt.Errorf("Couldn't open config file: %s", err)
	}

	var conf config
	err = json.NewDecoder(configFile).Decode(&conf)
	if err != nil {
		return nil, "", fmt.Errorf("Couldn't decode json config: %s", err)
	}

	parts := strings.SplitN(conf.Jid, "@", 2)
	if len(parts) != 2 {
		return nil, "", fmt.Errorf("xmpp: invalid username (want user@domain): %s" + conf.Jid)
	}
	user := parts[0]
	domain := parts[1]

	host, port, err := xmpp.Resolve(domain)
	if err != nil {
		return nil, "", fmt.Errorf("Failed to resolve xmpp host for domain %s: %s", domain, err)
	}
	addr := fmt.Sprintf("%s:%d", host, port)

	rawCert, err := hex.DecodeString(conf.ServerCertificateSHA256)
	if err != nil {
		return nil, "", fmt.Errorf("Bad server certificate : %s", err)
	}

	logfile, err := os.Create("log")
	cfg := &xmpp.Config{
		InLog: logfile,
		ServerCertificateSHA256: rawCert,
	}

	xmppClient, err := xmpp.Dial(addr, user, domain, conf.Password, cfg)
	if err != nil {
		return nil, "", fmt.Errorf("Couldn't connect to server: %s", err)
	}
	xmppClient.SignalPresence("alive")

	return xmppClient, conf.Jid, nil
}
<commit_msg>Don't use ourJid anymore<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/agl/xmpp"
	"github.com/jroimartin/gocui"
	"github.com/rakoo/goax"
)

var (
	ratchet *goax.Ratchet

	// The Key Exchange material marshalled as json
	kx string

	xmppClient *xmpp.Conn

	// contact type indexed by jid
	contacts map[string]contact
)

type contact struct {
	jid    string
	status string
}

// Convert a xmpp status ("away", "dnd") into a status, defaulting to
// "available"
func statusFromStatus(xstatus string) string {
	if xstatus == "" {
		return "available"
	}
	return xstatus
}

func main() {
	var err error
	xmppClient, err = getXmppClient()
	if err != nil {
		log.Fatal(err)
	}

	// Create ratchet and kx material
	var priv [32]byte
	io.ReadFull(rand.Reader, priv[:])
	ratchet = goax.New(rand.Reader, &priv)
	kxraw, err := ratchet.GetKeyExchangeMaterial()
	if err != nil {
		log.Fatal(err)
	}

	marshalled, err := json.Marshal(kxraw)
	if err != nil {
		log.Fatal(err)
	}
	kx = string(marshalled)

	// The ui
	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		log.Panicln(err)
	}
	defer g.Close()
	g.SetLayout(layout)
	if err := keybindings(g); err != nil {
		log.Panicln(err)
	}
	g.SelBgColor = gocui.ColorGreen
	g.SelFgColor = gocui.ColorBlack
	g.ShowCursor = true

	go func() {
		roster := <-resp
		switch v := roster.Value.(type) {
		case *xmpp.ClientIQ:
			var roster xmpp.Roster
			err := xml.NewDecoder(bytes.NewReader(v.Query)).Decode(&roster)
			if err != nil {
				debugf(g, "Couldn't decode into a roster: %s\n", err)
			}
			contacts = make(map[string]contact)
			for _, entry := range roster.Item {
				contacts[entry.Jid] = contact{entry.Jid, "unknown"}
			}
			setContacts(g, contacts)
		}
	}()

	go func() {
		for {
			st, err := xmppClient.Next()
			if err != nil {
				debugf(g, "! Error at next stanza: %s\n", err)
				continue
			}

			switch v := st.Value.(type) {
			case *xmpp.ClientPresence:
				bare := xmpp.RemoveResourceFromJid(v.From)
				if bare == ourJid {
					continue
				}
				if len(contacts) == 0 {
					contacts = make(map[string]contact)
				}
				c, ok := contacts[v.From]
				if !ok {
					contacts[v.From] = contact{v.From, statusFromStatus(v.Status)}
					setContacts(g, contacts)
				} else {
					if v.Type == "error" {
						delete(contacts, v.From)
						setContacts(g, contacts)
					} else if c.status != statusFromStatus(v.Status) {
						c.status = statusFromStatus(v.Status)
						setContacts(g, contacts)
					}
				}
			default:
				debugf(g, "! Got stanza: %v\n", st.Name)
			}
		}
	}()

	err = g.MainLoop()
	if err != nil && err != gocui.ErrorQuit {
		log.Panicln(err)
	}
}

type config struct {
	Jid                     string `json:"jid"`
	Password                string `json:"password"`
	ServerCertificateSHA256 string
}

func getXmppClient() (*xmpp.Conn, error) {
	// The xmpp connection
	configFile, err := os.Open(filepath.Join(os.Getenv("HOME"), ".config", "goax", "config.json"))
	if err != nil {
		return nil, fmt.Errorf("Couldn't open config file: %s", err)
	}

	var conf config
	err = json.NewDecoder(configFile).Decode(&conf)
	if err != nil {
		return nil, fmt.Errorf("Couldn't decode json config: %s", err)
	}

	parts := strings.SplitN(conf.Jid, "@", 2)
	if len(parts) != 2 {
		return nil, fmt.Errorf("xmpp: invalid username (want user@domain): %s" + conf.Jid)
	}
	user := parts[0]
	domain := parts[1]

	host, port, err := xmpp.Resolve(domain)
	if err != nil {
		return nil, fmt.Errorf("Failed to resolve xmpp host for domain %s: %s", domain, err)
	}
	addr := fmt.Sprintf("%s:%d", host, port)

	rawCert, err := hex.DecodeString(conf.ServerCertificateSHA256)
	if err != nil {
		return nil, fmt.Errorf("Bad server certificate : %s", err)
	}

	logfile, err := os.Create("log")
	cfg := &xmpp.Config{
		InLog: logfile,
		ServerCertificateSHA256: rawCert,
	}

	xmppClient, err := xmpp.Dial(addr, user, domain, conf.Password, cfg)
	if err != nil {
		return nil, fmt.Errorf("Couldn't connect to server: %s", err)
	}
	xmppClient.SignalPresence("alive")

	return xmppClient, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/timeglass/glass/_vendor/github.com/hashicorp/errwrap"

	"github.com/timeglass/glass/model"
	"github.com/timeglass/snow/monitor"
)

var Version = "0.0.0"
var Build = "gobuild"

var mbu = flag.Duration("mbu", time.Minute, "The minimal billable unit")
var bind = flag.String("bind", ":0", "Address to bind the Daemon to")
var force = flag.Bool("force", false, "Force start the Daemon")

func main() {
	flag.Parse()

	//by default timeout is four times the mbu
	//@todo make configurable
	timer := NewTimer(*mbu, 4*(*mbu))
	svr, err := NewServer(*bind, timer)
	if err != nil {
		log.Fatal(err)
	}

	//check version without delaying start times
	go svr.checkVersion()

	dir, err := os.Getwd()
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed to fetch current working dir: {{err}}", err))
	}

	monitor, err := monitor.New(dir, monitor.Recursive, time.Millisecond*50)
	if err != nil {
		log.Fatal(errwrap.Wrapf(fmt.Sprintf("Failed to create monitor for directory '%s': {{err}}"), err))
	}

	go func() {
		for err := range monitor.Errors() {
			log.Printf("Monitor Error: %s", err)
		}
	}()

	//whenever _something_ happens in any directory, wakeup the timer
	timer.Wakeup, err = monitor.Start()
	if err != nil {
		log.Fatal(errwrap.Wrapf(fmt.Sprintf("Failed to start monitor for directory '%s': {{err}}"), err))
	}

	m := model.New(dir)
	info, err := m.ReadDaemonInfo()
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed read Daemon info: {{err}}", err))
	}

	if info.Addr != "" && !*force {
		log.Fatal("It appears another Daemon is already running or a previous instance didn't shutdown properly, use -force to force start.")
	}

	info = model.NewDeamon(dir, svr.Addr())
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	go func() {
		<-sig
		svr.Stop()
	}()

	log.Printf("Listening on '%s'", svr.Addr())
	err = svr.Start()
	if err != nil && !strings.Contains(err.Error(), "closed network connection") {
		log.Fatal(err)
	}

	log.Printf("Writing information to database...")
	info.Addr = ""
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	log.Printf("Done")
}
<commit_msg>continue [spent 1m10s]<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/timeglass/glass/_vendor/github.com/hashicorp/errwrap"

	"github.com/timeglass/glass/model"
	"github.com/timeglass/snow/monitor"
)

var Version = "0.0.0"
var Build = "gobuild"

var mbu = flag.Duration("mbu", time.Minute, "The minimal billable unit")
var bind = flag.String("bind", ":0", "Address to bind the Daemon to")
var force = flag.Bool("force", false, "Force start the Daemon")

func main() {
	flag.Parse()

	//@todo, ensure restart after reboot

	//by default timeout is four times the mbu
	//@todo make configurable
	timer := NewTimer(*mbu, 4*(*mbu))
	svr, err := NewServer(*bind, timer)
	if err != nil {
		log.Fatal(err)
	}

	//check version without delaying start times
	go svr.checkVersion()

	dir, err := os.Getwd()
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed to fetch current working dir: {{err}}", err))
	}

	monitor, err := monitor.New(dir, monitor.Recursive, time.Millisecond*50)
	if err != nil {
		log.Fatal(errwrap.Wrapf(fmt.Sprintf("Failed to create monitor for directory '%s': {{err}}"), err))
	}

	go func() {
		for err := range monitor.Errors() {
			log.Printf("Monitor Error: %s", err)
		}
	}()

	//whenever _something_ happens in any directory, wakeup the timer
	timer.Wakeup, err = monitor.Start()
	if err != nil {
		log.Fatal(errwrap.Wrapf(fmt.Sprintf("Failed to start monitor for directory '%s': {{err}}"), err))
	}

	m := model.New(dir)
	info, err := m.ReadDaemonInfo()
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed read Daemon info: {{err}}", err))
	}

	if info.Addr != "" && !*force {
		log.Fatal("It appears another Daemon is already running or a previous instance didn't shutdown properly, use -force to force start.")
	}

	info = model.NewDeamon(dir, svr.Addr())
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	go func() {
		<-sig
		svr.Stop()
	}()

	log.Printf("Listening on '%s'", svr.Addr())
	err = svr.Start()
	if err != nil && !strings.Contains(err.Error(), "closed network connection") {
		log.Fatal(err)
	}

	log.Printf("Writing information to database...")
	info.Addr = ""
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	log.Printf("Done")
}
<|endoftext|>


<commit_before>package stun

import (
  "bytes"
  "encoding/binary"
  "errors"
)

type FingerprintAttribute struct {
  CRC []byte
}

func (h *FingerprintAttribute) Type() (AttributeType) {
  return Fingerprint
}

func (h *FingerprintAttribute) Encode(_ *Message) ([]byte, error) {
  buf := new(bytes.Buffer)
  err := binary.Write(buf, binary.BigEndian, attributeHeader(Attribute(h)))
  err = binary.Write(buf, binary.BigEndian, h.CRC)

  if err != nil {
    return nil, err
  }
  return buf.Bytes(), nil
}

func (h *FingerprintAttribute) Decode(data []byte, length uint16, _ *Header) (error) {
  if length != 4 || len(data) < 4 {
    return errors.New("Truncated Fingerprint Attribute")
  }
  h.CRC = data[0:4]
  return nil
}

func (h *FingerprintAttribute) Length() (uint16) {
  return 4
}
<commit_msg>encoding of fingerprint attribute<commit_after>package stun

import (
  "bytes"
  "encoding/binary"
  "errors"
  "hash/crc32"
)

const (
  crcXOR uint32 = 0x5354554e
)

type FingerprintAttribute struct {
  CRC []byte
}

func (h *FingerprintAttribute) Type() (AttributeType) {
  return Fingerprint
}

func (h *FingerprintAttribute) Encode(msg *Message) ([]byte, error) {
  buf := new(bytes.Buffer)
  err := binary.Write(buf, binary.BigEndian, attributeHeader(Attribute(h)))

  // Calculate partial message
  var partialMsg Message
  partialMsg.Header = msg.Header
  copy(partialMsg.Attributes, msg.Attributes)

  // Fingerprint must be last attribute.
  partialMsg.Attributes = partialMsg.Attributes[0:len(partialMsg.Attributes) - 1]

  // Add a new attribute w/ same length as msg integrity
  dummy := UnknownStunAttribute{ MessageIntegrity, make([]byte, 4) }
  partialMsg.Attributes = append(partialMsg.Attributes, &dummy)
  // calcualte the byte string
  msgBytes, err := partialMsg.Serialize()
  if err != nil {
    return nil, err
  }

  crc := crc32.ChecksumIEEE(msgBytes[0:len(msgBytes)-8]) ^ crcXOR
  err = binary.Write(buf, binary.BigEndian, crc)

  if err != nil {
    return nil, err
  }
  return buf.Bytes(), nil
}

func (h *FingerprintAttribute) Decode(data []byte, length uint16, _ *Header) (error) {
  if length != 4 || len(data) < 4 {
    return errors.New("Truncated Fingerprint Attribute")
  }
  h.CRC = data[0:4]
  return nil
}

func (h *FingerprintAttribute) Length() (uint16) {
  return 4
}
<|endoftext|>


<commit_before>package system

import (
	"testing"

	"reflect"

	"fmt"

	"github.com/stretchr/testify/assert"
	"kego.io/json"
)

func TestPropertyGetPointer(t *testing.T) {
	//!isNative && !isInterface => "*"
	assert.Equal(t, "", getPointer(&Type{Native: NewString("bool"), Interface: false}))
	assert.Equal(t, "", getPointer(&Type{Native: NewString("object"), Interface: true}))
	assert.Equal(t, "", getPointer(&Type{Native: NewString("bool"), Interface: true}))
	assert.Equal(t, "*", getPointer(&Type{Native: NewString("object"), Interface: false}))
	assert.Equal(t, "*", getPointer(&Type{Native: NewString("map"), Interface: false}))
	assert.Equal(t, "*", getPointer(&Type{Native: NewString("array"), Interface: false}))
}

func TestPropertyFormatTag(t *testing.T) {
	type parentStruct struct {
		*Object
	}
	type ruleStruct struct {
		*Object
	}
	parentType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "a", Type: NewReference("kego.io/system", "type")},
	}
	ruleType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "@a", Type: NewReference("kego.io/system", "type")},
	}
	json.RegisterType("a.b/c:a", reflect.TypeOf(&parentStruct{}))
	json.RegisterType("a.b/c:@a", reflect.TypeOf(&ruleStruct{}))
	RegisterType("a.b/c:a", parentType)
	RegisterType("a.b/c:@a", ruleType)
	defer json.UnregisterType("a.b/c:a")
	defer json.UnregisterType("a.b/c:@a")
	defer UnregisterType("a.b/c:a")
	defer UnregisterType("a.b/c:@a")

	r := &RuleHolder{
		rule:       &ruleStruct{},
		ruleType:   ruleType,
		parentType: parentType,
		path:       "d.e/f",
		imports:    map[string]string{},
	}
	s, err := formatTag([]byte("null"), r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	s, err = formatTag([]byte(`"a"`), r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"a\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	parentType.Context.Package = "kego.io/system"
	parentType.Id = "string"
	s, err = formatTag([]byte(`"a"`), r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"value\\\":\\\"a\\\"}}\"`", s)

	_, err = formatTag([]byte(`foo`), r)
	assert.Error(t, err)
}

type structWithCustomMarshaler struct {
	*Object
	throwError bool
}

func (s *structWithCustomMarshaler) MarshalJSON() ([]byte, error) {
	if s.throwError {
		return nil, fmt.Errorf("Here's an error")
	}
	return []byte(`"foo"`), nil
}

func TestMarshaler(t *testing.T) {
	f := structWithCustomMarshaler{}
	s, err := f.MarshalJSON()
	assert.NoError(t, err)
	assert.Equal(t, []byte(`"foo"`), s)
}

type typeThatWillCauseJsonMarshalToError chan string

func TestPropertyGetTag(t *testing.T) {
	type parentStruct struct {
		*Object
	}
	type structWithoutCustomMarshaler struct {
		A string
	}
	type ruleStruct struct {
		*Object
		B String
		C *structWithCustomMarshaler
		D typeThatWillCauseJsonMarshalToError
		E structWithoutCustomMarshaler
	}
	parentType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "a", Type: NewReference("kego.io/system", "type")},
	}
	ruleType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "@a", Type: NewReference("kego.io/system", "type")},
	}
	json.RegisterType("a.b/c:a", reflect.TypeOf(&parentStruct{}))
	json.RegisterType("a.b/c:@a", reflect.TypeOf(&ruleStruct{}))
	RegisterType("a.b/c:a", parentType)
	RegisterType("a.b/c:@a", ruleType)
	defer json.UnregisterType("a.b/c:a")
	defer json.UnregisterType("a.b/c:@a")
	defer UnregisterType("a.b/c:a")
	defer UnregisterType("a.b/c:@a")

	r := &RuleHolder{
		rule:       &ruleStruct{},
		ruleType:   ruleType,
		parentType: parentType,
		path:       "d.e/f",
		imports:    map[string]string{},
	}

	// ruleType has no defaulter property
	s, err := getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	ruleType.Properties = map[string]*Property{
		"b": &Property{
			Defaulter: true,
		},
	}

	// rule has no default field
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	r.rule = map[string]interface{}{"b": "c"}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"c\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	r.rule = map[string]interface{}{"d": "e"}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	r.rule = map[string]interface{}{"b": make(typeThatWillCauseJsonMarshalToError)}
	s, err = getTag(r)
	assert.Error(t, err)

	r.rule = &ruleStruct{B: NewString("c")}

	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"c\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	ruleType.Properties = map[string]*Property{
		"c": &Property{
			Defaulter: true,
		},
	}
	r.rule = &ruleStruct{C: &structWithCustomMarshaler{Object: &Object{Id: "f"}}}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"foo\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	r.rule = &ruleStruct{C: &structWithCustomMarshaler{Object: &Object{Id: "f"}, throwError: true}}
	s, err = getTag(r)
	assert.Error(t, err)

	ruleType.Properties = map[string]*Property{
		"d": &Property{
			Defaulter: true,
		},
	}
	r.rule = &ruleStruct{D: make(typeThatWillCauseJsonMarshalToError)}
	s, err = getTag(r)
	assert.Error(t, err)

	ruleType.Properties = map[string]*Property{
		"e": &Property{
			Defaulter: true,
		},
	}
	r.rule = &ruleStruct{E: structWithoutCustomMarshaler{A: "b"}}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":{\\\"A\\\":\\\"b\\\"},\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

}

func TestGoName(t *testing.T) {
	p := &Property{}
	s := p.GoName("foo")
	assert.Equal(t, "Foo", s)
	s = p.GoName("@foo")
	assert.Equal(t, "Foo_rule", s)
}

func TestGoTypeDescriptor(t *testing.T) {
	var i interface{}
	json.Unmarshal([]byte(`{
			"type": "system:property",
			"item": {
				"type": "json:@string"
			}
		}`), &i, "kego.io/system", map[string]string{})
	p, ok := i.(*Property)
	assert.True(t, ok, "Wrong type")
	s, err := p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "string", s)
}
<commit_msg>Tests<commit_after>package system

import (
	"testing"

	"reflect"

	"fmt"

	"github.com/stretchr/testify/assert"
	"kego.io/json"
)

func TestPropertyGetPointer(t *testing.T) {
	//!isNative && !isInterface => "*"
	assert.Equal(t, "", getPointer(&Type{Native: NewString("bool"), Interface: false}))
	assert.Equal(t, "", getPointer(&Type{Native: NewString("object"), Interface: true}))
	assert.Equal(t, "", getPointer(&Type{Native: NewString("bool"), Interface: true}))
	assert.Equal(t, "*", getPointer(&Type{Native: NewString("object"), Interface: false}))
	assert.Equal(t, "*", getPointer(&Type{Native: NewString("map"), Interface: false}))
	assert.Equal(t, "*", getPointer(&Type{Native: NewString("array"), Interface: false}))
}

func TestPropertyFormatTag(t *testing.T) {
	type parentStruct struct {
		*Object
	}
	type ruleStruct struct {
		*Object
	}
	parentType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "a", Type: NewReference("kego.io/system", "type")},
	}
	ruleType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "@a", Type: NewReference("kego.io/system", "type")},
	}
	json.RegisterType("a.b/c:a", reflect.TypeOf(&parentStruct{}))
	json.RegisterType("a.b/c:@a", reflect.TypeOf(&ruleStruct{}))
	RegisterType("a.b/c:a", parentType)
	RegisterType("a.b/c:@a", ruleType)
	defer json.UnregisterType("a.b/c:a")
	defer json.UnregisterType("a.b/c:@a")
	defer UnregisterType("a.b/c:a")
	defer UnregisterType("a.b/c:@a")

	r := &RuleHolder{
		rule:       &ruleStruct{},
		ruleType:   ruleType,
		parentType: parentType,
		path:       "d.e/f",
		imports:    map[string]string{},
	}
	s, err := formatTag([]byte("null"), r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	s, err = formatTag([]byte(`"a"`), r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"a\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	parentType.Context.Package = "kego.io/system"
	parentType.Id = "string"
	s, err = formatTag([]byte(`"a"`), r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"value\\\":\\\"a\\\"}}\"`", s)

	_, err = formatTag([]byte(`foo`), r)
	assert.Error(t, err)
}

type structWithCustomMarshaler struct {
	*Object
	throwError bool
}

func (s *structWithCustomMarshaler) MarshalJSON() ([]byte, error) {
	if s.throwError {
		return nil, fmt.Errorf("Here's an error")
	}
	return []byte(`"foo"`), nil
}

func TestMarshaler(t *testing.T) {
	f := structWithCustomMarshaler{}
	s, err := f.MarshalJSON()
	assert.NoError(t, err)
	assert.Equal(t, []byte(`"foo"`), s)
}

type typeThatWillCauseJsonMarshalToError chan string

func TestPropertyGetTag(t *testing.T) {
	type parentStruct struct {
		*Object
	}
	type structWithoutCustomMarshaler struct {
		A string
	}
	type ruleStruct struct {
		*Object
		B String
		C *structWithCustomMarshaler
		D typeThatWillCauseJsonMarshalToError
		E structWithoutCustomMarshaler
	}
	parentType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "a", Type: NewReference("kego.io/system", "type")},
	}
	ruleType := &Type{
		Object: &Object{Context: &Context{Package: "a.b/c"}, Id: "@a", Type: NewReference("kego.io/system", "type")},
	}
	json.RegisterType("a.b/c:a", reflect.TypeOf(&parentStruct{}))
	json.RegisterType("a.b/c:@a", reflect.TypeOf(&ruleStruct{}))
	RegisterType("a.b/c:a", parentType)
	RegisterType("a.b/c:@a", ruleType)
	defer json.UnregisterType("a.b/c:a")
	defer json.UnregisterType("a.b/c:@a")
	defer UnregisterType("a.b/c:a")
	defer UnregisterType("a.b/c:@a")

	r := &RuleHolder{
		rule:       &ruleStruct{},
		ruleType:   ruleType,
		parentType: parentType,
		path:       "d.e/f",
		imports:    map[string]string{},
	}

	// ruleType has no defaulter property
	s, err := getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	ruleType.Properties = map[string]*Property{
		"b": &Property{
			Defaulter: true,
		},
	}

	// rule has no default field
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	r.rule = map[string]interface{}{"b": "c"}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"c\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	r.rule = map[string]interface{}{"d": "e"}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "", s)

	r.rule = map[string]interface{}{"b": make(typeThatWillCauseJsonMarshalToError)}
	s, err = getTag(r)
	assert.Error(t, err)

	r.rule = &ruleStruct{B: NewString("c")}

	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"c\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	ruleType.Properties = map[string]*Property{
		"c": &Property{
			Defaulter: true,
		},
	}
	r.rule = &ruleStruct{C: &structWithCustomMarshaler{Object: &Object{Id: "f"}}}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":\\\"foo\\\",\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

	r.rule = &ruleStruct{C: &structWithCustomMarshaler{Object: &Object{Id: "f"}, throwError: true}}
	s, err = getTag(r)
	assert.Error(t, err)

	ruleType.Properties = map[string]*Property{
		"d": &Property{
			Defaulter: true,
		},
	}
	r.rule = &ruleStruct{D: make(typeThatWillCauseJsonMarshalToError)}
	s, err = getTag(r)
	assert.Error(t, err)

	ruleType.Properties = map[string]*Property{
		"e": &Property{
			Defaulter: true,
		},
	}
	r.rule = &ruleStruct{E: structWithoutCustomMarshaler{A: "b"}}
	s, err = getTag(r)
	assert.NoError(t, err)
	assert.Equal(t, "`kego:\"{\\\"default\\\":{\\\"type\\\":\\\"a.b/c:a\\\",\\\"value\\\":{\\\"A\\\":\\\"b\\\"},\\\"path\\\":\\\"d.e/f\\\"}}\"`", s)

}

func TestGoName(t *testing.T) {
	p := &Property{}
	s := p.GoName("foo")
	assert.Equal(t, "Foo", s)
	s = p.GoName("@foo")
	assert.Equal(t, "Foo_rule", s)
}

func TestGoTypeDescriptor(t *testing.T) {
	p := &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &JsonString_rule{
			Object: &Object{
				Type: NewReference("kego.io/json", "@string"),
			},
		},
	}
	s, err := p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "string", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &String_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@string"),
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "String", s)

	s, err = p.GoTypeDescriptor("kego.io/a", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "system.String", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		// We're just using property here because it's a handy
		// non-native type in the system package
		Item: &Property_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@property"),
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "*Property", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		// We're just using property here because it's a handy
		// non-native type in the system package
		Item: &Property_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@property"),
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/a", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "*system.Property", s)

	type a struct{}
	type a_rule struct{ *Object }
	tyr := &Type{Object: &Object{Id: "@a"}}
	ty := &Type{Object: &Object{Id: "a", Context: &Context{Package: "b.c/d"}}}
	json.RegisterType("b.c/d:a", reflect.TypeOf(&a{}))
	json.RegisterType("b.c/d:@a", reflect.TypeOf(&a_rule{}))
	RegisterType("b.c/d:a", ty)
	RegisterType("b.c/d:@a", tyr)
	defer json.UnregisterType("b.c/d:a")
	defer json.UnregisterType("b.c/d:@a")
	defer UnregisterType("b.c/d:a")
	defer UnregisterType("b.c/d:@a")

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &a_rule{
			Object: &Object{
				Type: NewReference("b.c/d", "@a"),
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{
		"d": "b.c/d",
	})
	assert.NoError(t, err)
	assert.Equal(t, "*d.A", s)

	s, err = p.GoTypeDescriptor("b.c/d", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "*A", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &String_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@string"),
			},
			Default: NewString("a"),
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "String `kego:\"{\\\"default\\\":{\\\"value\\\":\\\"a\\\"}}\"`", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &Map_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@map"),
			},
			Items: &String_rule{
				Object: &Object{
					Type: NewReference("kego.io/system", "@string"),
				},
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "map[string]String", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &Array_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@array"),
			},
			Items: &String_rule{
				Object: &Object{
					Type: NewReference("kego.io/system", "@string"),
				},
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "[]String", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &Map_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@map"),
			},
			Items: &Array_rule{
				Object: &Object{
					Type: NewReference("kego.io/system", "@array"),
				},
				Items: &String_rule{
					Object: &Object{
						Type: NewReference("kego.io/system", "@string"),
					},
				},
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "map[string][]String", s)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &Map_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@map"),
			},
			Items: &Array_rule{
				Object: &Object{
					Type: NewReference("kego.io/system", "@array"),
				},
				Items: &String_rule{
					Object: &Object{
						Type: NewReference("kego.io/system", "@string"),
					},
					Default: NewString("a"),
				},
			},
		},
	}
	s, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "map[string][]String `kego:\"{\\\"default\\\":{\\\"value\\\":\\\"a\\\"}}\"`", s)

}

func TestGoTypeDescriptorErrors(t *testing.T) {

	p := &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &JsonString_rule{
			Object: &Object{
				Type: NewReference("a.b/c", "notFoundType"),
			},
		},
	}
	_, err := p.GoTypeDescriptor("kego.io/system", map[string]string{})
	// Item is an unregistered type, so errors at NewRuleHolder
	assert.Error(t, err)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &Map_rule{
			Object: &Object{
				Type: NewReference("kego.io/system", "@map"),
			},
		},
	}
	_, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	// Collection item @map doesn't have Items field, so errors at collectionPrefixInnerRule
	assert.Error(t, err)

	type a struct{}
	type a_rule struct{ *Object }
	tyr := &Type{Object: &Object{Id: "@a"}}
	ty := &Type{Object: &Object{Id: "a", Context: &Context{Package: "b.c/d"}}}
	json.RegisterType("b.c/d:a", reflect.TypeOf(&a{}))
	json.RegisterType("b.c/d:@a", reflect.TypeOf(&a_rule{}))
	RegisterType("b.c/d:a", ty)
	RegisterType("b.c/d:@a", tyr)
	defer json.UnregisterType("b.c/d:a")
	defer json.UnregisterType("b.c/d:@a")
	defer UnregisterType("b.c/d:a")
	defer UnregisterType("b.c/d:@a")

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: &a_rule{
			Object: &Object{
				Type: NewReference("b.c/d", "@a"),
			},
		},
	}
	_, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	// Item a_rule is a valid type but package b.c/d is not in the final
	// imports specified to GoTypeDescriptor, so we get an error at
	// inner.parentType.GoTypeReference
	assert.Error(t, err)

	p = &Property{
		Object: &Object{
			Type: NewReference("kego.io/system", "property"),
		},
		Item: map[string]interface{}{
			"type":    "kego.io/system:@string",
			"default": make(typeThatWillCauseJsonMarshalToError),
		},
	}
	_, err = p.GoTypeDescriptor("kego.io/system", map[string]string{})
	// Item default is a chan, so errors at getTag
	assert.Error(t, err)

}
<|endoftext|>


<commit_before>// Copyright 2018 The Go 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 ssa

import (
	"fmt"
	"math"
)

type indVarFlags uint8

const (
	indVarMinExc indVarFlags = 1 << iota // minimum value is exclusive (default: inclusive)
	indVarMaxInc                         // maximum value is inclusive (default: exclusive)
)

type indVar struct {
	ind   *Value // induction variable
	min   *Value // minimum value, inclusive/exclusive depends on flags
	max   *Value // maximum value, inclusive/exclusive depends on flags
	entry *Block // entry block in the loop.
	flags indVarFlags
	// Invariant: for all blocks strictly dominated by entry:
	//	min <= ind <  max    [if flags == 0]
	//	min <  ind <  max    [if flags == indVarMinExc]
	//	min <= ind <= max    [if flags == indVarMaxInc]
	//	min <  ind <= max    [if flags == indVarMinExc|indVarMaxInc]
}

// findIndVar finds induction variables in a function.
//
// Look for variables and blocks that satisfy the following
//
// loop:
//   ind = (Phi min nxt),
//   if ind < max
//     then goto enter_loop
//     else goto exit_loop
//
//   enter_loop:
//	do something
//      nxt = inc + ind
//	goto loop
//
// exit_loop:
//
//
// TODO: handle 32 bit operations
func findIndVar(f *Func) []indVar {
	var iv []indVar
	sdom := f.sdom()

	for _, b := range f.Blocks {
		if b.Kind != BlockIf || len(b.Preds) != 2 {
			continue
		}

		var flags indVarFlags
		var ind, max *Value // induction, and maximum

		// Check thet the control if it either ind </<= max or max >/>= ind.
		// TODO: Handle 32-bit comparisons.
		// TODO: Handle unsigned comparisons?
		switch b.Control.Op {
		case OpLeq64:
			flags |= indVarMaxInc
			fallthrough
		case OpLess64:
			ind, max = b.Control.Args[0], b.Control.Args[1]
		case OpGeq64:
			flags |= indVarMaxInc
			fallthrough
		case OpGreater64:
			ind, max = b.Control.Args[1], b.Control.Args[0]
		default:
			continue
		}

		// See if the arguments are reversed (i < len() <=> len() > i)
		less := true
		if max.Op == OpPhi {
			ind, max = max, ind
			less = false
		}

		// Check that the induction variable is a phi that depends on itself.
		if ind.Op != OpPhi {
			continue
		}

		// Extract min and nxt knowing that nxt is an addition (e.g. Add64).
		var min, nxt *Value // minimum, and next value
		if n := ind.Args[0]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
			min, nxt = ind.Args[1], n
		} else if n := ind.Args[1]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
			min, nxt = ind.Args[0], n
		} else {
			// Not a recognized induction variable.
			continue
		}

		var inc *Value
		if nxt.Args[0] == ind { // nxt = ind + inc
			inc = nxt.Args[1]
		} else if nxt.Args[1] == ind { // nxt = inc + ind
			inc = nxt.Args[0]
		} else {
			panic("unreachable") // one of the cases must be true from the above.
		}

		// Expect the increment to be a nonzero constant.
		if inc.Op != OpConst64 {
			continue
		}
		step := inc.AuxInt
		if step == 0 {
			continue
		}

		// Increment sign must match comparison direction.
		// When incrementing, the termination comparison must be ind </<= max.
		// When decrementing, the termination comparison must be ind >/>= max.
		// See issue 26116.
		if step > 0 && !less {
			continue
		}
		if step < 0 && less {
			continue
		}

		// If the increment is negative, swap min/max and their flags
		if step < 0 {
			min, max = max, min
			oldf := flags
			flags = indVarMaxInc
			if oldf&indVarMaxInc == 0 {
				flags |= indVarMinExc
			}
			step = -step
		}

		// Up to now we extracted the induction variable (ind),
		// the increment delta (inc), the temporary sum (nxt),
		// the mininum value (min) and the maximum value (max).
		//
		// We also know that ind has the form (Phi min nxt) where
		// nxt is (Add inc nxt) which means: 1) inc dominates nxt
		// and 2) there is a loop starting at inc and containing nxt.
		//
		// We need to prove that the induction variable is incremented
		// only when it's smaller than the maximum value.
		// Two conditions must happen listed below to accept ind
		// as an induction variable.

		// First condition: loop entry has a single predecessor, which
		// is the header block.  This implies that b.Succs[0] is
		// reached iff ind < max.
		if len(b.Succs[0].b.Preds) != 1 {
			// b.Succs[1] must exit the loop.
			continue
		}

		// Second condition: b.Succs[0] dominates nxt so that
		// nxt is computed when inc < max, meaning nxt <= max.
		if !sdom.isAncestorEq(b.Succs[0].b, nxt.Block) {
			// inc+ind can only be reached through the branch that enters the loop.
			continue
		}

		// We can only guarantee that the loop runs within limits of induction variable
		// if (one of)
		// (1) the increment is ±1
		// (2) the limits are constants
		// (3) loop is of the form k0 upto Known_not_negative-k inclusive, step <= k
		// (4) loop is of the form k0 upto Known_not_negative-k exclusive, step <= k+1
		// (5) loop is of the form Known_not_negative downto k0, minint+step < k0
		if step > 1 {
			ok := false
			if min.Op == OpConst64 && max.Op == OpConst64 {
				if max.AuxInt > min.AuxInt && max.AuxInt%step == min.AuxInt%step { // handle overflow
					ok = true
				}
			}
			// Handle induction variables of these forms.
			// KNN is known-not-negative.
			// SIGNED ARITHMETIC ONLY. (see switch on b.Control.Op above)
			// Possibilities for KNN are len and cap; perhaps we can infer others.
			// for i := 0; i <= KNN-k    ; i += k
			// for i := 0; i <  KNN-(k-1); i += k
			// Also handle decreasing.

			// "Proof" copied from https://go-review.googlesource.com/c/go/+/104041/10/src/cmd/compile/internal/ssa/loopbce.go#164
			//
			//	In the case of
			//	// PC is Positive Constant
			//	L := len(A)-PC
			//	for i := 0; i < L; i = i+PC
			//
			//	we know:
			//
			//	0 + PC does not over/underflow.
			//	len(A)-PC does not over/underflow
			//	maximum value for L is MaxInt-PC
			//	i < L <= MaxInt-PC means i + PC < MaxInt hence no overflow.

			// To match in SSA:
			// if  (a) min.Op == OpConst64(k0)
			// and (b) k0 >= MININT + step
			// and (c) max.Op == OpSubtract(Op{StringLen,SliceLen,SliceCap}, k)
			// or  (c) max.Op == OpAdd(Op{StringLen,SliceLen,SliceCap}, -k)
			// or  (c) max.Op == Op{StringLen,SliceLen,SliceCap}
			// and (d) if upto loop, require indVarMaxInc && step <= k or !indVarMaxInc && step-1 <= k

			if min.Op == OpConst64 && min.AuxInt >= step+math.MinInt64 {
				knn := max
				k := int64(0)
				var kArg *Value

				switch max.Op {
				case OpSub64:
					knn = max.Args[0]
					kArg = max.Args[1]

				case OpAdd64:
					knn = max.Args[0]
					kArg = max.Args[1]
					if knn.Op == OpConst64 {
						knn, kArg = kArg, knn
					}
				}
				switch knn.Op {
				case OpSliceLen, OpStringLen, OpSliceCap:
				default:
					knn = nil
				}

				if kArg != nil && kArg.Op == OpConst64 {
					k = kArg.AuxInt
					if max.Op == OpAdd64 {
						k = -k
					}
				}
				if k >= 0 && knn != nil {
					if inc.AuxInt > 0 { // increasing iteration
						// The concern for the relation between step and k is to ensure that iv never exceeds knn
						// i.e., iv < knn-(K-1) ==> iv + K <= knn; iv <= knn-K ==> iv +K < knn
						if step <= k || flags&indVarMaxInc == 0 && step-1 == k {
							ok = true
						}
					} else { // decreasing iteration
						// Will be decrementing from max towards min; max is knn-k; will only attempt decrement if
						// knn-k >[=] min; underflow is only a concern if min-step is not smaller than min.
						// This all assumes signed integer arithmetic
						// This is already assured by the test above: min.AuxInt >= step+math.MinInt64
						ok = true
					}
				}
			}

			// TODO: other unrolling idioms
			// for i := 0; i < KNN - KNN % k ; i += k
			// for i := 0; i < KNN&^(k-1) ; i += k // k a power of 2
			// for i := 0; i < KNN&(-k) ; i += k // k a power of 2

			if !ok {
				continue
			}
		}

		if f.pass.debug >= 1 {
			printIndVar(b, ind, min, max, step, flags)
		}

		iv = append(iv, indVar{
			ind:   ind,
			min:   min,
			max:   max,
			entry: b.Succs[0].b,
			flags: flags,
		})
		b.Logf("found induction variable %v (inc = %v, min = %v, max = %v)\n", ind, inc, min, max)
	}

	return iv
}

func dropAdd64(v *Value) (*Value, int64) {
	if v.Op == OpAdd64 && v.Args[0].Op == OpConst64 {
		return v.Args[1], v.Args[0].AuxInt
	}
	if v.Op == OpAdd64 && v.Args[1].Op == OpConst64 {
		return v.Args[0], v.Args[1].AuxInt
	}
	return v, 0
}

func printIndVar(b *Block, i, min, max *Value, inc int64, flags indVarFlags) {
	mb1, mb2 := "[", "]"
	if flags&indVarMinExc != 0 {
		mb1 = "("
	}
	if flags&indVarMaxInc == 0 {
		mb2 = ")"
	}

	mlim1, mlim2 := fmt.Sprint(min.AuxInt), fmt.Sprint(max.AuxInt)
	if !min.isGenericIntConst() {
		if b.Func.pass.debug >= 2 {
			mlim1 = fmt.Sprint(min)
		} else {
			mlim1 = "?"
		}
	}
	if !max.isGenericIntConst() {
		if b.Func.pass.debug >= 2 {
			mlim2 = fmt.Sprint(max)
		} else {
			mlim2 = "?"
		}
	}
	extra := ""
	if b.Func.pass.debug >= 2 {
		extra = fmt.Sprintf(" (%s)", i)
	}
	b.Func.Warnl(b.Pos, "Induction variable: limits %v%v,%v%v, increment %d%s", mb1, mlim1, mlim2, mb2, inc, extra)
}
<commit_msg>cmd/compile: refactor some code in loopbce.go<commit_after>// Copyright 2018 The Go 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 ssa

import (
	"fmt"
	"math"
)

type indVarFlags uint8

const (
	indVarMinExc indVarFlags = 1 << iota // minimum value is exclusive (default: inclusive)
	indVarMaxInc                         // maximum value is inclusive (default: exclusive)
)

type indVar struct {
	ind   *Value // induction variable
	min   *Value // minimum value, inclusive/exclusive depends on flags
	max   *Value // maximum value, inclusive/exclusive depends on flags
	entry *Block // entry block in the loop.
	flags indVarFlags
	// Invariant: for all blocks strictly dominated by entry:
	//	min <= ind <  max    [if flags == 0]
	//	min <  ind <  max    [if flags == indVarMinExc]
	//	min <= ind <= max    [if flags == indVarMaxInc]
	//	min <  ind <= max    [if flags == indVarMinExc|indVarMaxInc]
}

// parseIndVar checks whether the SSA value passed as argument is a valid induction
// variable, and, if so, extracts:
//   * the minimum bound
//   * the increment value
//   * the "next" value (SSA value that is Phi'd into the induction variable every loop)
// Currently, we detect induction variables that match (Phi min nxt),
// with nxt being (Add inc ind).
// If it can't parse the induction variable correctly, it returns (nil, nil, nil).
func parseIndVar(ind *Value) (min, inc, nxt *Value) {
	if ind.Op != OpPhi {
		return
	}

	if n := ind.Args[0]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
		min, nxt = ind.Args[1], n
	} else if n := ind.Args[1]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
		min, nxt = ind.Args[0], n
	} else {
		// Not a recognized induction variable.
		return
	}

	if nxt.Args[0] == ind { // nxt = ind + inc
		inc = nxt.Args[1]
	} else if nxt.Args[1] == ind { // nxt = inc + ind
		inc = nxt.Args[0]
	} else {
		panic("unreachable") // one of the cases must be true from the above.
	}

	return
}

// findIndVar finds induction variables in a function.
//
// Look for variables and blocks that satisfy the following
//
// loop:
//   ind = (Phi min nxt),
//   if ind < max
//     then goto enter_loop
//     else goto exit_loop
//
//   enter_loop:
//	do something
//      nxt = inc + ind
//	goto loop
//
// exit_loop:
//
//
// TODO: handle 32 bit operations
func findIndVar(f *Func) []indVar {
	var iv []indVar
	sdom := f.sdom()

	for _, b := range f.Blocks {
		if b.Kind != BlockIf || len(b.Preds) != 2 {
			continue
		}

		var flags indVarFlags
		var ind, max *Value // induction, and maximum

		// Check thet the control if it either ind </<= max or max >/>= ind.
		// TODO: Handle 32-bit comparisons.
		// TODO: Handle unsigned comparisons?
		switch b.Control.Op {
		case OpLeq64:
			flags |= indVarMaxInc
			fallthrough
		case OpLess64:
			ind, max = b.Control.Args[0], b.Control.Args[1]
		case OpGeq64:
			flags |= indVarMaxInc
			fallthrough
		case OpGreater64:
			ind, max = b.Control.Args[1], b.Control.Args[0]
		default:
			continue
		}

		// See if the arguments are reversed (i < len() <=> len() > i)
		less := true
		if max.Op == OpPhi {
			ind, max = max, ind
			less = false
		}

		// See if this is really an induction variable
		min, inc, nxt := parseIndVar(ind)
		if min == nil {
			continue
		}

		// Expect the increment to be a nonzero constant.
		if inc.Op != OpConst64 {
			continue
		}
		step := inc.AuxInt
		if step == 0 {
			continue
		}

		// Increment sign must match comparison direction.
		// When incrementing, the termination comparison must be ind </<= max.
		// When decrementing, the termination comparison must be ind >/>= max.
		// See issue 26116.
		if step > 0 && !less {
			continue
		}
		if step < 0 && less {
			continue
		}

		// If the increment is negative, swap min/max and their flags
		if step < 0 {
			min, max = max, min
			oldf := flags
			flags = indVarMaxInc
			if oldf&indVarMaxInc == 0 {
				flags |= indVarMinExc
			}
			step = -step
		}

		// Up to now we extracted the induction variable (ind),
		// the increment delta (inc), the temporary sum (nxt),
		// the mininum value (min) and the maximum value (max).
		//
		// We also know that ind has the form (Phi min nxt) where
		// nxt is (Add inc nxt) which means: 1) inc dominates nxt
		// and 2) there is a loop starting at inc and containing nxt.
		//
		// We need to prove that the induction variable is incremented
		// only when it's smaller than the maximum value.
		// Two conditions must happen listed below to accept ind
		// as an induction variable.

		// First condition: loop entry has a single predecessor, which
		// is the header block.  This implies that b.Succs[0] is
		// reached iff ind < max.
		if len(b.Succs[0].b.Preds) != 1 {
			// b.Succs[1] must exit the loop.
			continue
		}

		// Second condition: b.Succs[0] dominates nxt so that
		// nxt is computed when inc < max, meaning nxt <= max.
		if !sdom.isAncestorEq(b.Succs[0].b, nxt.Block) {
			// inc+ind can only be reached through the branch that enters the loop.
			continue
		}

		// We can only guarantee that the loop runs within limits of induction variable
		// if (one of)
		// (1) the increment is ±1
		// (2) the limits are constants
		// (3) loop is of the form k0 upto Known_not_negative-k inclusive, step <= k
		// (4) loop is of the form k0 upto Known_not_negative-k exclusive, step <= k+1
		// (5) loop is of the form Known_not_negative downto k0, minint+step < k0
		if step > 1 {
			ok := false
			if min.Op == OpConst64 && max.Op == OpConst64 {
				if max.AuxInt > min.AuxInt && max.AuxInt%step == min.AuxInt%step { // handle overflow
					ok = true
				}
			}
			// Handle induction variables of these forms.
			// KNN is known-not-negative.
			// SIGNED ARITHMETIC ONLY. (see switch on b.Control.Op above)
			// Possibilities for KNN are len and cap; perhaps we can infer others.
			// for i := 0; i <= KNN-k    ; i += k
			// for i := 0; i <  KNN-(k-1); i += k
			// Also handle decreasing.

			// "Proof" copied from https://go-review.googlesource.com/c/go/+/104041/10/src/cmd/compile/internal/ssa/loopbce.go#164
			//
			//	In the case of
			//	// PC is Positive Constant
			//	L := len(A)-PC
			//	for i := 0; i < L; i = i+PC
			//
			//	we know:
			//
			//	0 + PC does not over/underflow.
			//	len(A)-PC does not over/underflow
			//	maximum value for L is MaxInt-PC
			//	i < L <= MaxInt-PC means i + PC < MaxInt hence no overflow.

			// To match in SSA:
			// if  (a) min.Op == OpConst64(k0)
			// and (b) k0 >= MININT + step
			// and (c) max.Op == OpSubtract(Op{StringLen,SliceLen,SliceCap}, k)
			// or  (c) max.Op == OpAdd(Op{StringLen,SliceLen,SliceCap}, -k)
			// or  (c) max.Op == Op{StringLen,SliceLen,SliceCap}
			// and (d) if upto loop, require indVarMaxInc && step <= k or !indVarMaxInc && step-1 <= k

			if min.Op == OpConst64 && min.AuxInt >= step+math.MinInt64 {
				knn := max
				k := int64(0)
				var kArg *Value

				switch max.Op {
				case OpSub64:
					knn = max.Args[0]
					kArg = max.Args[1]

				case OpAdd64:
					knn = max.Args[0]
					kArg = max.Args[1]
					if knn.Op == OpConst64 {
						knn, kArg = kArg, knn
					}
				}
				switch knn.Op {
				case OpSliceLen, OpStringLen, OpSliceCap:
				default:
					knn = nil
				}

				if kArg != nil && kArg.Op == OpConst64 {
					k = kArg.AuxInt
					if max.Op == OpAdd64 {
						k = -k
					}
				}
				if k >= 0 && knn != nil {
					if inc.AuxInt > 0 { // increasing iteration
						// The concern for the relation between step and k is to ensure that iv never exceeds knn
						// i.e., iv < knn-(K-1) ==> iv + K <= knn; iv <= knn-K ==> iv +K < knn
						if step <= k || flags&indVarMaxInc == 0 && step-1 == k {
							ok = true
						}
					} else { // decreasing iteration
						// Will be decrementing from max towards min; max is knn-k; will only attempt decrement if
						// knn-k >[=] min; underflow is only a concern if min-step is not smaller than min.
						// This all assumes signed integer arithmetic
						// This is already assured by the test above: min.AuxInt >= step+math.MinInt64
						ok = true
					}
				}
			}

			// TODO: other unrolling idioms
			// for i := 0; i < KNN - KNN % k ; i += k
			// for i := 0; i < KNN&^(k-1) ; i += k // k a power of 2
			// for i := 0; i < KNN&(-k) ; i += k // k a power of 2

			if !ok {
				continue
			}
		}

		if f.pass.debug >= 1 {
			printIndVar(b, ind, min, max, step, flags)
		}

		iv = append(iv, indVar{
			ind:   ind,
			min:   min,
			max:   max,
			entry: b.Succs[0].b,
			flags: flags,
		})
		b.Logf("found induction variable %v (inc = %v, min = %v, max = %v)\n", ind, inc, min, max)
	}

	return iv
}

func dropAdd64(v *Value) (*Value, int64) {
	if v.Op == OpAdd64 && v.Args[0].Op == OpConst64 {
		return v.Args[1], v.Args[0].AuxInt
	}
	if v.Op == OpAdd64 && v.Args[1].Op == OpConst64 {
		return v.Args[0], v.Args[1].AuxInt
	}
	return v, 0
}

func printIndVar(b *Block, i, min, max *Value, inc int64, flags indVarFlags) {
	mb1, mb2 := "[", "]"
	if flags&indVarMinExc != 0 {
		mb1 = "("
	}
	if flags&indVarMaxInc == 0 {
		mb2 = ")"
	}

	mlim1, mlim2 := fmt.Sprint(min.AuxInt), fmt.Sprint(max.AuxInt)
	if !min.isGenericIntConst() {
		if b.Func.pass.debug >= 2 {
			mlim1 = fmt.Sprint(min)
		} else {
			mlim1 = "?"
		}
	}
	if !max.isGenericIntConst() {
		if b.Func.pass.debug >= 2 {
			mlim2 = fmt.Sprint(max)
		} else {
			mlim2 = "?"
		}
	}
	extra := ""
	if b.Func.pass.debug >= 2 {
		extra = fmt.Sprintf(" (%s)", i)
	}
	b.Func.Warnl(b.Pos, "Induction variable: limits %v%v,%v%v, increment %d%s", mb1, mlim1, mlim2, mb2, inc, extra)
}
<|endoftext|>


<commit_before>package engine

import (
	"reflect"
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase_1 "github.com/keybase/client/protocol/go"
)

func runIdentify(username string) (idUI *FakeIdentifyUI, res *IdRes, err error) {
	idUI = &FakeIdentifyUI{}
	arg := IdEngineArg{
		UserAssertion: username,
	}
	ctx := Context{
		LogUI:      G.UI.GetLogUI(),
		IdentifyUI: idUI,
	}
	eng := NewIdEngine(&arg)
	err = RunEngine(eng, &ctx)
	res = eng.Result()
	return
}

func checkAliceProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "alice", true, map[string]string{
		"github":  "kbtester2",
		"twitter": "tacovontaco",
	})
}

func checkBobProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "bob", true, map[string]string{
		"github":  "kbtester1",
		"twitter": "kbtester1",
	})
}

func checkCharlieProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "charlie", true, map[string]string{
		"github":  "tacoplusplus",
		"twitter": "tacovontaco",
	})
}

func checkDougProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "doug", false, nil)
}

func checkKeyedProfile(t *testing.T, idUI *FakeIdentifyUI, result *IdRes, name string, hasImg bool, expectedProofs map[string]string) {
	if exported := result.User.Export(); !reflect.DeepEqual(idUI.User, exported) {
		t.Fatal("LaunchNetworkChecks User not equal to result user.", idUI.User, exported)
	}

	if hasImg && result.User.Image == nil {
		t.Logf("result user: %+v", result.User)
		t.Fatalf("%s: Missing user image.", name)
	} else if !hasImg && result.User.Image != nil {
		t.Fatalf("%s: User has an image but shouldn't", name)
	}

	if !reflect.DeepEqual(expectedProofs, idUI.Proofs) {
		t.Fatal("Wrong proofs.", expectedProofs, idUI.Proofs)
	}
}

func checkDisplayKeys(t *testing.T, idUI *FakeIdentifyUI, callCount, keyCount int) {
	if idUI.DisplayKeyCalls != callCount {
		t.Errorf("DisplayKey calls: %d.  expected %d.", idUI.DisplayKeyCalls, callCount)
	}

	if len(idUI.Keys) != keyCount {
		t.Errorf("keys: %d, expected %d.", len(idUI.Keys), keyCount)
		for k, v := range idUI.Keys {
			t.Logf("key: %+v, %+v", k, v)
		}
	}

	for k := range idUI.Keys {
		if k.PgpFingerprint == nil {
			t.Errorf("key %v: not pgp.  only pgp keys should be displayed.", k)
		}
	}
}

func TestIdAlice(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_alice")
	if err != nil {
		t.Fatal(err)
	}
	checkAliceProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdBob(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_bob")
	if err != nil {
		t.Fatal(err)
	}
	checkBobProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdCharlie(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_charlie")
	if err != nil {
		t.Fatal(err)
	}
	checkCharlieProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdDoug(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_doug")
	if err != nil {
		t.Fatal(err)
	}
	checkDougProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdEllen(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, _, err := runIdentify("t_ellen")
	if err == nil {
		t.Fatal("Expected no public key found error.")
	} else if _, ok := err.(libkb.NoKeyError); !ok {
		t.Fatal("Expected no public key found error. Got instead:", err)
	}
	checkDisplayKeys(t, idUI, 0, 0)
}

// TestIdPGPNotEldest creates a user with a pgp key that isn't
// eldest key, then runs identify to make sure the pgp key is
// still displayed.
func TestIdPGPNotEldest(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()

	// create new user, then add pgp key
	u := CreateAndSignupFakeUser(t, "login")
	secui := libkb.TestSecretUI{Passphrase: u.Passphrase}
	ctx := &Context{LogUI: G.UI.GetLogUI(), SecretUI: secui}
	_, key := armorKey(t, tc, u.Email)
	eng, err := NewPGPKeyImportEngineFromBytes([]byte(key), true, G)
	if err != nil {
		t.Fatal(err)
	}
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}

	G.Logout()

	idUI, _, err := runIdentify(u.Username)
	if err != nil {
		t.Fatal(err)
	}

	checkDisplayKeys(t, idUI, 1, 1)
}

type FakeIdentifyUI struct {
	Proofs          map[string]string
	User            *keybase_1.User
	Fapr            keybase_1.FinishAndPromptRes
	Keys            map[keybase_1.FOKID]*keybase_1.TrackDiff
	DisplayKeyCalls int
}

func (ui *FakeIdentifyUI) FinishWebProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	if ui.Proofs == nil {
		ui.Proofs = make(map[string]string)
	}
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishSocialProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	if ui.Proofs == nil {
		ui.Proofs = make(map[string]string)
	}
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishAndPrompt(*keybase_1.IdentifyOutcome) (res keybase_1.FinishAndPromptRes, err error) {
	res = ui.Fapr
	return
}
func (ui *FakeIdentifyUI) DisplayCryptocurrency(keybase_1.Cryptocurrency) {
}
func (ui *FakeIdentifyUI) DisplayKey(kid keybase_1.FOKID, td *keybase_1.TrackDiff) {
	if ui.Keys == nil {
		ui.Keys = make(map[keybase_1.FOKID]*keybase_1.TrackDiff)
	}
	ui.Keys[kid] = td
	ui.DisplayKeyCalls++
}
func (ui *FakeIdentifyUI) ReportLastTrack(*keybase_1.TrackSummary) {
}
func (ui *FakeIdentifyUI) Start(username string) {
}
func (ui *FakeIdentifyUI) LaunchNetworkChecks(id *keybase_1.Identity, user *keybase_1.User) {
	ui.User = user
}
func (ui *FakeIdentifyUI) DisplayTrackStatement(string) (err error) {
	return
}
func (ui *FakeIdentifyUI) SetStrict(b bool) {
}
<commit_msg>fixed build<commit_after>package engine

import (
	"reflect"
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase_1 "github.com/keybase/client/protocol/go"
)

func runIdentify(username string) (idUI *FakeIdentifyUI, res *IdRes, err error) {
	idUI = &FakeIdentifyUI{}
	arg := IdEngineArg{
		UserAssertion: username,
	}
	ctx := Context{
		LogUI:      G.UI.GetLogUI(),
		IdentifyUI: idUI,
	}
	eng := NewIdEngine(&arg)
	err = RunEngine(eng, &ctx)
	res = eng.Result()
	return
}

func checkAliceProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "alice", true, map[string]string{
		"github":  "kbtester2",
		"twitter": "tacovontaco",
	})
}

func checkBobProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "bob", true, map[string]string{
		"github":  "kbtester1",
		"twitter": "kbtester1",
	})
}

func checkCharlieProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "charlie", true, map[string]string{
		"github":  "tacoplusplus",
		"twitter": "tacovontaco",
	})
}

func checkDougProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdRes) {
	checkKeyedProfile(t, idUI, res, "doug", false, nil)
}

func checkKeyedProfile(t *testing.T, idUI *FakeIdentifyUI, result *IdRes, name string, hasImg bool, expectedProofs map[string]string) {
	if exported := result.User.Export(); !reflect.DeepEqual(idUI.User, exported) {
		t.Fatal("LaunchNetworkChecks User not equal to result user.", idUI.User, exported)
	}

	if hasImg && result.User.Image == nil {
		t.Logf("result user: %+v", result.User)
		t.Fatalf("%s: Missing user image.", name)
	} else if !hasImg && result.User.Image != nil {
		t.Fatalf("%s: User has an image but shouldn't", name)
	}

	if !reflect.DeepEqual(expectedProofs, idUI.Proofs) {
		t.Fatal("Wrong proofs.", expectedProofs, idUI.Proofs)
	}
}

func checkDisplayKeys(t *testing.T, idUI *FakeIdentifyUI, callCount, keyCount int) {
	if idUI.DisplayKeyCalls != callCount {
		t.Errorf("DisplayKey calls: %d.  expected %d.", idUI.DisplayKeyCalls, callCount)
	}

	if len(idUI.Keys) != keyCount {
		t.Errorf("keys: %d, expected %d.", len(idUI.Keys), keyCount)
		for k, v := range idUI.Keys {
			t.Logf("key: %+v, %+v", k, v)
		}
	}

	for k := range idUI.Keys {
		if k.PgpFingerprint == nil {
			t.Errorf("key %v: not pgp.  only pgp keys should be displayed.", k)
		}
	}
}

func TestIdAlice(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_alice")
	if err != nil {
		t.Fatal(err)
	}
	checkAliceProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdBob(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_bob")
	if err != nil {
		t.Fatal(err)
	}
	checkBobProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdCharlie(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_charlie")
	if err != nil {
		t.Fatal(err)
	}
	checkCharlieProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdDoug(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_doug")
	if err != nil {
		t.Fatal(err)
	}
	checkDougProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdEllen(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, _, err := runIdentify("t_ellen")
	if err == nil {
		t.Fatal("Expected no public key found error.")
	} else if _, ok := err.(libkb.NoKeyError); !ok {
		t.Fatal("Expected no public key found error. Got instead:", err)
	}
	checkDisplayKeys(t, idUI, 0, 0)
}

// TestIdPGPNotEldest creates a user with a pgp key that isn't
// eldest key, then runs identify to make sure the pgp key is
// still displayed.
func TestIdPGPNotEldest(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()

	// create new user, then add pgp key
	u := CreateAndSignupFakeUser(t, "login")
	secui := libkb.TestSecretUI{Passphrase: u.Passphrase}
	ctx := &Context{LogUI: G.UI.GetLogUI(), SecretUI: secui}
	_, key := armorKey(t, tc, u.Email)
	eng, err := NewPGPKeyImportEngineFromBytes([]byte(key), true, G)
	if err != nil {
		t.Fatal(err)
	}
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}

	G.Logout()

	idUI, _, err := runIdentify(u.Username)
	if err != nil {
		t.Fatal(err)
	}

	checkDisplayKeys(t, idUI, 1, 1)
}

type FakeIdentifyUI struct {
	Proofs          map[string]string
	User            *keybase_1.User
	Fapr            keybase_1.FinishAndPromptRes
	Keys            map[keybase_1.FOKID]*keybase_1.TrackDiff
	DisplayKeyCalls int
}

func (ui *FakeIdentifyUI) FinishWebProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	if ui.Proofs == nil {
		ui.Proofs = make(map[string]string)
	}
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishSocialProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	if ui.Proofs == nil {
		ui.Proofs = make(map[string]string)
	}
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishAndPrompt(*keybase_1.IdentifyOutcome) (res keybase_1.FinishAndPromptRes, err error) {
	res = ui.Fapr
	return
}
func (ui *FakeIdentifyUI) DisplayCryptocurrency(keybase_1.Cryptocurrency) {
}
func (ui *FakeIdentifyUI) DisplayKey(kid keybase_1.FOKID, td *keybase_1.TrackDiff) {
	if ui.Keys == nil {
		ui.Keys = make(map[keybase_1.FOKID]*keybase_1.TrackDiff)
	}
	ui.Keys[kid] = td
	ui.DisplayKeyCalls++
}
func (ui *FakeIdentifyUI) ReportLastTrack(*keybase_1.TrackSummary) {
}
func (ui *FakeIdentifyUI) Start(username string) {
}
func (ui *FakeIdentifyUI) Finish() {}
func (ui *FakeIdentifyUI) LaunchNetworkChecks(id *keybase_1.Identity, user *keybase_1.User) {
	ui.User = user
}
func (ui *FakeIdentifyUI) DisplayTrackStatement(string) (err error) {
	return
}
func (ui *FakeIdentifyUI) SetStrict(b bool) {
}
<|endoftext|>


<commit_before>package gusher

import (
	"github.com/deckarep/golang-set"
	"gopkg.in/igm/sockjs-go.v2/sockjs"
	"gopkg.in/tomb.v2"
	"log"
	"sync"
)

type gsession struct {
	s       sockjs.Session //don't know how to compose this
	toSock  chan string
	toGush  chan string
	t       tomb.Tomb
	closed  bool       //makes me sad
	closedm sync.Mutex //makes me sad
	subbed  mapset.Set
}

func newSession(sockjsSession sockjs.Session, toGush chan string, toSock chan string) *gsession {
	gs := &gsession{
		s:      sockjsSession,
		toSock: toSock,
		toGush: toGush,
		closed: false,
		subbed: mapset.NewThreadUnsafeSet(),
	}
	gs.t.Go(gs.sender)
	gs.t.Go(gs.receiver)
	return gs
}

func (gs *gsession) close() error {
	gs.closedm.Lock()
	defer gs.closedm.Unlock()
	if !gs.closed {
		gs.closed = true
		log.Println("session closed")
		gs.s.Close(1, "arghhhh") //do something better than this
		gs.t.Kill(nil)
		close(gs.toGush)
	}
	return gs.t.Wait()
}

//writepump
func (gs *gsession) sender() error {
	defer func() {
		log.Println("sender exiting")
		gs.close()
	}()

	for {
		select {
		case msg := <-gs.toSock:
			if err := gs.s.Send(msg); err != nil {
				return err
			}
		case <-gs.t.Dying():
			return tomb.ErrDying
		}
	}
}

//readpump
func (gs *gsession) receiver() error {
	defer func() {
		log.Println("receiver exiting")
		gs.close()
	}()

	for {
		raw, err := gs.s.Recv()
		if err != nil {
			return err
		}
		select {
		case gs.toGush <- raw:
		case <-gs.t.Dying():
			return tomb.ErrDying
		}
	}
}

//type msg struct {
//	raw string
//	err error
//}
//
//func (gs *gsession) receiver2() <-chan *msg {
//	defer func() { log.Println("receiver exiting") }()
//	c := make(chan *msg)
//	gs.t.Go(func() error {
//		for {
//			if raw, err := gs.s.Recv(); err != nil {
//				c <- &msg{"", err}
//				return err
//			} else {
//				c <- &msg{raw, nil}
//			}
//		}
//	})
//	return c
//}
<commit_msg>remove old code<commit_after>package gusher

import (
	"github.com/deckarep/golang-set"
	"gopkg.in/igm/sockjs-go.v2/sockjs"
	"gopkg.in/tomb.v2"
	"log"
	"sync"
)

type gsession struct {
	s       sockjs.Session //don't know how to compose this
	toSock  chan string
	toGush  chan string
	t       tomb.Tomb
	closed  bool       //makes me sad
	closedm sync.Mutex //makes me sad
	subbed  mapset.Set
}

func newSession(sockjsSession sockjs.Session, toGush chan string, toSock chan string) *gsession {
	gs := &gsession{
		s:      sockjsSession,
		toSock: toSock,
		toGush: toGush,
		closed: false,
		subbed: mapset.NewThreadUnsafeSet(),
	}
	gs.t.Go(gs.sender)
	gs.t.Go(gs.receiver)
	return gs
}

func (gs *gsession) close() error {
	gs.closedm.Lock()
	defer gs.closedm.Unlock()
	if !gs.closed {
		gs.closed = true
		log.Println("session closed")
		gs.s.Close(1, "arghhhh") //do something better than this
		gs.t.Kill(nil)
		close(gs.toGush)
	}
	return gs.t.Wait()
}

//writepump
func (gs *gsession) sender() error {
	defer func() {
		log.Println("sender exiting")
		gs.close()
	}()

	for {
		select {
		case msg := <-gs.toSock:
			if err := gs.s.Send(msg); err != nil {
				return err
			}
		case <-gs.t.Dying():
			return tomb.ErrDying
		}
	}
}

//readpump
func (gs *gsession) receiver() error {
	defer func() {
		log.Println("receiver exiting")
		gs.close()
	}()

	for {
		raw, err := gs.s.Recv()
		if err != nil {
			return err
		}
		select {
		case gs.toGush <- raw:
		case <-gs.t.Dying():
			return tomb.ErrDying
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os/exec"
	"time"

	pbb "github.com/brotherlogic/buildserver/proto"
	pbfc "github.com/brotherlogic/filecopier/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
)

const (
	pendWait = time.Minute
)

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	startState := job.State
	switch job.State {
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("SCHED: %v @ %v", key, time.Now())
		s.stateMutex.Unlock()
		if !job.Job.Bootstrap {
			if key != "" {
				job.Server = s.Registry.Identifier
				job.State = pb.State_BUILT
				job.RunningVersion = key
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
			job.Server = s.Registry.Identifier
		}
	case pb.State_BUILDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILD(%v): %v", job.CommandKey, s.scheduler.getState(job.CommandKey))
		s.stateMutex.Unlock()
		if s.taskComplete(job.CommandKey) {
			job.State = pb.State_BUILT
		}
	case pb.State_BUILT:
		output, _ := s.scheduler.getOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILT(%v): (%v): %v", job.CommandKey, len(output), output)
		s.stateMutex.Unlock()
		if job.Job.Bootstrap && len(output) > 0 {
			if job.BuildFail == 5 {
				s.deliverCrashReport(ctx, job, output)
				job.BuildFail = 0
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.BuildFail = 0
			key := s.scheduleRun(job.Job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
			if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
				s.pendingMap[time.Now().Weekday()] = make(map[string]int)
			}
			s.pendingMap[time.Now().Weekday()][job.Job.Name]++
		}
	case pb.State_PENDING:
		s.stateMutex.Lock()
		out, _ := s.scheduler.getOutput(job.CommandKey)
		s.stateMap[job.Job.Name] = fmt.Sprintf("OUTPUT = %v", out)
		s.stateMutex.Unlock()
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			job.State = pb.State_RUNNING
		}
	case pb.State_RUNNING:
		output, errout := s.scheduler.getOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("ROUTPUT = %v, %v", output, s.scheduler.getStatus(job.CommandKey))
		job.Status = s.scheduler.getStatus(job.CommandKey)
		s.stateMutex.Unlock()
		if len(job.CommandKey) > 0 && s.taskComplete(job.CommandKey) {
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("COMPLETE = (%v, %v)", job, output)
			s.stateMutex.Unlock()
			s.deliverCrashReport(ctx, job, "CRASH: "+output+fmt.Sprintf("%v", errout))
			job.State = pb.State_DIED
		}

		err := s.discover.discover(job.Job.Name, s.Registry.Identifier)
		if err != nil {
			if job.DiscoverCount > 30 {
				output2, errout2 := s.scheduler.getErrOutput(job.CommandKey)
				s.RaiseIssue(ctx, "Cannot Discover Running Server", fmt.Sprintf("%v on %v is not discoverable, despite running (%v) the output says %v (%v), %v, %v", job.Job.Name, s.Registry.Identifier, err, output, errout, output2, errout2), false)
			}
			job.DiscoverCount++
		} else {
			job.DiscoverCount = 0
		}

		// Restart this job if we need to
		if !job.Job.Bootstrap {
			if time.Now().Sub(time.Unix(job.LastVersionPull, 0)) > time.Minute*5 {
				version, err := s.getVersion(ctx, job.Job)
				job.LastVersionPull = time.Now().Unix()

				if err == nil && version.Version != job.RunningVersion {
					s.stateMutex.Lock()
					s.stateMap[job.Job.Name] = fmt.Sprintf("VERSION_MISMATCH = %v,%v", version, job.RunningVersion)
					s.stateMutex.Unlock()
					s.scheduler.killJob(job.CommandKey)
				}
			}
		}
	case pb.State_BRINK_OF_DEATH:
		if s.version.confirm(ctx, job.Job.Name) {
			s.scheduler.killJob(job.CommandKey)
			job.State = pb.State_ACKNOWLEDGED
		}
	case pb.State_DIED:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("DIED %v", job.CommandKey)
		s.stateMutex.Unlock()
		s.scheduler.removeJob(job.CommandKey)
		job.State = pb.State_ACKNOWLEDGED
	}

	if job.State != startState {
		job.LastTransitionTime = time.Now().Unix()
	}
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) (*pbb.Version, error) {
	versions, err := s.builder.build(ctx, job)
	if err != nil {
		return &pbb.Version{}, err
	}

	if len(versions) == 0 {
		return &pbb.Version{}, nil
	}

	return versions[0], nil

}

func updateJob(err error, job *pb.JobAssignment, resp *pbfc.CopyResponse) {
	if err == nil {
		job.QueuePos = resp.IndexInQueue
	}

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.JobAssignment) string {
	if job.Job.Bootstrap {
		c := s.translator.build(job.Job)
		return s.scheduler.Schedule(&rCommand{command: c, base: job.Job.Name})
	}

	versions, err := s.builder.build(ctx, job.Job)

	s.lastCopyStatus = fmt.Sprintf("%v", err)
	if len(versions) == 0 {
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("No Versions: %v", err)
		s.stateMutex.Unlock()
		return ""
	}

	t := time.Now()

	//Only copy if the latest version is different to the local version
	s.versionsMutex.Lock()
	v, ok := s.versions[job.Job.Name]
	s.versionsMutex.Unlock()
	if !ok || v.Version != versions[0].Version {
		s.copies++

		resp, err := s.builder.copy(ctx, versions[0])
		s.lastCopyTime = time.Now().Sub(t)
		s.lastCopyStatus = fmt.Sprintf("%v", err)
		if err != nil || resp.Status != pbfc.CopyStatus_COMPLETE || len(resp.Error) > 0 {
			updateJob(err, job, resp)
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("Copy fail (%v) -> %v", time.Now().Sub(t), err)
			s.stateMutex.Unlock()
			return ""
		}
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("Copied version %v", versions[0].Version)
		s.stateMutex.Unlock()

		//Save the version file alongside the binary
		data, _ := proto.Marshal(versions[0])
		ioutil.WriteFile("/home/simon/gobuild/bin/"+job.Job.Name+".version", data, 0644)
	} else {
		s.skippedCopies++
	}

	s.versionsMutex.Lock()
	s.versions[job.Job.Name] = versions[0]
	s.versionsMutex.Unlock()
	return versions[0].Version
}

func (s *Server) scheduleRun(job *pb.Job) string {
	c := s.translator.run(job)
	return s.scheduler.Schedule(&rCommand{command: c, base: job.Name})
}

func (s *Server) taskComplete(key string) bool {
	return s.scheduler.schedulerComplete(key)
}
<commit_msg>Fix for crashes<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os/exec"
	"time"

	pbb "github.com/brotherlogic/buildserver/proto"
	pbfc "github.com/brotherlogic/filecopier/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
)

const (
	pendWait = time.Minute
)

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	startState := job.State
	switch job.State {
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("SCHED: %v @ %v", key, time.Now())
		s.stateMutex.Unlock()
		if !job.Job.Bootstrap {
			if key != "" {
				job.Server = s.Registry.Identifier
				job.State = pb.State_BUILT
				job.RunningVersion = key
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
			job.Server = s.Registry.Identifier
		}
	case pb.State_BUILDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILD(%v): %v", job.CommandKey, s.scheduler.getState(job.CommandKey))
		s.stateMutex.Unlock()
		if s.taskComplete(job.CommandKey) {
			job.State = pb.State_BUILT
		}
	case pb.State_BUILT:
		output, _ := s.scheduler.getOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILT(%v): (%v): %v", job.CommandKey, len(output), output)
		s.stateMutex.Unlock()
		if job.Job.Bootstrap && len(output) > 0 {
			if job.BuildFail == 5 {
				s.deliverCrashReport(ctx, job, output)
				job.BuildFail = 0
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.BuildFail = 0
			key := s.scheduleRun(job.Job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
			if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
				s.pendingMap[time.Now().Weekday()] = make(map[string]int)
			}
			s.pendingMap[time.Now().Weekday()][job.Job.Name]++
		}
	case pb.State_PENDING:
		s.stateMutex.Lock()
		out, _ := s.scheduler.getOutput(job.CommandKey)
		s.stateMap[job.Job.Name] = fmt.Sprintf("OUTPUT = %v", out)
		s.stateMutex.Unlock()
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			job.State = pb.State_RUNNING
		}
	case pb.State_RUNNING:
		output, errout := s.scheduler.getOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("ROUTPUT = %v, %v", output, s.scheduler.getStatus(job.CommandKey))
		job.Status = s.scheduler.getStatus(job.CommandKey)
		s.stateMutex.Unlock()
		if len(job.CommandKey) > 0 && s.taskComplete(job.CommandKey) {
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("COMPLETE = (%v, %v)", job, output)
			s.stateMutex.Unlock()
			s.deliverCrashReport(ctx, job, output)
			job.State = pb.State_DIED
		}

		err := s.discover.discover(job.Job.Name, s.Registry.Identifier)
		if err != nil {
			if job.DiscoverCount > 30 {
				output2, errout2 := s.scheduler.getErrOutput(job.CommandKey)
				s.RaiseIssue(ctx, "Cannot Discover Running Server", fmt.Sprintf("%v on %v is not discoverable, despite running (%v) the output says %v (%v), %v, %v", job.Job.Name, s.Registry.Identifier, err, output, errout, output2, errout2), false)
			}
			job.DiscoverCount++
		} else {
			job.DiscoverCount = 0
		}

		// Restart this job if we need to
		if !job.Job.Bootstrap {
			if time.Now().Sub(time.Unix(job.LastVersionPull, 0)) > time.Minute*5 {
				version, err := s.getVersion(ctx, job.Job)
				job.LastVersionPull = time.Now().Unix()

				if err == nil && version.Version != job.RunningVersion {
					s.stateMutex.Lock()
					s.stateMap[job.Job.Name] = fmt.Sprintf("VERSION_MISMATCH = %v,%v", version, job.RunningVersion)
					s.stateMutex.Unlock()
					s.scheduler.killJob(job.CommandKey)
				}
			}
		}
	case pb.State_BRINK_OF_DEATH:
		if s.version.confirm(ctx, job.Job.Name) {
			s.scheduler.killJob(job.CommandKey)
			job.State = pb.State_ACKNOWLEDGED
		}
	case pb.State_DIED:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("DIED %v", job.CommandKey)
		s.stateMutex.Unlock()
		s.scheduler.removeJob(job.CommandKey)
		job.State = pb.State_ACKNOWLEDGED
	}

	if job.State != startState {
		job.LastTransitionTime = time.Now().Unix()
	}
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) (*pbb.Version, error) {
	versions, err := s.builder.build(ctx, job)
	if err != nil {
		return &pbb.Version{}, err
	}

	if len(versions) == 0 {
		return &pbb.Version{}, nil
	}

	return versions[0], nil

}

func updateJob(err error, job *pb.JobAssignment, resp *pbfc.CopyResponse) {
	if err == nil {
		job.QueuePos = resp.IndexInQueue
	}

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.JobAssignment) string {
	if job.Job.Bootstrap {
		c := s.translator.build(job.Job)
		return s.scheduler.Schedule(&rCommand{command: c, base: job.Job.Name})
	}

	versions, err := s.builder.build(ctx, job.Job)

	s.lastCopyStatus = fmt.Sprintf("%v", err)
	if len(versions) == 0 {
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("No Versions: %v", err)
		s.stateMutex.Unlock()
		return ""
	}

	t := time.Now()

	//Only copy if the latest version is different to the local version
	s.versionsMutex.Lock()
	v, ok := s.versions[job.Job.Name]
	s.versionsMutex.Unlock()
	if !ok || v.Version != versions[0].Version {
		s.copies++

		resp, err := s.builder.copy(ctx, versions[0])
		s.lastCopyTime = time.Now().Sub(t)
		s.lastCopyStatus = fmt.Sprintf("%v", err)
		if err != nil || resp.Status != pbfc.CopyStatus_COMPLETE || len(resp.Error) > 0 {
			updateJob(err, job, resp)
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("Copy fail (%v) -> %v", time.Now().Sub(t), err)
			s.stateMutex.Unlock()
			return ""
		}
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("Copied version %v", versions[0].Version)
		s.stateMutex.Unlock()

		//Save the version file alongside the binary
		data, _ := proto.Marshal(versions[0])
		ioutil.WriteFile("/home/simon/gobuild/bin/"+job.Job.Name+".version", data, 0644)
	} else {
		s.skippedCopies++
	}

	s.versionsMutex.Lock()
	s.versions[job.Job.Name] = versions[0]
	s.versionsMutex.Unlock()
	return versions[0].Version
}

func (s *Server) scheduleRun(job *pb.Job) string {
	c := s.translator.run(job)
	return s.scheduler.Schedule(&rCommand{command: c, base: job.Name})
}

func (s *Server) taskComplete(key string) bool {
	return s.scheduler.schedulerComplete(key)
}
<|endoftext|>


<commit_before>// Package goinline implements inlining for go identifiers.
package goinline

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"reflect"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

// Inline replaces each instance of identifier k with v.Ident in ast.File f,
// for k, v := range m.
// For all inlines that were triggeres it also adds imports from v.Imports to f.
// In addition, it removes top level type declarations of the form
// type k ...
// for all k in m.
//
// Every k in m should be a valid identifier.
// Every v.Ident should be a valid expression.
func Inline(fset *token.FileSet, f *ast.File, m map[string]Target) error {
	// Build the inline map.
	im := map[string]reflect.Value{}
	for k, v := range m {
		expr, err := parser.ParseExpr(k)
		if err != nil {
			return fmt.Errorf("failed to parse `%s`: %s", k, err)
		}
		if _, ok := expr.(*ast.Ident); !ok {
			return fmt.Errorf("expected identifier, got %s which is %T", k, expr)
		}
		expr, err = parser.ParseExpr(v.Ident)
		if err != nil {
			return fmt.Errorf("failed to parse `%s`: %s", v.Ident, err)
		}
		s := v.Ident
		if _, ok := expr.(*ast.StarExpr); ok {
			s = fmt.Sprintf("(%s)", s)
		}
		im[k] = reflect.ValueOf(ast.Ident{Name: s})
	}
	// Filter `type XXX ...` declarations out if we are inlining XXX.
	cmap := ast.NewCommentMap(fset, f, f.Comments)
	to := 0
	for _, d := range f.Decls {
		skip := false
		if t, ok := d.(*ast.GenDecl); ok {
			for _, s := range t.Specs {
				ts, ok := s.(*ast.TypeSpec)
				if !ok {
					continue
				}
				if t, ok := m[ts.Name.String()]; ok {
					if !t.NoFiltering {
						skip = true
					}
				}
			}
		}
		if !skip {
			f.Decls[to] = d
			to++
		}
	}
	if to != len(f.Decls) {
		f.Decls = f.Decls[:to]
		// Remove comments for the declarations that were filtered out.
		f.Comments = cmap.Filter(f).Comments()
	}
	// Add imports for the inlines that were triggered.
	for k := range inline(im, f) {
		for _, imp := range m[k].Imports {
			astutil.AddImport(fset, f, imp)
		}
	}
	return nil
}

// Target for inlining.
type Target struct {
	// Ident is a go identifier for the target.
	Ident string
	// Imports are the imporst to be added if the inline is triggered.
	Imports []string
	// NoFiltering prevents removing type Ident when inlining.
	NoFiltering bool
}

// ParseTarget parses a target string.
// Expected format:
// xxx->[import1,import2,...importn::]yyy
// Examples:
// Value->int
// X->go/topen::*token.FileSet
func ParseTarget(s string) (string, Target, error) {
	ps := strings.Split(s, "->")
	if len(ps) != 2 {
		return "", Target{}, fmt.Errorf("expected xxx->yyy, got `%s`", s)
	}
	name := ps[0]
	parts := strings.Split(ps[1], "::")
	if len(parts) > 2 {
		return "", Target{}, fmt.Errorf("expected something like a,b,c::v , got `%s`", ps[1])
	}
	if len(parts) == 1 {
		return name, Target{Ident: parts[0]}, nil
	}
	return name, Target{Ident: parts[1], Imports: strings.Split(parts[0], ",")}, nil
}

func inline(im map[string]reflect.Value, node ast.Node) map[string]bool {
	i := inliner{im: im, triggered: map[string]bool{}}
	ast.Walk(i, node)
	return i.triggered
}

type inliner struct {
	im        map[string]reflect.Value
	triggered map[string]bool
}

func (x inliner) Visit(node ast.Node) ast.Visitor {
	switch t := node.(type) {
	case *ast.Ident:
		v, ok := x.im[t.Name]
		if !ok {
			break
		}
		x.triggered[t.Name] = true
		reflect.ValueOf(t).Elem().Set(v)
	}
	return x
}
<commit_msg>comment typo<commit_after>// Package goinline implements inlining for go identifiers.
package goinline

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"reflect"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

// Inline replaces each instance of identifier k with v.Ident in ast.File f,
// for k, v := range m.
// For all inlines that were triggeres it also adds imports from v.Imports to f.
// In addition, it removes top level type declarations of the form
// type k ...
// for all k in m.
//
// Every k in m should be a valid identifier.
// Every v.Ident should be a valid expression.
func Inline(fset *token.FileSet, f *ast.File, m map[string]Target) error {
	// Build the inline map.
	im := map[string]reflect.Value{}
	for k, v := range m {
		expr, err := parser.ParseExpr(k)
		if err != nil {
			return fmt.Errorf("failed to parse `%s`: %s", k, err)
		}
		if _, ok := expr.(*ast.Ident); !ok {
			return fmt.Errorf("expected identifier, got %s which is %T", k, expr)
		}
		expr, err = parser.ParseExpr(v.Ident)
		if err != nil {
			return fmt.Errorf("failed to parse `%s`: %s", v.Ident, err)
		}
		s := v.Ident
		if _, ok := expr.(*ast.StarExpr); ok {
			s = fmt.Sprintf("(%s)", s)
		}
		im[k] = reflect.ValueOf(ast.Ident{Name: s})
	}
	// Filter `type XXX ...` declarations out if we are inlining XXX.
	cmap := ast.NewCommentMap(fset, f, f.Comments)
	to := 0
	for _, d := range f.Decls {
		skip := false
		if t, ok := d.(*ast.GenDecl); ok {
			for _, s := range t.Specs {
				ts, ok := s.(*ast.TypeSpec)
				if !ok {
					continue
				}
				if t, ok := m[ts.Name.String()]; ok {
					if !t.NoFiltering {
						skip = true
					}
				}
			}
		}
		if !skip {
			f.Decls[to] = d
			to++
		}
	}
	if to != len(f.Decls) {
		f.Decls = f.Decls[:to]
		// Remove comments for the declarations that were filtered out.
		f.Comments = cmap.Filter(f).Comments()
	}
	// Add imports for the inlines that were triggered.
	for k := range inline(im, f) {
		for _, imp := range m[k].Imports {
			astutil.AddImport(fset, f, imp)
		}
	}
	return nil
}

// Target for inlining.
type Target struct {
	// Ident is a go identifier for the target.
	Ident string
	// Imports are the imporst to be added if the inline is triggered.
	Imports []string
	// NoFiltering prevents removing type Ident when inlining.
	NoFiltering bool
}

// ParseTarget parses a target string.
// Expected format:
// xxx->[import1,import2,...importn::]yyy
// Examples:
// Value->int
// X->go/token::*token.FileSet
func ParseTarget(s string) (string, Target, error) {
	ps := strings.Split(s, "->")
	if len(ps) != 2 {
		return "", Target{}, fmt.Errorf("expected xxx->yyy, got `%s`", s)
	}
	name := ps[0]
	parts := strings.Split(ps[1], "::")
	if len(parts) > 2 {
		return "", Target{}, fmt.Errorf("expected something like a,b,c::v , got `%s`", ps[1])
	}
	if len(parts) == 1 {
		return name, Target{Ident: parts[0]}, nil
	}
	return name, Target{Ident: parts[1], Imports: strings.Split(parts[0], ",")}, nil
}

func inline(im map[string]reflect.Value, node ast.Node) map[string]bool {
	i := inliner{im: im, triggered: map[string]bool{}}
	ast.Walk(i, node)
	return i.triggered
}

type inliner struct {
	im        map[string]reflect.Value
	triggered map[string]bool
}

func (x inliner) Visit(node ast.Node) ast.Visitor {
	switch t := node.(type) {
	case *ast.Ident:
		v, ok := x.im[t.Name]
		if !ok {
			break
		}
		x.triggered[t.Name] = true
		reflect.ValueOf(t).Elem().Set(v)
	}
	return x
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 gcscaching_test

import (
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcscaching"
	"github.com/jacobsa/gcloud/gcs/gcsfake"
	"github.com/jacobsa/gcloud/gcs/gcsutil"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestIntegration(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type IntegrationTest struct {
	cache   gcscaching.StatCache
	clock   timeutil.SimulatedClock
	wrapped gcs.Bucket

	bucket gcs.Bucket
}

func init() { RegisterTestSuite(&IntegrationTest{}) }

func (t *IntegrationTest) SetUp(ti *TestInfo) {
	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))

	// Set up dependencies.
	const cacheCapacity = 100
	t.cache = gcscaching.NewStatCache(cacheCapacity)
	t.wrapped = gcsfake.NewFakeBucket(&t.clock, "some_bucket")

	t.bucket = gcscaching.NewFastStatBucket(
		ttl,
		t.cache,
		&t.clock,
		t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *IntegrationTest) StatDoesntCacheNotFoundErrors() {
	const name = "taco"
	var err error

	// Stat an unknown object.
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, err = t.bucket.StatObject(context.Background(), req)
	AssertThat(err, HasSameTypeAs(&gcs.NotFoundError{}))

	// Create the object through the back door.
	_, err = gcsutil.CreateObject(context.Background(), t.wrapped, name, "")
	AssertEq(nil, err)

	// Stat again. We should now see the object.
	o, err := t.bucket.StatObject(context.Background(), req)
	AssertEq(nil, err)
	ExpectNe(nil, o)
}

func (t *IntegrationTest) CreateInsertsIntoCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) StatInsertsIntoCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) ListInsertsIntoCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) UpdateUpdatesCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) DeleteRemovesFromCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) Expiration() {
	AssertFalse(true, "TODO")
}
<commit_msg>Defined a stat helper.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 gcscaching_test

import (
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcscaching"
	"github.com/jacobsa/gcloud/gcs/gcsfake"
	"github.com/jacobsa/gcloud/gcs/gcsutil"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestIntegration(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type IntegrationTest struct {
	cache   gcscaching.StatCache
	clock   timeutil.SimulatedClock
	wrapped gcs.Bucket

	bucket gcs.Bucket
}

func init() { RegisterTestSuite(&IntegrationTest{}) }

func (t *IntegrationTest) SetUp(ti *TestInfo) {
	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))

	// Set up dependencies.
	const cacheCapacity = 100
	t.cache = gcscaching.NewStatCache(cacheCapacity)
	t.wrapped = gcsfake.NewFakeBucket(&t.clock, "some_bucket")

	t.bucket = gcscaching.NewFastStatBucket(
		ttl,
		t.cache,
		&t.clock,
		t.wrapped)
}

func (t *IntegrationTest) stat(name string) (o *gcs.Object, err error) {
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err = t.bucket.StatObject(context.Background(), req)
	return
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *IntegrationTest) StatDoesntCacheNotFoundErrors() {
	const name = "taco"
	var err error

	// Stat an unknown object.
	_, err = t.stat(name)
	AssertThat(err, HasSameTypeAs(&gcs.NotFoundError{}))

	// Create the object through the back door.
	_, err = gcsutil.CreateObject(context.Background(), t.wrapped, name, "")
	AssertEq(nil, err)

	// Stat again. We should now see the object.
	o, err := t.stat(name)
	AssertEq(nil, err)
	ExpectNe(nil, o)
}

func (t *IntegrationTest) CreateInsertsIntoCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) StatInsertsIntoCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) ListInsertsIntoCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) UpdateUpdatesCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) DeleteRemovesFromCache() {
	AssertFalse(true, "TODO")
}

func (t *IntegrationTest) Expiration() {
	AssertFalse(true, "TODO")
}
<|endoftext|>