<commit_before>// Copyright 2016 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 main

import (
	"database/sql"
	"regexp"
	"sync"
	"time"

	pbinlog "github.com/cwen0/cdb-syncer/protocol"
	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/siddontang/go/sync2"
	"golang.org/x/net/context"
)

var (
	maxRetryCount = 100

	retryTimeout = 3 * time.Second
	waitTime     = 10 * time.Millisecond
	maxWaitTime  = 3 * time.Second
	eventTimeout = 3 * time.Second
	statusTime   = 30 * time.Second
)

// Syncer can sync your MySQL data into another MySQL database.
type Syncer struct {
	sync.Mutex

	cfg *Config

	meta Meta

	syncer *BinlogSyncer

	wg    sync.WaitGroup
	jobWg sync.WaitGroup

	toDBs []*sql.DB

	done chan struct{}
	jobs []chan *job

	closed sync2.AtomicBool

	start    time.Time
	lastTime time.Time

	ddlCount    sync2.AtomicInt64
	insertCount sync2.AtomicInt64
	updateCount sync2.AtomicInt64
	deleteCount sync2.AtomicInt64
	lastCount   sync2.AtomicInt64
	count       sync2.AtomicInt64
	ctx         context.Context
	cancel      context.CancelFunc
	reMap       map[string]*regexp.Regexp
}

// NewSyncer creates a new Syncer.
func NewSyncer(cfg *Config) *Syncer {
	syncer := new(Syncer)
	syncer.cfg = cfg
	syncer.meta = NewLocalMeta(cfg.Meta)
	syncer.closed.Set(false)
	syncer.lastCount.Set(0)
	syncer.count.Set(0)
	syncer.insertCount.Set(0)
	syncer.updateCount.Set(0)
	syncer.deleteCount.Set(0)
	syncer.done = make(chan struct{})
	syncer.jobs = newJobChans(cfg.WorkerCount)
	syncer.reMap = make(map[string]*regexp.Regexp)
	syncer.ctx, syncer.cancel = context.WithCancel(context.Background())
	return syncer
}

func newJobChans(count int) []chan *job {
	jobs := make([]chan *job, 0, count)
	for i := 0; i < count; i++ {
		jobs = append(jobs, make(chan *job, 1000))
	}

	return jobs
}

func closeJobChans(jobs []chan *job) {
	for _, ch := range jobs {
		close(ch)
	}
}

// Start starts syncer.
func (s *Syncer) Start() error {
	err := s.meta.Load()
	if err != nil {
		return errors.Trace(err)
	}

	s.wg.Add(1)

	err = s.run()
	if err != nil {
		return errors.Trace(err)
	}

	s.done <- struct{}{}

	return nil
}

func (s *Syncer) addCount(tp pbinlog.BinlogType, n int64) {
	switch tp {
	case pbinlog.BinlogType_INSERT:
		s.insertCount.Add(n)
	case pbinlog.BinlogType_UPDATE:
		s.updateCount.Add(n)
	case pbinlog.BinlogType_DELETE:
		s.deleteCount.Add(n)
	case pbinlog.BinlogType_DDL:
		s.ddlCount.Add(n)
	}

	s.count.Add(n)
}

func (s *Syncer) checkWait(job *job) bool {
	if job.tp == pbinlog.BinlogType_DDL {
		return true
	}

	if s.meta.Check() {
		return true
	}

	return false
}

