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

package health

import (
	"fmt"
	"net/http"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
)

// The HealthReport struct has slots for the levels of health that we monitor and aggregate.
type HealthReport struct {
	Live  bool
	Ready bool
}

type reporterState struct {
	// The reporter's name.
	name string

	// The health indicators that this reporter reports.
	reports HealthReport

	// Expiry time for this reporter's reports.  Zero means that reports never expire.
	timeout time.Duration

	// The most recent report.
	latest HealthReport

	// Time of that most recent report.
	timestamp time.Time
}

// TimedOut checks whether the reporter is due for another report. This is the case when
// the reports are configured to expire and the time since the last report exceeds the report timeout duration.
func (r *reporterState) TimedOut() bool {
	return r.timeout != 0 && time.Since(r.timestamp) > r.timeout
}

// A HealthAggregator receives health reports from individual reporters (which are typically
// components of a particular daemon or application) and aggregates them into an overall health
// summary.  For each monitored kind of health, all of the reporters that report that need to say
// that it is good; for example, to be 'ready' overall, all of the reporters that report readiness
// need to have recently said 'Ready: true'.
type HealthAggregator struct {
	// Mutex to protect concurrent access to this health aggregator.
	mutex *sync.Mutex

	// The previous health summary report which is cached so that we log only when the overall health report changes.
	lastReport *HealthReport

	// Map from reporter name to corresponding state.
	reporters map[string]*reporterState

	// HTTP server mux.  This is where we register handlers for particular URLs.
	httpServeMux *http.ServeMux

	// HTTP server.  Non-nil when there should be a server running.
	httpServer *http.Server
}

// RegisterReporter registers a reporter with a HealthAggregator.  The aggregator uses NAME to
// identify the reporter.  REPORTS indicates the kinds of health that this reporter will report.
// TIMEOUT is the expiry time for this reporter's reports; the implication of which is that the
// reporter should normally refresh its reports well before this time has expired.
func (aggregator *HealthAggregator) RegisterReporter(name string, reports *HealthReport, timeout time.Duration) {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	aggregator.reporters[name] = &reporterState{
		name:      name,
		reports:   *reports,
		timeout:   timeout,
		latest:    HealthReport{Live: true},
		timestamp: time.Now(),
	}
	return
}

// Report reports current health from a reporter to a HealthAggregator.  NAME is the reporter's name
// and REPORTS conveys the current status, for each kind of health that the reporter said it was
// going to report when it called RegisterReporter.
func (aggregator *HealthAggregator) Report(name string, report *HealthReport) {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	reporter := aggregator.reporters[name]
	reporter.latest = *report
	reporter.timestamp = time.Now()
	return
}

func NewHealthAggregator() *HealthAggregator {
	aggregator := &HealthAggregator{
		mutex:        &sync.Mutex{},
		lastReport:   &HealthReport{},
		reporters:    map[string]*reporterState{},
		httpServeMux: http.NewServeMux(),
	}
	aggregator.httpServeMux.HandleFunc("/readiness", func(rsp http.ResponseWriter, req *http.Request) {
		log.Debug("GET /readiness")
		status := StatusBad
		if aggregator.Summary().Ready {
			log.Debug("Felix is ready")
			status = StatusGood
		}
		rsp.WriteHeader(status)
	})
	aggregator.httpServeMux.HandleFunc("/liveness", func(rsp http.ResponseWriter, req *http.Request) {
		log.Debug("GET /liveness")
		status := StatusBad
		if aggregator.Summary().Live {
			log.Debug("Felix is live")
			status = StatusGood
		}
		rsp.WriteHeader(status)
	})
	return aggregator
}

// Summary calculates the current overall health for a HealthAggregator.
func (aggregator *HealthAggregator) Summary() *HealthReport {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()

	var failedLivenessChecks []*reporterState
	var failedReadinessChecks []*reporterState

	// In the absence of any reporters, default to indicating that we are both live and ready.
	summary := &HealthReport{Live: true, Ready: true}

	// Now for each reporter...
	for _, reporter := range aggregator.reporters {
		// Reset Live to false if that reporter is registered to report liveness and hasn't
		// recently said that it is live.
		stillLive := reporter.latest.Live && !reporter.TimedOut()
		if summary.Live && reporter.reports.Live && !stillLive {
			summary.Live = false
		}

		// Reset Ready to false if that reporter is registered to report readiness and
		// hasn't recently said that it is ready.
		stillReady := reporter.latest.Ready && !reporter.TimedOut()
		if summary.Ready && reporter.reports.Ready && !stillReady {
			summary.Ready = false
		}

		if reporter.reports.Live && !stillLive {
			failedLivenessChecks = append(failedLivenessChecks, reporter)
		}
		if reporter.reports.Ready && !stillReady {
			failedReadinessChecks = append(failedReadinessChecks, reporter)
		}
		if reporter.reports.Live && reporter.reports.Ready && stillLive && stillReady {
			log.WithFields(log.Fields{
				"name":           reporter.name,
				"reporter-state": reporter,
			}).Debug("Reporter is healthy")
		}
	}

	// Summary status has changed so update previous status and log.
	if summary.Live != aggregator.lastReport.Live || summary.Ready != aggregator.lastReport.Ready {
		aggregator.lastReport = summary
		log.WithField("lastSummary", summary).Info("Overall health status changed")

		for _, reporter := range failedLivenessChecks {
			log.WithFields(log.Fields{
				"name":           reporter.name,
				"reporter-state": reporter,
			}).Warn("Reporter failed liveness checks")
		}
		for _, reporter := range failedReadinessChecks {
			log.WithFields(log.Fields{
				"name":           reporter.name,
				"reporter-state": reporter,
			}).Warn("Reporter failed readiness checks")
		}
	}
	return summary
}

const (
	// The HTTP status that we use for 'ready' or 'live'.  204 means "No Content: The server
	// successfully processed the request and is not returning any content."  (Kubernetes
	// interpets any 200<=status<400 as 'good'.)
	StatusGood = 204

	// The HTTP status that we use for 'not ready' or 'not live'.  503 means "Service
	// Unavailable: The server is currently unavailable (because it is overloaded or down for
	// maintenance). Generally, this is a temporary state."  (Kubernetes interpets any
	// status>=400 as 'bad'.)
	StatusBad = 503
)

// ServeHTTP publishes the current overall liveness and readiness at http://HOST:PORT/liveness and
// http://HOST:PORT/readiness respectively.  A GET request on those URLs returns StatusGood or
// StatusBad, according to the current overall liveness or readiness.  These endpoints are designed
// for use by Kubernetes liveness and readiness probes.
func (aggregator *HealthAggregator) ServeHTTP(enabled bool, host string, port int) {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	if enabled {
		logCxt := log.WithFields(log.Fields{
			"host": host,
			"port": port,
		})
		if aggregator.httpServer != nil {
			logCxt.Info("Health enabled.  Server is already running.")
			return
		}
		logCxt.Info("Health enabled.  Starting server.")
		aggregator.httpServer = &http.Server{
			Addr:    fmt.Sprintf("%s:%v", host, port),
			Handler: aggregator.httpServeMux,
		}
		go func() {
			for {
				server := aggregator.getHTTPServer()
				if server == nil {
					// HTTP serving is now disabled.
					break
				}
				err := server.ListenAndServe()
				log.WithError(err).Error(
					"Health endpoint failed, trying to restart it...")
				time.Sleep(1 * time.Second)
			}
		}()
	} else {
		if aggregator.httpServer != nil {
			log.Info("Health disabled.  Stopping server.")
			aggregator.httpServer.Close()
			aggregator.httpServer = nil
		}
	}
}

func (aggregator *HealthAggregator) getHTTPServer() *http.Server {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	return aggregator.httpServer
}
<commit_msg>Improve health report diags:<commit_after>// Copyright (c) 2017-2019 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package health

import (
	"fmt"
	"net/http"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
)

// The HealthReport struct has slots for the levels of health that we monitor and aggregate.
type HealthReport struct {
	Live  bool
	Ready bool
}

type reporterState struct {
	// The reporter's name.
	name string

	// The health indicators that this reporter reports.
	reports HealthReport

	// Expiry time for this reporter's reports.  Zero means that reports never expire.
	timeout time.Duration

	// The most recent report.
	latest HealthReport

	// Time of that most recent report.
	timestamp time.Time
}

func (r *reporterState) RecentlyReady() bool {
	if !r.reports.Ready {
		return true
	}
	if r.TimedOut() {
		log.WithField("name", r.name).Warn("Report timed out")
		return false
	}
	return r.latest.Ready
}

func (r *reporterState) RecentlyLive() bool {
	if !r.reports.Live {
		return true
	}
	if r.TimedOut() {
		log.WithField("name", r.name).Warn("Report timed out")
		return false
	}
	return r.latest.Live
}

// TimedOut checks whether the reporter is due for another report. This is the case when
// the reports are configured to expire and the time since the last report exceeds the report timeout duration.
func (r *reporterState) TimedOut() bool {
	return r.timeout != 0 && time.Since(r.timestamp) > r.timeout
}

// A HealthAggregator receives health reports from individual reporters (which are typically
// components of a particular daemon or application) and aggregates them into an overall health
// summary.  For each monitored kind of health, all of the reporters that report that need to say
// that it is good; for example, to be 'ready' overall, all of the reporters that report readiness
// need to have recently said 'Ready: true'.
type HealthAggregator struct {
	// Mutex to protect concurrent access to this health aggregator.
	mutex *sync.Mutex

	// The previous health summary report which is cached so that we log only when the overall health report changes.
	lastReport *HealthReport

	// Map from reporter name to corresponding state.
	reporters map[string]*reporterState

	// HTTP server mux.  This is where we register handlers for particular URLs.
	httpServeMux *http.ServeMux

	// HTTP server.  Non-nil when there should be a server running.
	httpServer *http.Server
}

// RegisterReporter registers a reporter with a HealthAggregator.  The aggregator uses NAME to
// identify the reporter.  REPORTS indicates the kinds of health that this reporter will report.
// TIMEOUT is the expiry time for this reporter's reports; the implication of which is that the
// reporter should normally refresh its reports well before this time has expired.
func (aggregator *HealthAggregator) RegisterReporter(name string, reports *HealthReport, timeout time.Duration) {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	aggregator.reporters[name] = &reporterState{
		name:      name,
		reports:   *reports,
		timeout:   timeout,
		latest:    HealthReport{Live: true},
		timestamp: time.Now(),
	}
	return
}

// Report reports current health from a reporter to a HealthAggregator.  NAME is the reporter's name
// and REPORTS conveys the current status, for each kind of health that the reporter said it was
// going to report when it called RegisterReporter.
func (aggregator *HealthAggregator) Report(name string, report *HealthReport) {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	reporter := aggregator.reporters[name]

	logCxt := log.WithFields(log.Fields{
		"name":       name,
		"newReport":  report,
		"lastReport": reporter.latest,
	})

	logCxt.Debug("New health report")
	if reporter.latest != *report {
		logCxt.Info("Health of component changed")
		reporter.latest = *report
	}
	reporter.timestamp = time.Now()
	return
}

