<commit_before>// Package spipe handles establishing secure communication between two peers.

package spipe

import (
	"bytes"
	"errors"
	"fmt"
	"strings"

	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"hash"

	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	ci "github.com/jbenet/go-ipfs/crypto"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

// List of supported ECDH curves
var SupportedExchanges = "P-256,P-224,P-384,P-521"

// List of supported Ciphers
var SupportedCiphers = "AES-256,AES-128"

// List of supported Hashes
var SupportedHashes = "SHA256,SHA512,SHA1"

// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
var ErrUnsupportedKeyType = errors.New("unsupported key type")

// ErrClosed signals the closing of a connection.
var ErrClosed = errors.New("connection closed")

// handsahke performs initial communication over insecure channel to share
// keys, IDs, and initiate communication.
func (s *SecurePipe) handshake() error {
	// Generate and send Hello packet.
	// Hello = (rand, PublicKey, Supported)
	nonce := make([]byte, 16)
	_, err := rand.Read(nonce)
	if err != nil {
		return err
	}

	// u.DOut("handshake: %s <--> %s\n", s.local.ID.Pretty(), s.remote.ID.Pretty())
	myPubKey, err := s.local.PubKey.Bytes()
	if err != nil {
		return err
	}

	proposeMsg := new(Propose)
	proposeMsg.Rand = nonce
	proposeMsg.Pubkey = myPubKey
	proposeMsg.Exchanges = &SupportedExchanges
	proposeMsg.Ciphers = &SupportedCiphers
	proposeMsg.Hashes = &SupportedHashes

	encoded, err := proto.Marshal(proposeMsg)
	if err != nil {
		return err
	}

	// Send our Propose packet
	select {
	case s.insecure.Out <- encoded:
	case <-s.ctx.Done():
		return ErrClosed
	}

	// Parse their Propose packet and generate an Exchange packet.
	// Exchange = (EphemeralPubKey, Signature)
	var resp []byte
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case resp = <-s.insecure.In:
	}

	// u.POut("received encoded handshake\n")
	proposeResp := new(Propose)
	err = proto.Unmarshal(resp, proposeResp)
	if err != nil {
		return err
	}

	// get remote identity
	remotePubKey, err := ci.UnmarshalPublicKey(proposeResp.GetPubkey())
	if err != nil {
		return err
	}

	// get or construct peer
	s.remote, err = getOrConstructPeer(s.peers, remotePubKey)
	if err != nil {
		return err
	}
	u.DOut("[%s] Remote Peer Identified as %s\n", s.local.ID.Pretty(), s.remote.ID.Pretty())

	exchange, err := selectBest(SupportedExchanges, proposeResp.GetExchanges())
	if err != nil {
		return err
	}

	cipherType, err := selectBest(SupportedCiphers, proposeResp.GetCiphers())
	if err != nil {
		return err
	}

	hashType, err := selectBest(SupportedHashes, proposeResp.GetHashes())
	if err != nil {
		return err
	}

	// u.POut("Selected %s %s %s\n", exchange, cipherType, hashType)
	epubkey, done, err := ci.GenerateEKeyPair(exchange) // Generate EphemeralPubKey

	var handshake bytes.Buffer // Gather corpus to sign.
	handshake.Write(encoded)
	handshake.Write(resp)
	handshake.Write(epubkey)

	exPacket := new(Exchange)

	exPacket.Epubkey = epubkey
	exPacket.Signature, err = s.local.PrivKey.Sign(handshake.Bytes())
	if err != nil {
		return err
	}

	exEncoded, err := proto.Marshal(exPacket)

	// send out Exchange packet
	select {
	case s.insecure.Out <- exEncoded:
	case <-s.ctx.Done():
		return ErrClosed
	}

	// Parse their Exchange packet and generate a Finish packet.
	// Finish = E('Finish')
	var resp1 []byte
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case resp1 = <-s.insecure.In:
	}

	exchangeResp := new(Exchange)
	err = proto.Unmarshal(resp1, exchangeResp)
	if err != nil {
		return err
	}

	var theirHandshake bytes.Buffer
	theirHandshake.Write(resp)
	theirHandshake.Write(encoded)
	theirHandshake.Write(exchangeResp.GetEpubkey())

	// u.POut("Remote Peer Identified as %s\n", s.remote.ID.Pretty())
	ok, err := s.remote.PubKey.Verify(theirHandshake.Bytes(), exchangeResp.GetSignature())
	if err != nil {
		return err
	}

	if !ok {
		return errors.New("Bad signature!")
	}

	secret, err := done(exchangeResp.GetEpubkey())
	if err != nil {
		return err
	}

	cmp := bytes.Compare(myPubKey, proposeResp.GetPubkey())
	mIV, tIV, mCKey, tCKey, mMKey, tMKey := ci.KeyStretcher(cmp, cipherType, hashType, secret)

	go s.handleSecureIn(hashType, tIV, tCKey, tMKey)
	go s.handleSecureOut(hashType, mIV, mCKey, mMKey)

	finished := []byte("Finished")

	// send finished msg
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case s.Out <- finished:
	}

	// recv finished msg
	var resp2 []byte
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case resp2 = <-s.In:
	}

	if bytes.Compare(resp2, finished) != 0 {
		return errors.New("Negotiation failed.")
	}

	u.DOut("[%s] handshake: Got node id: %s\n", s.local.ID.Pretty(), s.remote.ID.Pretty())
	return nil
}

func makeMac(hashType string, key []byte) (hash.Hash, int) {
	switch hashType {
	case "SHA1":
		return hmac.New(sha1.New, key), sha1.Size
	case "SHA512":
		return hmac.New(sha512.New, key), sha512.Size
	default:
		return hmac.New(sha256.New, key), sha256.Size
	}
}

func (s *SecurePipe) handleSecureIn(hashType string, tIV, tCKey, tMKey []byte) {
	theirBlock, _ := aes.NewCipher(tCKey)
	theirCipher := cipher.NewCTR(theirBlock, tIV)

	theirMac, macSize := makeMac(hashType, tMKey)

	for {
		data, ok := <-s.insecure.In
		if !ok {
			return
		}

		// u.DOut("[peer %s] secure in [from = %s] %d\n", s.local.ID.Pretty(), s.remote.ID.Pretty(), len(data))
		if len(data) <= macSize {
			continue
		}

		mark := len(data) - macSize
		buff := make([]byte, mark)

		theirCipher.XORKeyStream(buff, data[0:mark])

		theirMac.Write(data[0:mark])
		expected := theirMac.Sum(nil)
		theirMac.Reset()

		hmacOk := hmac.Equal(data[mark:], expected)

		if hmacOk {
			s.Duplex.In <- buff
		} else {
			s.Duplex.In <- nil
		}
	}
}

func (s *SecurePipe) handleSecureOut(hashType string, mIV, mCKey, mMKey []byte) {
	myBlock, _ := aes.NewCipher(mCKey)
	myCipher := cipher.NewCTR(myBlock, mIV)

	myMac, macSize := makeMac(hashType, mMKey)

	for {
		data, ok := <-s.Out
		if !ok {
			return
		}

		if len(data) == 0 {
			continue
		}

		buff := make([]byte, len(data)+macSize)

		myCipher.XORKeyStream(buff, data)

		myMac.Write(buff[0:len(data)])
		copy(buff[len(data):], myMac.Sum(nil))
		myMac.Reset()

		// u.DOut("[peer %s] secure out [to = %s] %d\n", s.local.ID.Pretty(), s.remote.ID.Pretty(), len(buff))
		s.insecure.Out <- buff
	}
}

// IDFromPubKey retrieves a Public Key from the peer given by pk
func IDFromPubKey(pk ci.PubKey) (peer.ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return nil, err
	}
	hash, err := u.Hash(b)
	if err != nil {
		return nil, err
	}
	return peer.ID(hash), nil
}

// Determines which algorithm to use.  Note:  f(a, b) = f(b, a)
func selectBest(myPrefs, theirPrefs string) (string, error) {
	// Person with greatest hash gets first choice.
	myHash, err := u.Hash([]byte(myPrefs))
	if err != nil {
		return "", err
	}

	theirHash, err := u.Hash([]byte(theirPrefs))
	if err != nil {
		return "", err
	}

	cmp := bytes.Compare(myHash, theirHash)
	var firstChoiceArr, secChoiceArr []string

	if cmp == -1 {
		firstChoiceArr = strings.Split(theirPrefs, ",")
		secChoiceArr = strings.Split(myPrefs, ",")
	} else if cmp == 1 {
		firstChoiceArr = strings.Split(myPrefs, ",")
		secChoiceArr = strings.Split(theirPrefs, ",")
	} else { // Exact same preferences.
		myPrefsArr := strings.Split(myPrefs, ",")
		return myPrefsArr[0], nil
	}

	for _, secChoice := range secChoiceArr {
		for _, firstChoice := range firstChoiceArr {
			if firstChoice == secChoice {
				return firstChoice, nil
			}
		}
	}

	return "", errors.New("No algorithms in common!")
}

// getOrConstructPeer attempts to fetch a peer from a peerstore.
// if succeeds, verify ID and PubKey match.
// else, construct it.
func getOrConstructPeer(peers peer.Peerstore, rpk ci.PubKey) (*peer.Peer, error) {

	rid, err := IDFromPubKey(rpk)
	if err != nil {
		return nil, err
	}

	npeer, err := peers.Get(rid)
	if err != nil {
		if err != peer.ErrNotFound {
			return nil, err // unexpected error happened.
		}

		// dont have peer, so construct it + add it to peerstore.
		npeer = &peer.Peer{ID: rid, PubKey: rpk}
		if err := peers.Put(npeer); err != nil {
			return nil, err
		}

		// done, return the newly constructed peer.
		return npeer, nil
	}

	// did have it locally.

	// let's verify ID
	if !npeer.ID.Equal(rid) {
		e := "Expected peer.ID does not match sent pubkey's hash: %v - %v"
		return nil, fmt.Errorf(e, npeer.ID.Pretty(), rid.Pretty())
	}

	if npeer.PubKey == nil {
		// didn't have a pubkey, just set it.
		npeer.PubKey = rpk
		return npeer, nil
	}

	// did have pubkey, let's verify it's really the same.
	// this shouldn't ever happen, given we hashed, etc, but it could mean
	// expected code (or protocol) invariants violated.

	lb, err1 := npeer.PubKey.Bytes()
	if err1 != nil {
		return nil, err1
	}
	rb, err2 := rpk.Bytes()
	if err2 != nil {
		return nil, err2
	}

	if !bytes.Equal(lb, rb) {
		return nil, fmt.Errorf("WARNING: PubKey mismatch: %v", npeer.ID.Pretty())
	}
	return npeer, nil
}
<commit_msg>handshake catch<commit_after>// Package spipe handles establishing secure communication between two peers.

package spipe