func (s *Syncer) addJob(job *job) error {
	s.jobWg.Add(1)

	log.Debugf("add job [sql]%s; [position]%v", job.sql, job.pos)
	idx := int(genHashKey(job.key)) % s.cfg.WorkerCount
	s.jobs[idx] <- job

	wait := s.checkWait(job)
	if wait {
		s.jobWg.Wait()
		err := s.meta.Save(job.pos, true)
		if err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

func (s *Syncer) sync(db *sql.DB, jobChan chan *job) {
	defer s.wg.Done()

	idx := 0
	count := s.cfg.Batch
	sqls := make([]string, 0, count)
	args := make([][]interface{}, 0, count)
	lastSyncTime := time.Now()
	tpCnt := make(map[pbinlog.BinlogType]int64)

	clearF := func() {
		for i := 0; i < idx; i++ {
			s.jobWg.Done()
		}

		idx = 0
		sqls = sqls[0:0]
		args = args[0:0]
		lastSyncTime = time.Now()
		for tpName, v := range tpCnt {
			s.addCount(tpName, v)
			tpCnt[tpName] = 0
		}
	}

	var err error
	for {
		select {
		case job, ok := <-jobChan:
			if !ok {
				return
			}
			idx++

			if job.tp == pbinlog.BinlogType_DDL {
				err = executeSQL(db, sqls, args, true)
				if err != nil {
					log.Fatalf(errors.ErrorStack(err))
				}

				err = executeSQL(db, []string{job.sql}, [][]interface{}{job.args}, false)
				if err != nil {
					if !ignoreDDLError(err) {
						log.Fatalf(errors.ErrorStack(err))
					} else {
						log.Warnf("[ignore ddl error][sql]%s[args]%v[error]%v", job.sql, job.args, err)
					}
				}

				tpCnt[job.tp]++
				clearF()

			} else {
				sqls = append(sqls, job.sql)
				args = append(args, job.args)
				tpCnt[job.tp]++
			}

			if idx >= count {
				err = executeSQL(db, sqls, args, true)
				if err != nil {
					log.Fatalf(errors.ErrorStack(err))
				}
				clearF()
			}

		default:
			now := time.Now()
			if now.Sub(lastSyncTime) >= maxWaitTime {
				err = executeSQL(db, sqls, args, true)
				if err != nil {
					log.Fatalf(errors.ErrorStack(err))
				}
				clearF()
			}

			time.Sleep(waitTime)
		}
	}
}

func (s *Syncer) run() error {
	defer s.wg.Done()
	cfg := BinlogSyncerConfig{
		BinlogPath:    s.cfg.BinlogPath,
		BinlogNamePre: s.cfg.BinlogNamePre,
	}

	var err error

	s.syncer = NewBinlogSyncer(&cfg)

	s.toDBs, err = createDBs(s.cfg.To, s.cfg.WorkerCount+1)
	if err != nil {
		return errors.Trace(err)
	}

	s.genRegexMap()

	s.start = time.Now()
	s.lastTime = s.start
	s.wg.Add(s.cfg.WorkerCount)
	for i := 0; i < s.cfg.WorkerCount; i++ {
		go s.sync(s.toDBs[i], s.jobs[i])
	}

	s.wg.Add(1)
	go s.printStatus()

	pos := s.meta.Pos()
	s.syncer.Start(pos)
	for {
		ctx, cancel := context.WithTimeout(s.ctx, eventTimeout)
		binlog, pos, err := s.syncer.GetBinlogs(ctx)
		cancel()
		if err == context.Canceled {
			log.Infof("ready to quit! [%v]", pos)
			return nil
		} else if err == context.DeadlineExceeded {
			continue
		}

		if err != nil {
			return errors.Trace(err)
		}
		switch binlog.GetType() {
		case pbinlog.BinlogType_INSERT:
			sql, pKey, args, err := genInsertSQL(binlog)
			if err != nil {
				return errors.Errorf("gen insert sql failed: %v , DB: %s, table: %s", err, binlog.GetDbName(), binlog.GetTableName())
			}
			if s.skipRowEvent(sql, binlog.GetDbName()) {
				log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
				continue
			}
			job := newJob(pbinlog.BinlogType_INSERT, sql, args, pKey, true, pos)
			err = s.addJob(job)
			if err != nil {
				return errors.Trace(err)
			}
		case pbinlog.BinlogType_UPDATE:
			sql, pKey, args, err := genUpdateSQL(binlog)
			if err != nil {
				return errors.Errorf("gen update sql failed: %v , DB: %s, table: %s", err, binlog.GetDbName(), binlog.GetTableName())
			}
			if s.skipRowEvent(sql, binlog.GetDbName()) {
				log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
				continue
			}
			job := newJob(pbinlog.BinlogType_UPDATE, sql, args, pKey, true, pos)
			err = s.addJob(job)
			if err != nil {
				return errors.Trace(err)
			}
		case pbinlog.BinlogType_DELETE:
			sql, pKey, args, err := genDeleteSQL(binlog)
			if err != nil {
				return errors.Errorf("gen delete sql failed: %v , DB: %s, table: %s", err, binlog.GetDbName(), binlog.GetTableName())
			}
			if s.skipRowEvent(sql, binlog.GetDbName()) {
				log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
				continue
			}
			job := newJob(pbinlog.BinlogType_DELETE, sql, args, pKey, true, pos)
			err = s.addJob(job)
			if err != nil {
				return errors.Trace(err)
			}
		case pbinlog.BinlogType_DDL:
			sqls, pKey, args, err := genDdlSQL(binlog)
			if err != nil {
				return errors.Errorf("gen ddl sql failed: %v", err)
			}
			for _, sql := range sqls {
				if s.skipRowEvent(sql, binlog.GetDbName()) {
					log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
					continue
				}
				if s.skipQueryDDL(sql, binlog.GetDbName()) {
					log.Warnf("[skip query-ddl-sql]%s  [schema]:%s", sql, binlog.GetDbName())
					continue
				}
				s.jobWg.Wait()
				job := newJob(pbinlog.BinlogType_DDL, sql, args, pKey, false, pos)
				err = s.addJob(job)
				if err != nil {
					return errors.Trace(err)
				}
			}
		default:
			break
		}
	}
}

func (s *Syncer) printStatus() {
	defer s.wg.Done()

	timer := time.NewTicker(statusTime)
	defer timer.Stop()

	for {
		select {
		case <-s.ctx.Done():
			return
		case <-timer.C:
			now := time.Now()
			seconds := now.Unix() - s.lastTime.Unix()
			totalSeconds := now.Unix() - s.start.Unix()
			last := s.lastCount.Get()
			total := s.count.Get()

			tps, totalTps := int64(0), int64(0)
			if seconds > 0 {
				tps = (total - last) / seconds
				totalTps = total / totalSeconds
			}

			log.Infof("[syncer]total events = %d, insert = %d, update = %d, delete = %d, total tps = %d, recent tps = %d, %s.",
				total, s.insertCount.Get(), s.updateCount.Get(), s.deleteCount.Get(), totalTps, tps, s.meta)

			s.lastCount.Set(total)
			s.lastTime = time.Now()
		}
	}
}

func (s *Syncer) isClosed() bool {
	return s.closed.Get()
}

// Close closes syncer.
func (s *Syncer) Close() {
	s.Lock()
	defer s.Unlock()

	if s.isClosed() {
		return
	}

	s.cancel()

	<-s.done

	closeJobChans(s.jobs)
	s.wg.Wait()

	closeDBs(s.toDBs...)

	if s.syncer != nil {
		s.syncer = nil
	}

	s.closed.Set(true)
}

func (s *Syncer) genRegexMap() {
	for _, db := range s.cfg.DoDBs {
		if db[0] != '~' {
			continue
		}
		if _, ok := s.reMap[db]; !ok {
			s.reMap[db] = regexp.MustCompile(db[1:])
		}
	}

	for _, db := range s.cfg.IgnoreDBs {
		if db[0] != '~' {
			continue
		}
		if _, ok := s.reMap[db]; !ok {
			s.reMap[db] = regexp.MustCompile(db[1:])
		}
	}

	for _, tb := range s.cfg.DoTables {
		if tb.Name[0] == '~' {
			if _, ok := s.reMap[tb.Name]; !ok {
				s.reMap[tb.Name] = regexp.MustCompile(tb.Name[1:])
			}
		}
		if tb.Schema[0] == '~' {
			if _, ok := s.reMap[tb.Schema]; !ok {
				s.reMap[tb.Schema] = regexp.MustCompile(tb.Schema[1:])
			}
		}
	}

	for _, tb := range s.cfg.IgnoreTables {
		if tb.Name[0] == '~' {
			if _, ok := s.reMap[tb.Name]; !ok {
				s.reMap[tb.Name] = regexp.MustCompile(tb.Name[1:])
			}
		}
		if tb.Schema[0] == '~' {
			if _, ok := s.reMap[tb.Schema]; !ok {
				s.reMap[tb.Schema] = regexp.MustCompile(tb.Schema[1:])
			}
		}
	}
}
<commit_msg>*:add rows size check<commit_after>// Copyright 2016 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 main

import (
	"database/sql"
	"regexp"
	"sync"
	"time"

	pbinlog "github.com/cwen0/cdb-syncer/protocol"
	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/siddontang/go/sync2"
	"golang.org/x/net/context"
)

var (
	maxRetryCount = 100

	retryTimeout = 3 * time.Second
	waitTime     = 10 * time.Millisecond
	maxWaitTime  = 3 * time.Second
	eventTimeout = 3 * time.Second
	statusTime   = 30 * time.Second
)

// Syncer can sync your MySQL data into another MySQL database.
type Syncer struct {
	sync.Mutex

	cfg *Config

	meta Meta

	syncer *BinlogSyncer

	wg    sync.WaitGroup
	jobWg sync.WaitGroup

	toDBs []*sql.DB

	done chan struct{}
	jobs []chan *job

	closed sync2.AtomicBool

	start    time.Time
	lastTime time.Time

	ddlCount    sync2.AtomicInt64
	insertCount sync2.AtomicInt64
	updateCount sync2.AtomicInt64
	deleteCount sync2.AtomicInt64
	lastCount   sync2.AtomicInt64
	count       sync2.AtomicInt64
	ctx         context.Context
	cancel      context.CancelFunc
	reMap       map[string]*regexp.Regexp
}

// NewSyncer creates a new Syncer.
func NewSyncer(cfg *Config) *Syncer {
	syncer := new(Syncer)
	syncer.cfg = cfg
	syncer.meta = NewLocalMeta(cfg.Meta)
	syncer.closed.Set(false)
	syncer.lastCount.Set(0)
	syncer.count.Set(0)
	syncer.insertCount.Set(0)
	syncer.updateCount.Set(0)
	syncer.deleteCount.Set(0)
	syncer.done = make(chan struct{})
	syncer.jobs = newJobChans(cfg.WorkerCount)
	syncer.reMap = make(map[string]*regexp.Regexp)
	syncer.ctx, syncer.cancel = context.WithCancel(context.Background())
	return syncer
}

func newJobChans(count int) []chan *job {
	jobs := make([]chan *job, 0, count)
	for i := 0; i < count; i++ {
		jobs = append(jobs, make(chan *job, 1000))
	}

	return jobs
}

func closeJobChans(jobs []chan *job) {
	for _, ch := range jobs {
		close(ch)
	}
}

// Start starts syncer.
func (s *Syncer) Start() error {
	err := s.meta.Load()
	if err != nil {
		return errors.Trace(err)
	}

	s.wg.Add(1)

	err = s.run()
	if err != nil {
		return errors.Trace(err)
	}

	s.done <- struct{}{}

	return nil
}

func (s *Syncer) addCount(tp pbinlog.BinlogType, n int64) {
	switch tp {
	case pbinlog.BinlogType_INSERT:
		s.insertCount.Add(n)
	case pbinlog.BinlogType_UPDATE:
		s.updateCount.Add(n)
	case pbinlog.BinlogType_DELETE:
		s.deleteCount.Add(n)
	case pbinlog.BinlogType_DDL:
		s.ddlCount.Add(n)
	}

	s.count.Add(n)
}

func (s *Syncer) checkWait(job *job) bool {
	if job.tp == pbinlog.BinlogType_DDL {
		return true
	}

	if s.meta.Check() {
		return true
	}

	return false
}

func (s *Syncer) addJob(job *job) error {
	s.jobWg.Add(1)

	log.Debugf("add job [sql]%s; [position]%v", job.sql, job.pos)
	idx := int(genHashKey(job.key)) % s.cfg.WorkerCount
	s.jobs[idx] <- job

	wait := s.checkWait(job)
	if wait {
		s.jobWg.Wait()
		err := s.meta.Save(job.pos, true)
		if err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

func (s *Syncer) sync(db *sql.DB, jobChan chan *job) {
	defer s.wg.Done()

	idx := 0
	count := s.cfg.Batch
	sqls := make([]string, 0, count)
	args := make([][]interface{}, 0, count)
	lastSyncTime := time.Now()
	tpCnt := make(map[pbinlog.BinlogType]int64)

	clearF := func() {
		for i := 0; i < idx; i++ {
			s.jobWg.Done()
		}

		idx = 0
		sqls = sqls[0:0]
		args = args[0:0]
		lastSyncTime = time.Now()
		for tpName, v := range tpCnt {
			s.addCount(tpName, v)
			tpCnt[tpName] = 0
		}
	}

	var err error
	for {
		select {
		case job, ok := <-jobChan:
			if !ok {
				return
			}
			idx++

			if job.tp == pbinlog.BinlogType_DDL {
				err = executeSQL(db, sqls, args, true)
				if err != nil {
					log.Fatalf(errors.ErrorStack(err))
				}

				err = executeSQL(db, []string{job.sql}, [][]interface{}{job.args}, false)
				if err != nil {
					if !ignoreDDLError(err) {
						log.Fatalf(errors.ErrorStack(err))
					} else {
						log.Warnf("[ignore ddl error][sql]%s[args]%v[error]%v", job.sql, job.args, err)
					}
				}

				tpCnt[job.tp]++
				clearF()

			} else {
				sqls = append(sqls, job.sql)
				args = append(args, job.args)
				tpCnt[job.tp]++
			}

			if idx >= count {
				err = executeSQL(db, sqls, args, true)
				if err != nil {
					log.Fatalf(errors.ErrorStack(err))
				}
				clearF()
			}

		default:
			now := time.Now()
			if now.Sub(lastSyncTime) >= maxWaitTime {
				err = executeSQL(db, sqls, args, true)
				if err != nil {
					log.Fatalf(errors.ErrorStack(err))
				}
				clearF()
			}

			time.Sleep(waitTime)
		}
	}
}

func (s *Syncer) run() error {
	defer s.wg.Done()
	cfg := BinlogSyncerConfig{
		BinlogPath:    s.cfg.BinlogPath,
		BinlogNamePre: s.cfg.BinlogNamePre,
	}

	var err error

	s.syncer = NewBinlogSyncer(&cfg)

	s.toDBs, err = createDBs(s.cfg.To, s.cfg.WorkerCount+1)
	if err != nil {
		return errors.Trace(err)
	}

	s.genRegexMap()

	s.start = time.Now()
	s.lastTime = s.start
	s.wg.Add(s.cfg.WorkerCount)
	for i := 0; i < s.cfg.WorkerCount; i++ {
		go s.sync(s.toDBs[i], s.jobs[i])
	}

	s.wg.Add(1)
	go s.printStatus()

	pos := s.meta.Pos()
	s.syncer.Start(pos)
	for {
		ctx, cancel := context.WithTimeout(s.ctx, eventTimeout)
		binlog, pos, err := s.syncer.GetBinlogs(ctx)
		cancel()
		if err == context.Canceled {
			log.Infof("ready to quit! [%v]", pos)
			return nil
		} else if err == context.DeadlineExceeded {
			continue
		}

		if err != nil {
			return errors.Trace(err)
		}
		if len(binlog.GetRows()) <= 0 {
			log.Warnf("[skip binlog]%v :rows size is zero", binlog)
			continue
		}
		switch binlog.GetType() {
		case pbinlog.BinlogType_INSERT:
			sql, pKey, args, err := genInsertSQL(binlog)
			if err != nil {
				return errors.Errorf("gen insert sql failed: %v , DB: %s, table: %s", err, binlog.GetDbName(), binlog.GetTableName())
			}
			if s.skipRowEvent(sql, binlog.GetDbName()) {
				log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
				continue
			}
			job := newJob(pbinlog.BinlogType_INSERT, sql, args, pKey, true, pos)
			err = s.addJob(job)
			if err != nil {
				return errors.Trace(err)
			}
		case pbinlog.BinlogType_UPDATE:
			sql, pKey, args, err := genUpdateSQL(binlog)
			if err != nil {
				return errors.Errorf("gen update sql failed: %v , DB: %s, table: %s", err, binlog.GetDbName(), binlog.GetTableName())
			}
			if s.skipRowEvent(sql, binlog.GetDbName()) {
				log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
				continue
			}
			job := newJob(pbinlog.BinlogType_UPDATE, sql, args, pKey, true, pos)
			err = s.addJob(job)
			if err != nil {
				return errors.Trace(err)
			}
		case pbinlog.BinlogType_DELETE:
			sql, pKey, args, err := genDeleteSQL(binlog)
			if err != nil {
				return errors.Errorf("gen delete sql failed: %v , DB: %s, table: %s", err, binlog.GetDbName(), binlog.GetTableName())
			}
			if s.skipRowEvent(sql, binlog.GetDbName()) {
				log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
				continue
			}
			job := newJob(pbinlog.BinlogType_DELETE, sql, args, pKey, true, pos)
			err = s.addJob(job)
			if err != nil {
				return errors.Trace(err)
			}
		case pbinlog.BinlogType_DDL:
			sqls, pKey, args, err := genDdlSQL(binlog)
			if err != nil {
				return errors.Errorf("gen ddl sql failed: %v", err)
			}
			for _, sql := range sqls {
				if s.skipRowEvent(sql, binlog.GetDbName()) {
					log.Warnf("[skip query-sql]%s  [schema]:%s", sql, binlog.GetDbName())
					continue
				}
				if s.skipQueryDDL(sql, binlog.GetDbName()) {
					log.Warnf("[skip query-ddl-sql]%s  [schema]:%s", sql, binlog.GetDbName())
					continue
				}
				s.jobWg.Wait()
				job := newJob(pbinlog.BinlogType_DDL, sql, args, pKey, false, pos)
				err = s.addJob(job)
				if err != nil {
					return errors.Trace(err)
				}
			}
		default:
			break
		}
	}
}

func (s *Syncer) printStatus() {
	defer s.wg.Done()

	timer := time.NewTicker(statusTime)
	defer timer.Stop()

	for {
		select {
		case <-s.ctx.Done():
			return
		case <-timer.C:
			now := time.Now()
			seconds := now.Unix() - s.lastTime.Unix()
			totalSeconds := now.Unix() - s.start.Unix()
			last := s.lastCount.Get()
			total := s.count.Get()

			tps, totalTps := int64(0), int64(0)
			if seconds > 0 {
				tps = (total - last) / seconds
				totalTps = total / totalSeconds
			}

			log.Infof("[syncer]total events = %d, insert = %d, update = %d, delete = %d, total tps = %d, recent tps = %d, %s.",
				total, s.insertCount.Get(), s.updateCount.Get(), s.deleteCount.Get(), totalTps, tps, s.meta)

			s.lastCount.Set(total)
			s.lastTime = time.Now()
		}
	}
}

func (s *Syncer) isClosed() bool {
	return s.closed.Get()
}

// Close closes syncer.
func (s *Syncer) Close() {
	s.Lock()
	defer s.Unlock()

	if s.isClosed() {
		return
	}

	s.cancel()

	<-s.done

	closeJobChans(s.jobs)
	s.wg.Wait()

	closeDBs(s.toDBs...)

	if s.syncer != nil {
		s.syncer = nil
	}

	s.closed.Set(true)
}

func (s *Syncer) genRegexMap() {
	for _, db := range s.cfg.DoDBs {
		if db[0] != '~' {
			continue
		}
		if _, ok := s.reMap[db]; !ok {
			s.reMap[db] = regexp.MustCompile(db[1:])
		}
	}

	for _, db := range s.cfg.IgnoreDBs {
		if db[0] != '~' {
			continue
		}
		if _, ok := s.reMap[db]; !ok {
			s.reMap[db] = regexp.MustCompile(db[1:])
		}
	}

	for _, tb := range s.cfg.DoTables {
		if tb.Name[0] == '~' {
			if _, ok := s.reMap[tb.Name]; !ok {
				s.reMap[tb.Name] = regexp.MustCompile(tb.Name[1:])
			}
		}
		if tb.Schema[0] == '~' {
			if _, ok := s.reMap[tb.Schema]; !ok {
				s.reMap[tb.Schema] = regexp.MustCompile(tb.Schema[1:])
			}
		}
	}

	for _, tb := range s.cfg.IgnoreTables {
		if tb.Name[0] == '~' {
			if _, ok := s.reMap[tb.Name]; !ok {
				s.reMap[tb.Name] = regexp.MustCompile(tb.Name[1:])
			}
		}
		if tb.Schema[0] == '~' {
			if _, ok := s.reMap[tb.Schema]; !ok {
				s.reMap[tb.Schema] = regexp.MustCompile(tb.Schema[1:])
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strings"
	//"text/template"
)

// Column is a column in an SQL table.
type Column struct {
	Name      string
	Type      string
	IsPrimary bool
}

// Init sets the columns fields.
func (c *Column) Init(name, tag string) error {
	(*c).Name = name

	attributes := strings.Split(tag, ",")
	for _, attr := range attributes {
		pair := strings.Split(attr, ":")
		if len(pair) != 2 {
			return fmt.Errorf("Malformed tag: '%s'", attr)
		}

		switch strings.ToLower(pair[0]) {
		case "type":
			(*c).Type = pair[1]
		case "primary":
			(*c).IsPrimary = true
		default:
			return fmt.Errorf("Unknown attribute: '%s'", pair[0])
		}
	}

	return nil
}

// Table is an SQL table.
type Table struct {
	Name    string
	Columns []Column
}

// CreateTable returns a create table statement for the table.
func (t Table) CreateTable() string {
	return "CREATE TABLE" // to do
}

// DropTable returns a drop table statement for the table.
func (t Table) DropTable() string {
	return "DROP TABLE" // to do
}

// InsertRow returns an insert row statement for the table.
func (t Table) InsertRow() string {
	return "INSERT ROW" // to do
}

// DeleteRow returns a delete row statement for the table.
func (t Table) DeleteRow() string {
	return "DELETE ROW" // to do
}

// UpdateRow returns an update row statement for the table.
func (t Table) UpdateRow() string {
	return "UPDATE ROW" // to do
}

// SelectRow returns a select row statement for the table.
func (t Table) SelectRow() string {
	return "SELECT ROW" // to do
}

// InputFile is a go file with tables.
type InputFile struct {
	PackageName string
	BuildTarget string
	Tables      []Table
}

// Init initializes an InputFile from a path.
func (i *InputFile) Init(path string) error {

	// set the build target
	if strings.HasSuffix(path, ".go") {
		root := strings.TrimSuffix(path, ".go")
		dir, file := filepath.Split(root)
		(*i).BuildTarget = filepath.Join(dir, fmt.Sprintf("%s_tabler.go", file))
	} else {
		return fmt.Errorf("File '%s' is not a Go file.", path)
	}

	f, err := parser.ParseFile(
		token.NewFileSet(),
		path,
		nil,
		parser.ParseComments,
	)
	if err != nil {
		fmt.Errorf("Unable to parse '%s': %s", path, err)
	}

	// get package name
	if f.Name != nil {
		(*i).PackageName = f.Name.Name
	} else {
		fmt.Errorf("Missing package name in '%s'", path)
	}

	// build list of tables
	var isTable bool
	for _, decl := range f.Decls {

		// get the type declaration
		tdecl, ok := decl.(*ast.GenDecl)
		if !ok || tdecl.Doc == nil {
			continue
		}

		// find the @table decorator
		isTable = false
		for _, comment := range tdecl.Doc.List {
			if strings.Contains(comment.Text, "@table") {
				isTable = true
				break
			}
		}
		if !isTable {
			continue
		}

		table := Table{}

		// get the name of the table
		for _, spec := range tdecl.Specs {
			if ts, ok := spec.(*ast.TypeSpec); ok {
				if ts.Name == nil {
					continue
				}
				table.Name = ts.Name.Name
				break
			}
		}
		if table.Name == "" {
			return fmt.Errorf("Unable to extract name from a table struct.")
		}

		// parse tags and build columns
		sdecl := tdecl.Specs[0].(*ast.TypeSpec).Type.(*ast.StructType)
		fields := sdecl.Fields.List
		for _, field := range fields {
			col := Column{}
			if err := col.Init(field.Names[0].Name, field.Tag.Value); err != nil {
				return fmt.Errorf(
					"Unable to unmarshal tag '%s' from table '%s' in '%s'",
					field.Tag.Value,
					table.Name,
					path,
				)
			}
			table.Columns = append(table.Columns, col)
		}
		if len(table.Columns) > 0 {
			(*i).Tables = append((*i).Tables, table)
		}
	}

	return nil
}

func (i InputFile) Write() error {
	// to do
	return nil
}

func main() {
	for _, path := range os.Args[1:] {
		infile := InputFile{}
		if err := infile.Init(path); err != nil {
			log.Printf("%v", err)
			continue
		}
		infile.Write()
	}
}
<commit_msg>fix tag parser<commit_after>package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strings"
	//"text/template"
)

// Column is a column in an SQL table.
type Column struct {
	Name      string
	Type      string
	IsPrimary bool
}

// Init sets the columns fields.
func (c *Column) Init(name, tag string) error {
	(*c).Name = name

	attributes := strings.Split(
		strings.Trim(tag, "`"),
		",",
	)
	for _, attr := range attributes {
		pair := strings.Split(attr, ":")
		if len(pair) != 2 {
			return fmt.Errorf("Malformed tag: '%s'", attr)
		}

		switch strings.ToLower(pair[0]) {
		case "type":
			(*c).Type = pair[1]
		case "primary":
			(*c).IsPrimary = true
		default:
			return fmt.Errorf("Unknown attribute: '%s'", pair[0])
		}
	}

	return nil
}

// Table is an SQL table.
type Table struct {
	Name    string
	Columns []Column
}

// CreateTable returns a create table statement for the table.
func (t Table) CreateTable() string {
	return "CREATE TABLE" // to do
}

// DropTable returns a drop table statement for the table.
func (t Table) DropTable() string {
	return "DROP TABLE" // to do
}

// InsertRow returns an insert row statement for the table.
func (t Table) InsertRow() string {
	return "INSERT ROW" // to do
}

// DeleteRow returns a delete row statement for the table.
func (t Table) DeleteRow() string {
	return "DELETE ROW" // to do
}

// UpdateRow returns an update row statement for the table.
func (t Table) UpdateRow() string {
	return "UPDATE ROW" // to do
}

// SelectRow returns a select row statement for the table.
func (t Table) SelectRow() string {
	return "SELECT ROW" // to do
}

// InputFile is a go file with tables.
type InputFile struct {
	PackageName string
	BuildTarget string
	Tables      []Table
}

// Init initializes an InputFile from a path.
func (i *InputFile) Init(path string) error {

	// set the build target
	if strings.HasSuffix(path, ".go") {
		root := strings.TrimSuffix(path, ".go")
		dir, file := filepath.Split(root)
		(*i).BuildTarget = filepath.Join(dir, fmt.Sprintf("%s_tabler.go", file))
	} else {
		return fmt.Errorf("File '%s' is not a Go file.", path)
	}

	f, err := parser.ParseFile(
		token.NewFileSet(),
		path,
		nil,
		parser.ParseComments,
	)
	if err != nil {
		fmt.Errorf("Unable to parse '%s': %s", path, err)
	}

	// get package name
	if f.Name != nil {
		(*i).PackageName = f.Name.Name
	} else {
		fmt.Errorf("Missing package name in '%s'", path)
	}

	// build list of tables
	var isTable bool
	for _, decl := range f.Decls {

		// get the type declaration
		tdecl, ok := decl.(*ast.GenDecl)
		if !ok || tdecl.Doc == nil {
			continue
		}

		// find the @table decorator
		isTable = false
		for _, comment := range tdecl.Doc.List {
			if strings.Contains(comment.Text, "@table") {
				isTable = true
				break
			}
		}
		if !isTable {
			continue
		}

		table := Table{}

		// get the name of the table
		for _, spec := range tdecl.Specs {
			if ts, ok := spec.(*ast.TypeSpec); ok {
				if ts.Name == nil {
					continue
				}
				table.Name = ts.Name.Name
				break
			}
		}
		if table.Name == "" {
			return fmt.Errorf("Unable to extract name from a table struct.")
		}

		// parse tags and build columns
		sdecl := tdecl.Specs[0].(*ast.TypeSpec).Type.(*ast.StructType)
		fields := sdecl.Fields.List
		for _, field := range fields {
			col := Column{}
			if err := col.Init(field.Names[0].Name, field.Tag.Value); err != nil {
				return fmt.Errorf(
					"Unable to parse tag '%s' from table '%s' in '%s': %v",
					field.Tag.Value,
					table.Name,
					path,
					err,
				)
			}
			table.Columns = append(table.Columns, col)
		}
		if len(table.Columns) > 0 {
			(*i).Tables = append((*i).Tables, table)
		}
	}

	return nil
}

func (i InputFile) Write() error {
	// to do
	return nil
}

func main() {
	for _, path := range os.Args[1:] {
		infile := InputFile{}
		if err := infile.Init(path); err != nil {
			log.Printf("%v", err)
			continue
		}
		infile.Write()
	}
}
<|endoftext|>


<commit_before>package circuitbreaker

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/morikuni/guard"
)

type CircuitBreaker interface {
	guard.Guard

	Subscribe() <-chan StateChange
}

func New(window Window, threashold float64, backoff guard.Backoff) CircuitBreaker {
	window.Reset()
	cb := &circuitBreaker{
		window,
		threashold,
		close,
		backoff.Reset(),

		[]chan<- StateChange{},
		sync.RWMutex{},
	}
	return cb
}

const (
	close int32 = iota
	halfopen
	open
)

var ErrCircuitBreakerOpen = errors.New("circuit breaker open")

type circuitBreaker struct {
	window     Window
	threashold float64
	state      int32
	backoff    guard.Backoff

	subscribers []chan<- StateChange
	mu          sync.RWMutex
}

func (cb *circuitBreaker) Call(ctx context.Context, f func(context.Context) error) error {
	state, available := cb.currentState()
	if !available {
		return ErrCircuitBreakerOpen
	}

	err := f(ctx)
	switch err {
	case nil:
		cb.succeed(state)
	case context.Canceled:
		// this is normal, so do nothing.
	default:
		// context.DeadlimeExceeded and other errors are regarded as a failure.
		cb.fail(state)
	}
	return err
}

func (cb *circuitBreaker) succeed(state int32) {
	cb.window.PutSuccess()
	switch state {
	case close:
	case halfopen:
		cb.close()
	default:
		panic("never come here")
	}
}

func (cb *circuitBreaker) fail(state int32) {
	cb.window.PutFailure()
	switch state {
	case close:
		if cb.window.FailureRate() >= cb.threashold {
			cb.open(state)
		}
	case halfopen:
		cb.open(state)
	default:
		panic("never come here")
	}
}

func (cb *circuitBreaker) currentState() (state int32, available bool) {
	switch atomic.LoadInt32(&cb.state) {
	case close:
		return close, true
	case halfopen:
		return halfopen, true
	case open:
		return open, false
	}
	panic("never come here")
}

func (cb *circuitBreaker) change(from, to int32, sc StateChange) bool {
	ok := atomic.CompareAndSwapInt32(&cb.state, from, to)
	if ok {
		cb.notify(sc)
	}
	return ok
}

func (cb *circuitBreaker) open(state int32) {
	sc := CloseToOpen
	if state == halfopen {
		sc = HalfOpenToOpen
	}
	if cb.change(state, open, sc) {
		time.AfterFunc(cb.backoff.NextInterval(), func() {
			cb.change(open, halfopen, OpenToHalfOpen)
		})
	}
}

func (cb *circuitBreaker) close() {
	if cb.change(halfopen, close, HalfOpenToClose) {
		cb.backoff = cb.backoff.Reset()
		cb.window.Reset()
	}
}

func (cb *circuitBreaker) Subscribe() <-chan StateChange {
	c := make(chan StateChange, 100)

	cb.mu.Lock()
	defer cb.mu.Unlock()
	cb.subscribers = append(cb.subscribers, c)
	return c
}

func (cb *circuitBreaker) notify(sc StateChange) {
	cb.mu.RLock()
	defer cb.mu.RUnlock()
	for _, subscriber := range cb.subscribers {
		subscriber <- sc
	}
}

type StateChange int

const (
	CloseToOpen StateChange = iota
	HalfOpenToOpen
	HalfOpenToClose
	OpenToHalfOpen
)

func (sc StateChange) String() string {
	switch sc {
	case CloseToOpen:
		return "close to open"
	case HalfOpenToOpen:
		return "half-open to open"
	case HalfOpenToClose:
		return "half-open to close"
	case OpenToHalfOpen:
		return "open to half-open"
	default:
		panic(fmt.Sprint("unknown state change", sc))
	}
}
<commit_msg>Fix bug of StateChange.String()<commit_after>package circuitbreaker

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/morikuni/guard"
)

type CircuitBreaker interface {
	guard.Guard

	Subscribe() <-chan StateChange
}

func New(window Window, threashold float64, backoff guard.Backoff) CircuitBreaker {
	window.Reset()
	cb := &circuitBreaker{
		window,
		threashold,
		close,
		backoff.Reset(),

		[]chan<- StateChange{},
		sync.RWMutex{},
	}
	return cb
}

const (
	close int32 = iota
	halfopen
	open
)

var ErrCircuitBreakerOpen = errors.New("circuit breaker open")

type circuitBreaker struct {
	window     Window
	threashold float64
	state      int32
	backoff    guard.Backoff

	subscribers []chan<- StateChange
	mu          sync.RWMutex
}

func (cb *circuitBreaker) Call(ctx context.Context, f func(context.Context) error) error {
	state, available := cb.currentState()
	if !available {
		return ErrCircuitBreakerOpen
	}

	err := f(ctx)
	switch err {
	case nil:
		cb.succeed(state)
	case context.Canceled:
		// this is normal, so do nothing.
	default:
		// context.DeadlimeExceeded and other errors are regarded as a failure.
		cb.fail(state)
	}
	return err
}

func (cb *circuitBreaker) succeed(state int32) {
	cb.window.PutSuccess()
	switch state {
	case close:
	case halfopen:
		cb.close()
	default:
		panic("never come here")
	}
}

func (cb *circuitBreaker) fail(state int32) {
	cb.window.PutFailure()
	switch state {
	case close:
		if cb.window.FailureRate() >= cb.threashold {
			cb.open(state)
		}
	case halfopen:
		cb.open(state)
	default:
		panic("never come here")
	}
}

func (cb *circuitBreaker) currentState() (state int32, available bool) {
	switch atomic.LoadInt32(&cb.state) {
	case close:
		return close, true
	case halfopen:
		return halfopen, true
	case open:
		return open, false
	}
	panic("never come here")
}

func (cb *circuitBreaker) change(from, to int32, sc StateChange) bool {
	ok := atomic.CompareAndSwapInt32(&cb.state, from, to)
	if ok {
		cb.notify(sc)
	}
	return ok
}

func (cb *circuitBreaker) open(state int32) {
	sc := CloseToOpen
	if state == halfopen {
		sc = HalfOpenToOpen
	}
	if cb.change(state, open, sc) {
		time.AfterFunc(cb.backoff.NextInterval(), func() {
			cb.change(open, halfopen, OpenToHalfOpen)
		})
	}
}

func (cb *circuitBreaker) close() {
	if cb.change(halfopen, close, HalfOpenToClose) {
		cb.backoff = cb.backoff.Reset()
		cb.window.Reset()
	}
}

func (cb *circuitBreaker) Subscribe() <-chan StateChange {
	c := make(chan StateChange, 100)

	cb.mu.Lock()
	defer cb.mu.Unlock()
	cb.subscribers = append(cb.subscribers, c)
	return c
}

func (cb *circuitBreaker) notify(sc StateChange) {
	cb.mu.RLock()
	defer cb.mu.RUnlock()
	for _, subscriber := range cb.subscribers {
		subscriber <- sc
	}
}

type StateChange int

const (
	CloseToOpen StateChange = iota
	HalfOpenToOpen
	HalfOpenToClose
	OpenToHalfOpen
)

func (sc StateChange) String() string {
	switch sc {
	case CloseToOpen:
		return "close to open"
	case HalfOpenToOpen:
		return "half-open to open"
	case HalfOpenToClose:
		return "half-open to close"
	case OpenToHalfOpen:
		return "open to half-open"
	default:
		panic(fmt.Sprint("unknown state change", int(sc)))
	}
}
<|endoftext|>


<commit_before>package ast

import "fmt"

// Node encapsulates every AST node.
type Node interface {
	String() string
	Children() []Node
	Position() Position
}

type Position int

type BaseNode struct {
	pos int
}

func (b BaseNode) Position() Position {
	return Position(b.pos)
}

func (b BaseNode) Children() []Node {
	return nil
}

func (b BaseNode) String() string {
	return ""
}

// An Identifier is specifically a variable in code.
type Identifier struct {
	BaseNode
	Name string
	Type Type
}

func (i Identifier) String() string {
	return i.Name
}

type GlobalIdentifier struct {
	*Identifier
}

func (i Identifier) AssignableType() Type {
	return i.Type
}

// EvaluatesTo returns the known type of the variable.
func (i Identifier) EvaluatesTo() Type {
	return i.Type
}

// NewIdentifier intializes an identifier node with its type set to AnyType.
func NewIdentifier(name string) *Identifier {
	return &Identifier{Name: name, Type: AnyType}
}

// A statement is an executable piece of code. It may be as simple as
// a function call or a variable assignment. It also includes things like
// "if".
type Statement interface {
	Node
}

// An Expression is a snippet of code that evaluates to a single value when run
// and does not represent a program instruction.
type Expression interface {
	Node
	EvaluatesTo() Type
}

// AnyType is a bitmask of all the valid types.
const AnyType = String | Integer | Float | Boolean | Null | Resource | Array | Object

// OperatorExpression is an expression that applies an operator to one, two, or three
// operands. The operator determines how many operands it should contain.
type OperatorExpression struct {
	BaseNode
	Operand1 Expression
	Operand2 Expression
	Operand3 Expression
	Type     Type
	Operator string
}

func (o OperatorExpression) Children() []Node {
	n := make([]Node, 0, 3)
	if o.Operand1 != nil {
		n = append(n, o.Operand1)
	}
	if o.Operand2 != nil {
		n = append(n, o.Operand2)
	}
	if o.Operand3 != nil {
		n = append(n, o.Operand3)
	}
	return n
}

func (o OperatorExpression) String() string {
	return o.Operator
}

func (o OperatorExpression) EvaluatesTo() Type {
	return o.Type
}

type ExpressionStmt struct {
	Expression
}

func (e ExpressionStmt) String() string {
	if e.Expression != nil {
		return e.Expression.String()
	}
	return ""
}

func (e ExpressionStmt) Children() []Node {
	if e.Expression != nil {
		return e.Expression.Children()
	}
	return nil
}

// Echo returns a new echo statement.
func Echo(expr Expression) EchoStmt {
	return EchoStmt{Expression: expr}
}

// Echo represents an echo statement. It may be either a literal statement
// or it may be from data outside PHP-mode, such as "here" in: <? not here ?> here <? not here ?>
type EchoStmt struct {
	BaseNode
	Expression Expression
}

func (e EchoStmt) String() string {
	return "Echo"
}

func (e EchoStmt) Children() []Node {
	return []Node{e.Expression}
}

// ReturnStmt represents a function return.
type ReturnStmt struct {
	Expression
}

func (r ReturnStmt) String() string {
	return fmt.Sprintf("return %s", r.Expression.String())
}

func (r ReturnStmt) Children() []Node {
	return r.Expression.Children()
}

type BreakStmt struct {
	Expression
}

func (b BreakStmt) Children() []Node {
	if b.Expression != nil {
		return b.Expression.Children()
	}
	return nil
}

func (b BreakStmt) String() string {
	if b.Expression != nil {
		return fmt.Sprint("break", b.Expression.String())
	}
	return "break"
}

type ContinueStmt struct {
	Expression
}

type ThrowStmt struct {
	Expression
}

type IncludeStmt struct {
	Include
}

type Include struct {
	Expression
}

func (i Include) EvaluatesTo() Type {
	return AnyType
}

type ExitStmt struct {
	Expression
}

type NewExpression struct {
	Expression
}

type AssignmentExpression struct {
	BaseNode
	Assignee Assignable
	Value    Expression
	Operator string
}

func (a AssignmentExpression) String() string {
	return a.Operator
}

func (a AssignmentExpression) Children() []Node {
	return []Node{
		a.Assignee,
		a.Value,
	}
}

func (a AssignmentExpression) EvaluatesTo() Type {
	return a.Value.EvaluatesTo()
}

// AssignmentStmt represents an assignment.
type AssignmentStmt struct {
	AssignmentExpression
}

type Assignable interface {
	Node
	AssignableType() Type
}

type FunctionCallStmt struct {
	FunctionCallExpression
}

type FunctionCallExpression struct {
	BaseNode
	FunctionName string
	Arguments    []Expression
}

func (f FunctionCallExpression) EvaluatesTo() Type {
	return String | Integer | Float | Boolean | Null | Resource | Array | Object
}

func (f FunctionCallExpression) String() string {
	return fmt.Sprintf("%s()", f.FunctionName)
}

func (f FunctionCallExpression) Children() []Node {
	n := make([]Node, len(f.Arguments))
	for i, a := range f.Arguments {
		n[i] = a
	}
	return n
}

type Block struct {
	BaseNode
	Statements []Statement
	Scope      Scope
}

func (b Block) String() string {
	return "{}"
}

func (b Block) Children() []Node {
	n := make([]Node, len(b.Statements))
	for i, s := range b.Statements {
		n[i] = s
	}
	return n
}

type FunctionStmt struct {
	BaseNode
	*FunctionDefinition
	Body *Block
}

func (f FunctionStmt) String() string {
	return fmt.Sprintf("Func: %s", f.Name)
}

func (f FunctionStmt) Children() []Node {
	n := make([]Node, 0, 2)
	if f.FunctionDefinition != nil {
		n = append(n, f.FunctionDefinition)
	}
	if f.Body != nil {
		n = append(n, f.Body)
	}
	return n
}

type FunctionDefinition struct {
	BaseNode
	Name      string
	Arguments []FunctionArgument
}

func (fd FunctionDefinition) Children() []Node {
	n := make([]Node, len(fd.Arguments))
	for i, arg := range fd.Arguments {
		n[i] = arg
	}
	return n
}

type FunctionArgument struct {
	BaseNode
	TypeHint   string
	Default    *Literal
	Identifier *Identifier
}

func (fa FunctionArgument) String() string {
	return fmt.Sprintf("Arg: %s", fa.TypeHint)
}

func (fa FunctionArgument) Children() []Node {
	n := []Node{
		fa.Identifier,
	}
	if fa.Default != nil {
		n = append(n, fa.Default)
	}
	return n
}

type Class struct {
	BaseNode
	Name       string
	Extends    *Class
	Implements []string
	Methods    []Method
	Properties []Property
	Constants  []Constant
}

func (c Class) String() string {
	return fmt.Sprintf("class %s", c.Name)
}

func (c Class) Children() []Node {
	n := make([]Node, len(c.Methods)+len(c.Properties))
	for i, p := range c.Properties {
		n[i] = p
	}
	offset := len(c.Properties)
	for i, m := range c.Methods {
		n[i+offset] = m
	}
	return n
}

type Constant struct {
	BaseNode
	*Identifier
	Value interface{}
}

type ConstantExpression struct {
	*Identifier
}

type Interface struct {
	BaseNode
	Name     string
	Inherits []string
	Methods  []Method
}

type Property struct {
	BaseNode
	Name           string
	Visibility     Visibility
	Type           Type
	Initialization Expression
}

func (p Property) String() string {
	return fmt.Sprintf("Prop: %s", p.Name)
}

func (p Property) AssignableType() Type {
	return p.Type
}

type PropertyExpression struct {
	BaseNode
	Receiver Expression
	Name     string
	Type     Type
}

func (p PropertyExpression) String() string {
	return fmt.Sprintf("%s->%s", p.Receiver, p.Name)
}

func (p PropertyExpression) AssignableType() Type {
	return p.Type
}

func (p PropertyExpression) EvaluatesTo() Type {
	return AnyType
}

func (p PropertyExpression) Children() []Node {
	return []Node{
		p.Receiver,
	}
}

type ClassExpression struct {
	BaseNode
	Receiver   string
	Expression Expression
}

func (c ClassExpression) EvaluatesTo() Type {
	return AnyType
}

func (c ClassExpression) String() string {
	return fmt.Sprintf("%s::", c.Receiver)
}

func (c ClassExpression) Children() []Node {
	return []Node{c.Expression}
}

type Method struct {
	BaseNode
	*FunctionStmt
	Visibility Visibility
}

func (m Method) String() string {
	return m.Name
}

func (m Method) Children() []Node {
	return m.FunctionStmt.Children()
}

type MethodCallExpression struct {
	Receiver Expression
	*FunctionCallExpression
}

func (m MethodCallExpression) Children() []Node {
	return []Node{
		m.Receiver,
		m.FunctionCallExpression,
	}
}

func (m MethodCallExpression) String() string {
	return fmt.Sprintf("%s->", m.Receiver)
}

type Visibility int

const (
	Private Visibility = iota
	Protected
	Public
)

type IfStmt struct {
	BaseNode
	Condition   Expression
	TrueBranch  Statement
	FalseBranch Statement
}

func (i IfStmt) String() string {
	return "if"
}

func (i IfStmt) Children() []Node {
	n := make([]Node, 0, 3)
	n = append(n, i.Condition)
	n = append(n, i.TrueBranch)
	if i.FalseBranch != nil {
		n = append(n, i.FalseBranch)
	}
	return n
}

type SwitchStmt struct {
	BaseNode
	Expression  Expression
	Cases       []*SwitchCase
	DefaultCase *Block
}

func (s SwitchStmt) String() string {
	return "switch"
}

func (s SwitchStmt) Children() []Node {
	n := []Node{
		s.Expression,
	}
	for _, c := range s.Cases {
		n = append(n, c)
	}
	if s.DefaultCase != nil {
		n = append(n, s.DefaultCase)
	}
	return n
}

type SwitchCase struct {
	BaseNode
	Expression Expression
	Block      Block
}

func (s SwitchCase) String() string {
	return "case"
}

func (s SwitchCase) Children() []Node {
	return []Node{
		s.Expression,
		s.Block,
	}
}

type ForStmt struct {
	BaseNode
	Initialization Expression
	Termination    Expression
	Iteration      Expression
	LoopBlock      Statement
}

func (f ForStmt) String() string {
	return "for"
}

func (f ForStmt) Children() []Node {
	return []Node{
		f.Initialization,
		f.Termination,
		f.Iteration,
		f.LoopBlock,
	}
}

type WhileStmt struct {
	BaseNode
	Termination Expression
	LoopBlock   Statement
}

func (w WhileStmt) String() string {
	return fmt.Sprintf("while")
}

func (w WhileStmt) Children() []Node {
	return []Node{
		w.Termination,
		w.LoopBlock,
	}
}

type DoWhileStmt struct {
	BaseNode
	Termination Expression
	LoopBlock   Statement
}

func (d DoWhileStmt) String() string {
	return fmt.Sprintf("do ... while")
}

func (d DoWhileStmt) Children() []Node {
	return []Node{
		d.LoopBlock,
		d.Termination,
	}
}

type TryStmt struct {
	BaseNode
	TryBlock     *Block
	FinallyBlock *Block
	CatchStmts   []*CatchStmt
}

type CatchStmt struct {
	BaseNode
	CatchBlock *Block
	CatchType  string
	CatchVar   *Identifier
}

type Literal struct {
	BaseNode
	Type Type
}

func (l Literal) String() string {
	return fmt.Sprintf("Literal-%s", l.Type)
}

func (l Literal) EvaluatesTo() Type {
	return l.Type
}

type ForeachStmt struct {
	BaseNode
	Source    Expression
	Key       *Identifier
	Value     *Identifier
	LoopBlock Statement
}

func (f ForeachStmt) String() string {
	return "foreach"
}

func (f ForeachStmt) Children() []Node {
	n := []Node{f.Source}
	if f.Key != nil {
		n = append(n, f.Key)
	}
	n = append(n, f.Value, f.LoopBlock)
	return n
}

type ArrayExpression struct {
	BaseNode
	ArrayType
	Pairs []ArrayPair
}

func (a ArrayExpression) String() string {
	return "array"
}

func (a ArrayExpression) Children() []Node {
	n := make([]Node, len(a.Pairs))
	for i, p := range a.Pairs {
		n[i] = p
	}
	return n
}

type ArrayPair struct {
	BaseNode
	Key   Expression
	Value Expression
}

func (p ArrayPair) Children() []Node {
	if p.Key != nil {
		return []Node{p.Key, p.Value}
	}
	return []Node{p.Value}
}

func (a ArrayExpression) EvaluatesTo() Type {
	return Array
}

func (a ArrayExpression) AssignableType() Type {
	return AnyType
}

type ArrayLookupExpression struct {
	BaseNode
	Array Expression
	Index Expression
}

func (a ArrayLookupExpression) String() string {
	return fmt.Sprintf("%s[", a.Array)
}

func (a ArrayLookupExpression) Children() []Node {
	return []Node{a.Index}
}

func (a ArrayLookupExpression) EvaluatesTo() Type {
	return AnyType
}

func (a ArrayLookupExpression) AssignableType() Type {
	return AnyType
}

type ArrayAppendExpression struct {
	BaseNode
	Array Expression
}

func (a ArrayAppendExpression) EvaluatesTo() Type {
	return AnyType
}

func (a ArrayAppendExpression) AssignableType() Type {
	return AnyType
}
<commit_msg>Preventing panics when printing break or continue statements<commit_after>package ast

import "fmt"

// Node encapsulates every AST node.
type Node interface {
	String() string
	Children() []Node
	Position() Position
}

type Position int

type BaseNode struct {
	pos int
}

func (b BaseNode) Position() Position {
	return Position(b.pos)
}

func (b BaseNode) Children() []Node {
	return nil
}

func (b BaseNode) String() string {
	return ""
}

// An Identifier is specifically a variable in code.
type Identifier struct {
	BaseNode
	Name string
	Type Type
}

func (i Identifier) String() string {
	return i.Name
}

type GlobalIdentifier struct {
	*Identifier
}

func (i Identifier) AssignableType() Type {
	return i.Type
}

// EvaluatesTo returns the known type of the variable.
func (i Identifier) EvaluatesTo() Type {
	return i.Type
}

// NewIdentifier intializes an identifier node with its type set to AnyType.
func NewIdentifier(name string) *Identifier {
	return &Identifier{Name: name, Type: AnyType}
}

// A statement is an executable piece of code. It may be as simple as
// a function call or a variable assignment. It also includes things like
// "if".
type Statement interface {
	Node
}

// An Expression is a snippet of code that evaluates to a single value when run
// and does not represent a program instruction.
type Expression interface {
	Node
	EvaluatesTo() Type
}

// AnyType is a bitmask of all the valid types.
const AnyType = String | Integer | Float | Boolean | Null | Resource | Array | Object

// OperatorExpression is an expression that applies an operator to one, two, or three
// operands. The operator determines how many operands it should contain.
type OperatorExpression struct {
	BaseNode
	Operand1 Expression
	Operand2 Expression
	Operand3 Expression
	Type     Type
	Operator string
}

func (o OperatorExpression) Children() []Node {
	n := make([]Node, 0, 3)
	if o.Operand1 != nil {
		n = append(n, o.Operand1)
	}
	if o.Operand2 != nil {
		n = append(n, o.Operand2)
	}
	if o.Operand3 != nil {
		n = append(n, o.Operand3)
	}
	return n
}

func (o OperatorExpression) String() string {
	return o.Operator
}

func (o OperatorExpression) EvaluatesTo() Type {
	return o.Type
}

type ExpressionStmt struct {
	Expression
}

func (e ExpressionStmt) String() string {
	if e.Expression != nil {
		return e.Expression.String()
	}
	return ""
}

func (e ExpressionStmt) Children() []Node {
	if e.Expression != nil {
		return e.Expression.Children()
	}
	return nil
}

// Echo returns a new echo statement.
func Echo(expr Expression) EchoStmt {
	return EchoStmt{Expression: expr}
}

// Echo represents an echo statement. It may be either a literal statement
// or it may be from data outside PHP-mode, such as "here" in: <? not here ?> here <? not here ?>
type EchoStmt struct {
	BaseNode
	Expression Expression
}

func (e EchoStmt) String() string {
	return "Echo"
}

func (e EchoStmt) Children() []Node {
	return []Node{e.Expression}
}

// ReturnStmt represents a function return.
type ReturnStmt struct {
	Expression
}

func (r ReturnStmt) String() string {
	return fmt.Sprintf("return")
}

func (r ReturnStmt) Children() []Node {
	if r.Expression == nil {
		return nil
	}
	return []Node{r.Expression}
}

type BreakStmt struct {
	Expression
}

func (b BreakStmt) Children() []Node {
	if b.Expression != nil {
		return b.Expression.Children()
	}
	return nil
}

func (b BreakStmt) String() string {
	return "break"
}

type ContinueStmt struct {
	Expression
}

func (c ContinueStmt) String() string {
	return "continue"
}

func (c ContinueStmt) Children() []Node {
	if c.Expression != nil {
		return c.Expression.Children()
	}
	return nil
}

type ThrowStmt struct {
	Expression
}

type IncludeStmt struct {
	Include
}

type Include struct {
	Expression
}

func (i Include) EvaluatesTo() Type {
	return AnyType
}

type ExitStmt struct {
	Expression
}

type NewExpression struct {
	Expression
}

type AssignmentExpression struct {
	BaseNode
	Assignee Assignable
	Value    Expression
	Operator string
}

func (a AssignmentExpression) String() string {
	return a.Operator
}

func (a AssignmentExpression) Children() []Node {
	return []Node{
		a.Assignee,
		a.Value,
	}
}

func (a AssignmentExpression) EvaluatesTo() Type {
	return a.Value.EvaluatesTo()
}

// AssignmentStmt represents an assignment.
type AssignmentStmt struct {
	AssignmentExpression
}

type Assignable interface {
	Node
	AssignableType() Type
}

type FunctionCallStmt struct {
	FunctionCallExpression
}

type FunctionCallExpression struct {
	BaseNode
	FunctionName string
	Arguments    []Expression
}

func (f FunctionCallExpression) EvaluatesTo() Type {
	return String | Integer | Float | Boolean | Null | Resource | Array | Object
}

func (f FunctionCallExpression) String() string {
	return fmt.Sprintf("%s()", f.FunctionName)
}

func (f FunctionCallExpression) Children() []Node {
	n := make([]Node, len(f.Arguments))
	for i, a := range f.Arguments {
		n[i] = a
	}
	return n
}

type Block struct {
	BaseNode
	Statements []Statement
	Scope      Scope
}

func (b Block) String() string {
	return "{}"
}

func (b Block) Children() []Node {
	n := make([]Node, len(b.Statements))
	for i, s := range b.Statements {
		n[i] = s
	}
	return n
}

type FunctionStmt struct {
	BaseNode
	*FunctionDefinition
	Body *Block
}

func (f FunctionStmt) String() string {
	return fmt.Sprintf("Func: %s", f.Name)
}

func (f FunctionStmt) Children() []Node {
	n := make([]Node, 0, 2)
	if f.FunctionDefinition != nil {
		n = append(n, f.FunctionDefinition)
	}
	if f.Body != nil {
		n = append(n, f.Body)
	}
	return n
}

type FunctionDefinition struct {
	BaseNode
	Name      string
	Arguments []FunctionArgument
}

func (fd FunctionDefinition) Children() []Node {
	n := make([]Node, len(fd.Arguments))
	for i, arg := range fd.Arguments {
		n[i] = arg
	}
	return n
}

type FunctionArgument struct {
	BaseNode
	TypeHint   string
	Default    *Literal
	Identifier *Identifier
}

func (fa FunctionArgument) String() string {
	return fmt.Sprintf("Arg: %s", fa.TypeHint)
}

func (fa FunctionArgument) Children() []Node {
	n := []Node{
		fa.Identifier,
	}
	if fa.Default != nil {
		n = append(n, fa.Default)
	}
	return n
}

type Class struct {
	BaseNode
	Name       string
	Extends    *Class
	Implements []string
	Methods    []Method
	Properties []Property
	Constants  []Constant
}

func (c Class) String() string {
	return fmt.Sprintf("class %s", c.Name)
}

func (c Class) Children() []Node {
	n := make([]Node, len(c.Methods)+len(c.Properties))
	for i, p := range c.Properties {
		n[i] = p
	}
	offset := len(c.Properties)
	for i, m := range c.Methods {
		n[i+offset] = m
	}
	return n
}

type Constant struct {
	BaseNode
	*Identifier
	Value interface{}
}

type ConstantExpression struct {
	*Identifier
}

type Interface struct {
	BaseNode
	Name     string
	Inherits []string
	Methods  []Method
}

type Property struct {
	BaseNode
	Name           string
	Visibility     Visibility
	Type           Type
	Initialization Expression
}

func (p Property) String() string {
	return fmt.Sprintf("Prop: %s", p.Name)
}

func (p Property) AssignableType() Type {
	return p.Type
}

type PropertyExpression struct {
	BaseNode
	Receiver Expression
	Name     string
	Type     Type
}

func (p PropertyExpression) String() string {
	return fmt.Sprintf("%s->%s", p.Receiver, p.Name)
}

func (p PropertyExpression) AssignableType() Type {
	return p.Type
}

func (p PropertyExpression) EvaluatesTo() Type {
	return AnyType
}

func (p PropertyExpression) Children() []Node {
	return []Node{
		p.Receiver,
	}
}

type ClassExpression struct {
	BaseNode
	Receiver   string
	Expression Expression
}

func (c ClassExpression) EvaluatesTo() Type {
	return AnyType
}

func (c ClassExpression) String() string {
	return fmt.Sprintf("%s::", c.Receiver)
}

func (c ClassExpression) Children() []Node {
	return []Node{c.Expression}
}

type Method struct {
	BaseNode
	*FunctionStmt
	Visibility Visibility
}

func (m Method) String() string {
	return m.Name
}

func (m Method) Children() []Node {
	return m.FunctionStmt.Children()
}

type MethodCallExpression struct {
	Receiver Expression
	*FunctionCallExpression
}

func (m MethodCallExpression) Children() []Node {
	return []Node{
		m.Receiver,
		m.FunctionCallExpression,
	}
}

func (m MethodCallExpression) String() string {
	return fmt.Sprintf("%s->", m.Receiver)
}

type Visibility int

const (
	Private Visibility = iota
	Protected
	Public
)

type IfStmt struct {
	BaseNode
	Condition   Expression
	TrueBranch  Statement
	FalseBranch Statement
}

func (i IfStmt) String() string {
	return "if"
}

func (i IfStmt) Children() []Node {
	n := make([]Node, 0, 3)
	n = append(n, i.Condition)
	n = append(n, i.TrueBranch)
	if i.FalseBranch != nil {
		n = append(n, i.FalseBranch)
	}
	return n
}

type SwitchStmt struct {
	BaseNode
	Expression  Expression
	Cases       []*SwitchCase
	DefaultCase *Block
}

func (s SwitchStmt) String() string {
	return "switch"
}

func (s SwitchStmt) Children() []Node {
	n := []Node{
		s.Expression,
	}
	for _, c := range s.Cases {
		n = append(n, c)
	}
	if s.DefaultCase != nil {
		n = append(n, s.DefaultCase)
	}
	return n
}

type SwitchCase struct {
	BaseNode
	Expression Expression
	Block      Block
}

func (s SwitchCase) String() string {
	return "case"
}

func (s SwitchCase) Children() []Node {
	return []Node{
		s.Expression,
		s.Block,
	}
}

type ForStmt struct {
	BaseNode
	Initialization Expression
	Termination    Expression
	Iteration      Expression
	LoopBlock      Statement
}

func (f ForStmt) String() string {
	return "for"
}

func (f ForStmt) Children() []Node {
	return []Node{
		f.Initialization,
		f.Termination,
		f.Iteration,
		f.LoopBlock,
	}
}

type WhileStmt struct {
	BaseNode
	Termination Expression
	LoopBlock   Statement
}

func (w WhileStmt) String() string {
	return fmt.Sprintf("while")
}

func (w WhileStmt) Children() []Node {
	return []Node{
		w.Termination,
		w.LoopBlock,
	}
}

type DoWhileStmt struct {
	BaseNode
	Termination Expression
	LoopBlock   Statement
}

func (d DoWhileStmt) String() string {
	return fmt.Sprintf("do ... while")
}

func (d DoWhileStmt) Children() []Node {
	return []Node{
		d.LoopBlock,
		d.Termination,
	}
}

type TryStmt struct {
	BaseNode
	TryBlock     *Block
	FinallyBlock *Block
	CatchStmts   []*CatchStmt
}

type CatchStmt struct {
	BaseNode
	CatchBlock *Block
	CatchType  string
	CatchVar   *Identifier
}

type Literal struct {
	BaseNode
	Type Type
}

func (l Literal) String() string {
	return fmt.Sprintf("Literal-%s", l.Type)
}

func (l Literal) EvaluatesTo() Type {
	return l.Type
}

type ForeachStmt struct {
	BaseNode
	Source    Expression
	Key       *Identifier
	Value     *Identifier
	LoopBlock Statement
}

func (f ForeachStmt) String() string {
	return "foreach"
}

func (f ForeachStmt) Children() []Node {
	n := []Node{f.Source}
	if f.Key != nil {
		n = append(n, f.Key)
	}
	n = append(n, f.Value, f.LoopBlock)
	return n
}

type ArrayExpression struct {
	BaseNode
	ArrayType
	Pairs []ArrayPair
}

func (a ArrayExpression) String() string {
	return "array"
}

func (a ArrayExpression) Children() []Node {
	n := make([]Node, len(a.Pairs))
	for i, p := range a.Pairs {
		n[i] = p
	}
	return n
}

type ArrayPair struct {
	BaseNode
	Key   Expression
	Value Expression
}

func (p ArrayPair) Children() []Node {
	if p.Key != nil {
		return []Node{p.Key, p.Value}
	}
	return []Node{p.Value}
}

func (a ArrayExpression) EvaluatesTo() Type {
	return Array
}

func (a ArrayExpression) AssignableType() Type {
	return AnyType
}

type ArrayLookupExpression struct {
	BaseNode
	Array Expression
	Index Expression
}

func (a ArrayLookupExpression) String() string {
	return fmt.Sprintf("%s[", a.Array)
}

func (a ArrayLookupExpression) Children() []Node {
	return []Node{a.Index}
}

func (a ArrayLookupExpression) EvaluatesTo() Type {
	return AnyType
}

func (a ArrayLookupExpression) AssignableType() Type {
	return AnyType
}

type ArrayAppendExpression struct {
	BaseNode
	Array Expression
}

func (a ArrayAppendExpression) EvaluatesTo() Type {
	return AnyType
}

func (a ArrayAppendExpression) AssignableType() Type {
	return AnyType
}
<|endoftext|>


<commit_before>package allocdir

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"

	cstructs "github.com/hashicorp/nomad/client/structs"
)

// Test that building a chroot will skip nonexistent directories.
func TestTaskDir_EmbedNonExistent(t *testing.T) {
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	fakeDir := "/foobarbaz"
	mapping := map[string]string{fakeDir: fakeDir}
	if err := td.embedDirs(mapping); err != nil {
		t.Fatalf("embedDirs(%v) should should skip %v since it does not exist", mapping, fakeDir)
	}
}

// Test that building a chroot copies files from the host into the task dir.
func TestTaskDir_EmbedDirs(t *testing.T) {
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	// Create a fake host directory, with a file, and a subfolder that contains
	// a file.
	host, err := ioutil.TempDir("", "AllocDirHost")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(host)

	subDirName := "subdir"
	subDir := filepath.Join(host, subDirName)
	if err := os.MkdirAll(subDir, 0777); err != nil {
		t.Fatalf("Failed to make subdir %v: %v", subDir, err)
	}

	file := "foo"
	subFile := "bar"
	if err := ioutil.WriteFile(filepath.Join(host, file), []byte{'a'}, 0777); err != nil {
		t.Fatalf("Coudn't create file in host dir %v: %v", host, err)
	}

	if err := ioutil.WriteFile(filepath.Join(subDir, subFile), []byte{'a'}, 0777); err != nil {
		t.Fatalf("Coudn't create file in host subdir %v: %v", subDir, err)
	}

	// Create mapping from host dir to task dir.
	taskDest := "bin/test/"
	mapping := map[string]string{host: taskDest}
	if err := td.embedDirs(mapping); err != nil {
		t.Fatalf("embedDirs(%v) failed: %v", mapping, err)
	}

	exp := []string{filepath.Join(td.Dir, taskDest, file), filepath.Join(td.Dir, taskDest, subDirName, subFile)}
	for _, f := range exp {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			t.Fatalf("File %v not embedded: %v", f, err)
		}
	}
}

// Test that task dirs for image based isolation don't require root.
func TestTaskDir_NonRoot_Image(t *testing.T) {
	if os.Geteuid() == 0 {
		t.Skip("test should be run as non-root user")
	}
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	if err := td.Build(false, nil, cstructs.FSIsolationImage); err != nil {
		t.Fatalf("TaskDir.Build failed: %v", err)
	}
}

// Test that task dirs with no isolation don't require root.
func TestTaskDir_NonRoot(t *testing.T) {
	if os.Geteuid() == 0 {
		t.Skip("test should be run as non-root user")
	}
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	if err := td.Build(false, nil, cstructs.FSIsolationNone); err != nil {
		t.Fatalf("TaskDir.Build failed: %v", err)
	}

	// ${TASK_DIR}/alloc should not exist!
	if _, err = os.Stat(td.SharedTaskDir); !os.IsNotExist(err) {
		t.Fatalf("Expected a NotExist error for shared alloc dir in task dir: %q", td.SharedTaskDir)
	}

}
<commit_msg>spelling: could<commit_after>package allocdir

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"

	cstructs "github.com/hashicorp/nomad/client/structs"
)

// Test that building a chroot will skip nonexistent directories.
func TestTaskDir_EmbedNonExistent(t *testing.T) {
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	fakeDir := "/foobarbaz"
	mapping := map[string]string{fakeDir: fakeDir}
	if err := td.embedDirs(mapping); err != nil {
		t.Fatalf("embedDirs(%v) should should skip %v since it does not exist", mapping, fakeDir)
	}
}

// Test that building a chroot copies files from the host into the task dir.
func TestTaskDir_EmbedDirs(t *testing.T) {
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	// Create a fake host directory, with a file, and a subfolder that contains
	// a file.
	host, err := ioutil.TempDir("", "AllocDirHost")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(host)

	subDirName := "subdir"
	subDir := filepath.Join(host, subDirName)
	if err := os.MkdirAll(subDir, 0777); err != nil {
		t.Fatalf("Failed to make subdir %v: %v", subDir, err)
	}

	file := "foo"
	subFile := "bar"
	if err := ioutil.WriteFile(filepath.Join(host, file), []byte{'a'}, 0777); err != nil {
		t.Fatalf("Couldn't create file in host dir %v: %v", host, err)
	}

	if err := ioutil.WriteFile(filepath.Join(subDir, subFile), []byte{'a'}, 0777); err != nil {
		t.Fatalf("Couldn't create file in host subdir %v: %v", subDir, err)
	}

	// Create mapping from host dir to task dir.
	taskDest := "bin/test/"
	mapping := map[string]string{host: taskDest}
	if err := td.embedDirs(mapping); err != nil {
		t.Fatalf("embedDirs(%v) failed: %v", mapping, err)
	}

	exp := []string{filepath.Join(td.Dir, taskDest, file), filepath.Join(td.Dir, taskDest, subDirName, subFile)}
	for _, f := range exp {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			t.Fatalf("File %v not embedded: %v", f, err)
		}
	}
}