func NewHealthAggregator() *HealthAggregator {
	aggregator := &HealthAggregator{
		mutex:        &sync.Mutex{},
		lastReport:   &HealthReport{},
		reporters:    map[string]*reporterState{},
		httpServeMux: http.NewServeMux(),
	}
	aggregator.httpServeMux.HandleFunc("/readiness", func(rsp http.ResponseWriter, req *http.Request) {
		log.Debug("GET /readiness")
		status := StatusBad
		if aggregator.Summary().Ready {
			log.Debug("Health: ready")
			status = StatusGood
		} else {
			log.Warn("Health: not ready")
		}
		rsp.WriteHeader(status)
	})
	aggregator.httpServeMux.HandleFunc("/liveness", func(rsp http.ResponseWriter, req *http.Request) {
		log.Debug("GET /liveness")
		status := StatusBad
		if aggregator.Summary().Live {
			log.Debug("Health: live")
			status = StatusGood
		} else {
			log.Warn("Health: not live")
		}
		rsp.WriteHeader(status)
	})
	return aggregator
}

// Summary calculates the current overall health for a HealthAggregator.
func (aggregator *HealthAggregator) Summary() *HealthReport {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()

	// In the absence of any reporters, default to indicating that we are both live and ready.
	summary := &HealthReport{Live: true, Ready: true}

	// Now for each reporter...
	for _, reporter := range aggregator.reporters {
		log.WithField("reporter", reporter).Debug("Checking state of reporter")
		if !reporter.RecentlyLive() {
			log.WithField("name", reporter.name).Warn("Reporter is not live.")
			summary.Live = false
		}
		if !reporter.RecentlyReady() {
			log.WithField("name", reporter.name).Warn("Reporter is not ready.")
			summary.Ready = false
		}
	}

	// Summary status has changed so update previous status and log.
	if aggregator.lastReport == nil || *summary != *aggregator.lastReport {
		aggregator.lastReport = summary
		log.WithField("newStatus", summary).Info("Overall health status changed")
	}

	log.WithField("healthResult", summary).Debug("Calculated health summary")

	return summary
}

const (
	// The HTTP status that we use for 'ready' or 'live'.  204 means "No Content: The server
	// successfully processed the request and is not returning any content."  (Kubernetes
	// interpets any 200<=status<400 as 'good'.)
	StatusGood = 204

	// The HTTP status that we use for 'not ready' or 'not live'.  503 means "Service
	// Unavailable: The server is currently unavailable (because it is overloaded or down for
	// maintenance). Generally, this is a temporary state."  (Kubernetes interpets any
	// status>=400 as 'bad'.)
	StatusBad = 503
)

// ServeHTTP publishes the current overall liveness and readiness at http://HOST:PORT/liveness and
// http://HOST:PORT/readiness respectively.  A GET request on those URLs returns StatusGood or
// StatusBad, according to the current overall liveness or readiness.  These endpoints are designed
// for use by Kubernetes liveness and readiness probes.
func (aggregator *HealthAggregator) ServeHTTP(enabled bool, host string, port int) {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	if enabled {
		logCxt := log.WithFields(log.Fields{
			"host": host,
			"port": port,
		})
		if aggregator.httpServer != nil {
			logCxt.Info("Health enabled.  Server is already running.")
			return
		}
		logCxt.Info("Health enabled.  Starting server.")
		aggregator.httpServer = &http.Server{
			Addr:    fmt.Sprintf("%s:%v", host, port),
			Handler: aggregator.httpServeMux,
		}
		go func() {
			for {
				server := aggregator.getHTTPServer()
				if server == nil {
					// HTTP serving is now disabled.
					break
				}
				err := server.ListenAndServe()
				log.WithError(err).Error(
					"Health endpoint failed, trying to restart it...")
				time.Sleep(1 * time.Second)
			}
		}()
	} else {
		if aggregator.httpServer != nil {
			log.Info("Health disabled.  Stopping server.")
			_ = aggregator.httpServer.Close()
			aggregator.httpServer = nil
		}
	}
}

func (aggregator *HealthAggregator) getHTTPServer() *http.Server {
	aggregator.mutex.Lock()
	defer aggregator.mutex.Unlock()
	return aggregator.httpServer
}
<|endoftext|>


<commit_before>package tokenattributes

import (
	"github.com/balzaczyy/golucene/core/util"
)

/* The term text of a Token. */
type CharTermAttribute interface {
	// Copies the contents of buffer into the termBuffer array
	CopyBuffer(buffer []rune)
	// Returns the internal termBuffer rune slice which you can then
	// directly alter. If the slice is too small for your token, use
	// ResizeBuffer(int) to increase it. After altering the buffer, be
	// sure to call SetLength() to record the number of valid runes
	// that were placed into the termBuffer.
	//
	// NOTE: the returned buffer may be larger than the valid Length().
	Buffer() []rune
	Length() int
	// Appends teh specified string to this character sequence.
	//
	// The character of the string argument are appended, in order,
	// increasing the length of this sequence by the length of the
	// argument. If argument is "", then the three characters "nil" are
	// appended.
	AppendString(string) CharTermAttribute
}

const MIN_BUFFER_SIZE = 10

/* Default implementation of CharTermAttribute. */
type CharTermAttributeImpl struct {
	termBuffer []rune
	termLength int
	bytes      *util.BytesRef
}

func newCharTermAttributeImpl() *util.AttributeImpl {
	ans := &CharTermAttributeImpl{
		termBuffer: make([]rune, util.Oversize(MIN_BUFFER_SIZE, util.NUM_BYTES_CHAR)),
		bytes:      util.NewBytesRef(make([]byte, 0, MIN_BUFFER_SIZE)),
	}
	return util.NewAttributeImpl(ans)
}

func (a *CharTermAttributeImpl) Interfaces() []string {
	return []string{"CharTermAttribute", "TermToBytesRefAttribute"}
}

func (a *CharTermAttributeImpl) CopyBuffer(buffer []rune) {
	a.growTermBuffer(len(buffer))
	copy(a.termBuffer, buffer)
	a.termLength = len(buffer)
}

func (a *CharTermAttributeImpl) Buffer() []rune {
	return a.termBuffer
}

func (a *CharTermAttributeImpl) growTermBuffer(newSize int) {
	if len(a.termBuffer) < newSize {
		// not big enough: create a new slice with slight over allocation:
		a.termBuffer = make([]rune, util.Oversize(newSize, util.NUM_BYTES_CHAR))
	}
}

func (a *CharTermAttributeImpl) FillBytesRef() int {
	s := string(a.termBuffer[:a.termLength])
	hash := hashstr(s)
	a.bytes.Value = []byte(s)
	return hash
}

const primeRK = 16777619

/* simple string hash used by Go strings package */
func hashstr(sep string) int {
	hash := uint32(0)
	for i := 0; i < len(sep); i++ {
		hash = hash*primeRK + uint32(sep[i])
	}
	return int(hash)
}

func (a *CharTermAttributeImpl) BytesRef() *util.BytesRef {
	return a.bytes
}

func (a *CharTermAttributeImpl) Length() int {
	return a.termLength
}

func (a *CharTermAttributeImpl) AppendString(s string) CharTermAttribute {
	if s == "" { // needed for Appendable compliance
		return a.appendNil()
	}
	for _, ch := range s {
		a.termBuffer = append(a.termBuffer, ch)
		a.termLength++
	}
	return a
}

func (a *CharTermAttributeImpl) appendNil() CharTermAttribute {
	a.termBuffer = append(a.termBuffer, 'n')
	a.termBuffer = append(a.termBuffer, 'i')
	a.termBuffer = append(a.termBuffer, 'l')
	a.termLength += 3
	return a
}

func (a *CharTermAttributeImpl) Clear() {
	a.termLength = 0
}

func (a *CharTermAttributeImpl) String() string {
	return string(a.termBuffer[:a.termLength])
}
<commit_msg>fix term read issue<commit_after>package tokenattributes

import (
	"github.com/balzaczyy/golucene/core/util"
)

/* The term text of a Token. */
type CharTermAttribute interface {
	// Copies the contents of buffer into the termBuffer array
	CopyBuffer(buffer []rune)
	// Returns the internal termBuffer rune slice which you can then
	// directly alter. If the slice is too small for your token, use
	// ResizeBuffer(int) to increase it. After altering the buffer, be
	// sure to call SetLength() to record the number of valid runes
	// that were placed into the termBuffer.
	//
	// NOTE: the returned buffer may be larger than the valid Length().
	Buffer() []rune
	Length() int
	// Appends teh specified string to this character sequence.
	//
	// The character of the string argument are appended, in order,
	// increasing the length of this sequence by the length of the
	// argument. If argument is "", then the three characters "nil" are
	// appended.
	AppendString(string) CharTermAttribute
}

const MIN_BUFFER_SIZE = 10

/* Default implementation of CharTermAttribute. */
type CharTermAttributeImpl struct {
	termBuffer []rune
	termLength int
	bytes      *util.BytesRef
}

func newCharTermAttributeImpl() *util.AttributeImpl {
	ans := &CharTermAttributeImpl{
		termBuffer: make([]rune, util.Oversize(MIN_BUFFER_SIZE, util.NUM_BYTES_CHAR)),
		bytes:      util.NewBytesRef(make([]byte, 0, MIN_BUFFER_SIZE)),
	}
	return util.NewAttributeImpl(ans)
}

func (a *CharTermAttributeImpl) Interfaces() []string {
	return []string{"CharTermAttribute", "TermToBytesRefAttribute"}
}

func (a *CharTermAttributeImpl) CopyBuffer(buffer []rune) {
	a.growTermBuffer(len(buffer))
	copy(a.termBuffer, buffer)
	a.termLength = len(buffer)
}

func (a *CharTermAttributeImpl) Buffer() []rune {
	return a.termBuffer
}

func (a *CharTermAttributeImpl) growTermBuffer(newSize int) {
	if len(a.termBuffer) < newSize {
		// not big enough: create a new slice with slight over allocation:
		a.termBuffer = make([]rune, util.Oversize(newSize, util.NUM_BYTES_CHAR))
	}
}

func (a *CharTermAttributeImpl) FillBytesRef() int {
	s := string(a.termBuffer[:a.termLength])
	hash := hashstr(s)
	a.bytes.Value = []byte(s)
	return hash
}

const primeRK = 16777619

/* simple string hash used by Go strings package */
func hashstr(sep string) int {
	hash := uint32(0)
	for i := 0; i < len(sep); i++ {
		hash = hash*primeRK + uint32(sep[i])
	}
	return int(hash)
}

func (a *CharTermAttributeImpl) BytesRef() *util.BytesRef {
	return a.bytes
}

func (a *CharTermAttributeImpl) Length() int {
	return a.termLength
}

func (a *CharTermAttributeImpl) AppendString(s string) CharTermAttribute {
	if s == "" { // needed for Appendable compliance
		return a.appendNil()
	}
	for _, ch := range s {
		if a.termLength < len(a.termBuffer) {
			a.termBuffer[a.termLength] = ch
		} else {
			a.termBuffer = append(a.termBuffer, ch)
		}
		a.termLength++
	}
	return a
}

func (a *CharTermAttributeImpl) appendNil() CharTermAttribute {
	a.termBuffer = append(a.termBuffer, 'n')
	a.termBuffer = append(a.termBuffer, 'i')
	a.termBuffer = append(a.termBuffer, 'l')
	a.termLength += 3
	return a
}

func (a *CharTermAttributeImpl) Clear() {
	a.termLength = 0
}

func (a *CharTermAttributeImpl) String() string {
	return string(a.termBuffer[:a.termLength])
}
<|endoftext|>


<commit_before>package transactional

import (
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/storer"
	"github.com/go-git/go-git/v5/storage"
)