import (
	"bytes"
	"errors"
	"fmt"
	"strings"

	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"hash"

	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	ci "github.com/jbenet/go-ipfs/crypto"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

// List of supported ECDH curves
var SupportedExchanges = "P-256,P-224,P-384,P-521"

// List of supported Ciphers
var SupportedCiphers = "AES-256,AES-128"

// List of supported Hashes
var SupportedHashes = "SHA256,SHA512,SHA1"

// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
var ErrUnsupportedKeyType = errors.New("unsupported key type")

// ErrClosed signals the closing of a connection.
var ErrClosed = errors.New("connection closed")

// handsahke performs initial communication over insecure channel to share
// keys, IDs, and initiate communication.
func (s *SecurePipe) handshake() error {
	// Generate and send Hello packet.
	// Hello = (rand, PublicKey, Supported)
	nonce := make([]byte, 16)
	_, err := rand.Read(nonce)
	if err != nil {
		return err
	}

	// u.DOut("handshake: %s <--> %s\n", s.local.ID.Pretty(), s.remote.ID.Pretty())
	myPubKey, err := s.local.PubKey.Bytes()
	if err != nil {
		return err
	}

	proposeMsg := new(Propose)
	proposeMsg.Rand = nonce
	proposeMsg.Pubkey = myPubKey
	proposeMsg.Exchanges = &SupportedExchanges
	proposeMsg.Ciphers = &SupportedCiphers
	proposeMsg.Hashes = &SupportedHashes

	encoded, err := proto.Marshal(proposeMsg)
	if err != nil {
		return err
	}

	// Send our Propose packet
	select {
	case s.insecure.Out <- encoded:
	case <-s.ctx.Done():
		return ErrClosed
	}

	// Parse their Propose packet and generate an Exchange packet.
	// Exchange = (EphemeralPubKey, Signature)
	var resp []byte
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case resp = <-s.insecure.In:
	}

	// u.POut("received encoded handshake\n")
	proposeResp := new(Propose)
	err = proto.Unmarshal(resp, proposeResp)
	if err != nil {
		return err
	}

	// get remote identity
	remotePubKey, err := ci.UnmarshalPublicKey(proposeResp.GetPubkey())
	if err != nil {
		return err
	}

	// get or construct peer
	s.remote, err = getOrConstructPeer(s.peers, remotePubKey)
	if err != nil {
		return err
	}
	u.DOut("[%s] Remote Peer Identified as %s\n", s.local.ID.Pretty(), s.remote.ID.Pretty())

	exchange, err := selectBest(SupportedExchanges, proposeResp.GetExchanges())
	if err != nil {
		return err
	}

	cipherType, err := selectBest(SupportedCiphers, proposeResp.GetCiphers())
	if err != nil {
		return err
	}

	hashType, err := selectBest(SupportedHashes, proposeResp.GetHashes())
	if err != nil {
		return err
	}

	// u.POut("Selected %s %s %s\n", exchange, cipherType, hashType)
	epubkey, done, err := ci.GenerateEKeyPair(exchange) // Generate EphemeralPubKey

	var handshake bytes.Buffer // Gather corpus to sign.
	handshake.Write(encoded)
	handshake.Write(resp)
	handshake.Write(epubkey)

	exPacket := new(Exchange)

	exPacket.Epubkey = epubkey
	exPacket.Signature, err = s.local.PrivKey.Sign(handshake.Bytes())
	if err != nil {
		return err
	}

	exEncoded, err := proto.Marshal(exPacket)

	// send out Exchange packet
	select {
	case s.insecure.Out <- exEncoded:
	case <-s.ctx.Done():
		return ErrClosed
	}

	// Parse their Exchange packet and generate a Finish packet.
	// Finish = E('Finish')
	var resp1 []byte
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case resp1 = <-s.insecure.In:
	}

	exchangeResp := new(Exchange)
	err = proto.Unmarshal(resp1, exchangeResp)
	if err != nil {
		return err
	}

	var theirHandshake bytes.Buffer
	theirHandshake.Write(resp)
	theirHandshake.Write(encoded)
	theirHandshake.Write(exchangeResp.GetEpubkey())

	// u.POut("Remote Peer Identified as %s\n", s.remote.ID.Pretty())
	ok, err := s.remote.PubKey.Verify(theirHandshake.Bytes(), exchangeResp.GetSignature())
	if err != nil {
		return err
	}

	if !ok {
		return errors.New("Bad signature!")
	}

	secret, err := done(exchangeResp.GetEpubkey())
	if err != nil {
		return err
	}

	cmp := bytes.Compare(myPubKey, proposeResp.GetPubkey())
	mIV, tIV, mCKey, tCKey, mMKey, tMKey := ci.KeyStretcher(cmp, cipherType, hashType, secret)

	go s.handleSecureIn(hashType, tIV, tCKey, tMKey)
	go s.handleSecureOut(hashType, mIV, mCKey, mMKey)

	finished := []byte("Finished")

	// send finished msg
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case s.Out <- finished:
	}

	// recv finished msg
	var resp2 []byte
	select {
	case <-s.ctx.Done():
		return ErrClosed
	case resp2 = <-s.In:
	}

	if bytes.Compare(resp2, finished) != 0 {
		return errors.New("Negotiation failed.")
	}

	u.DOut("[%s] handshake: Got node id: %s\n", s.local.ID.Pretty(), s.remote.ID.Pretty())
	return nil
}

func makeMac(hashType string, key []byte) (hash.Hash, int) {
	switch hashType {
	case "SHA1":
		return hmac.New(sha1.New, key), sha1.Size
	case "SHA512":
		return hmac.New(sha512.New, key), sha512.Size
	default:
		return hmac.New(sha256.New, key), sha256.Size
	}
}

func (s *SecurePipe) handleSecureIn(hashType string, tIV, tCKey, tMKey []byte) {
	theirBlock, _ := aes.NewCipher(tCKey)
	theirCipher := cipher.NewCTR(theirBlock, tIV)

	theirMac, macSize := makeMac(hashType, tMKey)

	for {
		data, ok := <-s.insecure.In
		if !ok {
			return
		}

		// u.DOut("[peer %s] secure in [from = %s] %d\n", s.local.ID.Pretty(), s.remote.ID.Pretty(), len(data))
		if len(data) <= macSize {
			continue
		}

		mark := len(data) - macSize
		buff := make([]byte, mark)

		theirCipher.XORKeyStream(buff, data[0:mark])

		theirMac.Write(data[0:mark])
		expected := theirMac.Sum(nil)
		theirMac.Reset()

		hmacOk := hmac.Equal(data[mark:], expected)

		if hmacOk {
			s.Duplex.In <- buff
		} else {
			s.Duplex.In <- nil
		}
	}
}

func (s *SecurePipe) handleSecureOut(hashType string, mIV, mCKey, mMKey []byte) {
	myBlock, _ := aes.NewCipher(mCKey)
	myCipher := cipher.NewCTR(myBlock, mIV)

	myMac, macSize := makeMac(hashType, mMKey)

	for {
		data, ok := <-s.Out
		if !ok {
			return
		}

		if len(data) == 0 {
			continue
		}

		buff := make([]byte, len(data)+macSize)

		myCipher.XORKeyStream(buff, data)

		myMac.Write(buff[0:len(data)])
		copy(buff[len(data):], myMac.Sum(nil))
		myMac.Reset()

		// u.DOut("[peer %s] secure out [to = %s] %d\n", s.local.ID.Pretty(), s.remote.ID.Pretty(), len(buff))
		s.insecure.Out <- buff
	}
}

// IDFromPubKey retrieves a Public Key from the peer given by pk
func IDFromPubKey(pk ci.PubKey) (peer.ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return nil, err
	}
	hash, err := u.Hash(b)
	if err != nil {
		return nil, err
	}
	return peer.ID(hash), nil
}

// Determines which algorithm to use.  Note:  f(a, b) = f(b, a)
func selectBest(myPrefs, theirPrefs string) (string, error) {
	// Person with greatest hash gets first choice.
	myHash, err := u.Hash([]byte(myPrefs))
	if err != nil {
		return "", err
	}

	theirHash, err := u.Hash([]byte(theirPrefs))
	if err != nil {
		return "", err
	}

	cmp := bytes.Compare(myHash, theirHash)
	var firstChoiceArr, secChoiceArr []string

	if cmp == -1 {
		firstChoiceArr = strings.Split(theirPrefs, ",")
		secChoiceArr = strings.Split(myPrefs, ",")
	} else if cmp == 1 {
		firstChoiceArr = strings.Split(myPrefs, ",")
		secChoiceArr = strings.Split(theirPrefs, ",")
	} else { // Exact same preferences.
		myPrefsArr := strings.Split(myPrefs, ",")
		return myPrefsArr[0], nil
	}

	for _, secChoice := range secChoiceArr {
		for _, firstChoice := range firstChoiceArr {
			if firstChoice == secChoice {
				return firstChoice, nil
			}
		}
	}

	return "", errors.New("No algorithms in common!")
}