// Test that task dirs for image based isolation don't require root.
func TestTaskDir_NonRoot_Image(t *testing.T) {
	if os.Geteuid() == 0 {
		t.Skip("test should be run as non-root user")
	}
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	if err := td.Build(false, nil, cstructs.FSIsolationImage); err != nil {
		t.Fatalf("TaskDir.Build failed: %v", err)
	}
}

// Test that task dirs with no isolation don't require root.
func TestTaskDir_NonRoot(t *testing.T) {
	if os.Geteuid() == 0 {
		t.Skip("test should be run as non-root user")
	}
	tmp, err := ioutil.TempDir("", "AllocDir")
	if err != nil {
		t.Fatalf("Couldn't create temp dir: %v", err)
	}
	defer os.RemoveAll(tmp)

	d := NewAllocDir(testLogger(), tmp)
	defer d.Destroy()
	td := d.NewTaskDir(t1.Name)
	if err := d.Build(); err != nil {
		t.Fatalf("Build() failed: %v", err)
	}

	if err := td.Build(false, nil, cstructs.FSIsolationNone); err != nil {
		t.Fatalf("TaskDir.Build failed: %v", err)
	}

	// ${TASK_DIR}/alloc should not exist!
	if _, err = os.Stat(td.SharedTaskDir); !os.IsNotExist(err) {
		t.Fatalf("Expected a NotExist error for shared alloc dir in task dir: %q", td.SharedTaskDir)
	}

}
<|endoftext|>