// ReferenceStorage implements the storer.ReferenceStorage for the transactional package.
type ReferenceStorage struct {
	storer.ReferenceStorer
	temporal storer.ReferenceStorer

	// deleted, remaining references at this maps are going to be deleted when
	// commit is requested, the entries are added when RemoveReference is called
	// and deleted if SetReference is called.
	deleted map[plumbing.ReferenceName]struct{}
	// packRefs if true PackRefs is going to be called in the based storer when
	// commit is called.
	packRefs bool
}

// NewReferenceStorage returns a new ReferenceStorer based on a base storer and
// a temporal storer.
func NewReferenceStorage(base, temporal storer.ReferenceStorer) *ReferenceStorage {
	return &ReferenceStorage{
		ReferenceStorer: base,
		temporal:        temporal,

		deleted: make(map[plumbing.ReferenceName]struct{}),
	}
}

// SetReference honors the storer.ReferenceStorer interface.
func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error {
	delete(r.deleted, ref.Name())
	return r.temporal.SetReference(ref)
}

// SetReference honors the storer.ReferenceStorer interface.
func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error {
	if old == nil {
		return r.SetReference(ref)
	}

	tmp, err := r.temporal.Reference(old.Name())
	if err == plumbing.ErrReferenceNotFound {
		tmp, err = r.ReferenceStorer.Reference(old.Name())
	}

	if err != nil {
		return err
	}

	if tmp.Hash() != old.Hash() {
		return storage.ErrReferenceHasChanged
	}

	return r.SetReference(ref)
}

// Reference honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) {
	if _, deleted := r.deleted[n]; deleted {
		return nil, plumbing.ErrReferenceNotFound
	}

	ref, err := r.temporal.Reference(n)
	if err == plumbing.ErrReferenceNotFound {
		return r.ReferenceStorer.Reference(n)
	}

	return ref, err
}

// IterReferences honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) {
	baseIter, err := r.ReferenceStorer.IterReferences()
	if err != nil {
		return nil, err
	}

	temporalIter, err := r.temporal.IterReferences()
	if err != nil {
		return nil, err
	}

	return storer.NewMultiReferenceIter([]storer.ReferenceIter{
		baseIter,
		temporalIter,
	}), nil
}

// CountLooseRefs honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) CountLooseRefs() (int, error) {
	tc, err := r.temporal.CountLooseRefs()
	if err != nil {
		return -1, err
	}

	bc, err := r.ReferenceStorer.CountLooseRefs()
	if err != nil {
		return -1, err
	}

	return tc + bc, nil
}

// PackRefs honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) PackRefs() error {
	r.packRefs = true
	return nil
}

// RemoveReference honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error {
	r.deleted[n] = struct{}{}
	return r.temporal.RemoveReference(n)
}

// Commit it copies the reference information of the temporal storage into the
// base storage.
func (r ReferenceStorage) Commit() error {
	for name := range r.deleted {
		if err := r.ReferenceStorer.RemoveReference(name); err != nil {
			return err
		}
	}

	iter, err := r.temporal.IterReferences()
	if err != nil {
		return err
	}

	return iter.ForEach(func(ref *plumbing.Reference) error {
		return r.ReferenceStorer.SetReference(ref)
	})
}
<commit_msg>transactional/ReferenceStorage: Drop packRefs field<commit_after>package transactional

import (
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/storer"
	"github.com/go-git/go-git/v5/storage"
)

// ReferenceStorage implements the storer.ReferenceStorage for the transactional package.
type ReferenceStorage struct {
	storer.ReferenceStorer
	temporal storer.ReferenceStorer

	// deleted, remaining references at this maps are going to be deleted when
	// commit is requested, the entries are added when RemoveReference is called
	// and deleted if SetReference is called.
	deleted map[plumbing.ReferenceName]struct{}
}

// NewReferenceStorage returns a new ReferenceStorer based on a base storer and
// a temporal storer.
func NewReferenceStorage(base, temporal storer.ReferenceStorer) *ReferenceStorage {
	return &ReferenceStorage{
		ReferenceStorer: base,
		temporal:        temporal,

		deleted: make(map[plumbing.ReferenceName]struct{}),
	}
}

// SetReference honors the storer.ReferenceStorer interface.
func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error {
	delete(r.deleted, ref.Name())
	return r.temporal.SetReference(ref)
}

// SetReference honors the storer.ReferenceStorer interface.
func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error {
	if old == nil {
		return r.SetReference(ref)
	}

	tmp, err := r.temporal.Reference(old.Name())
	if err == plumbing.ErrReferenceNotFound {
		tmp, err = r.ReferenceStorer.Reference(old.Name())
	}

	if err != nil {
		return err
	}

	if tmp.Hash() != old.Hash() {
		return storage.ErrReferenceHasChanged
	}

	return r.SetReference(ref)
}

// Reference honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) {
	if _, deleted := r.deleted[n]; deleted {
		return nil, plumbing.ErrReferenceNotFound
	}

	ref, err := r.temporal.Reference(n)
	if err == plumbing.ErrReferenceNotFound {
		return r.ReferenceStorer.Reference(n)
	}

	return ref, err
}

// IterReferences honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) {
	baseIter, err := r.ReferenceStorer.IterReferences()
	if err != nil {
		return nil, err
	}

	temporalIter, err := r.temporal.IterReferences()
	if err != nil {
		return nil, err
	}

	return storer.NewMultiReferenceIter([]storer.ReferenceIter{
		baseIter,
		temporalIter,
	}), nil
}

// CountLooseRefs honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) CountLooseRefs() (int, error) {
	tc, err := r.temporal.CountLooseRefs()
	if err != nil {
		return -1, err
	}

	bc, err := r.ReferenceStorer.CountLooseRefs()
	if err != nil {
		return -1, err
	}

	return tc + bc, nil
}

// PackRefs honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) PackRefs() error {
	return nil
}

// RemoveReference honors the storer.ReferenceStorer interface.
func (r ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error {
	r.deleted[n] = struct{}{}
	return r.temporal.RemoveReference(n)
}

// Commit it copies the reference information of the temporal storage into the
// base storage.
func (r ReferenceStorage) Commit() error {
	for name := range r.deleted {
		if err := r.ReferenceStorer.RemoveReference(name); err != nil {
			return err
		}
	}

	iter, err := r.temporal.IterReferences()
	if err != nil {
		return err
	}

	return iter.ForEach(func(ref *plumbing.Reference) error {
		return r.ReferenceStorer.SetReference(ref)
	})
}
<|endoftext|>


<commit_before>// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Verify that unbuffered channels act as pure fifos.

package main

const N = 10

func AsynchFifo() {
	ch := new(chan int, N);
	for i := 0; i < N; i++ {
		ch -< i
	}
	for i := 0; i < N; i++ {
		if <-ch != i {
			print "bad receive\n";
			sys.exit(1);
		}
	}
}

func Chain(ch *chan<- int, val int, in *chan<- int, out *chan-< int) {
	<-in;
	if <-ch != val {
		panic val
	}
	out -< 1
}

// thread together a daisy chain to read the elements in sequence
func SynchFifo() {
	ch := new(chan int);
	in := new(chan int);
	start := in;
	for i := 0; i < N; i++ {
		out := new(chan int);
		go Chain(ch, i, in, out);
		in = out;
	}
	start -< 0;
	for i := 0; i < N; i++ {
		ch -< i
	}
}

func main() {
	AsynchFifo();
	SynchFifo();
}

<commit_msg>fix bug - need to read final message in daisy chain to avoid hang<commit_after>// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Verify that unbuffered channels act as pure fifos.

package main

const N = 10

func AsynchFifo() {
	ch := new(chan int, N);
	for i := 0; i < N; i++ {
		ch -< i
	}
	for i := 0; i < N; i++ {
		if <-ch != i {
			print "bad receive\n";
			sys.exit(1);
		}
	}
}

func Chain(ch *chan<- int, val int, in *chan<- int, out *chan-< int) {
	<-in;
	if <-ch != val {
		panic val
	}
	out -< 1
}

// thread together a daisy chain to read the elements in sequence
func SynchFifo() {
	ch := new(chan int);
	in := new(chan int);
	start := in;
	for i := 0; i < N; i++ {
		out := new(chan int);
		go Chain(ch, i, in, out);
		in = out;
	}
	start -< 0;
	for i := 0; i < N; i++ {
		ch -< i
	}
	<-in
}

func main() {
	AsynchFifo();
	SynchFifo();
}

<|endoftext|>


<commit_before>package ddcloud

import (
	"fmt"
	"testing"

	"github.com/DimensionDataResearch/go-dd-cloud-compute/compute"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

/*
 * Acceptance-test configurations.
 */

// A basic virtual listener (and the network domain that contains it).
func testAccDDCloudVirtualListenerBasic(name string, listenerIPAddress string, enabled bool) string {
	return fmt.Sprintf(`
		provider "ddcloud" {
			region		= "AU"
		}

		resource "ddcloud_networkdomain" "acc_test_domain" {
			name		= "acc-test-networkdomain"
			description	= "Network domain for Terraform acceptance test."
			datacenter	= "AU9"

			plan		= "ADVANCED"
		}

		resource "ddcloud_virtual_listener" "acc_test_listener" {
			name                 	= "%s"
			protocol             	= "HTTP"
			optimization_profiles 	= ["TCP"]
			ipv4                	= "%s"
			enabled                 = "%t"

			networkdomain 		 	= "${ddcloud_networkdomain.acc_test_domain.id}"
		}
	`, name, listenerIPAddress, enabled)
}

/*
 * Acceptance tests.
 */

// Acceptance test for ddcloud_virtual_listener (basic):
//
// Create a virtual listener and verify that it gets created with the correct configuration.
func TestAccVirtualListenerBasicCreate(t *testing.T) {
	resource.Test(t, resource.TestCase{
		Providers: testAccProviders,
		CheckDestroy: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerDestroy,
			testCheckDDCloudNetworkDomainDestroy,
		),
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccDDCloudVirtualListenerBasic(
					"AccTestListener",
					"192.168.18.10",
					true,
				),
				Check: resource.ComposeTestCheckFunc(
					testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
					testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
						Name:              "AccTestListener",
						Protocol:          compute.VirtualListenerStandardProtocolHTTP,
						ListenerIPAddress: "192.168.18.10",
						Enabled:           true,
						OptimizationProfiles: []string{
							"TCP",
						},
					}),
				),
			},
		},
	})
}

// Acceptance test for ddcloud_virtual_listener (disabling causes in-place update):
//
// Create a virtual listener, then disable it, and verify that it gets updated in-place to Disabled.
func TestAccVirtualListenerBasicUpdateDisable(t *testing.T) {
	testAccResourceUpdateInPlace(t, testAccResourceUpdate{
		ResourceName: "ddcloud_virtual_listener.acc_test_listener",
		CheckDestroy: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerDestroy,
			testCheckDDCloudNetworkDomainDestroy,
		),

		// Create
		InitialConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener",
			"192.168.18.10",
			true,
		),
		InitialCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:              "AccTestListener",
				Protocol:          compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress: "192.168.18.10",
				Enabled:           true,
				OptimizationProfiles: []string{
					"TCP",
				},
			}),
		),

		// Update
		UpdateConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener",
			"192.168.18.10",
			false,
		),
		UpdateCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:              "AccTestListener",
				Protocol:          compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress: "192.168.18.10",
				Enabled:           false,
				OptimizationProfiles: []string{
					"TCP",
				},
			}),
		),
	})
}