// getOrConstructPeer attempts to fetch a peer from a peerstore.
// if succeeds, verify ID and PubKey match.
// else, construct it.
func getOrConstructPeer(peers peer.Peerstore, rpk ci.PubKey) (*peer.Peer, error) {

	rid, err := IDFromPubKey(rpk)
	if err != nil {
		return nil, err
	}

	npeer, err := peers.Get(rid)
	if err != nil || npeer == nil {
		if err != peer.ErrNotFound {
			return nil, err // unexpected error happened.
		}

		// dont have peer, so construct it + add it to peerstore.
		npeer = &peer.Peer{ID: rid, PubKey: rpk}
		if err := peers.Put(npeer); err != nil {
			return nil, err
		}

		// done, return the newly constructed peer.
		return npeer, nil
	}

	// did have it locally.

	// let's verify ID
	if !npeer.ID.Equal(rid) {
		e := "Expected peer.ID does not match sent pubkey's hash: %v - %v"
		return nil, fmt.Errorf(e, npeer.ID.Pretty(), rid.Pretty())
	}

	if npeer.PubKey == nil {
		// didn't have a pubkey, just set it.
		npeer.PubKey = rpk
		return npeer, nil
	}

	// did have pubkey, let's verify it's really the same.
	// this shouldn't ever happen, given we hashed, etc, but it could mean
	// expected code (or protocol) invariants violated.

	lb, err1 := npeer.PubKey.Bytes()
	if err1 != nil {
		return nil, err1
	}
	rb, err2 := rpk.Bytes()
	if err2 != nil {
		return nil, err2
	}

	if !bytes.Equal(lb, rb) {
		return nil, fmt.Errorf("WARNING: PubKey mismatch: %v", npeer.ID.Pretty())
	}
	return npeer, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package parser

import (
	"fmt"
	"testing"

	. "github.com/pingcap/check"
	"github.com/pingcap/tidb/expression/expressions"
	"github.com/pingcap/tidb/stmt/stmts"
)

func TestT(t *testing.T) {
	TestingT(t)
}

var _ = Suite(&testParserSuite{})

type testParserSuite struct {
}

// TODO: table 43 and 50 parse failed
func (s *testParserSuite) TestParser0(c *C) {
	table := []struct {
		src string
		ok  bool
	}{
		{"", true},
		{";", true},
		{"CREATE", false},
		{"CREATE TABLE", false},
		{"CREATE TABLE foo (", false},
		// 5
		{"CREATE TABLE foo ()", false},
		{"CREATE TABLE foo ();", false},
		{"CREATE TABLE foo (a TINYINT UNSIGNED);", true},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true},
		// 10
		{"CREATE TABLE foo (a bigint unsigned, b bool);", true},
		{"CREATE TABLE foo (a TINYINT, b SMALLINT) CREATE TABLE bar (x INT, y int64)", false},
		{"CREATE TABLE foo (a int, b float); CREATE TABLE bar (x double, y float)", true},
		{"INSERT INTO foo VALUES (1234)", true},
		{"INSERT INTO foo VALUES (1234, 5678)", true},
		// 15
		{"INSERT INTO foo VALUES (1 || 2)", true},
		{"INSERT INTO foo VALUES (1 | 2)", true},
		{"INSERT INTO foo VALUES (false || true)", true},
		{"INSERT INTO foo VALUES (bar(5678))", false},
		// 20
		{"INSERT INTO foo VALUES ()", true},
		{"CREATE TABLE foo (a.b, b);", false},
		{"CREATE TABLE foo (a, b.c);", false},
		{"SELECT * FROM t", true},
		{"SELECT * FROM t AS u", true},
		// 25
		{"SELECT * FROM t, v", true},
		{"SELECT * FROM t AS u, v", true},
		{"SELECT * FROM t, v AS w", true},
		{"SELECT * FROM t AS u, v AS w", true},
		{"SELECT * FROM foo, bar, foo", true},
		// 30
		{"CREATE TABLE foo (a bytes)", false},
		{"SELECT DISTINCTS * FROM t", false},
		{"SELECT DISTINCT * FROM t", true},
		{"INSERT INTO foo (a) VALUES (42)", true},
		{"INSERT INTO foo (a,) VALUES (42,)", false},
		// 35
		{"INSERT INTO foo (a,b) VALUES (42,314)", true},
		{"INSERT INTO foo (a,b,) VALUES (42,314)", false},
		{"INSERT INTO foo (a,b,) VALUES (42,314,)", false},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) -- foo", true},
		// 40
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) // foo", true},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true},
		{"CREATE TABLE foo /* foo */ (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true},
		/*{`-- Examples
		ALTER TABLE Stock ADD Qty int;

		ALTER TABLE Income DROP COLUMN Taxes;

		CREATE TABLE department
		(
			DepartmentID   int,
			DepartmentName string,	// optional comma
		);

		CREATE TABLE employee
		(
			LastName	string,
			DepartmentID	int	// optional comma
		);

		DROP TABLE Inventory;

		INSERT INTO department (DepartmentID) VALUES (42);

		INSERT INTO department (
			DepartmentName,
			DepartmentID,
		)
		VALUES (
			"R&D",
			42,
		);

		INSERT INTO department VALUES (
			42,
			"R&D",
		);

		SELECT * FROM Stock;

		SELECT DepartmentID
		FROM department
		WHERE DepartmentID == 42
		ORDER BY DepartmentName;

		SELECT employee.LastName
		FROM department, employee
		WHERE department.DepartmentID == employee.DepartmentID
		ORDER BY DepartmentID;

		SELECT a.b, c.d
		FROM
			x AS a,
			(
				SELECT * FROM y; // optional semicolon
			) AS c
		WHERE a.e > c.e;

		SELECT a.b, c.d
		FROM
			x AS a,
			(
				SELECT * FROM y // no semicolon
			) AS c
		WHERE a.e > c.e;

		TRUNCATE TABLE department;

		SELECT DepartmentID
		FROM department
		WHERE DepartmentID == ?1
		ORDER BY DepartmentName;

		SELECT employee.LastName
		FROM department, employee
		WHERE department.DepartmentID == $1 && employee.LastName > $2
		ORDER BY DepartmentID;

		`, true},
		*/
		{"BEGIN", true},
		{"START TRANSACTION", true},
		// 45
		{"COMMIT", true},
		{"ROLLBACK", true},
		{`
		BEGIN;
			INSERT INTO foo VALUES (42, 3.14);
			INSERT INTO foo VALUES (-1, 2.78);
		COMMIT;`, true},
		{` // A
		BEGIN;
			INSERT INTO tmp SELECT * from bar;
		SELECT * from tmp;

		// B
		ROLLBACK;`, true},
		// 50
		/*
			{`-- 6
				ALTER TABLE none DROP COLUMN c1;
			`, true},
		*/

		// set
		// user defined
		{"SET @a = 1", true},
		// session system variables
		{"SET SESSION autocommit = 1", true},
		{"SET @@session.autocommit = 1", true},
		{"SET LOCAL autocommit = 1", true},
		{"SET @@local.autocommit = 1", true},
		{"SET @@autocommit = 1", true},
		{"SET autocommit = 1", true},
		// global system variables
		{"SET GLOBAL autocommit = 1", true},
		{"SET @@global.autocommit = 1", true},
		// SET CHARACTER SET
		{"SET CHARACTER SET utf8mb4;", true},
		{"SET CHARACTER SET 'utf8mb4';", true},

		// qualified select
		{"SELECT a.b.c FROM t", true},
		{"SELECT a.b.*.c FROM t", false},
		{"SELECT a.b.* FROM t", true},
		{"SELECT a FROM t", true},
		{"SELECT a.b.c.d FROM t", false},

		// Do statement
		{"DO 1", true},
		{"DO 1 from t", false},

		// Sign expression
		{"SELECT ++1", true},
		{"SELECT -*1", false},
		{"SELECT -+1", true},
		{"SELECT -1", true},
		{"SELECT --1", true},

		// Select for update
		{"SELECT * from t for update", true},
		{"SELECT * from t lock in share mode", true},

		// For alter table
		{"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED", true},
		{"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED FIRST", true},
		{"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED AFTER b", true},

		// from join
		{"SELECT * from t1, t2, t3", true},
		{"select * from t1 join t2 left join t3 on t2.id = t3.id", true},
		{"select * from t1 right join t2 on t1.id = t2.id left join t3 on t3.id = t2.id", true},
		{"select * from t1 right join t2 on t1.id = t2.id left join t3", false},

		// For default value
		{"CREATE TABLE sbtest (id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, k integer UNSIGNED DEFAULT '0' NOT NULL, c char(120) DEFAULT '' NOT NULL, pad char(60) DEFAULT '' NOT NULL, PRIMARY KEY  (id) )", true},

		// For show full columns
		{"show columns in t;", true},
		{"show full columns in t;", true},

		// For set names
		{"set names utf8", true},
		{"set names utf8 collate utf8_unicode_ci", true},

		// For show character set
		{"show character set;", true},
		// For on duplicate key update
		{"INSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true},
		{"INSERT IGNORE INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true},

		// For buildin functions
		{"SELECT DAYOFMONTH('2007-02-03');", true},

		{"SELECT SUBSTRING('Quadratically',5);", true},
		{"SELECT SUBSTRING('Quadratically',5, 3);", true},
		{"SELECT SUBSTRING('Quadratically' FROM 5);", true},
		{"SELECT SUBSTRING('Quadratically' FROM 5 FOR 3);", true},

		{"SELECT CONVERT('111', SIGNED);", true},

		{"SELECT DATABASE();", true},

		// For delete statement
		{"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true},
		{"DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true},
		{"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id limit 10;", false},

		// For time fsp
		{"CREATE TABLE t( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );", true},

		// For row
		{"select row(1)", false},
		{"select row(1, 1,)", false},
		{"select (1, 1,)", false},
		{"select row(1, 1) > row(1, 1), row(1, 1, 1) > row(1, 1, 1)", true},
		{"Select (1, 1) > (1, 1)", true},

		// For SHOW statement
		{"SHOW VARIABLES LIKE 'character_set_results'", true},
		{"SHOW GLOBAL VARIABLES LIKE 'character_set_results'", true},
		{"SHOW SESSION VARIABLES LIKE 'character_set_results'", true},
		{"SHOW VARIABLES", true},
		{"SHOW GLOBAL VARIABLES", true},

		// For compare subquery
		{"SELECT 1 > (select 1)", true},
		{"SELECT 1 > ANY (select 1)", true},
		{"SELECT 1 > ALL (select 1)", true},
		{"SELECT 1 > SOME (select 1)", true},

		// For exists subquery
		{"SELECT EXISTS select 1", false},
		{"SELECT EXISTS (select 1)", true},
		{"SELECT + EXISTS (select 1)", true},
		{"SELECT - EXISTS (select 1)", true},
		{"SELECT NOT EXISTS (select 1)", true},
		{"SELECT + NOT EXISTS (select 1)", false},
		{"SELECT - NOT EXISTS (select 1)", false},

		// For update statement
		{"UPDATE t SET id = id + 1 ORDER BY id DESC;", true},
		{"UPDATE items,month SET items.price=month.price WHERE items.id=month.id;", true},
		{"UPDATE items,month SET items.price=month.price WHERE items.id=month.id LIMIT 10;", false},
		{"UPDATE user T0 LEFT OUTER JOIN user_profile T1 ON T1.id = T0.profile_id SET T0.profile_id = 1 WHERE T0.profile_id IN (1);", true},

		// For cast with charset
		{"SELECT *, CAST(data AS CHAR CHARACTER SET utf8) FROM t;", true},

		// For binary operator
		{"SELECT binary 'a';", true},

		// For hexadecimal
		{"SELECT x'0a', X'11', 0x11", true},
		{"select x'0xaa'", false},
		{"select 0X11", false},

		// For comparison
		{"select 1 <=> 0, 1 <=> null, 1 = null", true},
	}

	for _, t := range table {
		fmt.Printf("%s\n", t.src)
		l := NewLexer(t.src)
		ok := yyParse(l) == 0
		c.Assert(ok, Equals, t.ok, Commentf("source %v", t.src))

		switch ok {
		case true:
			c.Assert(len(l.errs), Equals, 0)
		case false:
			c.Assert(len(l.errs), Not(Equals), 0)
		}
	}

	// Testcase for unreserved keywords
	unreservedKws := []string{
		"auto_increment", "after", "begin", "bit", "bool", "boolean", "charset", "columns", "commit",
		"date", "datetime", "deallocate", "do", "end", "engine", "engines", "execute", "first", "full",
		"local", "names", "offset", "password", "prepare", "quick", "rollback", "session", "signed",
		"start", "global", "tables", "text", "time", "timestamp", "transaction", "truncate", "unknown",
		"value", "warnings", "year", "now", "substring", "mode", "any", "some",
	}
	for _, kw := range unreservedKws {
		src := fmt.Sprintf("SELECT %s FROM tbl;", kw)
		l := NewLexer(src)
		c.Assert(yyParse(l), Equals, 0)
		c.Assert(l.errs, HasLen, 0, Commentf("source %s", src))
	}

	// Testcase for prepared statement
	src := "SELECT id+?, id+? from t;"
	l := NewLexer(src)
	l.SetPrepare()
	c.Assert(yyParse(l), Equals, 0)
	c.Assert(len(l.ParamList), Equals, 2)
	c.Assert(len(l.Stmts()), Equals, 1)

	// Testcase for -- Comment and unary -- operator
	src = "CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED); -- foo\nSelect --1 from foo;"
	l = NewLexer(src)
	l.SetPrepare()
	c.Assert(yyParse(l), Equals, 0)
	c.Assert(len(l.Stmts()), Equals, 2)

	// Testcase for CONVERT(expr,type)
	src = "SELECT CONVERT('111', SIGNED);"
	l = NewLexer(src)
	c.Assert(yyParse(l), Equals, 0)
	st := l.Stmts()[0]
	ss, ok := st.(*stmts.SelectStmt)
	c.Assert(ok, IsTrue)
	cv, ok := ss.Fields[0].Expr.(*expressions.FunctionCast)
	c.Assert(ok, IsTrue)
	c.Assert(cv.FunctionType, Equals, expressions.ConvertFunction)
}
<commit_msg>parser: add test case for where clause in select<commit_after>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package parser

import (
	"fmt"
	"testing"

	. "github.com/pingcap/check"
	"github.com/pingcap/tidb/expression/expressions"
	"github.com/pingcap/tidb/stmt/stmts"
)

func TestT(t *testing.T) {
	TestingT(t)
}

var _ = Suite(&testParserSuite{})

type testParserSuite struct {
}

// TODO: table 43 and 50 parse failed
func (s *testParserSuite) TestParser0(c *C) {
	table := []struct {
		src string
		ok  bool
	}{
		{"", true},
		{";", true},
		{"CREATE", false},
		{"CREATE TABLE", false},
		{"CREATE TABLE foo (", false},
		// 5
		{"CREATE TABLE foo ()", false},
		{"CREATE TABLE foo ();", false},
		{"CREATE TABLE foo (a TINYINT UNSIGNED);", true},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true},
		// 10
		{"CREATE TABLE foo (a bigint unsigned, b bool);", true},
		{"CREATE TABLE foo (a TINYINT, b SMALLINT) CREATE TABLE bar (x INT, y int64)", false},
		{"CREATE TABLE foo (a int, b float); CREATE TABLE bar (x double, y float)", true},
		{"INSERT INTO foo VALUES (1234)", true},
		{"INSERT INTO foo VALUES (1234, 5678)", true},
		// 15
		{"INSERT INTO foo VALUES (1 || 2)", true},
		{"INSERT INTO foo VALUES (1 | 2)", true},
		{"INSERT INTO foo VALUES (false || true)", true},
		{"INSERT INTO foo VALUES (bar(5678))", false},
		// 20
		{"INSERT INTO foo VALUES ()", true},
		{"CREATE TABLE foo (a.b, b);", false},
		{"CREATE TABLE foo (a, b.c);", false},
		{"SELECT * FROM t", true},
		{"SELECT * FROM t AS u", true},
		// 25
		{"SELECT * FROM t, v", true},
		{"SELECT * FROM t AS u, v", true},
		{"SELECT * FROM t, v AS w", true},
		{"SELECT * FROM t AS u, v AS w", true},
		{"SELECT * FROM foo, bar, foo", true},
		// 30
		{"CREATE TABLE foo (a bytes)", false},
		{"SELECT DISTINCTS * FROM t", false},
		{"SELECT DISTINCT * FROM t", true},
		{"INSERT INTO foo (a) VALUES (42)", true},
		{"INSERT INTO foo (a,) VALUES (42,)", false},
		// 35
		{"INSERT INTO foo (a,b) VALUES (42,314)", true},
		{"INSERT INTO foo (a,b,) VALUES (42,314)", false},
		{"INSERT INTO foo (a,b,) VALUES (42,314,)", false},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) -- foo", true},
		// 40
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) // foo", true},
		{"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true},
		{"CREATE TABLE foo /* foo */ (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true},
		/*{`-- Examples
		ALTER TABLE Stock ADD Qty int;

		ALTER TABLE Income DROP COLUMN Taxes;

		CREATE TABLE department
		(
			DepartmentID   int,
			DepartmentName string,	// optional comma
		);

		CREATE TABLE employee
		(
			LastName	string,
			DepartmentID	int	// optional comma
		);

		DROP TABLE Inventory;

		INSERT INTO department (DepartmentID) VALUES (42);

		INSERT INTO department (
			DepartmentName,
			DepartmentID,
		)
		VALUES (
			"R&D",
			42,
		);

		INSERT INTO department VALUES (
			42,
			"R&D",
		);

		SELECT * FROM Stock;

		SELECT DepartmentID
		FROM department
		WHERE DepartmentID == 42
		ORDER BY DepartmentName;

		SELECT employee.LastName
		FROM department, employee
		WHERE department.DepartmentID == employee.DepartmentID
		ORDER BY DepartmentID;

		SELECT a.b, c.d
		FROM
			x AS a,
			(
				SELECT * FROM y; // optional semicolon
			) AS c
		WHERE a.e > c.e;

		SELECT a.b, c.d
		FROM
			x AS a,
			(
				SELECT * FROM y // no semicolon
			) AS c
		WHERE a.e > c.e;

		TRUNCATE TABLE department;

		SELECT DepartmentID
		FROM department
		WHERE DepartmentID == ?1
		ORDER BY DepartmentName;

		SELECT employee.LastName
		FROM department, employee
		WHERE department.DepartmentID == $1 && employee.LastName > $2
		ORDER BY DepartmentID;

		`, true},
		*/
		{"BEGIN", true},
		{"START TRANSACTION", true},
		// 45
		{"COMMIT", true},
		{"ROLLBACK", true},
		{`
		BEGIN;
			INSERT INTO foo VALUES (42, 3.14);
			INSERT INTO foo VALUES (-1, 2.78);
		COMMIT;`, true},
		{` // A
		BEGIN;
			INSERT INTO tmp SELECT * from bar;
		SELECT * from tmp;

		// B
		ROLLBACK;`, true},
		// 50
		/*
			{`-- 6
				ALTER TABLE none DROP COLUMN c1;
			`, true},
		*/

		// set
		// user defined
		{"SET @a = 1", true},
		// session system variables
		{"SET SESSION autocommit = 1", true},
		{"SET @@session.autocommit = 1", true},
		{"SET LOCAL autocommit = 1", true},
		{"SET @@local.autocommit = 1", true},
		{"SET @@autocommit = 1", true},
		{"SET autocommit = 1", true},
		// global system variables
		{"SET GLOBAL autocommit = 1", true},
		{"SET @@global.autocommit = 1", true},
		// SET CHARACTER SET
		{"SET CHARACTER SET utf8mb4;", true},
		{"SET CHARACTER SET 'utf8mb4';", true},

		// qualified select
		{"SELECT a.b.c FROM t", true},
		{"SELECT a.b.*.c FROM t", false},
		{"SELECT a.b.* FROM t", true},
		{"SELECT a FROM t", true},
		{"SELECT a.b.c.d FROM t", false},

		// Do statement
		{"DO 1", true},
		{"DO 1 from t", false},

		// Sign expression
		{"SELECT ++1", true},
		{"SELECT -*1", false},
		{"SELECT -+1", true},
		{"SELECT -1", true},
		{"SELECT --1", true},

		// Select for update
		{"SELECT * from t for update", true},
		{"SELECT * from t lock in share mode", true},

		// For alter table
		{"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED", true},
		{"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED FIRST", true},
		{"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED AFTER b", true},

		// from join
		{"SELECT * from t1, t2, t3", true},
		{"select * from t1 join t2 left join t3 on t2.id = t3.id", true},
		{"select * from t1 right join t2 on t1.id = t2.id left join t3 on t3.id = t2.id", true},
		{"select * from t1 right join t2 on t1.id = t2.id left join t3", false},

		// For default value
		{"CREATE TABLE sbtest (id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, k integer UNSIGNED DEFAULT '0' NOT NULL, c char(120) DEFAULT '' NOT NULL, pad char(60) DEFAULT '' NOT NULL, PRIMARY KEY  (id) )", true},

		// For show full columns
		{"show columns in t;", true},
		{"show full columns in t;", true},

		// For set names
		{"set names utf8", true},
		{"set names utf8 collate utf8_unicode_ci", true},

		// For show character set
		{"show character set;", true},
		// For on duplicate key update
		{"INSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true},
		{"INSERT IGNORE INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true},

		// For buildin functions
		{"SELECT DAYOFMONTH('2007-02-03');", true},

		{"SELECT SUBSTRING('Quadratically',5);", true},
		{"SELECT SUBSTRING('Quadratically',5, 3);", true},
		{"SELECT SUBSTRING('Quadratically' FROM 5);", true},
		{"SELECT SUBSTRING('Quadratically' FROM 5 FOR 3);", true},

		{"SELECT CONVERT('111', SIGNED);", true},

		{"SELECT DATABASE();", true},

		// For delete statement
		{"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true},
		{"DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true},
		{"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id limit 10;", false},

		// For time fsp
		{"CREATE TABLE t( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );", true},

		// For row
		{"select row(1)", false},
		{"select row(1, 1,)", false},
		{"select (1, 1,)", false},
		{"select row(1, 1) > row(1, 1), row(1, 1, 1) > row(1, 1, 1)", true},
		{"Select (1, 1) > (1, 1)", true},

		// For SHOW statement
		{"SHOW VARIABLES LIKE 'character_set_results'", true},
		{"SHOW GLOBAL VARIABLES LIKE 'character_set_results'", true},
		{"SHOW SESSION VARIABLES LIKE 'character_set_results'", true},
		{"SHOW VARIABLES", true},
		{"SHOW GLOBAL VARIABLES", true},

		// For compare subquery
		{"SELECT 1 > (select 1)", true},
		{"SELECT 1 > ANY (select 1)", true},
		{"SELECT 1 > ALL (select 1)", true},
		{"SELECT 1 > SOME (select 1)", true},

		// For exists subquery
		{"SELECT EXISTS select 1", false},
		{"SELECT EXISTS (select 1)", true},
		{"SELECT + EXISTS (select 1)", true},
		{"SELECT - EXISTS (select 1)", true},
		{"SELECT NOT EXISTS (select 1)", true},
		{"SELECT + NOT EXISTS (select 1)", false},
		{"SELECT - NOT EXISTS (select 1)", false},

		// For update statement
		{"UPDATE t SET id = id + 1 ORDER BY id DESC;", true},
		{"UPDATE items,month SET items.price=month.price WHERE items.id=month.id;", true},
		{"UPDATE items,month SET items.price=month.price WHERE items.id=month.id LIMIT 10;", false},
		{"UPDATE user T0 LEFT OUTER JOIN user_profile T1 ON T1.id = T0.profile_id SET T0.profile_id = 1 WHERE T0.profile_id IN (1);", true},

		// For cast with charset
		{"SELECT *, CAST(data AS CHAR CHARACTER SET utf8) FROM t;", true},

		// For binary operator
		{"SELECT binary 'a';", true},

		// For hexadecimal
		{"SELECT x'0a', X'11', 0x11", true},
		{"select x'0xaa'", false},
		{"select 0X11", false},

		// For comparison
		{"select 1 <=> 0, 1 <=> null, 1 = null", true},

		// For select with where clause
		{"SELECT 1 WHERE 1 = 1", true},
	}

	for _, t := range table {
		fmt.Printf("%s\n", t.src)
		l := NewLexer(t.src)
		ok := yyParse(l) == 0
		c.Assert(ok, Equals, t.ok, Commentf("source %v", t.src))

		switch ok {
		case true:
			c.Assert(len(l.errs), Equals, 0)
		case false:
			c.Assert(len(l.errs), Not(Equals), 0)
		}
	}

	// Testcase for unreserved keywords
	unreservedKws := []string{
		"auto_increment", "after", "begin", "bit", "bool", "boolean", "charset", "columns", "commit",
		"date", "datetime", "deallocate", "do", "end", "engine", "engines", "execute", "first", "full",
		"local", "names", "offset", "password", "prepare", "quick", "rollback", "session", "signed",
		"start", "global", "tables", "text", "time", "timestamp", "transaction", "truncate", "unknown",
		"value", "warnings", "year", "now", "substring", "mode", "any", "some",
	}
	for _, kw := range unreservedKws {
		src := fmt.Sprintf("SELECT %s FROM tbl;", kw)
		l := NewLexer(src)
		c.Assert(yyParse(l), Equals, 0)
		c.Assert(l.errs, HasLen, 0, Commentf("source %s", src))
	}

	// Testcase for prepared statement
	src := "SELECT id+?, id+? from t;"
	l := NewLexer(src)
	l.SetPrepare()
	c.Assert(yyParse(l), Equals, 0)
	c.Assert(len(l.ParamList), Equals, 2)
	c.Assert(len(l.Stmts()), Equals, 1)

	// Testcase for -- Comment and unary -- operator
	src = "CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED); -- foo\nSelect --1 from foo;"
	l = NewLexer(src)
	l.SetPrepare()
	c.Assert(yyParse(l), Equals, 0)
	c.Assert(len(l.Stmts()), Equals, 2)

	// Testcase for CONVERT(expr,type)
	src = "SELECT CONVERT('111', SIGNED);"
	l = NewLexer(src)
	c.Assert(yyParse(l), Equals, 0)
	st := l.Stmts()[0]
	ss, ok := st.(*stmts.SelectStmt)
	c.Assert(ok, IsTrue)
	cv, ok := ss.Fields[0].Expr.(*expressions.FunctionCast)
	c.Assert(ok, IsTrue)
	c.Assert(cv.FunctionType, Equals, expressions.ConvertFunction)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/laziac/go-nagios/nagios"
	"github.com/nightlyone/checklogfile"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var opts struct {
	Verbose         bool     `short:"v" long:"verbose" description:"be verbose debug"`
	Logfile         string   `short:"f" long:"logfile" required:"true" description:"parse this logfile"`
	Tag             string   `short:"t" long:"tag" default:"default" description:"tag to use for reporting"`
	OffsetFile      string   `short:"o" long:"offsetfile" description:"file describing the offset we restart scaning for events"`
	OkPattern       []string `short:"k" long:"okpattern" description:"pattern for event clearing a previous event"`
	CriticalPattern []string `short:"c" long:"criticalpattern" description:"pattern for critical event"`
	WarningPattern  []string `short:"w" long:"warningpattern" description:"pattern for warning event"`
	UnknownPattern  []string `short:"u" long:"unknownpattern" description:"pattern meaning we don't know yet"`
}

// Try to read offsetfile
func GetOffset() int64 {
	offset := int64(0)
	if b, err := ioutil.ReadFile(opts.OffsetFile); err == nil && len(b) > 0 {
		buf := bytes.NewReader(b)
		fmt.Fscan(buf, &offset)
	}
	return offset
}

// Try to process passed log file
func ProcessLog() (nagios.Status, error) {
	var fp checklogfile.ReadSeekCloser

	fp, err := os.Open(opts.Logfile)
	if err != nil {
		return nagios.UNKNOWN, err
	}
	ext := filepath.Ext(opts.Logfile)
	fp = checklogfile.NewCompressorSeekWrapper(fp, ext)
	lf := checklogfile.NewLogFile(fp, GetOffset())
	defer lf.Close()
	defer func() {
		offset := lf.Offset()
		s := fmt.Sprintf("%d", offset)
		ioutil.WriteFile(opts.OffsetFile, []byte(s), 0600)
	}()

	if err := lf.AddPatterns(checklogfile.MonitorOk, opts.OkPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	if err := lf.AddPatterns(checklogfile.MonitorCritical, opts.CriticalPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	if err := lf.AddPatterns(checklogfile.MonitorWarning, opts.WarningPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	if err := lf.AddPatterns(checklogfile.MonitorUnknown, opts.UnknownPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	res, count, err := lf.Scan()
	lines := int64(0)
	for i, v := range count {
		lines += v
		level := strings.ToLower(nagios.Status(i).String())
		nagios.Perfdata(opts.Tag+"-"+level, float64(v), "", nil, nil)
	}
	return nagios.Status(res), err
}

func main() {
	_, err := flags.Parse(&opts)

	if err != nil {
		// --help is not an error
		if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
			return
		} else {
			nagios.Exit(nagios.UNKNOWN, err.Error())
		}
	}

	state, err := ProcessLog()
	if err == nil {
		nagios.Exit(state, "")
	}
	nagios.Exit(state, err.Error())
}
<commit_msg>Switched to different host for go-nagios<commit_after>package main

import (
	"bytes"
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/nightlyone/go-nagios/nagios"
	"github.com/nightlyone/checklogfile"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var opts struct {
	Verbose         bool     `short:"v" long:"verbose" description:"be verbose debug"`
	Logfile         string   `short:"f" long:"logfile" required:"true" description:"parse this logfile"`
	Tag             string   `short:"t" long:"tag" default:"default" description:"tag to use for reporting"`
	OffsetFile      string   `short:"o" long:"offsetfile" description:"file describing the offset we restart scaning for events"`
	OkPattern       []string `short:"k" long:"okpattern" description:"pattern for event clearing a previous event"`
	CriticalPattern []string `short:"c" long:"criticalpattern" description:"pattern for critical event"`
	WarningPattern  []string `short:"w" long:"warningpattern" description:"pattern for warning event"`
	UnknownPattern  []string `short:"u" long:"unknownpattern" description:"pattern meaning we don't know yet"`
}

// Try to read offsetfile
func GetOffset() int64 {
	offset := int64(0)
	if b, err := ioutil.ReadFile(opts.OffsetFile); err == nil && len(b) > 0 {
		buf := bytes.NewReader(b)
		fmt.Fscan(buf, &offset)
	}
	return offset
}

// Try to process passed log file
func ProcessLog() (nagios.Status, error) {
	var fp checklogfile.ReadSeekCloser

	fp, err := os.Open(opts.Logfile)
	if err != nil {
		return nagios.UNKNOWN, err
	}
	ext := filepath.Ext(opts.Logfile)
	fp = checklogfile.NewCompressorSeekWrapper(fp, ext)
	lf := checklogfile.NewLogFile(fp, GetOffset())
	defer lf.Close()
	defer func() {
		offset := lf.Offset()
		s := fmt.Sprintf("%d", offset)
		ioutil.WriteFile(opts.OffsetFile, []byte(s), 0600)
	}()

	if err := lf.AddPatterns(checklogfile.MonitorOk, opts.OkPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	if err := lf.AddPatterns(checklogfile.MonitorCritical, opts.CriticalPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	if err := lf.AddPatterns(checklogfile.MonitorWarning, opts.WarningPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	if err := lf.AddPatterns(checklogfile.MonitorUnknown, opts.UnknownPattern); err != nil {
		return nagios.UNKNOWN, err
	}
	res, count, err := lf.Scan()
	lines := int64(0)
	for i, v := range count {
		lines += v
		level := strings.ToLower(nagios.Status(i).String())
		nagios.Perfdata(opts.Tag+"-"+level, float64(v), "", nil, nil)
	}
	return nagios.Status(res), err
}

func main() {
	_, err := flags.Parse(&opts)

	if err != nil {
		// --help is not an error
		if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
			return
		} else {
			nagios.Exit(nagios.UNKNOWN, err.Error())
		}
	}

	state, err := ProcessLog()
	if err == nil {
		nagios.Exit(state, "")
	}
	nagios.Exit(state, err.Error())
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"fmt"
	"log"
)

var cmdUninstall = &Command{
	UsageLine: "uninstall <appid...>",
	Short:     "Uninstall an app",
}

func init() {
	cmdUninstall.Run = runUninstall
}

func runUninstall(args []string) {
	if len(args) < 1 {
		log.Fatalf("No package names given")
	}
	device := mustOneDevice()
	for _, id := range args {
		fmt.Printf("Uninstalling %s... ", id)
		if err := device.Uninstall(id); err != nil {
			fmt.Println()
			log.Fatalf("Could not uninstall %s: %v", id, err)
		}
		fmt.Println("done")
	}
}
<commit_msg>Check that app is installed before uninstalling it<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"errors"
	"fmt"
	"log"
)

var cmdUninstall = &Command{
	UsageLine: "uninstall <appid...>",
	Short:     "Uninstall an app",
}

func init() {
	cmdUninstall.Run = runUninstall
}

func runUninstall(args []string) {
	if len(args) < 1 {
		log.Fatalf("No package names given")
	}
	device := mustOneDevice()
	inst := mustInstalled(device)
	for _, id := range args {
		var err error
		fmt.Printf("Uninstalling %s... ", id)
		if _, installed := inst[id]; installed {
			err = device.Uninstall(id)
		} else {
			err = errors.New("not installed")
		}
		if err != nil {
			fmt.Println()
			log.Fatalf("Could not uninstall %s: %v", id, err)
		}
		fmt.Println("done")
	}
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/funkygao/gocli"
	"github.com/peterh/liner"
)

type Console struct {
	Ui          cli.Ui
	Cmd         string
	Cmds        map[string]cli.CommandFactory
	Line        *liner.State
	historyFile string
}

func (this *Console) Run(args []string) (exitCode int) {
	this.Line = liner.NewLiner()
	this.Line.SetCtrlCAborts(true)
	this.Line.SetCompleter(func(line string) (c []string) {
		for cmd, _ := range this.Cmds {
			if strings.HasPrefix(cmd, strings.ToLower(line)) {
				c = append(c, cmd)
			}
		}
		return
	})
	defer this.Line.Close()

	if usr, err := user.Current(); err == nil {
		this.historyFile = filepath.Join(usr.HomeDir, fmt.Sprintf(".%s_history", this.Cmd))
		if f, e := os.Open(this.historyFile); e == nil {
			this.Line.ReadHistory(f)
			f.Close()
		}
	}

	for {
		line, err := this.Line.Prompt(fmt.Sprintf("%s> ", this.Cmd))
		if err != err {
			break
		}
		line = strings.TrimSpace(line)
		if line == "" || line == "exit" {
			break
		}

		if this.runCommand(line) {
			// write out the history
			if len(this.historyFile) > 0 {
				this.Line.AppendHistory(line)
				if f, e := os.Create(this.historyFile); e == nil {
					this.Line.WriteHistory(f)
					f.Close()
				}
			}
		} else {
			break
		}
	}
	return
}

func (this *Console) runCommand(cmd string) (ok bool) {
	ok = true

	parts := strings.Split(cmd, " ")
	switch parts[0] {
	case "help":
		this.doHelp()
	case "history":
		this.doHistory()
	default:
		if _, present := this.Cmds[parts[0]]; !present {
			this.Ui.Error(fmt.Sprintf("unkown command: %s", parts[0]))
			return
		}

		cmd, _ := this.Cmds[parts[0]]()
		cmd.Run(parts)

	}

	return
}

func (this *Console) doHelp() {
	outline := ""
	width := 0
	for cmd, _ := range this.Cmds {
		outline += cmd + " "
		width += len(cmd)
		if width > 80 {
			outline += "\n"
			width = 0
		}
	}
	this.Ui.Output(outline)
}

func (this *Console) doHistory() {
	if this.historyFile == "" {
		return
	}

	if history, err := ioutil.ReadFile(this.historyFile); err == nil {
		this.Ui.Output(string(history))
	}
}

func (*Console) Synopsis() string {
	return "Interactive mode"
}

func (this *Console) Help() string {
	help := fmt.Sprintf(`
Usage: %s console [options]

	Interactive mode

`, this.Cmd)
	return strings.TrimSpace(help)
}
<commit_msg>fixed a typo<commit_after>package command

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/funkygao/gocli"
	"github.com/peterh/liner"
)

type Console struct {
	Ui          cli.Ui
	Cmd         string
	Cmds        map[string]cli.CommandFactory
	Line        *liner.State
	historyFile string
}

func (this *Console) Run(args []string) (exitCode int) {
	this.Line = liner.NewLiner()
	this.Line.SetCtrlCAborts(true)
	this.Line.SetCompleter(func(line string) (c []string) {
		for cmd, _ := range this.Cmds {
			if strings.HasPrefix(cmd, strings.ToLower(line)) {
				c = append(c, cmd)
			}
		}
		return
	})
	defer this.Line.Close()

	if usr, err := user.Current(); err == nil {
		this.historyFile = filepath.Join(usr.HomeDir, fmt.Sprintf(".%s_history", this.Cmd))
		if f, e := os.Open(this.historyFile); e == nil {
			this.Line.ReadHistory(f)
			f.Close()
		}
	}

	for {
		line, err := this.Line.Prompt(fmt.Sprintf("%s> ", this.Cmd))
		if err != err {
			break
		}
		line = strings.TrimSpace(line)
		if line == "" || line == "exit" {
			break
		}

		if this.runCommand(line) {
			// write out the history
			if len(this.historyFile) > 0 {
				this.Line.AppendHistory(line)
				if f, e := os.Create(this.historyFile); e == nil {
					this.Line.WriteHistory(f)
					f.Close()
				}
			}
		} else {
			break
		}
	}
	return
}

func (this *Console) runCommand(cmd string) (ok bool) {
	ok = true

	parts := strings.Split(cmd, " ")
	switch parts[0] {
	case "help":
		this.doHelp()
	case "history":
		this.doHistory()
	default:
		if _, present := this.Cmds[parts[0]]; !present {
			this.Ui.Error(fmt.Sprintf("unknown command: %s", parts[0]))
			return
		}

		cmd, _ := this.Cmds[parts[0]]()
		cmd.Run(parts)

	}

	return
}

func (this *Console) doHelp() {
	outline := ""
	width := 0
	for cmd, _ := range this.Cmds {
		outline += cmd + " "
		width += len(cmd)
		if width > 80 {
			outline += "\n"
			width = 0
		}
	}
	this.Ui.Output(outline)
}

func (this *Console) doHistory() {
	if this.historyFile == "" {
		return
	}

	if history, err := ioutil.ReadFile(this.historyFile); err == nil {
		this.Ui.Output(string(history))
	}
}

func (*Console) Synopsis() string {
	return "Interactive mode"
}

func (this *Console) Help() string {
	help := fmt.Sprintf(`
Usage: %s console [options]

	Interactive mode

`, this.Cmd)
	return strings.TrimSpace(help)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors 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 main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

var (
	subchart1ChartPath = "./../../pkg/chartutil/testdata/subpop/charts/subchart1"
	frobnitzChartPath  = "./../../pkg/chartutil/testdata/frobnitz"
)

func TestTemplateCmd(t *testing.T) {
	subchart1AbsChartPath, err := filepath.Abs(subchart1ChartPath)
	if err != nil {
		t.Fatal(err)
	}
	tests := []struct {
		name        string
		desc        string
		args        []string
		expectKey   string
		expectValue string
	}{
		{
			name:        "check_name",
			desc:        "check for a known name in chart",
			args:        []string{subchart1ChartPath},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: nginx",
		},
		{
			name:        "check_set_name",
			desc:        "verify --set values exist",
			args:        []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: apache",
		},
		{
			name:        "check_execute",
			desc:        "verify --execute single template",
			args:        []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: apache",
		},
		{
			name:        "check_execute_absolute",
			desc:        "verify --execute single template",
			args:        []string{subchart1ChartPath, "-x", subchart1AbsChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: apache",
		},
		{
			name:        "check_execute_subchart_template",
			desc:        "verify --execute single template on a subchart template",
			args:        []string{subchart1ChartPath, "-x", "charts/subcharta/templates/service.yaml", "--set", "subcharta.service.name=foobar"},
			expectKey:   "subchart1/charts/subcharta/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: foobar",
		},
		{
			name:        "check_execute_subchart_template_for_tgz_subchart",
			desc:        "verify --execute single template on a subchart template where the subchart is a .tgz in the chart directory",
			args:        []string{frobnitzChartPath, "-x", "charts/mariner/templates/placeholder.tpl", "--set", "mariner.name=moon"},
			expectKey:   "frobnitz/charts/mariner/templates/placeholder.tpl",
			expectValue: "Goodbye moon",
		},
		{
			name:        "check_namespace",
			desc:        "verify --namespace",
			args:        []string{subchart1ChartPath, "--namespace", "test"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "namespace: \"test\"",
		},
		{
			name:        "check_release_name",
			desc:        "verify --release exists",
			args:        []string{subchart1ChartPath, "--name", "test"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "release-name: \"test\"",
		},
		{
			name:        "check_notes",
			desc:        "verify --notes shows notes",
			args:        []string{subchart1ChartPath, "--notes", "true"},
			expectKey:   "subchart1/templates/NOTES.txt",
			expectValue: "Sample notes for subchart1",
		},
		{
			name:        "check_values_files",
			desc:        "verify --values files values exist",
			args:        []string{subchart1ChartPath, "--values", subchart1ChartPath + "/charts/subchartA/values.yaml"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "name: apache",
		},
		{
			name:        "check_name_template",
			desc:        "verify --name-template result exists",
			args:        []string{subchart1ChartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "release-name: \"foobar-YWJj-baz\"",
		},
		{
			name:        "check_kube_version",
			desc:        "verify --kube-version overrides the kubernetes version",
			args:        []string{subchart1ChartPath, "--kube-version", "1.6"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "kube-version/major: \"1\"\n    kube-version/minor: \"6\"\n    kube-version/gitversion: \"v1.6.0\"",
		},
	}

	var buf bytes.Buffer
	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			// capture stdout
			old := os.Stdout
			r, w, _ := os.Pipe()
			os.Stdout = w
			// execute template command
			out := bytes.NewBuffer(nil)
			cmd := newTemplateCmd(out)
			cmd.SetArgs(tt.args)
			err := cmd.Execute()
			if err != nil {
				t.Errorf("expected: %v, got %v", tt.expectValue, err)
			}
			// restore stdout
			w.Close()
			os.Stdout = old
			var b bytes.Buffer
			io.Copy(&b, r)
			r.Close()
			// scan yaml into map[<path>]yaml
			scanner := bufio.NewScanner(&b)
			next := false
			lastKey := ""
			m := map[string]string{}
			for scanner.Scan() {
				if scanner.Text() == "---" {
					next = true
				} else if next {
					// remove '# Source: '
					head := "# Source: "
					lastKey = scanner.Text()[len(head):]
					next = false
				} else {
					m[lastKey] = m[lastKey] + scanner.Text() + "\n"
				}
			}
			if err := scanner.Err(); err != nil {
				fmt.Fprintln(os.Stderr, "reading standard input:", err)
			}
			if v, ok := m[tt.expectKey]; ok {
				if !strings.Contains(v, tt.expectValue) {
					t.Errorf("failed to match expected value %s in %s", tt.expectValue, v)
				}
			} else {
				t.Errorf("could not find key %s", tt.expectKey)
			}
			buf.Reset()
		})
	}
}
<commit_msg>test helm template -x with non-existent manifest<commit_after>/*
Copyright 2016 The Kubernetes Authors 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 main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

var (
	subchart1ChartPath = "./../../pkg/chartutil/testdata/subpop/charts/subchart1"
	frobnitzChartPath  = "./../../pkg/chartutil/testdata/frobnitz"
)

func TestTemplateCmd(t *testing.T) {
	subchart1AbsChartPath, err := filepath.Abs(subchart1ChartPath)
	if err != nil {
		t.Fatal(err)
	}
	tests := []struct {
		name        string
		desc        string
		args        []string
		expectKey   string
		expectValue string
		expectError string
	}{
		{
			name:        "check_name",
			desc:        "check for a known name in chart",
			args:        []string{subchart1ChartPath},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: nginx",
		},
		{
			name:        "check_set_name",
			desc:        "verify --set values exist",
			args:        []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: apache",
		},
		{
			name:        "check_execute",
			desc:        "verify --execute single template",
			args:        []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: apache",
		},
		{
			name:        "check_execute_non_existent",
			desc:        "verify --execute fails on a template that doesnt exist",
			args:        []string{subchart1ChartPath, "-x", "templates/thisdoesntexist.yaml"},
			expectError: "could not find template",
		},
		{
			name:        "check_execute_absolute",
			desc:        "verify --execute single template",
			args:        []string{subchart1ChartPath, "-x", subchart1AbsChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: apache",
		},
		{
			name:        "check_execute_subchart_template",
			desc:        "verify --execute single template on a subchart template",
			args:        []string{subchart1ChartPath, "-x", "charts/subcharta/templates/service.yaml", "--set", "subcharta.service.name=foobar"},
			expectKey:   "subchart1/charts/subcharta/templates/service.yaml",
			expectValue: "protocol: TCP\n    name: foobar",
		},
		{
			name:        "check_execute_subchart_template_for_tgz_subchart",
			desc:        "verify --execute single template on a subchart template where the subchart is a .tgz in the chart directory",
			args:        []string{frobnitzChartPath, "-x", "charts/mariner/templates/placeholder.tpl", "--set", "mariner.name=moon"},
			expectKey:   "frobnitz/charts/mariner/templates/placeholder.tpl",
			expectValue: "Goodbye moon",
		},
		{
			name:        "check_namespace",
			desc:        "verify --namespace",
			args:        []string{subchart1ChartPath, "--namespace", "test"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "namespace: \"test\"",
		},
		{
			name:        "check_release_name",
			desc:        "verify --release exists",
			args:        []string{subchart1ChartPath, "--name", "test"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "release-name: \"test\"",
		},
		{
			name:        "check_notes",
			desc:        "verify --notes shows notes",
			args:        []string{subchart1ChartPath, "--notes", "true"},
			expectKey:   "subchart1/templates/NOTES.txt",
			expectValue: "Sample notes for subchart1",
		},
		{
			name:        "check_values_files",
			desc:        "verify --values files values exist",
			args:        []string{subchart1ChartPath, "--values", subchart1ChartPath + "/charts/subchartA/values.yaml"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "name: apache",
		},
		{
			name:        "check_name_template",
			desc:        "verify --name-template result exists",
			args:        []string{subchart1ChartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "release-name: \"foobar-YWJj-baz\"",
		},
		{
			name:        "check_kube_version",
			desc:        "verify --kube-version overrides the kubernetes version",
			args:        []string{subchart1ChartPath, "--kube-version", "1.6"},
			expectKey:   "subchart1/templates/service.yaml",
			expectValue: "kube-version/major: \"1\"\n    kube-version/minor: \"6\"\n    kube-version/gitversion: \"v1.6.0\"",
		},
	}

	var buf bytes.Buffer
	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			// capture stdout
			old := os.Stdout
			r, w, _ := os.Pipe()
			os.Stdout = w
			// execute template command
			out := bytes.NewBuffer(nil)
			cmd := newTemplateCmd(out)
			cmd.SetArgs(tt.args)
			err := cmd.Execute()

			if tt.expectError != "" {
				if err == nil {
					t.Errorf("expected err: %s, but no error occurred", tt.expectError)
				}
				// non nil error, check if it contains the expected error
				if strings.Contains(err.Error(), tt.expectError) {
					// had the error we were looking for, this test case is
					// done
					return
				} else {
					t.Fatalf("expected err: %q, got: %q", tt.expectError, err)
				}
			} else if err != nil {
				t.Errorf("expected no error, got %v", err)
			}
			// restore stdout
			w.Close()
			os.Stdout = old
			var b bytes.Buffer
			io.Copy(&b, r)
			r.Close()
			// scan yaml into map[<path>]yaml
			scanner := bufio.NewScanner(&b)
			next := false
			lastKey := ""
			m := map[string]string{}
			for scanner.Scan() {
				if scanner.Text() == "---" {
					next = true
				} else if next {
					// remove '# Source: '
					head := "# Source: "
					lastKey = scanner.Text()[len(head):]
					next = false
				} else {
					m[lastKey] = m[lastKey] + scanner.Text() + "\n"
				}
			}
			if err := scanner.Err(); err != nil {
				fmt.Fprintln(os.Stderr, "reading standard input:", err)
			}
			if v, ok := m[tt.expectKey]; ok {
				if !strings.Contains(v, tt.expectValue) {
					t.Errorf("failed to match expected value %s in %s", tt.expectValue, v)
				}
			} else {
				t.Errorf("could not find key %s", tt.expectKey)
			}
			buf.Reset()
		})
	}
}
<|endoftext|>


<commit_before>package run

import (
	"fmt"
	"net"
	"time"

	"github.com/influxdb/influxdb/cluster"
	"github.com/influxdb/influxdb/meta"
	"github.com/influxdb/influxdb/services/admin"
	"github.com/influxdb/influxdb/services/collectd"
	"github.com/influxdb/influxdb/services/continuous_querier"
	"github.com/influxdb/influxdb/services/graphite"
	"github.com/influxdb/influxdb/services/hh"
	"github.com/influxdb/influxdb/services/httpd"
	"github.com/influxdb/influxdb/services/opentsdb"
	"github.com/influxdb/influxdb/services/retention"
	"github.com/influxdb/influxdb/services/udp"
	"github.com/influxdb/influxdb/tcp"
	"github.com/influxdb/influxdb/tsdb"
)

// Server represents a container for the metadata and storage data and services.
// It is built using a Config and it manages the startup and shutdown of all
// services in the proper order.
type Server struct {
	err     chan error
	closing chan struct{}

	Hostname    string
	BindAddress string
	Listener    net.Listener

	MetaStore     *meta.Store
	TSDBStore     *tsdb.Store
	QueryExecutor *tsdb.QueryExecutor
	PointsWriter  *cluster.PointsWriter
	ShardWriter   *cluster.ShardWriter
	HintedHandoff *hh.Service

	Services []Service
}

// NewServer returns a new instance of Server built from a config.
func NewServer(c *Config) *Server {
	// Construct base meta store and data store.
	s := &Server{
		err:     make(chan error),
		closing: make(chan struct{}),

		Hostname:    c.Meta.Hostname,
		BindAddress: c.Meta.BindAddress,

		MetaStore: meta.NewStore(c.Meta),
		TSDBStore: tsdb.NewStore(c.Data.Dir),
	}

	// Initialize query executor.
	s.QueryExecutor = tsdb.NewQueryExecutor(s.TSDBStore)
	s.QueryExecutor.MetaStore = s.MetaStore
	s.QueryExecutor.MetaStatementExecutor = &meta.StatementExecutor{Store: s.MetaStore}

	// Set the shard writer
	s.ShardWriter = cluster.NewShardWriter(time.Duration(c.Cluster.ShardWriterTimeout))
	s.ShardWriter.MetaStore = s.MetaStore

	// Create the hinted handoff service
	s.HintedHandoff = hh.NewService(c.HintedHandoff, s.ShardWriter)

	// Initialize points writer.
	s.PointsWriter = cluster.NewPointsWriter()
	s.PointsWriter.MetaStore = s.MetaStore
	s.PointsWriter.TSDBStore = s.TSDBStore
	s.PointsWriter.ShardWriter = s.ShardWriter
	s.PointsWriter.HintedHandoff = s.HintedHandoff

	// Append services.
	s.appendClusterService(c.Cluster)
	s.appendAdminService(c.Admin)
	s.appendContinuousQueryService(c.ContinuousQuery)
	s.appendHTTPDService(c.HTTPD)
	s.appendCollectdService(c.Collectd)
	s.appendOpenTSDBService(c.OpenTSDB)
	s.appendUDPService(c.UDP)
	s.appendRetentionPolicyService(c.Retention)
	for _, g := range c.Graphites {
		s.appendGraphiteService(g)
	}

	return s
}

func (s *Server) appendClusterService(c cluster.Config) {
	srv := cluster.NewService(c)
	srv.TSDBStore = s.TSDBStore
	srv.MetaStore = s.MetaStore
	s.Services = append(s.Services, srv)
}

func (s *Server) appendRetentionPolicyService(c retention.Config) {
	if !c.Enabled {
		return
	}
	srv := retention.NewService(c)
	srv.MetaStore = s.MetaStore
	srv.TSDBStore = s.TSDBStore
	s.Services = append(s.Services, srv)
}

func (s *Server) appendAdminService(c admin.Config) {
	if !c.Enabled {
		return
	}
	srv := admin.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendHTTPDService(c httpd.Config) {
	if !c.Enabled {
		return
	}
	srv := httpd.NewService(c)
	srv.Handler.MetaStore = s.MetaStore
	srv.Handler.QueryExecutor = s.QueryExecutor
	srv.Handler.PointsWriter = s.PointsWriter

	// If a ContinuousQuerier service has been started, attach it.
	for _, srvc := range s.Services {
		if cqsrvc, ok := srvc.(continuous_querier.ContinuousQuerier); ok {
			srv.Handler.ContinuousQuerier = cqsrvc
		}
	}

	s.Services = append(s.Services, srv)
}

func (s *Server) appendCollectdService(c collectd.Config) {
	if !c.Enabled {
		return
	}
	srv := collectd.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendOpenTSDBService(c opentsdb.Config) {
	if !c.Enabled {
		return
	}
	srv := opentsdb.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendGraphiteService(c graphite.Config) {
	if !c.Enabled {
		return
	}
	srv := graphite.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendUDPService(c udp.Config) {
	if !c.Enabled {
		return
	}
	srv := udp.NewService(c)
	srv.PointsWriter = s.PointsWriter
}

func (s *Server) appendContinuousQueryService(c continuous_querier.Config) {
	if !c.Enabled {
		return
	}
	srv := continuous_querier.NewService(c)
	srv.MetaStore = s.MetaStore
	srv.QueryExecutor = s.QueryExecutor
	srv.PointsWriter = s.PointsWriter
	s.Services = append(s.Services, srv)
}

// Err returns an error channel that multiplexes all out of band errors received from all services.
func (s *Server) Err() <-chan error { return s.err }

// Open opens the meta and data store and all services.
func (s *Server) Open() error {
	if err := func() error {
		// Resolve host to address.
		_, port, err := net.SplitHostPort(s.BindAddress)
		if err != nil {
			return fmt.Errorf("split bind address: %s", err)
		}
		hostport := net.JoinHostPort(s.Hostname, port)
		addr, err := net.ResolveTCPAddr("tcp", hostport)
		if err != nil {
			return fmt.Errorf("resolve tcp: addr=%s, err=%s", hostport, err)
		}
		s.MetaStore.Addr = addr

		// Open shared TCP connection.
		ln, err := net.Listen("tcp", s.BindAddress)
		if err != nil {
			return fmt.Errorf("listen: %s", err)
		}
		s.Listener = ln

		// Multiplex listener.
		mux := tcp.NewMux()
		s.MetaStore.RaftListener = mux.Listen(meta.MuxRaftHeader)
		s.MetaStore.ExecListener = mux.Listen(meta.MuxExecHeader)
		s.Services[0].(*cluster.Service).Listener = mux.Listen(cluster.MuxHeader)
		go mux.Serve(ln)

		// Open meta store.
		if err := s.MetaStore.Open(); err != nil {
			return fmt.Errorf("open meta store: %s", err)
		}
		go s.monitorErrorChan(s.MetaStore.Err())

		// Wait for the store to initialize.
		<-s.MetaStore.Ready()

		// Open TSDB store.
		if err := s.TSDBStore.Open(); err != nil {
			return fmt.Errorf("open tsdb store: %s", err)
		}

		// Open the hinted handoff service
		if err := s.HintedHandoff.Open(); err != nil {
			return fmt.Errorf("open hinted handoff: %s", err)
		}

		for _, service := range s.Services {
			if err := service.Open(); err != nil {
				return fmt.Errorf("open service: %s", err)
			}
		}

		return nil

	}(); err != nil {
		s.Close()
		return err
	}

	return nil
}

// Close shuts down the meta and data stores and all services.
func (s *Server) Close() error {
	if s.Listener != nil {
		s.Listener.Close()
	}
	if s.MetaStore != nil {
		s.MetaStore.Close()
	}
	if s.TSDBStore != nil {
		s.TSDBStore.Close()
	}
	if s.HintedHandoff != nil {
		s.HintedHandoff.Close()
	}
	for _, service := range s.Services {
		service.Close()
	}
	close(s.closing)
	return nil
}

// monitorErrorChan reads an error channel and resends it through the server.
func (s *Server) monitorErrorChan(ch <-chan error) {
	for {
		select {
		case err, ok := <-ch:
			if !ok {
				return
			}
			s.err <- err
		case <-s.closing:
			return
		}
	}
}

// Service represents a service attached to the server.
type Service interface {
	Open() error
	Close() error
}
<commit_msg>Fix UDP service, broken by 092bc3f and uncorrectly fixed in cc78fe4<commit_after>package run

import (
	"fmt"
	"net"
	"time"

	"github.com/influxdb/influxdb/cluster"
	"github.com/influxdb/influxdb/meta"
	"github.com/influxdb/influxdb/services/admin"
	"github.com/influxdb/influxdb/services/collectd"
	"github.com/influxdb/influxdb/services/continuous_querier"
	"github.com/influxdb/influxdb/services/graphite"
	"github.com/influxdb/influxdb/services/hh"
	"github.com/influxdb/influxdb/services/httpd"
	"github.com/influxdb/influxdb/services/opentsdb"
	"github.com/influxdb/influxdb/services/retention"
	"github.com/influxdb/influxdb/services/udp"
	"github.com/influxdb/influxdb/tcp"
	"github.com/influxdb/influxdb/tsdb"
)

// Server represents a container for the metadata and storage data and services.
// It is built using a Config and it manages the startup and shutdown of all
// services in the proper order.
type Server struct {
	err     chan error
	closing chan struct{}

	Hostname    string
	BindAddress string
	Listener    net.Listener

	MetaStore     *meta.Store
	TSDBStore     *tsdb.Store
	QueryExecutor *tsdb.QueryExecutor
	PointsWriter  *cluster.PointsWriter
	ShardWriter   *cluster.ShardWriter
	HintedHandoff *hh.Service

	Services []Service
}

// NewServer returns a new instance of Server built from a config.
func NewServer(c *Config) *Server {
	// Construct base meta store and data store.
	s := &Server{
		err:     make(chan error),
		closing: make(chan struct{}),

		Hostname:    c.Meta.Hostname,
		BindAddress: c.Meta.BindAddress,

		MetaStore: meta.NewStore(c.Meta),
		TSDBStore: tsdb.NewStore(c.Data.Dir),
	}

	// Initialize query executor.
	s.QueryExecutor = tsdb.NewQueryExecutor(s.TSDBStore)
	s.QueryExecutor.MetaStore = s.MetaStore
	s.QueryExecutor.MetaStatementExecutor = &meta.StatementExecutor{Store: s.MetaStore}

	// Set the shard writer
	s.ShardWriter = cluster.NewShardWriter(time.Duration(c.Cluster.ShardWriterTimeout))
	s.ShardWriter.MetaStore = s.MetaStore

	// Create the hinted handoff service
	s.HintedHandoff = hh.NewService(c.HintedHandoff, s.ShardWriter)

	// Initialize points writer.
	s.PointsWriter = cluster.NewPointsWriter()
	s.PointsWriter.MetaStore = s.MetaStore
	s.PointsWriter.TSDBStore = s.TSDBStore
	s.PointsWriter.ShardWriter = s.ShardWriter
	s.PointsWriter.HintedHandoff = s.HintedHandoff

	// Append services.
	s.appendClusterService(c.Cluster)
	s.appendAdminService(c.Admin)
	s.appendContinuousQueryService(c.ContinuousQuery)
	s.appendHTTPDService(c.HTTPD)
	s.appendCollectdService(c.Collectd)
	s.appendOpenTSDBService(c.OpenTSDB)
	s.appendUDPService(c.UDP)
	s.appendRetentionPolicyService(c.Retention)
	for _, g := range c.Graphites {
		s.appendGraphiteService(g)
	}

	return s
}

func (s *Server) appendClusterService(c cluster.Config) {
	srv := cluster.NewService(c)
	srv.TSDBStore = s.TSDBStore
	srv.MetaStore = s.MetaStore
	s.Services = append(s.Services, srv)
}

func (s *Server) appendRetentionPolicyService(c retention.Config) {
	if !c.Enabled {
		return
	}
	srv := retention.NewService(c)
	srv.MetaStore = s.MetaStore
	srv.TSDBStore = s.TSDBStore
	s.Services = append(s.Services, srv)
}

func (s *Server) appendAdminService(c admin.Config) {
	if !c.Enabled {
		return
	}
	srv := admin.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendHTTPDService(c httpd.Config) {
	if !c.Enabled {
		return
	}
	srv := httpd.NewService(c)
	srv.Handler.MetaStore = s.MetaStore
	srv.Handler.QueryExecutor = s.QueryExecutor
	srv.Handler.PointsWriter = s.PointsWriter

	// If a ContinuousQuerier service has been started, attach it.
	for _, srvc := range s.Services {
		if cqsrvc, ok := srvc.(continuous_querier.ContinuousQuerier); ok {
			srv.Handler.ContinuousQuerier = cqsrvc
		}
	}

	s.Services = append(s.Services, srv)
}

func (s *Server) appendCollectdService(c collectd.Config) {
	if !c.Enabled {
		return
	}
	srv := collectd.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendOpenTSDBService(c opentsdb.Config) {
	if !c.Enabled {
		return
	}
	srv := opentsdb.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendGraphiteService(c graphite.Config) {
	if !c.Enabled {
		return
	}
	srv := graphite.NewService(c)
	s.Services = append(s.Services, srv)
}

func (s *Server) appendUDPService(c udp.Config) {
	if !c.Enabled {
		return
	}
	srv := udp.NewService(c)
	srv.PointsWriter = s.PointsWriter
	s.Services = append(s.Services, srv)
}

func (s *Server) appendContinuousQueryService(c continuous_querier.Config) {
	if !c.Enabled {
		return
	}
	srv := continuous_querier.NewService(c)
	srv.MetaStore = s.MetaStore
	srv.QueryExecutor = s.QueryExecutor
	srv.PointsWriter = s.PointsWriter
	s.Services = append(s.Services, srv)
}

// Err returns an error channel that multiplexes all out of band errors received from all services.
func (s *Server) Err() <-chan error { return s.err }

// Open opens the meta and data store and all services.
func (s *Server) Open() error {
	if err := func() error {
		// Resolve host to address.
		_, port, err := net.SplitHostPort(s.BindAddress)
		if err != nil {
			return fmt.Errorf("split bind address: %s", err)
		}
		hostport := net.JoinHostPort(s.Hostname, port)
		addr, err := net.ResolveTCPAddr("tcp", hostport)
		if err != nil {
			return fmt.Errorf("resolve tcp: addr=%s, err=%s", hostport, err)
		}
		s.MetaStore.Addr = addr

		// Open shared TCP connection.
		ln, err := net.Listen("tcp", s.BindAddress)
		if err != nil {
			return fmt.Errorf("listen: %s", err)
		}
		s.Listener = ln

		// Multiplex listener.
		mux := tcp.NewMux()
		s.MetaStore.RaftListener = mux.Listen(meta.MuxRaftHeader)
		s.MetaStore.ExecListener = mux.Listen(meta.MuxExecHeader)
		s.Services[0].(*cluster.Service).Listener = mux.Listen(cluster.MuxHeader)
		go mux.Serve(ln)

		// Open meta store.
		if err := s.MetaStore.Open(); err != nil {
			return fmt.Errorf("open meta store: %s", err)
		}
		go s.monitorErrorChan(s.MetaStore.Err())

		// Wait for the store to initialize.
		<-s.MetaStore.Ready()

		// Open TSDB store.
		if err := s.TSDBStore.Open(); err != nil {
			return fmt.Errorf("open tsdb store: %s", err)
		}

		// Open the hinted handoff service
		if err := s.HintedHandoff.Open(); err != nil {
			return fmt.Errorf("open hinted handoff: %s", err)
		}

		for _, service := range s.Services {
			if err := service.Open(); err != nil {
				return fmt.Errorf("open service: %s", err)
			}
		}

		return nil

	}(); err != nil {
		s.Close()
		return err
	}

	return nil
}

// Close shuts down the meta and data stores and all services.
func (s *Server) Close() error {
	if s.Listener != nil {
		s.Listener.Close()
	}
	if s.MetaStore != nil {
		s.MetaStore.Close()
	}
	if s.TSDBStore != nil {
		s.TSDBStore.Close()
	}
	if s.HintedHandoff != nil {
		s.HintedHandoff.Close()
	}
	for _, service := range s.Services {
		service.Close()
	}
	close(s.closing)
	return nil
}

// monitorErrorChan reads an error channel and resends it through the server.
func (s *Server) monitorErrorChan(ch <-chan error) {
	for {
		select {
		case err, ok := <-ch:
			if !ok {
				return
			}
			s.err <- err
		case <-s.closing:
			return
		}
	}
}

// Service represents a service attached to the server.
type Service interface {
	Open() error
	Close() error
}
<|endoftext|>


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

package cmd

import (
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/guacsec/guac/pkg/assembler"
	"github.com/guacsec/guac/pkg/assembler/graphdb"
	"github.com/guacsec/guac/pkg/handler/processor"
	"github.com/guacsec/guac/pkg/ingestor/parser"
	"github.com/guacsec/guac/pkg/logging"
	"github.com/spf13/cobra"
)

var flags = struct {
	dbAddr string
	creds  string
	realm  string
}{}

type options struct {
	dbAddr string
	user   string
	pass   string
	realm  string
}

var docs []processor.DocumentTree

func init() {
	exampleCmd.PersistentFlags().StringVar(&flags.dbAddr, "db-addr", "neo4j://localhost:7687", "address to neo4j db")
	exampleCmd.PersistentFlags().StringVar(&flags.creds, "creds", "", "credentials to access neo4j in 'user:pass' format")
	exampleCmd.PersistentFlags().StringVar(&flags.realm, "realm", "neo4j", "realm to connecto graph db")
	exampleCmd.MarkPersistentFlagRequired("creds")
}

var exampleCmd = &cobra.Command{
	Use:   "example",
	Short: "example ingestor for ingesting a set of example documents and populating a graph for GUAC",
	Run: func(cmd *cobra.Command, args []string) {
		ctx := logging.WithLogger(context.Background())
		logger := logging.FromContext(ctx)

		opts, err := validateFlags()
		if err != nil {
			logger.Errorf("unable to validate flags: %v", err)
			os.Exit(1)
		}

		// Access graphDB

		authToken := graphdb.CreateAuthTokenWithUsernameAndPassword(opts.user, opts.pass, opts.realm)
		client, err := graphdb.NewGraphClient(opts.dbAddr, authToken)
		if err != nil {
			logger.Errorf("unable to initialize graph client: %v", err)
			os.Exit(1)
		}

		// Parse sample documents
		g := assembler.Graph{
			Nodes: []assembler.GuacNode{},
			Edges: []assembler.GuacEdge{},
		}
		for _, doc := range docs {
			inputs, err := parser.ParseDocumentTree(doc)
			if err != nil {
				logger.Errorf("unable to parse document: %v", err)
				os.Exit(1)
			}

			g.AppendGraph(inputs...)
		}
		logger.Infof("graph nodes: %v, edges: %v", len(g.Nodes), len(g.Edges))

		if err := assembler.StoreGraph(g, client); err != nil {
			logger.Errorf("unable to store graph: %v", err)
			os.Exit(1)
		}
	},
}

func validateFlags() (options, error) {
	var opts options
	credsSplit := strings.Split(flags.creds, ":")
	if len(credsSplit) != 2 {
		return opts, fmt.Errorf("creds flag not in correct format user:pass")
	}
	opts.user = credsSplit[0]
	opts.pass = credsSplit[1]
	opts.dbAddr = flags.dbAddr

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

package cmd

import (
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/guacsec/guac/pkg/assembler"
	"github.com/guacsec/guac/pkg/assembler/graphdb"
	"github.com/guacsec/guac/pkg/handler/processor"
	"github.com/guacsec/guac/pkg/ingestor/parser"
	"github.com/guacsec/guac/pkg/logging"
	"github.com/spf13/cobra"
)

var flags = struct {
	dbAddr string
	creds  string
	realm  string
}{}

type options struct {
	dbAddr string
	user   string
	pass   string
	realm  string
}

var docs []processor.DocumentTree

func init() {
	exampleCmd.PersistentFlags().StringVar(&flags.dbAddr, "db-addr", "neo4j://localhost:7687", "address to neo4j db")
	exampleCmd.PersistentFlags().StringVar(&flags.creds, "creds", "", "credentials to access neo4j in 'user:pass' format")
	exampleCmd.PersistentFlags().StringVar(&flags.realm, "realm", "neo4j", "realm to connecto graph db")
	_ = exampleCmd.MarkPersistentFlagRequired("creds")
}

var exampleCmd = &cobra.Command{
	Use:   "example",
	Short: "example ingestor for ingesting a set of example documents and populating a graph for GUAC",
	Run: func(cmd *cobra.Command, args []string) {
		ctx := logging.WithLogger(context.Background())
		logger := logging.FromContext(ctx)

		opts, err := validateFlags()
		if err != nil {
			logger.Errorf("unable to validate flags: %v", err)
			os.Exit(1)
		}

		// Access graphDB

		authToken := graphdb.CreateAuthTokenWithUsernameAndPassword(opts.user, opts.pass, opts.realm)
		client, err := graphdb.NewGraphClient(opts.dbAddr, authToken)
		if err != nil {
			logger.Errorf("unable to initialize graph client: %v", err)
			os.Exit(1)
		}

		// Parse sample documents
		g := assembler.Graph{
			Nodes: []assembler.GuacNode{},
			Edges: []assembler.GuacEdge{},
		}
		for _, doc := range docs {
			inputs, err := parser.ParseDocumentTree(doc)
			if err != nil {
				logger.Errorf("unable to parse document: %v", err)
				os.Exit(1)
			}

			g.AppendGraph(inputs...)
		}
		logger.Infof("graph nodes: %v, edges: %v", len(g.Nodes), len(g.Edges))

		if err := assembler.StoreGraph(g, client); err != nil {
			logger.Errorf("unable to store graph: %v", err)
			os.Exit(1)
		}
	},
}

func validateFlags() (options, error) {
	var opts options
	credsSplit := strings.Split(flags.creds, ":")
	if len(credsSplit) != 2 {
		return opts, fmt.Errorf("creds flag not in correct format user:pass")
	}
	opts.user = credsSplit[0]
	opts.pass = credsSplit[1]
	opts.dbAddr = flags.dbAddr

	return opts, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	log "github.com/sirupsen/logrus"
	"time"

	"github.com/grafana/metrictank/schema"
)

func produceArtificialMetrics(schemas []*schema.MetricData) {
	for tick := range time.NewTicker(artificialMetricsInterval).C {
		for _, metric := range schemas {
			metric.Time = tick.Unix()
			metric.Value = float64(tick.Unix())
		}
		gateway.Flush(schemas)
		log.Infof("flushed schemas for ts %d", tick.Unix())
	}
}

//generateSchemas generates a MetricData that hashes to each of numPartitions partitions
func generateSchemas(numPartitions int32) []*schema.MetricData {
	var metrics []*schema.MetricData
	for i := int32(0); i < numPartitions; i++ {
		metrics = append(metrics, generateSchema(i))
	}
	return metrics
}

//generateSchema generates a single MetricData that hashes to the given partition
func generateSchema(desiredPartition int32) *schema.MetricData {
	metric := schema.MetricData{
		OrgId:    orgId,
		Unit:     "partyparrots",
		Mtype:    "gauge",
		Interval: int(artificialMetricsInterval.Seconds()),
	}

	for i := 1; true; i++ {
		metric.Name = fmt.Sprintf("parrot.testdata.%d.generated.%s", desiredPartition, generatePartitionSuffix(i))
		id, err := metric.PartitionID(partitionMethod, partitionCount)
		if err != nil {
			log.Fatal(err)
		}
		if id == desiredPartition {
			log.Infof("metric for partition %d: %s", desiredPartition, metric.Name)
			return &metric
		}
	}
	return nil
}

var alphabet = []rune("abcdefghijklmnopqrstuvwxyz")

//generatePartitionSuffix deterministically generates a suffix for partition by brute force
func generatePartitionSuffix(i int) string {
	if i == 0 {
		return ""
	}
	return generatePartitionSuffix(i/26) + string(alphabet[i%26])
}
<commit_msg>tweak parition suffix generation function<commit_after>package main

import (
	"fmt"
	log "github.com/sirupsen/logrus"
	"time"

	"github.com/grafana/metrictank/schema"
)

func produceArtificialMetrics(schemas []*schema.MetricData) {
	for tick := range time.NewTicker(artificialMetricsInterval).C {
		for _, metric := range schemas {
			metric.Time = tick.Unix()
			metric.Value = float64(tick.Unix())
		}
		gateway.Flush(schemas)
		log.Infof("flushed schemas for ts %d", tick.Unix())
	}
}

//generateSchemas generates a MetricData that hashes to each of numPartitions partitions
func generateSchemas(numPartitions int32) []*schema.MetricData {
	var metrics []*schema.MetricData
	for i := int32(0); i < numPartitions; i++ {
		metrics = append(metrics, generateSchema(i))
	}
	return metrics
}

//generateSchema generates a single MetricData that hashes to the given partition
func generateSchema(desiredPartition int32) *schema.MetricData {
	metric := schema.MetricData{
		OrgId:    orgId,
		Unit:     "partyparrots",
		Mtype:    "gauge",
		Interval: int(artificialMetricsInterval.Seconds()),
	}

	for i := 1; true; i++ {
		metric.Name = fmt.Sprintf("parrot.testdata.%d.generated.%s", desiredPartition, generatePartitionSuffix(i))
		id, err := metric.PartitionID(partitionMethod, partitionCount)
		if err != nil {
			log.Fatal(err)
		}
		if id == desiredPartition {
			log.Infof("metric for partition %d: %s", desiredPartition, metric.Name)
			return &metric
		}
	}
	return nil
}

var alphabet = []rune("abcdefghijklmnopqrstuvwxyz")

//generatePartitionSuffix deterministically generates a suffix for partition by brute force
func generatePartitionSuffix(i int) string {
	if i > 25 {
		return generatePartitionSuffix((i/26)-1) + string(alphabet[i%26])
	}
	return string(alphabet[i%26])
}
<|endoftext|>