<commit_before>//  Copyright (c) 2015 Couchbase, 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, 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 searchers

import (
	"sort"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
	"github.com/blevesearch/bleve/search/scorers"
)

// DocIDSearcher returns documents matching a predefined set of identifiers.
type DocIDSearcher struct {
	ids     []string
	current int
	scorer  *scorers.ConstantScorer
}

func NewDocIDSearcher(indexReader index.IndexReader, ids []string, boost float64, explain bool) (*DocIDSearcher, error) {
	kept := make([]string, len(ids))
	copy(kept, ids)
	sort.Strings(kept)

	if len(ids) > 0 {
		idReader, err := indexReader.DocIDReader(kept[0], kept[len(kept)-1])
		if err != nil {
			return nil, err
		}
		defer idReader.Close()
		j := 0
		for _, id := range kept {
			doc, err := idReader.Advance(id)
			if err != nil {
				return nil, err
			}
			// Non-duplicate match
			if doc == id && (j == 0 || kept[j-1] != id) {
				kept[j] = id
				j++
			}
		}
		kept = kept[:j]
	}

	scorer := scorers.NewConstantScorer(1.0, boost, explain)
	return &DocIDSearcher{
		ids:    kept,
		scorer: scorer,
	}, nil
}

func (s *DocIDSearcher) Count() uint64 {
	return uint64(len(s.ids))
}