// Acceptance test for ddcloud_virtual_listener (changing name causes destroy-and-recreate):
//
// Create a virtual listener, then change its name, and verify that it gets destroyed and recreated with the new name.
func TestAccVirtualListenerBasicUpdateName(t *testing.T) {
	testAccResourceUpdateReplace(t, testAccResourceUpdate{
		ResourceName: "ddcloud_virtual_listener.acc_test_listener",
		CheckDestroy: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerDestroy,
			testCheckDDCloudNetworkDomainDestroy,
		),

		// Create
		InitialConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener",
			"192.168.18.10",
			true,
		),
		InitialCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:              "AccTestListener",
				Protocol:          compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress: "192.168.18.10",
				Enabled:           true,
				OptimizationProfiles: []string{
					"TCP",
				},
			}),
		),

		// Update
		UpdateConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener1",
			"192.168.18.10",
			true,
		),
		UpdateCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:              "AccTestListener1",
				Protocol:          compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress: "192.168.18.10",
				Enabled:           true,
				OptimizationProfiles: []string{
					"TCP",
				},
			}),
		),
	})
}

/*
 * Acceptance-test checks.
 */

// Acceptance test check for ddcloud_virtual_listener:
//
// Check if the virtual listener exists.
func testCheckDDCloudVirtualListenerExists(name string, exists bool) resource.TestCheckFunc {
	name = ensureResourceTypePrefix(name, "ddcloud_virtual_listener")

	return func(state *terraform.State) error {
		res, ok := state.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		virtualListenerID := res.Primary.ID

		client := testAccProvider.Meta().(*providerState).Client()
		virtualListener, err := client.GetVirtualListener(virtualListenerID)
		if err != nil {
			return fmt.Errorf("bad: Get VirtualListener: %s", err)
		}
		if exists && virtualListener == nil {
			return fmt.Errorf("bad: virtual listener not found with Id '%s'", virtualListenerID)
		} else if !exists && virtualListener != nil {
			return fmt.Errorf("bad: virtual listener still exists with Id '%s'", virtualListenerID)
		}

		return nil
	}
}

// Acceptance test check for ddcloud_virtual_listener:
//
// Check if the VirtualListener's configuration matches the expected configuration.
func testCheckDDCloudVirtualListenerMatches(name string, expected compute.VirtualListener) resource.TestCheckFunc {
	name = ensureResourceTypePrefix(name, "ddcloud_virtual_listener")

	return func(state *terraform.State) error {
		res, ok := state.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		virtualListenerID := res.Primary.ID

		client := testAccProvider.Meta().(*providerState).Client()
		virtualListener, err := client.GetVirtualListener(virtualListenerID)
		if err != nil {
			return fmt.Errorf("bad: Get VirtualListener: %s", err)
		}
		if virtualListener == nil {
			return fmt.Errorf("bad: virtual listener not found with Id '%s'", virtualListenerID)
		}

		if virtualListener.Name != expected.Name {
			return fmt.Errorf("bad: virtual listener '%s' has name '%s' (expected '%s')", virtualListenerID, virtualListener.Name, expected.Name)
		}

		if virtualListener.Description != expected.Description {
			return fmt.Errorf("bad: virtual listener '%s' has name '%s' (expected '%s')", virtualListenerID, virtualListener.Description, expected.Description)
		}

		if virtualListener.ListenerIPAddress != expected.ListenerIPAddress {
			return fmt.Errorf("bad: virtual listener '%s' has IPv4 address '%s' (expected '%s')", virtualListenerID, virtualListener.ListenerIPAddress, expected.ListenerIPAddress)
		}

		if virtualListener.Enabled != expected.Enabled {
			return fmt.Errorf("bad: virtual listener '%s' has enablement status '%t' (expected '%t')", virtualListenerID, virtualListener.Enabled, expected.Enabled)
		}

		return nil
	}
}

// Acceptance test resource-destruction check for ddcloud_virtual_listener:
//
// Check all VirtualListeners specified in the configuration have been destroyed.
func testCheckDDCloudVirtualListenerDestroy(state *terraform.State) error {
	for _, res := range state.RootModule().Resources {
		if res.Type != "ddcloud_virtual_listener" {
			continue
		}

		virtualListenerID := res.Primary.ID

		client := testAccProvider.Meta().(*providerState).Client()
		virtualListener, err := client.GetVirtualListener(virtualListenerID)
		if err != nil {
			return nil
		}
		if virtualListener != nil {
			return fmt.Errorf("Virtual listener '%s' still exists", virtualListenerID)
		}
	}

	return nil
}
<commit_msg>Fix compile error.<commit_after>package ddcloud

import (
	"fmt"
	"testing"

	"github.com/DimensionDataResearch/go-dd-cloud-compute/compute"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

/*
 * Acceptance-test configurations.
 */

// A basic virtual listener (and the network domain that contains it).
func testAccDDCloudVirtualListenerBasic(name string, listenerIPAddress string, enabled bool) string {
	return fmt.Sprintf(`
		provider "ddcloud" {
			region		= "AU"
		}

		resource "ddcloud_networkdomain" "acc_test_domain" {
			name		= "acc-test-networkdomain"
			description	= "Network domain for Terraform acceptance test."
			datacenter	= "AU9"

			plan		= "ADVANCED"
		}

		resource "ddcloud_virtual_listener" "acc_test_listener" {
			name                 	= "%s"
			protocol             	= "HTTP"
			optimization_profiles 	= ["TCP"]
			ipv4                	= "%s"
			enabled                 = "%t"

			networkdomain 		 	= "${ddcloud_networkdomain.acc_test_domain.id}"
		}
	`, name, listenerIPAddress, enabled)
}

/*
 * Acceptance tests.
 */

// Acceptance test for ddcloud_virtual_listener (basic):
//
// Create a virtual listener and verify that it gets created with the correct configuration.
func TestAccVirtualListenerBasicCreate(t *testing.T) {
	resource.Test(t, resource.TestCase{
		Providers: testAccProviders,
		CheckDestroy: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerDestroy,
			testCheckDDCloudNetworkDomainDestroy,
		),
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccDDCloudVirtualListenerBasic(
					"AccTestListener",
					"192.168.18.10",
					true,
				),
				Check: resource.ComposeTestCheckFunc(
					testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
					testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
						Name:                "AccTestListener",
						Protocol:            compute.VirtualListenerStandardProtocolHTTP,
						ListenerIPAddress:   "192.168.18.10",
						Enabled:             true,
						OptimizationProfile: "TCP",
					}),
				),
			},
		},
	})
}

// Acceptance test for ddcloud_virtual_listener (disabling causes in-place update):
//
// Create a virtual listener, then disable it, and verify that it gets updated in-place to Disabled.
func TestAccVirtualListenerBasicUpdateDisable(t *testing.T) {
	testAccResourceUpdateInPlace(t, testAccResourceUpdate{
		ResourceName: "ddcloud_virtual_listener.acc_test_listener",
		CheckDestroy: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerDestroy,
			testCheckDDCloudNetworkDomainDestroy,
		),

		// Create
		InitialConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener",
			"192.168.18.10",
			true,
		),
		InitialCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:                "AccTestListener",
				Protocol:            compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress:   "192.168.18.10",
				Enabled:             true,
				OptimizationProfile: "TCP",
			}),
		),

		// Update
		UpdateConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener",
			"192.168.18.10",
			false,
		),
		UpdateCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:                "AccTestListener",
				Protocol:            compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress:   "192.168.18.10",
				Enabled:             false,
				OptimizationProfile: "TCP",
			}),
		),
	})
}

// Acceptance test for ddcloud_virtual_listener (changing name causes destroy-and-recreate):
//
// Create a virtual listener, then change its name, and verify that it gets destroyed and recreated with the new name.
func TestAccVirtualListenerBasicUpdateName(t *testing.T) {
	testAccResourceUpdateReplace(t, testAccResourceUpdate{
		ResourceName: "ddcloud_virtual_listener.acc_test_listener",
		CheckDestroy: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerDestroy,
			testCheckDDCloudNetworkDomainDestroy,
		),

		// Create
		InitialConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener",
			"192.168.18.10",
			true,
		),
		InitialCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:                "AccTestListener",
				Protocol:            compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress:   "192.168.18.10",
				Enabled:             true,
				OptimizationProfile: "TCP",
			}),
		),

		// Update
		UpdateConfig: testAccDDCloudVirtualListenerBasic(
			"AccTestListener1",
			"192.168.18.10",
			true,
		),
		UpdateCheck: resource.ComposeTestCheckFunc(
			testCheckDDCloudVirtualListenerExists("acc_test_listener", true),
			testCheckDDCloudVirtualListenerMatches("acc_test_listener", compute.VirtualListener{
				Name:                "AccTestListener1",
				Protocol:            compute.VirtualListenerStandardProtocolHTTP,
				ListenerIPAddress:   "192.168.18.10",
				Enabled:             true,
				OptimizationProfile: "TCP",
			}),
		),
	})
}

/*
 * Acceptance-test checks.
 */

// Acceptance test check for ddcloud_virtual_listener:
//
// Check if the virtual listener exists.
func testCheckDDCloudVirtualListenerExists(name string, exists bool) resource.TestCheckFunc {
	name = ensureResourceTypePrefix(name, "ddcloud_virtual_listener")

	return func(state *terraform.State) error {
		res, ok := state.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		virtualListenerID := res.Primary.ID

		client := testAccProvider.Meta().(*providerState).Client()
		virtualListener, err := client.GetVirtualListener(virtualListenerID)
		if err != nil {
			return fmt.Errorf("bad: Get VirtualListener: %s", err)
		}
		if exists && virtualListener == nil {
			return fmt.Errorf("bad: virtual listener not found with Id '%s'", virtualListenerID)
		} else if !exists && virtualListener != nil {
			return fmt.Errorf("bad: virtual listener still exists with Id '%s'", virtualListenerID)
		}

		return nil
	}
}

// Acceptance test check for ddcloud_virtual_listener:
//
// Check if the VirtualListener's configuration matches the expected configuration.
func testCheckDDCloudVirtualListenerMatches(name string, expected compute.VirtualListener) resource.TestCheckFunc {
	name = ensureResourceTypePrefix(name, "ddcloud_virtual_listener")

	return func(state *terraform.State) error {
		res, ok := state.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		virtualListenerID := res.Primary.ID

		client := testAccProvider.Meta().(*providerState).Client()
		virtualListener, err := client.GetVirtualListener(virtualListenerID)
		if err != nil {
			return fmt.Errorf("bad: Get VirtualListener: %s", err)
		}
		if virtualListener == nil {
			return fmt.Errorf("bad: virtual listener not found with Id '%s'", virtualListenerID)
		}

		if virtualListener.Name != expected.Name {
			return fmt.Errorf("bad: virtual listener '%s' has name '%s' (expected '%s')", virtualListenerID, virtualListener.Name, expected.Name)
		}

		if virtualListener.Description != expected.Description {
			return fmt.Errorf("bad: virtual listener '%s' has name '%s' (expected '%s')", virtualListenerID, virtualListener.Description, expected.Description)
		}

		if virtualListener.ListenerIPAddress != expected.ListenerIPAddress {
			return fmt.Errorf("bad: virtual listener '%s' has IPv4 address '%s' (expected '%s')", virtualListenerID, virtualListener.ListenerIPAddress, expected.ListenerIPAddress)
		}

		if virtualListener.Enabled != expected.Enabled {
			return fmt.Errorf("bad: virtual listener '%s' has enablement status '%t' (expected '%t')", virtualListenerID, virtualListener.Enabled, expected.Enabled)
		}

		return nil
	}
}