func (s *DocIDSearcher) Weight() float64 {
	return s.scorer.Weight()
}

func (s *DocIDSearcher) SetQueryNorm(qnorm float64) {
	s.scorer.SetQueryNorm(qnorm)
}

func (s *DocIDSearcher) Next() (*search.DocumentMatch, error) {
	if s.current >= len(s.ids) {
		return nil, nil
	}
	id := s.ids[s.current]
	s.current++
	docMatch := s.scorer.Score(id)
	return docMatch, nil

}

func (s *DocIDSearcher) Advance(ID string) (*search.DocumentMatch, error) {
	s.current = sort.SearchStrings(s.ids, ID)
	return s.Next()
}

func (s *DocIDSearcher) Close() error {
	return nil
}

func (s *DocIDSearcher) Min() int {
	return 0
}
<commit_msg>searcher_docid: catch DocIDReader.Close() possible error<commit_after>//  Copyright (c) 2015 Couchbase, 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, 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 searchers

import (
	"sort"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
	"github.com/blevesearch/bleve/search/scorers"
)

// DocIDSearcher returns documents matching a predefined set of identifiers.
type DocIDSearcher struct {
	ids     []string
	current int
	scorer  *scorers.ConstantScorer
}

func NewDocIDSearcher(indexReader index.IndexReader, ids []string, boost float64,
	explain bool) (searcher *DocIDSearcher, err error) {

	kept := make([]string, len(ids))
	copy(kept, ids)
	sort.Strings(kept)

	if len(ids) > 0 {
		var idReader index.DocIDReader
		idReader, err = indexReader.DocIDReader(kept[0], kept[len(kept)-1])
		if err != nil {
			return nil, err
		}
		defer func() {
			if cerr := idReader.Close(); err == nil && cerr != nil {
				err = cerr
			}
		}()
		j := 0
		for _, id := range kept {
			doc, err := idReader.Advance(id)
			if err != nil {
				return nil, err
			}
			// Non-duplicate match
			if doc == id && (j == 0 || kept[j-1] != id) {
				kept[j] = id
				j++
			}
		}
		kept = kept[:j]
	}

	scorer := scorers.NewConstantScorer(1.0, boost, explain)
	return &DocIDSearcher{
		ids:    kept,
		scorer: scorer,
	}, nil
}

func (s *DocIDSearcher) Count() uint64 {
	return uint64(len(s.ids))
}

func (s *DocIDSearcher) Weight() float64 {
	return s.scorer.Weight()
}

func (s *DocIDSearcher) SetQueryNorm(qnorm float64) {
	s.scorer.SetQueryNorm(qnorm)
}

func (s *DocIDSearcher) Next() (*search.DocumentMatch, error) {
	if s.current >= len(s.ids) {
		return nil, nil
	}
	id := s.ids[s.current]
	s.current++
	docMatch := s.scorer.Score(id)
	return docMatch, nil

}

func (s *DocIDSearcher) Advance(ID string) (*search.DocumentMatch, error) {
	s.current = sort.SearchStrings(s.ids, ID)
	return s.Next()
}

func (s *DocIDSearcher) Close() error {
	return nil
}

func (s *DocIDSearcher) Min() int {
	return 0
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/oracle/bmcs-go-sdk"

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

type ResourceCoreDHCPOptionsTestSuite struct {
	suite.Suite
	Client       *baremetal.Client
	Provider     terraform.ResourceProvider
	Providers    map[string]terraform.ResourceProvider
	Config       string
	ResourceName string
}

var defaultDhcpOpts = `
resource "oci_core_default_dhcp_options" "default" {
	manage_default_resource_id = "${oci_core_virtual_network.t.default_dhcp_options_id}"
	options {
		type = "DomainNameServer"
		server_type = "CustomDnsServer"
		custom_dns_servers = [  "8.8.4.4", "8.8.8.8" ]
	}
	options {
		type = "SearchDomain"
		search_domain_names = [ "test.com" ]
	}
}
`

func (s *ResourceCoreDHCPOptionsTestSuite) SetupTest() {
	s.Client = testAccClient
	s.Provider = testAccProvider
	s.Providers = testAccProviders
	s.Config = testProviderConfig() + `
	resource "oci_core_virtual_network" "t" {
		cidr_block = "10.0.0.0/16"
		compartment_id = "${var.compartment_id}"
		display_name = "network_name"
	}

	resource "oci_core_dhcp_options" "opt1" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "VcnLocalPlusInternet"
		}
	}

	resource "oci_core_dhcp_options" "opt2" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "VcnLocalPlusInternet"
		}
		options {
			type = "SearchDomain"
			search_domain_names = [ "test.com" ]
		}
	}

	resource "oci_core_dhcp_options" "opt3" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "CustomDnsServer"
			custom_dns_servers = [  "8.8.4.4", "8.8.8.8" ]
		}
	}

	resource "oci_core_dhcp_options" "opt4" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "CustomDnsServer"
			custom_dns_servers = [  "8.8.4.4", "8.8.8.8" ]
		}
		options {
			type = "SearchDomain"
			search_domain_names = [ "test.com" ]
		}
	}`
}

func (s *ResourceCoreDHCPOptionsTestSuite) TestAccResourceCoreDHCPOptions_basic() {

	resource.Test(s.T(), resource.TestCase{
		Providers: s.Providers,
		Steps: []resource.TestStep{
			{
				ImportState:       true,
				ImportStateVerify: true,
				Config:            s.Config + defaultDhcpOpts,
				Check: resource.ComposeTestCheckFunc(

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt1", "display_name", "display_name"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt1", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt1", "options.0.server_type", "VcnLocalPlusInternet"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt2", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt2", "options.0.server_type", "VcnLocalPlusInternet"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt2", "options.1.type", "SearchDomain"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt3", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt3", "options.0.server_type", "CustomDnsServer"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt4", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt4", "options.0.server_type", "CustomDnsServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt4", "options.1.type", "SearchDomain"),

					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.0.server_type", "CustomDnsServer"),
					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.1.type", "SearchDomain"),
				),
			},
			// Verify removing default DHCP options
			{
				Config: s.Config,
				Check:  nil,
			},
			// Verify adding default DHCP options again
			{
				Config: s.Config + defaultDhcpOpts,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("oci_core_dhcp_options.default", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.default", "options.0.server_type", "CustomDnsServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.default", "options.1.type", "SearchDomain"),
				),
			},
		},
	})
}