// Acceptance test resource-destruction check for ddcloud_virtual_listener:
//
// Check all VirtualListeners specified in the configuration have been destroyed.
func testCheckDDCloudVirtualListenerDestroy(state *terraform.State) error {
	for _, res := range state.RootModule().Resources {
		if res.Type != "ddcloud_virtual_listener" {
			continue
		}

		virtualListenerID := res.Primary.ID

		client := testAccProvider.Meta().(*providerState).Client()
		virtualListener, err := client.GetVirtualListener(virtualListenerID)
		if err != nil {
			return nil
		}
		if virtualListener != nil {
			return fmt.Errorf("Virtual listener '%s' still exists", virtualListenerID)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package test

import (
	"github.com/eaciit/toolkit"
	. "github.com/frezadev/hdc/hive"
	// . "github.com/eaciit/hdc/hive"
	//. "github.com/RyanCi/hdc/hive"
	"os"
	"testing"
)

var h *Hive
var e error

type Sample7 struct {
	Code        string `tag_name:"code"`
	Description string `tag_name:"description"`
	Total_emp   string `tag_name:"total_emp"`
	Salary      string `tag_name:"salary"`
}

type Students struct {
	Name    string
	Age     int
	Phone   string
	Address string
}

func killApp(code int) {
	if h != nil {
		h.Conn.Close()
	}
	os.Exit(code)
}

func fatalCheck(t *testing.T, what string, e error) {
	if e != nil {
		t.Fatalf("%s: %s", what, e.Error())
	}
}

func TestHiveConnect(t *testing.T) {
	h = HiveConfig("192.168.0.223:10000", "default", "hdfs", "", "")
}

/* Populate will exec query and immidiately return the value into object
Populate is suitable for short type query that return limited data,
Exec is suitable for long type query that return massive amount of data and require time to produce it

Ideally Populate should call Exec as well but already have predefined function on it receiving process
*/
func TestHivePopulate(t *testing.T) {
	q := "select * from sample_07 limit 5;"

	var result []toolkit.M

	h.Conn.Open()

	e := h.Populate(q, &result)
	fatalCheck(t, "Populate", e)

	if len(result) != 5 {
		t.Logf("Error want %d got %d", 5, len(result))
	}

	t.Logf("Result: \n%s", toolkit.JsonString(result))

	h.Conn.Close()
}

func TestHiveExec(t *testing.T) {
	i := 0
	q := "select * from sample_07 limit 5;"

	h.Conn.Open()

	e := h.Exec(q, func(x HiveResult) error {
		i++
		t.Logf("Receiving data: %s", toolkit.JsonString(x))
		return nil
	})

	if e != nil {
		t.Fatalf("Error exec query: %s", e.Error())
	}

	if i < 5 {
		t.Fatalf("Error receive result. Expect %d got %d", 5, i)
	}

	h.Conn.Close()
}

func TestHiveExecMulti(t *testing.T) {
	h.Conn.Open()

	var ms1, ms2 []HiveResult
	q := "select * from sample_07 limit 5"

	e := h.Exec(q, func(x HiveResult) error {
		ms1 = append(ms1, x)
		return nil
	})

	fatalCheck(t, "HS1 exec", e)

	e = h.Exec(q, func(x HiveResult) error {
		ms2 = append(ms2, x)
		return nil
	})

	fatalCheck(t, "HS2 Exec", e)

	t.Logf("Value of HS1\n%s\n\nValue of HS2\n%s", toolkit.JsonString(ms1), toolkit.JsonString(ms2))

	h.Conn.Close()
}

func TestLoad(t *testing.T) {
	h.Conn.Open()

	var Student Students

	retVal, err := h.Load("students", "|", &Student)

	if err != nil {
		t.Log(err)
	}
	h.Conn.Close()
	t.Log(retVal)
}

//for now, this function works on simple csv file
func TestLoadFile(t *testing.T) {
	h.Conn.Open()

	var Student Students

	retVal, err := h.LoadFile("/home/developer/contoh.txt", "students", "txt", &Student)

	if err != nil {
		t.Log(err)
	}
	h.Conn.Close()
	t.Log(retVal)
}
<commit_msg>change import part<commit_after>package test

import (
	"github.com/eaciit/toolkit"
	//. "github.com/frezadev/hdc/hive"
	. "github.com/eaciit/hdc/hive"
	//. "github.com/RyanCi/hdc/hive"
	"os"
	"testing"
)

var h *Hive
var e error

type Sample7 struct {
	Code        string `tag_name:"code"`
	Description string `tag_name:"description"`
	Total_emp   string `tag_name:"total_emp"`
	Salary      string `tag_name:"salary"`
}

type Students struct {
	Name    string
	Age     int
	Phone   string
	Address string
}

func killApp(code int) {
	if h != nil {
		h.Conn.Close()
	}
	os.Exit(code)
}

func fatalCheck(t *testing.T, what string, e error) {
	if e != nil {
		t.Fatalf("%s: %s", what, e.Error())
	}
}

func TestHiveConnect(t *testing.T) {
	h = HiveConfig("192.168.0.223:10000", "default", "hdfs", "", "")
}

/* Populate will exec query and immidiately return the value into object
Populate is suitable for short type query that return limited data,
Exec is suitable for long type query that return massive amount of data and require time to produce it

Ideally Populate should call Exec as well but already have predefined function on it receiving process
*/
func TestHivePopulate(t *testing.T) {
	q := "select * from sample_07 limit 5;"

	var result []toolkit.M

	h.Conn.Open()

	e := h.Populate(q, &result)
	fatalCheck(t, "Populate", e)

	if len(result) != 5 {
		t.Logf("Error want %d got %d", 5, len(result))
	}

	t.Logf("Result: \n%s", toolkit.JsonString(result))

	h.Conn.Close()
}

func TestHiveExec(t *testing.T) {
	i := 0
	q := "select * from sample_07 limit 5;"

	h.Conn.Open()

	e := h.Exec(q, func(x HiveResult) error {
		i++
		t.Logf("Receiving data: %s", toolkit.JsonString(x))
		return nil
	})

	if e != nil {
		t.Fatalf("Error exec query: %s", e.Error())
	}

	if i < 5 {
		t.Fatalf("Error receive result. Expect %d got %d", 5, i)
	}

	h.Conn.Close()
}

func TestHiveExecMulti(t *testing.T) {
	h.Conn.Open()

	var ms1, ms2 []HiveResult
	q := "select * from sample_07 limit 5"

	e := h.Exec(q, func(x HiveResult) error {
		ms1 = append(ms1, x)
		return nil
	})

	fatalCheck(t, "HS1 exec", e)

	e = h.Exec(q, func(x HiveResult) error {
		ms2 = append(ms2, x)
		return nil
	})

	fatalCheck(t, "HS2 Exec", e)

	t.Logf("Value of HS1\n%s\n\nValue of HS2\n%s", toolkit.JsonString(ms1), toolkit.JsonString(ms2))

	h.Conn.Close()
}

func TestLoad(t *testing.T) {
	h.Conn.Open()

	var Student Students

	retVal, err := h.Load("students", "|", &Student)

	if err != nil {
		t.Log(err)
	}
	h.Conn.Close()
	t.Log(retVal)
}

//for now, this function works on simple csv file
func TestLoadFile(t *testing.T) {
	h.Conn.Open()

	var Student Students

	retVal, err := h.LoadFile("/home/developer/contoh.txt", "students", "txt", &Student)

	if err != nil {
		t.Log(err)
	}
	h.Conn.Close()
	t.Log(retVal)
}
<|endoftext|>


<commit_before>package main

func main() {
	f32 := float32(10)
	i64 := int64(f32)
	u32 := uint32(10)
	f64 := float64(u32)
	i8 := int8(42)
	f64 = float64(i8)

	_ = i8
	_ = f64
	_ = i64
}
<commit_msg>test2: make convert2.go more comprehensive and useful<commit_after>package main

var i8 int8
var u8 uint8
var i16 int16
var u16 uint16
var i32 int32
var u32 uint32
var i64 int64
var u64 uint64
var f32 float32
var f64 float64

var w float64

func main() {
	f64 = 16717361816799281152
	u64 = uint64(f64)
	w = float64(u64)
}
<|endoftext|>


<commit_before>package servicedefinition

import (
	"github.com/zenoss/serviced/commons"
	"github.com/zenoss/serviced/domain/service"

	"fmt"
	"log"
	"sort"
	"testing"
)

var testSvc *ServiceDefinition

func init() {

	// Test definition should match on disk (filesystem based) definition
	testSvc = &ServiceDefinition{
		Name:        "testsvc",
		Description: "Top level service. This directory is part of a unit test.",
		Services: []ServiceDefinition{
			ServiceDefinition{
				Name:    "s1",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]ConfigFile{
					"/etc/my.cnf": ConfigFile{Owner: "root:root", Filename: "/etc/my.cnf", Permissions: "0660", Content: "\n# SAMPLE config file for mysql\n\n[mysqld]\n\ninnodb_buffer_pool_size = 16G\n\n"},
				},
				Endpoints: []service.ServiceEndpoint{
					ServiceEndpoint{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "www",
						Name:        "www",
						Purpose:     "export",
					},
					ServiceEndpoint{
						Protocol:    "tcp",
						PortNumber:  8081,
						Application: "websvc",
						Name:        "websvc",
						Purpose:     "import",
						AddressConfig: AddressResourceConfig{
							Port:     8081,
							Protocol: commons.TCP,
						},
					},
				},
				LogConfigs: []LogConfig{
					LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
					},
				},
				Snapshot: SnapshotCommands{
					Pause:  "echo pause",
					Resume: "echo resume",
				},
			},
			ServiceDefinition{
				Name:    "s2",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]ConfigFile{
					"/foo/bar.txt": ConfigFile{
						Filename:    "/foo/bar.txt",
						Owner:       "zenoss:zenoss",
						Permissions: "660",
						Content:     "baz\n",
					},
				},
				Endpoints: []service.ServiceEndpoint{
					ServiceEndpoint{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "websvc",
						Name:        "websvc",
						Purpose:     "export",
						VHosts:      []string{"testhost"},
					},
				},
				LogConfigs: []LogConfig{
					LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
					},
				},
				Snapshot: SnapshotCommands{
					Pause:  "echo pause",
					Resume: "echo resume",
				},
			},
		},
	}

}