func TestResourceCoreDHCPOptionsTestSuite(t *testing.T) {
	suite.Run(t, new(ResourceCoreDHCPOptionsTestSuite))
}
<commit_msg>Fix default DHCP options test resource<commit_after>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/oracle/bmcs-go-sdk"

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

type ResourceCoreDHCPOptionsTestSuite struct {
	suite.Suite
	Client       *baremetal.Client
	Provider     terraform.ResourceProvider
	Providers    map[string]terraform.ResourceProvider
	Config       string
	ResourceName string
}

var defaultDhcpOpts = `
resource "oci_core_default_dhcp_options" "default" {
	manage_default_resource_id = "${oci_core_virtual_network.t.default_dhcp_options_id}"
	options {
		type = "DomainNameServer"
		server_type = "CustomDnsServer"
		custom_dns_servers = [  "8.8.4.4", "8.8.8.8" ]
	}
	options {
		type = "SearchDomain"
		search_domain_names = [ "test.com" ]
	}
}
`

func (s *ResourceCoreDHCPOptionsTestSuite) SetupTest() {
	s.Client = testAccClient
	s.Provider = testAccProvider
	s.Providers = testAccProviders
	s.Config = testProviderConfig() + `
	resource "oci_core_virtual_network" "t" {
		cidr_block = "10.0.0.0/16"
		compartment_id = "${var.compartment_id}"
		display_name = "network_name"
	}

	resource "oci_core_dhcp_options" "opt1" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "VcnLocalPlusInternet"
		}
	}

	resource "oci_core_dhcp_options" "opt2" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "VcnLocalPlusInternet"
		}
		options {
			type = "SearchDomain"
			search_domain_names = [ "test.com" ]
		}
	}

	resource "oci_core_dhcp_options" "opt3" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "CustomDnsServer"
			custom_dns_servers = [  "8.8.4.4", "8.8.8.8" ]
		}
	}

	resource "oci_core_dhcp_options" "opt4" {
		compartment_id = "${var.compartment_id}"
		vcn_id = "${oci_core_virtual_network.t.id}"
		display_name = "display_name"
		options {
			type = "DomainNameServer"
			server_type = "CustomDnsServer"
			custom_dns_servers = [  "8.8.4.4", "8.8.8.8" ]
		}
		options {
			type = "SearchDomain"
			search_domain_names = [ "test.com" ]
		}
	}`
}

func (s *ResourceCoreDHCPOptionsTestSuite) TestAccResourceCoreDHCPOptions_basic() {

	resource.Test(s.T(), resource.TestCase{
		Providers: s.Providers,
		Steps: []resource.TestStep{
			{
				ImportState:       true,
				ImportStateVerify: true,
				Config:            s.Config + defaultDhcpOpts,
				Check: resource.ComposeTestCheckFunc(

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt1", "display_name", "display_name"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt1", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt1", "options.0.server_type", "VcnLocalPlusInternet"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt2", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt2", "options.0.server_type", "VcnLocalPlusInternet"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt2", "options.1.type", "SearchDomain"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt3", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt3", "options.0.server_type", "CustomDnsServer"),

					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt4", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt4", "options.0.server_type", "CustomDnsServer"),
					resource.TestCheckResourceAttr("oci_core_dhcp_options.opt4", "options.1.type", "SearchDomain"),

					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.0.server_type", "CustomDnsServer"),
					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.1.type", "SearchDomain"),
				),
			},
			// Verify removing default DHCP options
			{
				Config: s.Config,
				Check:  nil,
			},
			// Verify adding default DHCP options again
			{
				Config: s.Config + defaultDhcpOpts,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.0.type", "DomainNameServer"),
					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.0.server_type", "CustomDnsServer"),
					resource.TestCheckResourceAttr("oci_core_default_dhcp_options.default", "options.1.type", "SearchDomain"),
				),
			},
		},
	})
}

func TestResourceCoreDHCPOptionsTestSuite(t *testing.T) {
	suite.Run(t, new(ResourceCoreDHCPOptionsTestSuite))
}
<|endoftext|>


<commit_before>// +build unit

// Copyright 2016 Mesosphere, 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,
// 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 client

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	httpHelpers "github.com/dcos/dcos-metrics/util/http/helpers"
	. "github.com/smartystreets/goconvey/convey"
)

func TestClient(t *testing.T) {
	Convey("User-Agent should match Git version", t, func() {
		var gotUserAgent string

		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			td, err := json.Marshal(map[string]string{
				"foo": "bar",
			})
			if err != nil {
				panic(err)
			}

			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write(td)

			gotUserAgent = r.UserAgent()
		}))
		defer ts.Close()

		u, err := url.Parse(ts.URL)
		if err != nil {
			panic(err)
		}

		if err := Fetch(http.DefaultClient, *u, nil); err != nil {
			panic(err)
		}

		// Default is "unset"; this is set by 'scripts/build.sh' via ldflags.
		// The actual test for the version in the built binary is in TestMain,
		// located in dcos-metrics_test.go.
		So(gotUserAgent, ShouldEqual, "unset")
	})
}

func TestFetch(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		td, err := json.Marshal(map[string]string{
			"foo": "bar",
		})
		if err != nil {
			panic(err)
		}

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(td)
	}))
	defer ts.Close()

	testClient, err := httpHelpers.NewMetricsClient("", "")
	if err != nil {
		t.Error("Error retreiving HTTP Client:", err)
	}

	Convey("Should fetch data UNAUTHENTICATED from the Mesos API and return", t, func() {
		var data map[string]string
		host, err := extractHostFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		testURL := url.URL{
			Scheme: "http",
			Host:   host,
			Path:   "/",
		}
		err = Fetch(testClient, testURL, &data)

		So(data["foo"], ShouldEqual, "bar")
		So(err, ShouldBeNil)
	})

	// TODO(roger): write a test for the auth portion once it's implemented
	Convey("Should fetch data AUTHENTICATED from the Mesos API and return", t, nil)
}

func extractHostFromURL(u string) (string, error) {
	parsed, err := url.Parse(u)
	if err != nil {
		return "", err
	}
	return parsed.Host, nil
}
<commit_msg>remove skipped test for authed http fetch<commit_after>// +build unit

// Copyright 2016 Mesosphere, 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,
// 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 client

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	httpHelpers "github.com/dcos/dcos-metrics/util/http/helpers"
	. "github.com/smartystreets/goconvey/convey"
)

func TestClient(t *testing.T) {
	Convey("User-Agent should match Git version", t, func() {
		var gotUserAgent string

		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			td, err := json.Marshal(map[string]string{
				"foo": "bar",
			})
			if err != nil {
				panic(err)
			}

			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write(td)

			gotUserAgent = r.UserAgent()
		}))
		defer ts.Close()

		u, err := url.Parse(ts.URL)
		if err != nil {
			panic(err)
		}

		if err := Fetch(http.DefaultClient, *u, nil); err != nil {
			panic(err)
		}

		// Default is "unset"; this is set by 'scripts/build.sh' via ldflags.
		// The actual test for the version in the built binary is in TestMain,
		// located in dcos-metrics_test.go.
		So(gotUserAgent, ShouldEqual, "unset")
	})
}

func TestFetch(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		td, err := json.Marshal(map[string]string{
			"foo": "bar",
		})
		if err != nil {
			panic(err)
		}

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(td)
	}))
	defer ts.Close()

	testClient, err := httpHelpers.NewMetricsClient("", "")
	if err != nil {
		t.Error("Error retreiving HTTP Client:", err)
	}

	Convey("Should fetch data and return", t, func() {
		var data map[string]string
		host, err := extractHostFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		testURL := url.URL{
			Scheme: "http",
			Host:   host,
			Path:   "/",
		}
		err = Fetch(testClient, testURL, &data)

		So(data["foo"], ShouldEqual, "bar")
		So(err, ShouldBeNil)
	})
}

func extractHostFromURL(u string) (string, error) {
	parsed, err := url.Parse(u)
	if err != nil {
		return "", err
	}
	return parsed.Host, nil
}
<|endoftext|>


<commit_before>package delta_geometry

import (
	"math"
)

// 指定された座標(x,y)に該当するワールドデルタの番号を返す
// ただし、-12.0 <= x <= +12.0、-12.0 <= y <= +12.0
func GetWorldDeltaId(x float64, y float64) byte {
	mod := func(a float64, b float64) float64 {
		for ; a >= +b; a -= b {
		}
		for ; a < 0.0; a += b {
		}
		return a
	}
	xx := mod(x, 24.0)
	yy := math.Abs(y)
	var base byte
	if y >= 0.0 {
		base = 0
	} else {
		base = 4
	}
	switch {
	case yy >= +2.0*(xx-0.0):
		return base + 0
	case yy <= -2.0*(xx-12.0):
		return base + 1
	case yy >= +2.0*(xx-12.0):
		return base + 2
	case yy <= -2.0*(xx-24.0):
		return base + 3
	default:
		return base + 0
	}
}

func GetSubDeltaId(upper bool, x float64, y float64) byte {
	if upper {
		return GetUpperDeltaId(x, y)
	} else {
		return GetLowerDeltaId(x, y)
	}
}

// 指定された座標(x,y)に該当する上向きのサブデルタの番号を返す
// ただし、0.0 <= x <= +12.0、0.0 <= y <= +12.0
func GetUpperDeltaId(x float64, y float64) byte {
	switch {
	case y < -2.0*(x-6.0):
		return 3
	case y < +2.0*(x-6.0):
		return 2
	case y > 6.0:
		return 1
	default:
		return 0
	}
}

// 指定された座標(x,y)に該当する下向きのサブデルタの番号を返す
// ただし、0.0 <= x <= +12.0、0.0 <= y <= +12.0
func GetLowerDeltaId(x float64, y float64) byte {
	switch {
	case y > -2.0*(x-12.0):
		return 3
	case y > +2.0*x:
		return 2
	case y < 6.0:
		return 1
	default:
		return 0
	}
}

// 指定されたワールドデルタが上向きかどうかを返す
func IsUpperWorldDelta(id byte) bool {
	if id < 4 {
		return id%2 == 1
	} else {
		return id%2 == 0
	}
}

// 指定されたサブデルタが上向きかどうか返す
func IsUpperSubDelta(parent_is_upper bool, id byte) bool {
	if parent_is_upper {
		return id != 0
	} else {
		return id == 0
	}
}

func IsUpperDelta(ids []byte) bool {
	upper := IsUpperWorldDelta(ids[0])
	for i, length := 1, len(ids); i < length; i++ {
		upper = IsUpperSubDelta(upper, ids[i])
	}
	return upper
}

var TRANSFORM_WORLD_DELTA_X []float64 = []float64{+6.0, +0.0, -6.0, -12.0, +6.0, +0.0, -6.0, -12.0}
var TRANSFORM_WORLD_DELTA_Y []float64 = []float64{+0.0, +0.0, +0.0, +0.0, +12.0, +12.0, +12.0, +12.0}

func TransformWorldDelta(id byte, x float64, y float64) (float64, float64) {
	xx := (x + TRANSFORM_WORLD_DELTA_X[id])
	yy := (y + TRANSFORM_WORLD_DELTA_Y[id])
	return xx, yy
	// TODO: mod
	// xx = (x + TRANSFORM_WORLD_DELTA_X[id]) % 12
	// yy = (y + TRANSFORM_WORLD_DELTA_Y[id]) % 12
}

func TransformSubDelta(upper bool, id byte, x float64, y float64) (float64, float64) {
	if upper {
		return TransformUpperDelta(id, x, y)
	} else {
		return TransformLowerDelta(id, x, y)
	}
}

var TRANSFORM_UPPER_DELTA_X []float64 = []float64{-3.0, -3.0, -6.0, -0.0}
var TRANSFORM_UPPER_DELTA_Y []float64 = []float64{-0.0, -6.0, -0.0, -0.0}

func TransformUpperDelta(id byte, x float64, y float64) (float64, float64) {
	xx := (x + TRANSFORM_UPPER_DELTA_X[id]) * 2
	yy := (y + TRANSFORM_UPPER_DELTA_Y[id]) * 2
	return xx, yy
}

var TRANSFORM_LOWER_DELTA_X []float64 = []float64{-3.0, -3.0, -0.0, -6.0}
var TRANSFORM_LOWER_DELTA_Y []float64 = []float64{-6.0, -0.0, -6.0, -6.0}

func TransformLowerDelta(id byte, x float64, y float64) (float64, float64) {
	xx := (x + TRANSFORM_LOWER_DELTA_X[id]) * 2
	yy := (y + TRANSFORM_LOWER_DELTA_Y[id]) * 2
	return xx, yy
}

func GetDeltaIds(x float64, y float64, level byte) []byte {
	ids := []byte{GetWorldDeltaId(x, y)}
	xx, yy := TransformWorldDelta(ids[0], x, y)
	upper := IsUpperWorldDelta(ids[0])

	for i := byte(2); i <= level; i++ {
		ids = append(ids, GetSubDeltaId(upper, xx, yy))
		xx, yy = TransformSubDelta(upper, ids[len(ids)-1], xx, yy)
		upper = IsUpperSubDelta(upper, ids[len(ids)-1])
	}

	return ids
}

var WORLD_DELTA_CENTER map[byte][]float64 = map[byte][]float64{
	0: []float64{+0.0, +8.0},
	1: []float64{+6.0, +4.0},
	2: []float64{+12.0, +8.0},
	3: []float64{+18.0, +4.0},
	4: []float64{+0.0, -8.0},
	5: []float64{+6.0, -4.0},
	6: []float64{+12.0, -8.0},
	7: []float64{+18.0, -4.0},
}

func GetWorldDeltaCenter(id byte) (float64, float64) {
	xy := WORLD_DELTA_CENTER[id]
	return xy[0], xy[1]
}

var UPPER_SUB_DELTA_DISTANCE map[byte][]float64 = map[byte][]float64{
	0: []float64{+0.0, +0.0},
	1: []float64{+0.0, +4.0},
	2: []float64{+3.0, -2.0},
	3: []float64{-3.0, -2.0},
}

func GetUpperSubDeltaDistance(id byte) (float64, float64) {
	xy := UPPER_SUB_DELTA_DISTANCE[id]
	return xy[0], xy[1]
}

var LOWER_SUB_DELTA_DISTANCE map[byte][]float64 = map[byte][]float64{
	0: []float64{+0.0, +0.0},
	1: []float64{+0.0, -4.0},
	2: []float64{-3.0, +2.0},
	3: []float64{+3.0, +2.0},
}

func GetLowerSubDeltaDistance(id byte) (float64, float64) {
	xy := LOWER_SUB_DELTA_DISTANCE[id]
	return xy[0], xy[1]
}

func GetSubDeltaDistance(parent_is_upper bool, id byte) (float64, float64) {
	if parent_is_upper {
		return GetUpperSubDeltaDistance(id)
	} else {
		return GetLowerSubDeltaDistance(id)
	}
}

func GetCenter(ids []byte) (float64, float64) {
	w_id, s_ids := ids[0], ids[1:]

	x, y := GetWorldDeltaCenter(w_id)
	upper := IsUpperWorldDelta(w_id)

	for i, length := 0, len(s_ids); i < length; i++ {
		xx, yy := GetSubDeltaDistance(upper, s_ids[i])
		upper = IsUpperSubDelta(upper, s_ids[i])
		x += xx / math.Pow(2, float64(i))
		y += yy / math.Pow(2, float64(i))
	}

	if x > 12.0 {
		x -= 24.0
	}

	return x, y
}

func GetCoordinates(ids []byte) [4][2]float64 {
	cx, cy := GetCenter(ids)
	level := len(ids)
	var sign float64
	if IsUpperDelta(ids) {
		sign = +1
	} else {
		sign = -1
	}
	scale := 1.0 / math.Pow(2, float64(level-1)) * sign

	dx1 := 0.0
	dy1 := 8.0 * scale
	dx2 := 6.0 * scale
	dy2 := 4.0 * scale

	return [4][2]float64{
		[2]float64{cx, cy},
		[2]float64{cx + dx1, cy + dy1},
		[2]float64{cx + dx2, cy - dy2},
		[2]float64{cx - dx2, cy - dy2},
	}
}
<commit_msg>エクスポートの必要の無い定数を小文字に変更<commit_after>package delta_geometry

import (
	"math"
)

// 指定された座標(x,y)に該当するワールドデルタの番号を返す
// ただし、-12.0 <= x <= +12.0、-12.0 <= y <= +12.0
func GetWorldDeltaId(x float64, y float64) byte {
	mod := func(a float64, b float64) float64 {
		for ; a >= +b; a -= b {
		}
		for ; a < 0.0; a += b {
		}
		return a
	}
	xx := mod(x, 24.0)
	yy := math.Abs(y)
	var base byte
	if y >= 0.0 {
		base = 0
	} else {
		base = 4
	}
	switch {
	case yy >= +2.0*(xx-0.0):
		return base + 0
	case yy <= -2.0*(xx-12.0):
		return base + 1
	case yy >= +2.0*(xx-12.0):
		return base + 2
	case yy <= -2.0*(xx-24.0):
		return base + 3
	default:
		return base + 0
	}
}

func GetSubDeltaId(upper bool, x float64, y float64) byte {
	if upper {
		return GetUpperDeltaId(x, y)
	} else {
		return GetLowerDeltaId(x, y)
	}
}

// 指定された座標(x,y)に該当する上向きのサブデルタの番号を返す
// ただし、0.0 <= x <= +12.0、0.0 <= y <= +12.0
func GetUpperDeltaId(x float64, y float64) byte {
	switch {
	case y < -2.0*(x-6.0):
		return 3
	case y < +2.0*(x-6.0):
		return 2
	case y > 6.0:
		return 1
	default:
		return 0
	}
}

// 指定された座標(x,y)に該当する下向きのサブデルタの番号を返す
// ただし、0.0 <= x <= +12.0、0.0 <= y <= +12.0
func GetLowerDeltaId(x float64, y float64) byte {
	switch {
	case y > -2.0*(x-12.0):
		return 3
	case y > +2.0*x:
		return 2
	case y < 6.0:
		return 1
	default:
		return 0
	}
}

// 指定されたワールドデルタが上向きかどうかを返す
func IsUpperWorldDelta(id byte) bool {
	if id < 4 {
		return id%2 == 1
	} else {
		return id%2 == 0
	}
}

// 指定されたサブデルタが上向きかどうか返す
func IsUpperSubDelta(parent_is_upper bool, id byte) bool {
	if parent_is_upper {
		return id != 0
	} else {
		return id == 0
	}
}

func IsUpperDelta(ids []byte) bool {
	upper := IsUpperWorldDelta(ids[0])
	for i, length := 1, len(ids); i < length; i++ {
		upper = IsUpperSubDelta(upper, ids[i])
	}
	return upper
}

var transform_world_delta_x []float64 = []float64{+6.0, +0.0, -6.0, -12.0, +6.0, +0.0, -6.0, -12.0}
var transform_world_delta_y []float64 = []float64{+0.0, +0.0, +0.0, +0.0, +12.0, +12.0, +12.0, +12.0}

func TransformWorldDelta(id byte, x float64, y float64) (float64, float64) {
	xx := (x + transform_world_delta_x[id])
	yy := (y + transform_world_delta_y[id])
	return xx, yy
	// TODO: mod
	// xx = (x + TRANSFORM_WORLD_DELTA_X[id]) % 12
	// yy = (y + TRANSFORM_WORLD_DELTA_Y[id]) % 12
}

func TransformSubDelta(upper bool, id byte, x float64, y float64) (float64, float64) {
	if upper {
		return TransformUpperDelta(id, x, y)
	} else {
		return TransformLowerDelta(id, x, y)
	}
}

var transform_upper_delta_x []float64 = []float64{-3.0, -3.0, -6.0, -0.0}
var transform_upper_delta_y []float64 = []float64{-0.0, -6.0, -0.0, -0.0}

func TransformUpperDelta(id byte, x float64, y float64) (float64, float64) {
	xx := (x + transform_upper_delta_x[id]) * 2
	yy := (y + transform_upper_delta_y[id]) * 2
	return xx, yy
}

var transform_lower_delta_x []float64 = []float64{-3.0, -3.0, -0.0, -6.0}
var transform_lower_delta_y []float64 = []float64{-6.0, -0.0, -6.0, -6.0}

func TransformLowerDelta(id byte, x float64, y float64) (float64, float64) {
	xx := (x + transform_lower_delta_x[id]) * 2
	yy := (y + transform_lower_delta_y[id]) * 2
	return xx, yy
}

func GetDeltaIds(x float64, y float64, level byte) []byte {
	ids := []byte{GetWorldDeltaId(x, y)}
	xx, yy := TransformWorldDelta(ids[0], x, y)
	upper := IsUpperWorldDelta(ids[0])

	for i := byte(2); i <= level; i++ {
		ids = append(ids, GetSubDeltaId(upper, xx, yy))
		xx, yy = TransformSubDelta(upper, ids[len(ids)-1], xx, yy)
		upper = IsUpperSubDelta(upper, ids[len(ids)-1])
	}

	return ids
}

var world_delta_center map[byte][]float64 = map[byte][]float64{
	0: []float64{+0.0, +8.0},
	1: []float64{+6.0, +4.0},
	2: []float64{+12.0, +8.0},
	3: []float64{+18.0, +4.0},
	4: []float64{+0.0, -8.0},
	5: []float64{+6.0, -4.0},
	6: []float64{+12.0, -8.0},
	7: []float64{+18.0, -4.0},
}

func GetWorldDeltaCenter(id byte) (float64, float64) {
	xy := world_delta_center[id]
	return xy[0], xy[1]
}

var upper_sub_delta_distance map[byte][]float64 = map[byte][]float64{
	0: []float64{+0.0, +0.0},
	1: []float64{+0.0, +4.0},
	2: []float64{+3.0, -2.0},
	3: []float64{-3.0, -2.0},
}

func GetUpperSubDeltaDistance(id byte) (float64, float64) {
	xy := upper_sub_delta_distance[id]
	return xy[0], xy[1]
}

var lower_sub_delta_distance map[byte][]float64 = map[byte][]float64{
	0: []float64{+0.0, +0.0},
	1: []float64{+0.0, -4.0},
	2: []float64{-3.0, +2.0},
	3: []float64{+3.0, +2.0},
}

func GetLowerSubDeltaDistance(id byte) (float64, float64) {
	xy := lower_sub_delta_distance[id]
	return xy[0], xy[1]
}

func GetSubDeltaDistance(parent_is_upper bool, id byte) (float64, float64) {
	if parent_is_upper {
		return GetUpperSubDeltaDistance(id)
	} else {
		return GetLowerSubDeltaDistance(id)
	}
}

func GetCenter(ids []byte) (float64, float64) {
	w_id, s_ids := ids[0], ids[1:]

	x, y := GetWorldDeltaCenter(w_id)
	upper := IsUpperWorldDelta(w_id)

	for i, length := 0, len(s_ids); i < length; i++ {
		xx, yy := GetSubDeltaDistance(upper, s_ids[i])
		upper = IsUpperSubDelta(upper, s_ids[i])
		x += xx / math.Pow(2, float64(i))
		y += yy / math.Pow(2, float64(i))
	}

	if x > 12.0 {
		x -= 24.0
	}

	return x, y
}

func GetCoordinates(ids []byte) [4][2]float64 {
	cx, cy := GetCenter(ids)
	level := len(ids)
	var sign float64
	if IsUpperDelta(ids) {
		sign = +1
	} else {
		sign = -1
	}
	scale := 1.0 / math.Pow(2, float64(level-1)) * sign

	dx1 := 0.0
	dy1 := 8.0 * scale
	dx2 := 6.0 * scale
	dy2 := 4.0 * scale

	return [4][2]float64{
		[2]float64{cx, cy},
		[2]float64{cx + dx1, cy + dy1},
		[2]float64{cx + dx2, cy - dy2},
		[2]float64{cx - dx2, cy - dy2},
	}
}
<|endoftext|>