// This function checks if the given ServiceDefinition is equivalent. True is
// returned if true, false is returned otherwise. A non-empty message is returned
// that identifies the first inequality that was discovered.
func (a *ServiceDefinition) equals(b *ServiceDefinition) (identical bool, msg string) {

	if a.Name != b.Name {
		return false, fmt.Sprintf("Names are not equal %s != %s", a.Name, b.Name)
	}
	if a.Description != b.Description {
		return false, fmt.Sprintf("Descriptions are not equal %s != %s", a.Description, b.Description)
	}
	if a.ImageID != b.ImageID {
		return false, fmt.Sprintf("ImageIDs are not equal %s != %s", a.ImageID, b.ImageID)
	}
	if a.Command != b.Command {
		return false, fmt.Sprintf("Commands are not equal %s != %s", a.Command, b.Command)
	}
	if len(a.Endpoints) != len(b.Endpoints) {
		return false, fmt.Sprintf("Number of endpoints differ between %s [%s] and %s [%s]",
			a.Name, b.Name, len(a.Endpoints), len(b.Endpoints))
	}
	if len(a.Services) != len(b.Services) {
		return false, fmt.Sprintf("Number of sub services differ between %s [%s] and %s [%s]",
			a.Name, b.Name, len(a.Endpoints), len(b.Endpoints))
	}
	sort.Sort(ServiceDefinitionByName(a.Services))
	sort.Sort(ServiceDefinitionByName(b.Services))

	for i := range a.Services {
		identical, msg := a.Services[i].equals(&b.Services[i])
		if identical != true {
			return identical, msg
		}
	}

	// check config files
	if len(a.ConfigFiles) != len(b.ConfigFiles) {
		log.Printf("s1 :%v  \n\ns2 %s", a.ConfigFiles, b.ConfigFiles)
		return false, fmt.Sprintf("%s has %d configs, %s has %d configs",
			a, len(a.ConfigFiles), b, len(b.ConfigFiles))
	}
	for filename, confFile := range a.ConfigFiles {
		if _, ok := b.ConfigFiles[filename]; !ok {
			return false, fmt.Sprintf("%s has configFile %s, but %s does not", a, filename, b)
		}
		if confFile != b.ConfigFiles[filename] {
			return false, fmt.Sprintf("ConfigFile mismatch %s, a: %v, b: %v", filename, confFile, b.ConfigFiles[filename])
		}
	}

	// check snapshot
	if a.Snapshot.Pause != b.Snapshot.Pause {
		return false, fmt.Sprintf("Snapshot pause commands are not equal %s != %s", a.Snapshot.Pause, b.Snapshot.Pause)
	}
	if a.Snapshot.Resume != b.Snapshot.Resume {
		return false, fmt.Sprintf("Snapshot resume commands are not equal %s != %s", a.Snapshot.Resume, b.Snapshot.Resume)
	}

	return true, ""
}

func TestServiceDefinitionFromPath(t *testing.T) {

	sd, err := BuildFromPath("./testsvc")

	t.Logf("testsvc %v", sd)
	if err != nil {
		t.Fatalf("Problem parsing template: %s", err)
	}
	identical, msg := testSvc.equals(sd)
	if !identical {
		t.Fatalf(msg)
	}

}
<commit_msg>fix bad merge<commit_after>package servicedefinition

import (
	"github.com/zenoss/serviced/commons"

	"fmt"
	"log"
	"sort"
	"testing"
)

var testSvc *ServiceDefinition

func init() {

	// Test definition should match on disk (filesystem based) definition
	testSvc = &ServiceDefinition{
		Name:        "testsvc",
		Description: "Top level service. This directory is part of a unit test.",
		Services: []ServiceDefinition{
			ServiceDefinition{
				Name:    "s1",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]ConfigFile{
					"/etc/my.cnf": ConfigFile{Owner: "root:root", Filename: "/etc/my.cnf", Permissions: "0660", Content: "\n# SAMPLE config file for mysql\n\n[mysqld]\n\ninnodb_buffer_pool_size = 16G\n\n"},
				},
				Endpoints: []EndpointDefinition{
					EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "www",
						Name:        "www",
						Purpose:     "export",
					},
					EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8081,
						Application: "websvc",
						Name:        "websvc",
						Purpose:     "import",
						AddressConfig: AddressResourceConfig{
							Port:     8081,
							Protocol: commons.TCP,
						},
					},
				},
				LogConfigs: []LogConfig{
					LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
					},
				},
				Snapshot: SnapshotCommands{
					Pause:  "echo pause",
					Resume: "echo resume",
				},
			},
			ServiceDefinition{
				Name:    "s2",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]ConfigFile{
					"/foo/bar.txt": ConfigFile{
						Filename:    "/foo/bar.txt",
						Owner:       "zenoss:zenoss",
						Permissions: "660",
						Content:     "baz\n",
					},
				},
				Endpoints: []EndpointDefinition{
					EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "websvc",
						Name:        "websvc",
						Purpose:     "export",
						VHosts:      []string{"testhost"},
					},
				},
				LogConfigs: []LogConfig{
					LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
					},
				},
				Snapshot: SnapshotCommands{
					Pause:  "echo pause",
					Resume: "echo resume",
				},
			},
		},
	}

}

// This function checks if the given ServiceDefinition is equivalent. True is
// returned if true, false is returned otherwise. A non-empty message is returned
// that identifies the first inequality that was discovered.
func (a *ServiceDefinition) equals(b *ServiceDefinition) (identical bool, msg string) {

	if a.Name != b.Name {
		return false, fmt.Sprintf("Names are not equal %s != %s", a.Name, b.Name)
	}
	if a.Description != b.Description {
		return false, fmt.Sprintf("Descriptions are not equal %s != %s", a.Description, b.Description)
	}
	if a.ImageID != b.ImageID {
		return false, fmt.Sprintf("ImageIDs are not equal %s != %s", a.ImageID, b.ImageID)
	}
	if a.Command != b.Command {
		return false, fmt.Sprintf("Commands are not equal %s != %s", a.Command, b.Command)
	}
	if len(a.Endpoints) != len(b.Endpoints) {
		return false, fmt.Sprintf("Number of endpoints differ between %s [%s] and %s [%s]",
			a.Name, b.Name, len(a.Endpoints), len(b.Endpoints))
	}
	if len(a.Services) != len(b.Services) {
		return false, fmt.Sprintf("Number of sub services differ between %s [%s] and %s [%s]",
			a.Name, b.Name, len(a.Endpoints), len(b.Endpoints))
	}
	sort.Sort(ServiceDefinitionByName(a.Services))
	sort.Sort(ServiceDefinitionByName(b.Services))

	for i := range a.Services {
		identical, msg := a.Services[i].equals(&b.Services[i])
		if identical != true {
			return identical, msg
		}
	}

	// check config files
	if len(a.ConfigFiles) != len(b.ConfigFiles) {
		log.Printf("s1 :%v  \n\ns2 %s", a.ConfigFiles, b.ConfigFiles)
		return false, fmt.Sprintf("%s has %d configs, %s has %d configs",
			a, len(a.ConfigFiles), b, len(b.ConfigFiles))
	}
	for filename, confFile := range a.ConfigFiles {
		if _, ok := b.ConfigFiles[filename]; !ok {
			return false, fmt.Sprintf("%s has configFile %s, but %s does not", a, filename, b)
		}
		if confFile != b.ConfigFiles[filename] {
			return false, fmt.Sprintf("ConfigFile mismatch %s, a: %v, b: %v", filename, confFile, b.ConfigFiles[filename])
		}
	}

	// check snapshot
	if a.Snapshot.Pause != b.Snapshot.Pause {
		return false, fmt.Sprintf("Snapshot pause commands are not equal %s != %s", a.Snapshot.Pause, b.Snapshot.Pause)
	}
	if a.Snapshot.Resume != b.Snapshot.Resume {
		return false, fmt.Sprintf("Snapshot resume commands are not equal %s != %s", a.Snapshot.Resume, b.Snapshot.Resume)
	}

	return true, ""
}

func TestServiceDefinitionFromPath(t *testing.T) {

	sd, err := BuildFromPath("./testsvc")

	if err != nil {
		t.Fatalf("Problem parsing template: %s", err)
	}
	identical, msg := testSvc.equals(sd)
	if !identical {
		t.Fatalf(msg)
	}

}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package nwo

import (
	"context"
	"io/ioutil"
	"path"
	"time"

	"github.com/hyperledger/fabric-protos-go/common"
	"github.com/hyperledger/fabric-protos-go/orderer"
	"github.com/hyperledger/fabric/core/comm"
	"github.com/pkg/errors"
)

// Broadcast sends given env to Broadcast API of specified orderer.
func Broadcast(n *Network, o *Orderer, env *common.Envelope) (*orderer.BroadcastResponse, error) {
	gRPCclient, err := CreateGRPCClient(n, o)
	if err != nil {
		return nil, err
	}

	addr := n.OrdererAddress(o, ListenPort)
	conn, err := gRPCclient.NewConnection(addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	broadcaster, err := orderer.NewAtomicBroadcastClient(conn).Broadcast(context.Background())
	if err != nil {
		return nil, err
	}

	err = broadcaster.Send(env)
	if err != nil {
		return nil, err
	}

	resp, err := broadcaster.Recv()
	if err != nil {
		return nil, err
	}

	return resp, nil
}

// Deliver sends given env to Deliver API of specified orderer.
func Deliver(n *Network, o *Orderer, env *common.Envelope) (*common.Block, error) {
	gRPCclient, err := CreateGRPCClient(n, o)
	if err != nil {
		return nil, err
	}

	addr := n.OrdererAddress(o, ListenPort)
	conn, err := gRPCclient.NewConnection(addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	deliverer, err := orderer.NewAtomicBroadcastClient(conn).Deliver(context.Background())
	if err != nil {
		return nil, err
	}

	err = deliverer.Send(env)
	if err != nil {
		return nil, err
	}

	resp, err := deliverer.Recv()
	if err != nil {
		return nil, err
	}

	blk := resp.GetBlock()
	if blk == nil {
		return nil, errors.Errorf("block not found")
	}

	return blk, nil
}

func CreateGRPCClient(n *Network, o *Orderer) (*comm.GRPCClient, error) {
	config := comm.ClientConfig{}
	config.Timeout = 5 * time.Second

	secOpts := comm.SecureOptions{
		UseTLS:            true,
		RequireClientCert: false,
	}

	caPEM, err := ioutil.ReadFile(path.Join(n.OrdererLocalTLSDir(o), "ca.crt"))
	if err != nil {
		return nil, err
	}

	secOpts.ServerRootCAs = [][]byte{caPEM}
	config.SecOpts = secOpts

	grpcClient, err := comm.NewGRPCClient(config)
	if err != nil {
		return nil, err
	}

	return grpcClient, nil
}
<commit_msg>FAB-16286 Unexport and rename IT func<commit_after>/*
Copyright IBM Corp All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package nwo

import (
	"context"
	"io/ioutil"
	"path"
	"time"

	"github.com/hyperledger/fabric-protos-go/common"
	"github.com/hyperledger/fabric-protos-go/orderer"
	"github.com/hyperledger/fabric/core/comm"
	"github.com/pkg/errors"
)

// Broadcast sends given env to Broadcast API of specified orderer.
func Broadcast(n *Network, o *Orderer, env *common.Envelope) (*orderer.BroadcastResponse, error) {
	gRPCclient, err := createOrdererGRPCClient(n, o)
	if err != nil {
		return nil, err
	}

	addr := n.OrdererAddress(o, ListenPort)
	conn, err := gRPCclient.NewConnection(addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	broadcaster, err := orderer.NewAtomicBroadcastClient(conn).Broadcast(context.Background())
	if err != nil {
		return nil, err
	}

	err = broadcaster.Send(env)
	if err != nil {
		return nil, err
	}

	resp, err := broadcaster.Recv()
	if err != nil {
		return nil, err
	}

	return resp, nil
}

// Deliver sends given env to Deliver API of specified orderer.
func Deliver(n *Network, o *Orderer, env *common.Envelope) (*common.Block, error) {
	gRPCclient, err := createOrdererGRPCClient(n, o)
	if err != nil {
		return nil, err
	}

	addr := n.OrdererAddress(o, ListenPort)
	conn, err := gRPCclient.NewConnection(addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	deliverer, err := orderer.NewAtomicBroadcastClient(conn).Deliver(context.Background())
	if err != nil {
		return nil, err
	}

	err = deliverer.Send(env)
	if err != nil {
		return nil, err
	}

	resp, err := deliverer.Recv()
	if err != nil {
		return nil, err
	}

	blk := resp.GetBlock()
	if blk == nil {
		return nil, errors.Errorf("block not found")
	}

	return blk, nil
}

func createOrdererGRPCClient(n *Network, o *Orderer) (*comm.GRPCClient, error) {
	config := comm.ClientConfig{}
	config.Timeout = 5 * time.Second

	secOpts := comm.SecureOptions{
		UseTLS:            true,
		RequireClientCert: false,
	}

	caPEM, err := ioutil.ReadFile(path.Join(n.OrdererLocalTLSDir(o), "ca.crt"))
	if err != nil {
		return nil, err
	}

	secOpts.ServerRootCAs = [][]byte{caPEM}
	config.SecOpts = secOpts

	grpcClient, err := comm.NewGRPCClient(config)
	if err != nil {
		return nil, err
	}

	return grpcClient, nil
}
<|endoftext|>


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

package integrations

import (
	"context"
	"errors"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"testing"

	repo_model "code.gitea.io/gitea/models/repo"
	"code.gitea.io/gitea/models/unittest"
	user_model "code.gitea.io/gitea/models/user"
	base "code.gitea.io/gitea/modules/migration"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/structs"
	"code.gitea.io/gitea/modules/util"
	"code.gitea.io/gitea/services/migrations"

	"github.com/stretchr/testify/assert"
	"gopkg.in/yaml.v2"
)

func TestDumpRestore(t *testing.T) {
	onGiteaRun(t, func(t *testing.T, u *url.URL) {
		AllowLocalNetworks := setting.Migrations.AllowLocalNetworks
		setting.Migrations.AllowLocalNetworks = true
		AppVer := setting.AppVer
		// Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string.
		setting.AppVer = "1.16.0"
		defer func() {
			setting.Migrations.AllowLocalNetworks = AllowLocalNetworks
			setting.AppVer = AppVer
		}()

		assert.NoError(t, migrations.Init())

		reponame := "repo1"

		basePath, err := os.MkdirTemp("", reponame)
		assert.NoError(t, err)
		defer util.RemoveAll(basePath)

		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
		repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
		session := loginUser(t, repoOwner.Name)
		token := getTokenForLoggedInUser(t, session)

		//
		// Phase 1: dump repo1 from the Gitea instance to the filesystem
		//

		ctx := context.Background()
		opts := migrations.MigrateOptions{
			GitServiceType: structs.GiteaService,
			Issues:         true,
			PullRequests:   true,
			Labels:         true,
			Milestones:     true,
			Comments:       true,
			AuthToken:      token,
			CloneAddr:      repo.CloneLink().HTTPS,
			RepoName:       reponame,
		}
		err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
		assert.NoError(t, err)

		//
		// Verify desired side effects of the dump
		//
		d := filepath.Join(basePath, repo.OwnerName, repo.Name)
		for _, f := range []string{"repo.yml", "topic.yml", "label.yml", "milestone.yml", "issue.yml"} {
			assert.FileExists(t, filepath.Join(d, f))
		}

		//
		// Phase 2: restore from the filesystem to the Gitea instance in restoredrepo
		//

		newreponame := "restored"
		err = migrations.RestoreRepository(ctx, d, repo.OwnerName, newreponame, []string{
			"labels", "issues", "comments", "milestones", "pull_requests",
		}, false)
		assert.NoError(t, err)

		newrepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: newreponame}).(*repo_model.Repository)

		//
		// Phase 3: dump restored from the Gitea instance to the filesystem
		//
		opts.RepoName = newreponame
		opts.CloneAddr = newrepo.CloneLink().HTTPS
		err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
		assert.NoError(t, err)

		//
		// Verify the dump of restored is the same as the dump of repo1
		//
		comparator := &compareDump{
			t:        t,
			basePath: basePath,
		}
		comparator.assertEquals(repo, newrepo)
	})
}

type compareDump struct {
	t          *testing.T
	basePath   string
	repoBefore *repo_model.Repository
	dirBefore  string
	repoAfter  *repo_model.Repository
	dirAfter   string
}

type compareField struct {
	before    interface{}
	after     interface{}
	ignore    bool
	transform func(string) string
	nested    *compareFields
}

type compareFields map[string]compareField

func (c *compareDump) replaceRepoName(original string) string {
	return strings.ReplaceAll(original, c.repoBefore.Name, c.repoAfter.Name)
}

func (c *compareDump) assertEquals(repoBefore, repoAfter *repo_model.Repository) {
	c.repoBefore = repoBefore
	c.dirBefore = filepath.Join(c.basePath, repoBefore.OwnerName, repoBefore.Name)
	c.repoAfter = repoAfter
	c.dirAfter = filepath.Join(c.basePath, repoAfter.OwnerName, repoAfter.Name)

	for _, filename := range []string{"repo.yml", "label.yml"} {
		beforeBytes, err := os.ReadFile(filepath.Join(c.dirBefore, filename))
		assert.NoError(c.t, err)
		before := c.replaceRepoName(string(beforeBytes))
		after, err := os.ReadFile(filepath.Join(c.dirAfter, filename))
		assert.NoError(c.t, err)
		assert.EqualValues(c.t, before, string(after))
	}

	//
	// base.Repository
	//
	_ = c.assertEqual("repo.yml", base.Repository{}, compareFields{
		"Name": {
			before: c.repoBefore.Name,
			after:  c.repoAfter.Name,
		},
		"CloneURL":    {transform: c.replaceRepoName},
		"OriginalURL": {transform: c.replaceRepoName},
	})

	//
	// base.Label
	//
	labels, ok := c.assertEqual("label.yml", []base.Label{}, compareFields{}).([]*base.Label)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(labels), 1)

	//
	// base.Milestone
	//
	milestones, ok := c.assertEqual("milestone.yml", []base.Milestone{}, compareFields{
		"Updated": {ignore: true}, // the database updates that field independently
	}).([]*base.Milestone)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(milestones), 1)

	//
	// base.Issue and the associated comments
	//
	issues, ok := c.assertEqual("issue.yml", []base.Issue{}, compareFields{
		"Assignees": {ignore: true}, // not implemented yet
	}).([]*base.Issue)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(issues), 1)
	for _, issue := range issues {
		filename := filepath.Join("comments", fmt.Sprintf("%d.yml", issue.Number))
		comments, ok := c.assertEqual(filename, []base.Comment{}, compareFields{}).([]*base.Comment)
		assert.True(c.t, ok)
		for _, comment := range comments {
			assert.EqualValues(c.t, issue.Number, comment.IssueIndex)
		}
	}

	//
	// base.PullRequest and the associated comments
	//
	comparePullRequestBranch := &compareFields{
		"RepoName": {
			before: c.repoBefore.Name,
			after:  c.repoAfter.Name,
		},
		"CloneURL": {transform: c.replaceRepoName},
	}
	prs, ok := c.assertEqual("pull_request.yml", []base.PullRequest{}, compareFields{
		"Assignees": {ignore: true}, // not implemented yet
		"Head":      {nested: comparePullRequestBranch},
		"Base":      {nested: comparePullRequestBranch},
		"Labels":    {ignore: true}, // because org labels are not handled propery
	}).([]*base.PullRequest)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(prs), 1)
	for _, pr := range prs {
		filename := filepath.Join("comments", fmt.Sprintf("%d.yml", pr.Number))
		comments, ok := c.assertEqual(filename, []base.Comment{}, compareFields{}).([]*base.Comment)
		assert.True(c.t, ok)
		for _, comment := range comments {
			assert.EqualValues(c.t, pr.Number, comment.IssueIndex)
		}
	}
}

func (c *compareDump) assertLoadYAMLFiles(beforeFilename, afterFilename string, before, after interface{}) {
	_, beforeErr := os.Stat(beforeFilename)
	_, afterErr := os.Stat(afterFilename)
	assert.EqualValues(c.t, errors.Is(beforeErr, os.ErrNotExist), errors.Is(afterErr, os.ErrNotExist))
	if errors.Is(beforeErr, os.ErrNotExist) {
		return
	}

	beforeBytes, err := os.ReadFile(beforeFilename)
	assert.NoError(c.t, err)
	assert.NoError(c.t, yaml.Unmarshal(beforeBytes, before))
	afterBytes, err := os.ReadFile(afterFilename)
	assert.NoError(c.t, err)
	assert.NoError(c.t, yaml.Unmarshal(afterBytes, after))
}

func (c *compareDump) assertLoadFiles(beforeFilename, afterFilename string, t reflect.Type) (before, after reflect.Value) {
	var beforePtr, afterPtr reflect.Value
	if t.Kind() == reflect.Slice {
		//
		// Given []Something{} create afterPtr, beforePtr []*Something{}
		//
		sliceType := reflect.SliceOf(reflect.PtrTo(t.Elem()))
		beforeSlice := reflect.MakeSlice(sliceType, 0, 10)
		beforePtr = reflect.New(beforeSlice.Type())
		beforePtr.Elem().Set(beforeSlice)
		afterSlice := reflect.MakeSlice(sliceType, 0, 10)
		afterPtr = reflect.New(afterSlice.Type())
		afterPtr.Elem().Set(afterSlice)
	} else {
		//
		// Given Something{} create afterPtr, beforePtr *Something{}
		//
		beforePtr = reflect.New(t)
		afterPtr = reflect.New(t)
	}
	c.assertLoadYAMLFiles(beforeFilename, afterFilename, beforePtr.Interface(), afterPtr.Interface())
	return beforePtr.Elem(), afterPtr.Elem()
}

func (c *compareDump) assertEqual(filename string, kind interface{}, fields compareFields) (i interface{}) {
	beforeFilename := filepath.Join(c.dirBefore, filename)
	afterFilename := filepath.Join(c.dirAfter, filename)

	typeOf := reflect.TypeOf(kind)
	before, after := c.assertLoadFiles(beforeFilename, afterFilename, typeOf)
	if typeOf.Kind() == reflect.Slice {
		i = c.assertEqualSlices(before, after, fields)
	} else {
		i = c.assertEqualValues(before, after, fields)
	}
	return i
}

func (c *compareDump) assertEqualSlices(before, after reflect.Value, fields compareFields) interface{} {
	assert.EqualValues(c.t, before.Len(), after.Len())
	if before.Len() == after.Len() {
		for i := 0; i < before.Len(); i++ {
			_ = c.assertEqualValues(
				reflect.Indirect(before.Index(i).Elem()),
				reflect.Indirect(after.Index(i).Elem()),
				fields)
		}
	}
	return after.Interface()
}

func (c *compareDump) assertEqualValues(before, after reflect.Value, fields compareFields) interface{} {
	for _, field := range reflect.VisibleFields(before.Type()) {
		bf := before.FieldByName(field.Name)
		bi := bf.Interface()
		af := after.FieldByName(field.Name)
		ai := af.Interface()
		if compare, ok := fields[field.Name]; ok {
			if compare.ignore == true {
				//
				// Ignore
				//
				continue
			}
			if compare.transform != nil {
				//
				// Transform these strings before comparing them
				//
				bs, ok := bi.(string)
				assert.True(c.t, ok)
				as, ok := ai.(string)
				assert.True(c.t, ok)
				assert.EqualValues(c.t, compare.transform(bs), compare.transform(as))
				continue
			}
			if compare.before != nil && compare.after != nil {
				//
				// The fields are expected to have different values
				//
				assert.EqualValues(c.t, compare.before, bi)
				assert.EqualValues(c.t, compare.after, ai)
				continue
			}
			if compare.nested != nil {
				//
				// The fields are a struct, recurse
				//
				c.assertEqualValues(bf, af, *compare.nested)
				continue
			}
		}
		assert.EqualValues(c.t, bi, ai)
	}
	return after.Interface()
}
<commit_msg>tests: remove redundant comparison in repo dump/restore (#18660)<commit_after>// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package integrations

import (
	"context"
	"errors"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"testing"

	repo_model "code.gitea.io/gitea/models/repo"
	"code.gitea.io/gitea/models/unittest"
	user_model "code.gitea.io/gitea/models/user"
	base "code.gitea.io/gitea/modules/migration"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/structs"
	"code.gitea.io/gitea/modules/util"
	"code.gitea.io/gitea/services/migrations"

	"github.com/stretchr/testify/assert"
	"gopkg.in/yaml.v2"
)

func TestDumpRestore(t *testing.T) {
	onGiteaRun(t, func(t *testing.T, u *url.URL) {
		AllowLocalNetworks := setting.Migrations.AllowLocalNetworks
		setting.Migrations.AllowLocalNetworks = true
		AppVer := setting.AppVer
		// Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string.
		setting.AppVer = "1.16.0"
		defer func() {
			setting.Migrations.AllowLocalNetworks = AllowLocalNetworks
			setting.AppVer = AppVer
		}()

		assert.NoError(t, migrations.Init())

		reponame := "repo1"

		basePath, err := os.MkdirTemp("", reponame)
		assert.NoError(t, err)
		defer util.RemoveAll(basePath)

		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
		repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
		session := loginUser(t, repoOwner.Name)
		token := getTokenForLoggedInUser(t, session)

		//
		// Phase 1: dump repo1 from the Gitea instance to the filesystem
		//

		ctx := context.Background()
		opts := migrations.MigrateOptions{
			GitServiceType: structs.GiteaService,
			Issues:         true,
			PullRequests:   true,
			Labels:         true,
			Milestones:     true,
			Comments:       true,
			AuthToken:      token,
			CloneAddr:      repo.CloneLink().HTTPS,
			RepoName:       reponame,
		}
		err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
		assert.NoError(t, err)

		//
		// Verify desired side effects of the dump
		//
		d := filepath.Join(basePath, repo.OwnerName, repo.Name)
		for _, f := range []string{"repo.yml", "topic.yml", "label.yml", "milestone.yml", "issue.yml"} {
			assert.FileExists(t, filepath.Join(d, f))
		}

		//
		// Phase 2: restore from the filesystem to the Gitea instance in restoredrepo
		//

		newreponame := "restored"
		err = migrations.RestoreRepository(ctx, d, repo.OwnerName, newreponame, []string{
			"labels", "issues", "comments", "milestones", "pull_requests",
		}, false)
		assert.NoError(t, err)

		newrepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: newreponame}).(*repo_model.Repository)

		//
		// Phase 3: dump restored from the Gitea instance to the filesystem
		//
		opts.RepoName = newreponame
		opts.CloneAddr = newrepo.CloneLink().HTTPS
		err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
		assert.NoError(t, err)

		//
		// Verify the dump of restored is the same as the dump of repo1
		//
		comparator := &compareDump{
			t:        t,
			basePath: basePath,
		}
		comparator.assertEquals(repo, newrepo)
	})
}

type compareDump struct {
	t          *testing.T
	basePath   string
	repoBefore *repo_model.Repository
	dirBefore  string
	repoAfter  *repo_model.Repository
	dirAfter   string
}

type compareField struct {
	before    interface{}
	after     interface{}
	ignore    bool
	transform func(string) string
	nested    *compareFields
}

type compareFields map[string]compareField

func (c *compareDump) replaceRepoName(original string) string {
	return strings.ReplaceAll(original, c.repoBefore.Name, c.repoAfter.Name)
}

func (c *compareDump) assertEquals(repoBefore, repoAfter *repo_model.Repository) {
	c.repoBefore = repoBefore
	c.dirBefore = filepath.Join(c.basePath, repoBefore.OwnerName, repoBefore.Name)
	c.repoAfter = repoAfter
	c.dirAfter = filepath.Join(c.basePath, repoAfter.OwnerName, repoAfter.Name)

	//
	// base.Repository
	//
	_ = c.assertEqual("repo.yml", base.Repository{}, compareFields{
		"Name": {
			before: c.repoBefore.Name,
			after:  c.repoAfter.Name,
		},
		"CloneURL":    {transform: c.replaceRepoName},
		"OriginalURL": {transform: c.replaceRepoName},
	})

	//
	// base.Label
	//
	labels, ok := c.assertEqual("label.yml", []base.Label{}, compareFields{}).([]*base.Label)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(labels), 1)

	//
	// base.Milestone
	//
	milestones, ok := c.assertEqual("milestone.yml", []base.Milestone{}, compareFields{
		"Updated": {ignore: true}, // the database updates that field independently
	}).([]*base.Milestone)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(milestones), 1)

	//
	// base.Issue and the associated comments
	//
	issues, ok := c.assertEqual("issue.yml", []base.Issue{}, compareFields{
		"Assignees": {ignore: true}, // not implemented yet
	}).([]*base.Issue)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(issues), 1)
	for _, issue := range issues {
		filename := filepath.Join("comments", fmt.Sprintf("%d.yml", issue.Number))
		comments, ok := c.assertEqual(filename, []base.Comment{}, compareFields{}).([]*base.Comment)
		assert.True(c.t, ok)
		for _, comment := range comments {
			assert.EqualValues(c.t, issue.Number, comment.IssueIndex)
		}
	}

	//
	// base.PullRequest and the associated comments
	//
	comparePullRequestBranch := &compareFields{
		"RepoName": {
			before: c.repoBefore.Name,
			after:  c.repoAfter.Name,
		},
		"CloneURL": {transform: c.replaceRepoName},
	}
	prs, ok := c.assertEqual("pull_request.yml", []base.PullRequest{}, compareFields{
		"Assignees": {ignore: true}, // not implemented yet
		"Head":      {nested: comparePullRequestBranch},
		"Base":      {nested: comparePullRequestBranch},
		"Labels":    {ignore: true}, // because org labels are not handled propery
	}).([]*base.PullRequest)
	assert.True(c.t, ok)
	assert.GreaterOrEqual(c.t, len(prs), 1)
	for _, pr := range prs {
		filename := filepath.Join("comments", fmt.Sprintf("%d.yml", pr.Number))
		comments, ok := c.assertEqual(filename, []base.Comment{}, compareFields{}).([]*base.Comment)
		assert.True(c.t, ok)
		for _, comment := range comments {
			assert.EqualValues(c.t, pr.Number, comment.IssueIndex)
		}
	}
}

func (c *compareDump) assertLoadYAMLFiles(beforeFilename, afterFilename string, before, after interface{}) {
	_, beforeErr := os.Stat(beforeFilename)
	_, afterErr := os.Stat(afterFilename)
	assert.EqualValues(c.t, errors.Is(beforeErr, os.ErrNotExist), errors.Is(afterErr, os.ErrNotExist))
	if errors.Is(beforeErr, os.ErrNotExist) {
		return
	}

	beforeBytes, err := os.ReadFile(beforeFilename)
	assert.NoError(c.t, err)
	assert.NoError(c.t, yaml.Unmarshal(beforeBytes, before))
	afterBytes, err := os.ReadFile(afterFilename)
	assert.NoError(c.t, err)
	assert.NoError(c.t, yaml.Unmarshal(afterBytes, after))
}

func (c *compareDump) assertLoadFiles(beforeFilename, afterFilename string, t reflect.Type) (before, after reflect.Value) {
	var beforePtr, afterPtr reflect.Value
	if t.Kind() == reflect.Slice {
		//
		// Given []Something{} create afterPtr, beforePtr []*Something{}
		//
		sliceType := reflect.SliceOf(reflect.PtrTo(t.Elem()))
		beforeSlice := reflect.MakeSlice(sliceType, 0, 10)
		beforePtr = reflect.New(beforeSlice.Type())
		beforePtr.Elem().Set(beforeSlice)
		afterSlice := reflect.MakeSlice(sliceType, 0, 10)
		afterPtr = reflect.New(afterSlice.Type())
		afterPtr.Elem().Set(afterSlice)
	} else {
		//
		// Given Something{} create afterPtr, beforePtr *Something{}
		//
		beforePtr = reflect.New(t)
		afterPtr = reflect.New(t)
	}
	c.assertLoadYAMLFiles(beforeFilename, afterFilename, beforePtr.Interface(), afterPtr.Interface())
	return beforePtr.Elem(), afterPtr.Elem()
}

func (c *compareDump) assertEqual(filename string, kind interface{}, fields compareFields) (i interface{}) {
	beforeFilename := filepath.Join(c.dirBefore, filename)
	afterFilename := filepath.Join(c.dirAfter, filename)

	typeOf := reflect.TypeOf(kind)
	before, after := c.assertLoadFiles(beforeFilename, afterFilename, typeOf)
	if typeOf.Kind() == reflect.Slice {
		i = c.assertEqualSlices(before, after, fields)
	} else {
		i = c.assertEqualValues(before, after, fields)
	}
	return i
}

func (c *compareDump) assertEqualSlices(before, after reflect.Value, fields compareFields) interface{} {
	assert.EqualValues(c.t, before.Len(), after.Len())
	if before.Len() == after.Len() {
		for i := 0; i < before.Len(); i++ {
			_ = c.assertEqualValues(
				reflect.Indirect(before.Index(i).Elem()),
				reflect.Indirect(after.Index(i).Elem()),
				fields)
		}
	}
	return after.Interface()
}

func (c *compareDump) assertEqualValues(before, after reflect.Value, fields compareFields) interface{} {
	for _, field := range reflect.VisibleFields(before.Type()) {
		bf := before.FieldByName(field.Name)
		bi := bf.Interface()
		af := after.FieldByName(field.Name)
		ai := af.Interface()
		if compare, ok := fields[field.Name]; ok {
			if compare.ignore == true {
				//
				// Ignore
				//
				continue
			}
			if compare.transform != nil {
				//
				// Transform these strings before comparing them
				//
				bs, ok := bi.(string)
				assert.True(c.t, ok)
				as, ok := ai.(string)
				assert.True(c.t, ok)
				assert.EqualValues(c.t, compare.transform(bs), compare.transform(as))
				continue
			}
			if compare.before != nil && compare.after != nil {
				//
				// The fields are expected to have different values
				//
				assert.EqualValues(c.t, compare.before, bi)
				assert.EqualValues(c.t, compare.after, ai)
				continue
			}
			if compare.nested != nil {
				//
				// The fields are a struct, recurse
				//
				c.assertEqualValues(bf, af, *compare.nested)
				continue
			}
		}
		assert.EqualValues(c.t, bi, ai)
	}
	return after.Interface()
}
<|endoftext|>