<commit_before>// 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.

// Binary to decimal floating point conversion.
// Algorithm:
//   1) store mantissa in multiprecision decimal
//   2) shift decimal by exponent
//   3) read digits out & format

package strconv

import "math"

// TODO: move elsewhere?
type floatInfo struct {
	mantbits uint
	expbits  uint
	bias     int
}

var float32info = floatInfo{23, 8, -127}
var float64info = floatInfo{52, 11, -1023}

// Ftoa32 converts the 32-bit floating-point number f to a string,
// according to the format fmt and precision prec.
//
// The format fmt is one of
// 'b' (-ddddp±ddd, a binary exponent),
// 'e' (-d.dddde±dd, a decimal exponent),
// 'E' (-d.ddddE±dd, a decimal exponent),
// 'f' (-ddd.dddd, no exponent),
// 'g' ('e' for large exponents, 'f' otherwise), or
// 'G' ('E' for large exponents, 'f' otherwise).
//
// The precision prec controls the number of digits
// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
// For 'g' and 'G' it is the total number of digits.
// The special precision -1 uses the smallest number of digits
// necessary such that Atof32 will return f exactly.
//
// Ftoa32(f) is not the same as Ftoa64(float32(f)),
// because correct rounding and the number of digits
// needed to identify f depend on the precision of the representation.
func Ftoa32(f float32, fmt byte, prec int) string {
	return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
}

// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number.
func Ftoa64(f float64, fmt byte, prec int) string {
	return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
}

// FtoaN converts the 64-bit floating-point number f to a string,
// according to the format fmt and precision prec, but it rounds the
// result assuming that it was obtained from a floating-point value
// of n bits (32 or 64).
func FtoaN(f float64, fmt byte, prec int, n int) string {
	if n == 32 {
		return Ftoa32(float32(f), fmt, prec)
	}
	return Ftoa64(f, fmt, prec)
}

func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
	neg := bits>>flt.expbits>>flt.mantbits != 0
	exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
	mant := bits & (uint64(1)<<flt.mantbits - 1)

	switch exp {
	case 1<<flt.expbits - 1:
		// Inf, NaN
		if mant != 0 {
			return "NaN"
		}
		if neg {
			return "-Inf"
		}
		return "+Inf"

	case 0:
		// denormalized
		exp++

	default:
		// add implicit top bit
		mant |= uint64(1) << flt.mantbits
	}
	exp += flt.bias

	// Pick off easy binary format.
	if fmt == 'b' {
		return fmtB(neg, mant, exp, flt)
	}

	// Create exact decimal representation.
	// The shift is exp - flt.mantbits because mant is a 1-bit integer
	// followed by a flt.mantbits fraction, and we are treating it as
	// a 1+flt.mantbits-bit integer.
	d := newDecimal(mant).Shift(exp - int(flt.mantbits))

	// Round appropriately.
	// Negative precision means "only as much as needed to be exact."
	shortest := false
	if prec < 0 {
		shortest = true
		roundShortest(d, mant, exp, flt)
		switch fmt {
		case 'e', 'E':
			prec = d.nd - 1
		case 'f':
			prec = max(d.nd-d.dp, 0)
		case 'g', 'G':
			prec = d.nd
		}
	} else {
		switch fmt {
		case 'e', 'E':
			d.Round(prec + 1)
		case 'f':
			d.Round(d.dp + prec)
		case 'g', 'G':
			if prec == 0 {
				prec = 1
			}
			d.Round(prec)
		}
	}

	switch fmt {
	case 'e', 'E':
		return fmtE(neg, d, prec, fmt)
	case 'f':
		return fmtF(neg, d, prec)
	case 'g', 'G':
		// trailing fractional zeros in 'e' form will be trimmed.
		eprec := prec
		if eprec > d.nd && d.nd >= d.dp {
			eprec = d.nd
		}
		// %e is used if the exponent from the conversion
		// is less than -4 or greater than or equal to the precision.
		// if precision was the shortest possible, use precision 6 for this decision.
		if shortest {
			eprec = 6
		}
		exp := d.dp - 1
		if exp < -4 || exp >= eprec {
			if prec > d.nd {
				prec = d.nd
			}
			return fmtE(neg, d, prec-1, fmt+'e'-'g')
		}
		if prec > d.dp {
			prec = d.nd
		}
		return fmtF(neg, d, max(prec-d.dp, 0))
	}

	return "%" + string(fmt)
}

// Round d (= mant * 2^exp) to the shortest number of digits
// that will let the original floating point value be precisely
// reconstructed.  Size is original floating point size (64 or 32).
func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
	// If mantissa is zero, the number is zero; stop now.
	if mant == 0 {
		d.nd = 0
		return
	}

	// TODO(rsc): Unless exp == minexp, if the number of digits in d
	// is less than 17, it seems likely that it would be
	// the shortest possible number already.  So maybe we can
	// bail out without doing the extra multiprecision math here.

	// Compute upper and lower such that any decimal number
	// between upper and lower (possibly inclusive)
	// will round to the original floating point number.

	// d = mant << (exp - mantbits)
	// Next highest floating point number is mant+1 << exp-mantbits.
	// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
	upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)

	// d = mant << (exp - mantbits)
	// Next lowest floating point number is mant-1 << exp-mantbits,
	// unless mant-1 drops the significant bit and exp is not the minimum exp,
	// in which case the next lowest is mant*2-1 << exp-mantbits-1.
	// Either way, call it mantlo << explo-mantbits.
	// Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
	minexp := flt.bias + 1 // minimum possible exponent
	var mantlo uint64
	var explo int
	if mant > 1<<flt.mantbits || exp == minexp {
		mantlo = mant - 1
		explo = exp
	} else {
		mantlo = mant*2 - 1
		explo = exp - 1
	}
	lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)

	// The upper and lower bounds are possible outputs only if
	// the original mantissa is even, so that IEEE round-to-even
	// would round to the original mantissa and not the neighbors.
	inclusive := mant%2 == 0

	// Now we can figure out the minimum number of digits required.
	// Walk along until d has distinguished itself from upper and lower.
	for i := 0; i < d.nd; i++ {
		var l, m, u byte // lower, middle, upper digits
		if i < lower.nd {
			l = lower.d[i]
		} else {
			l = '0'
		}
		m = d.d[i]
		if i < upper.nd {
			u = upper.d[i]
		} else {
			u = '0'
		}

		// Okay to round down (truncate) if lower has a different digit
		// or if lower is inclusive and is exactly the result of rounding down.
		okdown := l != m || (inclusive && l == m && i+1 == lower.nd)

		// Okay to round up if upper has a different digit and
		// either upper is inclusive or upper is bigger than the result of rounding up.
		okup := m != u && (inclusive || i+1 < upper.nd)

		// If it's okay to do either, then round to the nearest one.
		// If it's okay to do only one, do it.
		switch {
		case okdown && okup:
			d.Round(i + 1)
			return
		case okdown:
			d.RoundDown(i + 1)
			return
		case okup:
			d.RoundUp(i + 1)
			return
		}
	}
}

// %e: -d.ddddde±dd
func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
	buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
	w := 0                                 // write index

	// sign
	if neg {
		buf[w] = '-'
		w++
	}

	// first digit
	if d.nd == 0 {
		buf[w] = '0'
	} else {
		buf[w] = d.d[0]
	}
	w++

	// .moredigits
	if prec > 0 {
		buf[w] = '.'
		w++
		for i := 0; i < prec; i++ {
			if 1+i < d.nd {
				buf[w] = d.d[1+i]
			} else {
				buf[w] = '0'
			}
			w++
		}
	}

	// e±
	buf[w] = fmt
	w++
	exp := d.dp - 1
	if d.nd == 0 { // special case: 0 has exponent 0
		exp = 0
	}
	if exp < 0 {
		buf[w] = '-'
		exp = -exp
	} else {
		buf[w] = '+'
	}
	w++

	// dddd
	// count digits
	n := 0
	for e := exp; e > 0; e /= 10 {
		n++
	}
	// leading zeros
	for i := n; i < 2; i++ {
		buf[w] = '0'
		w++
	}
	// digits
	w += n
	n = 0
	for e := exp; e > 0; e /= 10 {
		n++
		buf[w-n] = byte(e%10 + '0')
	}

	return string(buf[0:w])
}

// %f: -ddddddd.ddddd
func fmtF(neg bool, d *decimal, prec int) string {
	buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
	w := 0

	// sign
	if neg {
		buf[w] = '-'
		w++
	}

	// integer, padded with zeros as needed.
	if d.dp > 0 {
		var i int
		for i = 0; i < d.dp && i < d.nd; i++ {
			buf[w] = d.d[i]
			w++
		}
		for ; i < d.dp; i++ {
			buf[w] = '0'
			w++
		}
	} else {
		buf[w] = '0'
		w++
	}

	// fraction
	if prec > 0 {
		buf[w] = '.'
		w++
		for i := 0; i < prec; i++ {
			if d.dp+i < 0 || d.dp+i >= d.nd {
				buf[w] = '0'
			} else {
				buf[w] = d.d[d.dp+i]
			}
			w++
		}
	}

	return string(buf[0:w])
}

// %b: -ddddddddp+ddd
func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
	var buf [50]byte
	w := len(buf)
	exp -= int(flt.mantbits)
	esign := byte('+')
	if exp < 0 {
		esign = '-'
		exp = -exp
	}
	n := 0
	for exp > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(exp%10 + '0')
		exp /= 10
	}
	w--
	buf[w] = esign
	w--
	buf[w] = 'p'
	n = 0
	for mant > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(mant%10 + '0')
		mant /= 10
	}
	if neg {
		w--
		buf[w] = '-'
	}
	return string(buf[w:])
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<commit_msg>strconv/ftoa: avoid a double shift. (shifts by variables are expensive.)<commit_after>// 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.

// Binary to decimal floating point conversion.
// Algorithm:
//   1) store mantissa in multiprecision decimal
//   2) shift decimal by exponent
//   3) read digits out & format

package strconv

import "math"

// TODO: move elsewhere?
type floatInfo struct {
	mantbits uint
	expbits  uint
	bias     int
}

var float32info = floatInfo{23, 8, -127}
var float64info = floatInfo{52, 11, -1023}

// Ftoa32 converts the 32-bit floating-point number f to a string,
// according to the format fmt and precision prec.
//
// The format fmt is one of
// 'b' (-ddddp±ddd, a binary exponent),
// 'e' (-d.dddde±dd, a decimal exponent),
// 'E' (-d.ddddE±dd, a decimal exponent),
// 'f' (-ddd.dddd, no exponent),
// 'g' ('e' for large exponents, 'f' otherwise), or
// 'G' ('E' for large exponents, 'f' otherwise).
//
// The precision prec controls the number of digits
// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
// For 'g' and 'G' it is the total number of digits.
// The special precision -1 uses the smallest number of digits
// necessary such that Atof32 will return f exactly.
//
// Ftoa32(f) is not the same as Ftoa64(float32(f)),
// because correct rounding and the number of digits
// needed to identify f depend on the precision of the representation.
func Ftoa32(f float32, fmt byte, prec int) string {
	return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
}

// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number.
func Ftoa64(f float64, fmt byte, prec int) string {
	return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
}

// FtoaN converts the 64-bit floating-point number f to a string,
// according to the format fmt and precision prec, but it rounds the
// result assuming that it was obtained from a floating-point value
// of n bits (32 or 64).
func FtoaN(f float64, fmt byte, prec int, n int) string {
	if n == 32 {
		return Ftoa32(float32(f), fmt, prec)
	}
	return Ftoa64(f, fmt, prec)
}

func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
	neg := bits>>(flt.expbits+flt.mantbits) != 0
	exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
	mant := bits & (uint64(1)<<flt.mantbits - 1)

	switch exp {
	case 1<<flt.expbits - 1:
		// Inf, NaN
		if mant != 0 {
			return "NaN"
		}
		if neg {
			return "-Inf"
		}
		return "+Inf"

	case 0:
		// denormalized
		exp++

	default:
		// add implicit top bit
		mant |= uint64(1) << flt.mantbits
	}
	exp += flt.bias

	// Pick off easy binary format.
	if fmt == 'b' {
		return fmtB(neg, mant, exp, flt)
	}

	// Create exact decimal representation.
	// The shift is exp - flt.mantbits because mant is a 1-bit integer
	// followed by a flt.mantbits fraction, and we are treating it as
	// a 1+flt.mantbits-bit integer.
	d := newDecimal(mant).Shift(exp - int(flt.mantbits))

	// Round appropriately.
	// Negative precision means "only as much as needed to be exact."
	shortest := false
	if prec < 0 {
		shortest = true
		roundShortest(d, mant, exp, flt)
		switch fmt {
		case 'e', 'E':
			prec = d.nd - 1
		case 'f':
			prec = max(d.nd-d.dp, 0)
		case 'g', 'G':
			prec = d.nd
		}
	} else {
		switch fmt {
		case 'e', 'E':
			d.Round(prec + 1)
		case 'f':
			d.Round(d.dp + prec)
		case 'g', 'G':
			if prec == 0 {
				prec = 1
			}
			d.Round(prec)
		}
	}

	switch fmt {
	case 'e', 'E':
		return fmtE(neg, d, prec, fmt)
	case 'f':
		return fmtF(neg, d, prec)
	case 'g', 'G':
		// trailing fractional zeros in 'e' form will be trimmed.
		eprec := prec
		if eprec > d.nd && d.nd >= d.dp {
			eprec = d.nd
		}
		// %e is used if the exponent from the conversion
		// is less than -4 or greater than or equal to the precision.
		// if precision was the shortest possible, use precision 6 for this decision.
		if shortest {
			eprec = 6
		}
		exp := d.dp - 1
		if exp < -4 || exp >= eprec {
			if prec > d.nd {
				prec = d.nd
			}
			return fmtE(neg, d, prec-1, fmt+'e'-'g')
		}
		if prec > d.dp {
			prec = d.nd
		}
		return fmtF(neg, d, max(prec-d.dp, 0))
	}

	return "%" + string(fmt)
}

// Round d (= mant * 2^exp) to the shortest number of digits
// that will let the original floating point value be precisely
// reconstructed.  Size is original floating point size (64 or 32).
func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
	// If mantissa is zero, the number is zero; stop now.
	if mant == 0 {
		d.nd = 0
		return
	}

	// TODO(rsc): Unless exp == minexp, if the number of digits in d
	// is less than 17, it seems likely that it would be
	// the shortest possible number already.  So maybe we can
	// bail out without doing the extra multiprecision math here.

	// Compute upper and lower such that any decimal number
	// between upper and lower (possibly inclusive)
	// will round to the original floating point number.

	// d = mant << (exp - mantbits)
	// Next highest floating point number is mant+1 << exp-mantbits.
	// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
	upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)

	// d = mant << (exp - mantbits)
	// Next lowest floating point number is mant-1 << exp-mantbits,
	// unless mant-1 drops the significant bit and exp is not the minimum exp,
	// in which case the next lowest is mant*2-1 << exp-mantbits-1.
	// Either way, call it mantlo << explo-mantbits.
	// Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
	minexp := flt.bias + 1 // minimum possible exponent
	var mantlo uint64
	var explo int
	if mant > 1<<flt.mantbits || exp == minexp {
		mantlo = mant - 1
		explo = exp
	} else {
		mantlo = mant*2 - 1
		explo = exp - 1
	}
	lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)

	// The upper and lower bounds are possible outputs only if
	// the original mantissa is even, so that IEEE round-to-even
	// would round to the original mantissa and not the neighbors.
	inclusive := mant%2 == 0

	// Now we can figure out the minimum number of digits required.
	// Walk along until d has distinguished itself from upper and lower.
	for i := 0; i < d.nd; i++ {
		var l, m, u byte // lower, middle, upper digits
		if i < lower.nd {
			l = lower.d[i]
		} else {
			l = '0'
		}
		m = d.d[i]
		if i < upper.nd {
			u = upper.d[i]
		} else {
			u = '0'
		}

		// Okay to round down (truncate) if lower has a different digit
		// or if lower is inclusive and is exactly the result of rounding down.
		okdown := l != m || (inclusive && l == m && i+1 == lower.nd)

		// Okay to round up if upper has a different digit and
		// either upper is inclusive or upper is bigger than the result of rounding up.
		okup := m != u && (inclusive || i+1 < upper.nd)

		// If it's okay to do either, then round to the nearest one.
		// If it's okay to do only one, do it.
		switch {
		case okdown && okup:
			d.Round(i + 1)
			return
		case okdown:
			d.RoundDown(i + 1)
			return
		case okup:
			d.RoundUp(i + 1)
			return
		}
	}
}

// %e: -d.ddddde±dd
func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
	buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
	w := 0                                 // write index

	// sign
	if neg {
		buf[w] = '-'
		w++
	}

	// first digit
	if d.nd == 0 {
		buf[w] = '0'
	} else {
		buf[w] = d.d[0]
	}
	w++

	// .moredigits
	if prec > 0 {
		buf[w] = '.'
		w++
		for i := 0; i < prec; i++ {
			if 1+i < d.nd {
				buf[w] = d.d[1+i]
			} else {
				buf[w] = '0'
			}
			w++
		}
	}

	// e±
	buf[w] = fmt
	w++
	exp := d.dp - 1
	if d.nd == 0 { // special case: 0 has exponent 0
		exp = 0
	}
	if exp < 0 {
		buf[w] = '-'
		exp = -exp
	} else {
		buf[w] = '+'
	}
	w++

	// dddd
	// count digits
	n := 0
	for e := exp; e > 0; e /= 10 {
		n++
	}
	// leading zeros
	for i := n; i < 2; i++ {
		buf[w] = '0'
		w++
	}
	// digits
	w += n
	n = 0
	for e := exp; e > 0; e /= 10 {
		n++
		buf[w-n] = byte(e%10 + '0')
	}

	return string(buf[0:w])
}

// %f: -ddddddd.ddddd
func fmtF(neg bool, d *decimal, prec int) string {
	buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
	w := 0

	// sign
	if neg {
		buf[w] = '-'
		w++
	}

	// integer, padded with zeros as needed.
	if d.dp > 0 {
		var i int
		for i = 0; i < d.dp && i < d.nd; i++ {
			buf[w] = d.d[i]
			w++
		}
		for ; i < d.dp; i++ {
			buf[w] = '0'
			w++
		}
	} else {
		buf[w] = '0'
		w++
	}

	// fraction
	if prec > 0 {
		buf[w] = '.'
		w++
		for i := 0; i < prec; i++ {
			if d.dp+i < 0 || d.dp+i >= d.nd {
				buf[w] = '0'
			} else {
				buf[w] = d.d[d.dp+i]
			}
			w++
		}
	}

	return string(buf[0:w])
}

// %b: -ddddddddp+ddd
func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
	var buf [50]byte
	w := len(buf)
	exp -= int(flt.mantbits)
	esign := byte('+')
	if exp < 0 {
		esign = '-'
		exp = -exp
	}
	n := 0
	for exp > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(exp%10 + '0')
		exp /= 10
	}
	w--
	buf[w] = esign
	w--
	buf[w] = 'p'
	n = 0
	for mant > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(mant%10 + '0')
		mant /= 10
	}
	if neg {
		w--
		buf[w] = '-'
	}
	return string(buf[w:])
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package resources

import (
	corev1 "k8s.io/api/core/v1"

	"fmt"

	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
	"github.com/tektoncd/pipeline/pkg/templating"
)

// ApplyParameters applies the params from a TaskRun.Input.Parameters to a TaskSpec
func ApplyParameters(spec *v1alpha1.TaskSpec, tr *v1alpha1.TaskRun, defaults ...v1alpha1.TaskParam) *v1alpha1.TaskSpec {
	// This assumes that the TaskRun inputs have been validated against what the Task requests.
	replacements := map[string]string{}
	// Set all the default replacements
	for _, p := range defaults {
		if p.Default != "" {
			replacements[fmt.Sprintf("inputs.params.%s", p.Name)] = p.Default
		}
	}
	// Set and overwrite params with the ones from the TaskRun
	for _, p := range tr.Spec.Inputs.Params {
		replacements[fmt.Sprintf("inputs.params.%s", p.Name)] = p.Value
	}

	return ApplyReplacements(spec, replacements)
}

// ApplyResources applies the templating from values in resources which are referenced in spec as subitems
// of the replacementStr.
func ApplyResources(spec *v1alpha1.TaskSpec, resolvedResources map[string]v1alpha1.PipelineResourceInterface, replacementStr string) *v1alpha1.TaskSpec {
	replacements := map[string]string{}
	for name, r := range resolvedResources {
		for k, v := range r.Replacements() {
			replacements[fmt.Sprintf("%s.resources.%s.%s", replacementStr, name, k)] = v
		}
	}
	return ApplyReplacements(spec, replacements)
}

// ApplyReplacements replaces placeholders for declared parameters with the specified replacements.
func ApplyReplacements(spec *v1alpha1.TaskSpec, replacements map[string]string) *v1alpha1.TaskSpec {
	spec = spec.DeepCopy()

	// Apply variable expansion to steps fields.
	steps := spec.Steps
	for i := range steps {
		applyContainerReplacements(&steps[i], replacements)
	}

	// Apply variable expansion to containerTemplate fields.
	if spec.ContainerTemplate != nil {
		applyContainerReplacements(spec.ContainerTemplate, replacements)
	}

	// Apply variable expansion to the build's volumes
	for i, v := range spec.Volumes {
		spec.Volumes[i].Name = templating.ApplyReplacements(v.Name, replacements)
		if v.VolumeSource.ConfigMap != nil {
			spec.Volumes[i].ConfigMap.Name = templating.ApplyReplacements(v.ConfigMap.Name, replacements)
		}
		if v.VolumeSource.Secret != nil {
			spec.Volumes[i].Secret.SecretName = templating.ApplyReplacements(v.Secret.SecretName, replacements)
		}
		if v.PersistentVolumeClaim != nil {
			spec.Volumes[i].PersistentVolumeClaim.ClaimName = templating.ApplyReplacements(v.PersistentVolumeClaim.ClaimName, replacements)
		}
	}

	return spec
}

func applyContainerReplacements(container *corev1.Container, replacements map[string]string) {
	container.Name = templating.ApplyReplacements(container.Name, replacements)
	container.Image = templating.ApplyReplacements(container.Image, replacements)
	for ia, a := range container.Args {
		container.Args[ia] = templating.ApplyReplacements(a, replacements)
	}
	for ie, e := range container.Env {
		container.Env[ie].Value = templating.ApplyReplacements(e.Value, replacements)
		if container.Env[ie].ValueFrom != nil {
			if e.ValueFrom.SecretKeyRef != nil {
				container.Env[ie].ValueFrom.SecretKeyRef.LocalObjectReference.Name = templating.ApplyReplacements(e.ValueFrom.SecretKeyRef.LocalObjectReference.Name, replacements)
				container.Env[ie].ValueFrom.SecretKeyRef.Key = templating.ApplyReplacements(e.ValueFrom.SecretKeyRef.Key, replacements)
			}
			if e.ValueFrom.ConfigMapKeyRef != nil {
				container.Env[ie].ValueFrom.ConfigMapKeyRef.LocalObjectReference.Name = templating.ApplyReplacements(e.ValueFrom.ConfigMapKeyRef.LocalObjectReference.Name, replacements)
				container.Env[ie].ValueFrom.ConfigMapKeyRef.Key = templating.ApplyReplacements(e.ValueFrom.ConfigMapKeyRef.Key, replacements)
			}
		}
	}
	for ie, e := range container.EnvFrom {
		container.EnvFrom[ie].Prefix = templating.ApplyReplacements(e.Prefix, replacements)
		if e.ConfigMapRef != nil {
			container.EnvFrom[ie].ConfigMapRef.LocalObjectReference.Name = templating.ApplyReplacements(e.ConfigMapRef.LocalObjectReference.Name, replacements)
		}
		if e.SecretRef != nil {
			container.EnvFrom[ie].SecretRef.LocalObjectReference.Name = templating.ApplyReplacements(e.SecretRef.LocalObjectReference.Name, replacements)
		}
	}
	container.WorkingDir = templating.ApplyReplacements(container.WorkingDir, replacements)
	for ic, c := range container.Command {
		container.Command[ic] = templating.ApplyReplacements(c, replacements)
	}
	for iv, v := range container.VolumeMounts {
		container.VolumeMounts[iv].Name = templating.ApplyReplacements(v.Name, replacements)
		container.VolumeMounts[iv].MountPath = templating.ApplyReplacements(v.MountPath, replacements)
		container.VolumeMounts[iv].SubPath = templating.ApplyReplacements(v.SubPath, replacements)
	}
}
<commit_msg>Change import order in taskrun's apply.go.<commit_after>/*
Copyright 2018 The Knative Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package resources

import (
	"fmt"

	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
	"github.com/tektoncd/pipeline/pkg/templating"
	corev1 "k8s.io/api/core/v1"
)

// ApplyParameters applies the params from a TaskRun.Input.Parameters to a TaskSpec
func ApplyParameters(spec *v1alpha1.TaskSpec, tr *v1alpha1.TaskRun, defaults ...v1alpha1.TaskParam) *v1alpha1.TaskSpec {
	// This assumes that the TaskRun inputs have been validated against what the Task requests.
	replacements := map[string]string{}
	// Set all the default replacements
	for _, p := range defaults {
		if p.Default != "" {
			replacements[fmt.Sprintf("inputs.params.%s", p.Name)] = p.Default
		}
	}
	// Set and overwrite params with the ones from the TaskRun
	for _, p := range tr.Spec.Inputs.Params {
		replacements[fmt.Sprintf("inputs.params.%s", p.Name)] = p.Value
	}

	return ApplyReplacements(spec, replacements)
}

// ApplyResources applies the templating from values in resources which are referenced in spec as subitems
// of the replacementStr.
func ApplyResources(spec *v1alpha1.TaskSpec, resolvedResources map[string]v1alpha1.PipelineResourceInterface, replacementStr string) *v1alpha1.TaskSpec {
	replacements := map[string]string{}
	for name, r := range resolvedResources {
		for k, v := range r.Replacements() {
			replacements[fmt.Sprintf("%s.resources.%s.%s", replacementStr, name, k)] = v
		}
	}
	return ApplyReplacements(spec, replacements)
}

// ApplyReplacements replaces placeholders for declared parameters with the specified replacements.
func ApplyReplacements(spec *v1alpha1.TaskSpec, replacements map[string]string) *v1alpha1.TaskSpec {
	spec = spec.DeepCopy()

	// Apply variable expansion to steps fields.
	steps := spec.Steps
	for i := range steps {
		applyContainerReplacements(&steps[i], replacements)
	}

	// Apply variable expansion to containerTemplate fields.
	if spec.ContainerTemplate != nil {
		applyContainerReplacements(spec.ContainerTemplate, replacements)
	}

	// Apply variable expansion to the build's volumes
	for i, v := range spec.Volumes {
		spec.Volumes[i].Name = templating.ApplyReplacements(v.Name, replacements)
		if v.VolumeSource.ConfigMap != nil {
			spec.Volumes[i].ConfigMap.Name = templating.ApplyReplacements(v.ConfigMap.Name, replacements)
		}
		if v.VolumeSource.Secret != nil {
			spec.Volumes[i].Secret.SecretName = templating.ApplyReplacements(v.Secret.SecretName, replacements)
		}
		if v.PersistentVolumeClaim != nil {
			spec.Volumes[i].PersistentVolumeClaim.ClaimName = templating.ApplyReplacements(v.PersistentVolumeClaim.ClaimName, replacements)
		}
	}

	return spec
}

func applyContainerReplacements(container *corev1.Container, replacements map[string]string) {
	container.Name = templating.ApplyReplacements(container.Name, replacements)
	container.Image = templating.ApplyReplacements(container.Image, replacements)
	for ia, a := range container.Args {
		container.Args[ia] = templating.ApplyReplacements(a, replacements)
	}
	for ie, e := range container.Env {
		container.Env[ie].Value = templating.ApplyReplacements(e.Value, replacements)
		if container.Env[ie].ValueFrom != nil {
			if e.ValueFrom.SecretKeyRef != nil {
				container.Env[ie].ValueFrom.SecretKeyRef.LocalObjectReference.Name = templating.ApplyReplacements(e.ValueFrom.SecretKeyRef.LocalObjectReference.Name, replacements)
				container.Env[ie].ValueFrom.SecretKeyRef.Key = templating.ApplyReplacements(e.ValueFrom.SecretKeyRef.Key, replacements)
			}
			if e.ValueFrom.ConfigMapKeyRef != nil {
				container.Env[ie].ValueFrom.ConfigMapKeyRef.LocalObjectReference.Name = templating.ApplyReplacements(e.ValueFrom.ConfigMapKeyRef.LocalObjectReference.Name, replacements)
				container.Env[ie].ValueFrom.ConfigMapKeyRef.Key = templating.ApplyReplacements(e.ValueFrom.ConfigMapKeyRef.Key, replacements)
			}
		}
	}
	for ie, e := range container.EnvFrom {
		container.EnvFrom[ie].Prefix = templating.ApplyReplacements(e.Prefix, replacements)
		if e.ConfigMapRef != nil {
			container.EnvFrom[ie].ConfigMapRef.LocalObjectReference.Name = templating.ApplyReplacements(e.ConfigMapRef.LocalObjectReference.Name, replacements)
		}
		if e.SecretRef != nil {
			container.EnvFrom[ie].SecretRef.LocalObjectReference.Name = templating.ApplyReplacements(e.SecretRef.LocalObjectReference.Name, replacements)
		}
	}
	container.WorkingDir = templating.ApplyReplacements(container.WorkingDir, replacements)
	for ic, c := range container.Command {
		container.Command[ic] = templating.ApplyReplacements(c, replacements)
	}
	for iv, v := range container.VolumeMounts {
		container.VolumeMounts[iv].Name = templating.ApplyReplacements(v.Name, replacements)
		container.VolumeMounts[iv].MountPath = templating.ApplyReplacements(v.MountPath, replacements)
		container.VolumeMounts[iv].SubPath = templating.ApplyReplacements(v.SubPath, replacements)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 l2plugin

import (
	"fmt"

	govppapi "git.fd.io/govpp.git/api"
	log "github.com/ligato/cn-infra/logging/logrus"
	"github.com/ligato/cn-infra/utils/safeclose"
	"github.com/ligato/vpp-agent/idxvpp"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/ifaceidx"
	l2ba "github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/bin_api/l2"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/model/l2"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/vppcalls"
	"github.com/ligato/vpp-agent/plugins/govppmux"
)

// XConnectConfigurator implements PluginHandlerVPP
type XConnectConfigurator struct {
	GoVppmux    *govppmux.GOVPPPlugin
	SwIfIndexes ifaceidx.SwIfIndex
	XcIndexes   idxvpp.NameToIdxRW
	XcIndexSeq  uint32
	vppChan     *govppapi.Channel
}

// XConnectMeta meta hold info about transmit interface
type XConnectMeta struct {
	TransmitInterface string
	configured        bool // true if already configured on VPP, false if still waiting for creation of the rx or tx interface
}

// Init members (channels...) and start go routines
func (plugin *XConnectConfigurator) Init() (err error) {

	log.DefaultLogger().Debug("Initializing L2 xConnect")

	// Init VPP API channel
	plugin.vppChan, err = plugin.GoVppmux.NewAPIChannel()
	if err != nil {
		return err
	}

	// check bin api message compatibility
	err = vppcalls.CheckMsgCompatibilityForL2XConnect(plugin.vppChan)
	if err != nil {
		return err
	}

	return nil
}

// Close GOVPP channel
func (plugin *XConnectConfigurator) Close() error {
	return safeclose.Close(plugin.vppChan)
}

// ConfigureXConnectPair process the NB config and propagates it to bin api calls
func (plugin *XConnectConfigurator) ConfigureXConnectPair(xConnectPairInput *l2.XConnectPairs_XConnectPair) error {
	log.DefaultLogger().Println("Configuring L2 xConnect pair", xConnectPairInput.ReceiveInterface)

	// Find interfaces
	receiveInterfaceIndex, _, rxFound := plugin.SwIfIndexes.LookupIdx(xConnectPairInput.ReceiveInterface)
	if !rxFound {
		log.DefaultLogger().WithField("Interface", xConnectPairInput.ReceiveInterface).Warn("Receive interface not found.")
	}
	transmitInterfaceIndex, _, txFound := plugin.SwIfIndexes.LookupIdx(xConnectPairInput.TransmitInterface)
	if !txFound {
		log.DefaultLogger().WithField("Interface", xConnectPairInput.TransmitInterface).Warn("Transmit interface not found.")
	}

	if rxFound && txFound {
		// can be configured now
		err := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, transmitInterfaceIndex, plugin.vppChan)
		if err != nil {
			log.DefaultLogger().WithField("Error", err).Error("Failed to create l2xConnect")
			return err
		}
	} else {
		log.DefaultLogger().Error("l2xConnect")
	}

	// Prepare meta
	meta := XConnectMeta{
		TransmitInterface: xConnectPairInput.TransmitInterface,
		configured:        rxFound && txFound,
	}

	// Register
	plugin.XcIndexes.RegisterName(xConnectPairInput.ReceiveInterface, plugin.XcIndexSeq, meta)
	plugin.XcIndexSeq++

	return nil
}

// ModifyXConnectPair processes the NB config and propagates it to bin api calls
func (plugin *XConnectConfigurator) ModifyXConnectPair(newConfig *l2.XConnectPairs_XConnectPair, oldConfig *l2.XConnectPairs_XConnectPair) error {
	log.DefaultLogger().Println("Modifying L2 xConnect pair")

	// interfaces
	receiveInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(newConfig.ReceiveInterface)
	if !found {
		log.DefaultLogger().WithField("Interface", newConfig.ReceiveInterface).Error("Receive interface not found.")
		return nil
	}
	newTransmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(newConfig.TransmitInterface)
	if !found {
		log.DefaultLogger().WithField("Interface", newConfig.TransmitInterface).Error("New transmit interface not found.")
		return nil
	}
	oldTransmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(oldConfig.TransmitInterface)
	if !found {
		log.DefaultLogger().WithField("Interface", newConfig.TransmitInterface).Debug("Old transmit interface not found.")
		oldTransmitInterfaceIndex = 0
		// do not return, not an error
	}
	if oldTransmitInterfaceIndex == newTransmitInterfaceIndex {
		// nothing to update
		return nil
	} else if oldTransmitInterfaceIndex == 0 {
		// create new xConnect only
		err := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, newTransmitInterfaceIndex, plugin.vppChan)
		if err != nil {
			log.DefaultLogger().WithField("Error", err).Error("Failed to set l2xConnect")
			return err
		}
	} else {
		errDel := vppcalls.VppUnsetL2XConnect(receiveInterfaceIndex, oldTransmitInterfaceIndex, plugin.vppChan)
		if errDel != nil {
			log.DefaultLogger().WithField("Error", errDel).Error("Failed to remove l2xConnect")
			return errDel
		}
		errCreate := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, newTransmitInterfaceIndex, plugin.vppChan)
		if errCreate != nil {
			log.DefaultLogger().WithField("Error", errCreate).Error("Failed to set l2xConnect")
			return errCreate
		}
	}

	meta := XConnectMeta{
		TransmitInterface: newConfig.TransmitInterface,
	}
	plugin.XcIndexes.RegisterName(newConfig.ReceiveInterface, receiveInterfaceIndex, meta)
	plugin.XcIndexSeq++

	return nil
}

// DeleteXConnectPair process the NB config and propagates it to bin api calls
func (plugin *XConnectConfigurator) DeleteXConnectPair(xConnectPairInput *l2.XConnectPairs_XConnectPair) error {
	return plugin.deleteL2XConnectPair(xConnectPairInput.ReceiveInterface, xConnectPairInput.TransmitInterface)
}

// LookupXConnectPairs registers missing l2 xConnect pairs
func (plugin *XConnectConfigurator) LookupXConnectPairs() error {
	req := &l2ba.L2XconnectDump{}
	reqContext := plugin.vppChan.SendMultiRequest(req)
	var index uint32 = 1
	for {
		msg := &l2ba.L2XconnectDetails{}
		stop, err := reqContext.ReceiveReply(msg)
		if err != nil {
			log.DefaultLogger().Error(err)
			return err
		}
		if stop {
			break
		}
		// Store name if missing
		_, _, found := plugin.XcIndexes.LookupName(index)
		xcIdentifier := string(msg.RxSwIfIndex)
		if !found {
			log.DefaultLogger().WithFields(log.Fields{"Name": xcIdentifier, "Index": index}).Debug("L2 xConnect pair registered.")
			plugin.XcIndexes.RegisterName(xcIdentifier, index, nil)
		} else {
			log.DefaultLogger().WithFields(log.Fields{"Name": xcIdentifier, "Index": index}).Debug("L2 xConnect pair already registered.")
		}
		index++
	}

	return nil
}

// ResolveCreatedInterface configures xconnect pairs that use the interface as rx or tx and have not been configured yet
func (plugin *XConnectConfigurator) ResolveCreatedInterface(interfaceName string, interfaceIndex uint32) error {
	log.DefaultLogger().Println("Resolving L2 xConnect pairs for created interface ", interfaceName)
	var err error

	// lookup for the interface in rx interfaces
	err = plugin.resolveRxInterface(interfaceName, true)

	// lookup for the interface in tx interfaces
	rxIfs := plugin.XcIndexes.LookupNameByMetadata("TransmitInterface", interfaceName)
	for _, rxIf := range rxIfs {
		err = plugin.resolveRxInterface(rxIf, true)
	}

	return err
}

// ResolveDeletedInterface deltes xconnect pairs that have not been deleted yet and use the interface as rx or tx
func (plugin *XConnectConfigurator) ResolveDeletedInterface(interfaceName string) error {
	log.DefaultLogger().Println("Resolving L2 xConnect pairs for deleted interface ", interfaceName)

	var err error

	// lookup for the interface in rx interfaces
	err = plugin.resolveRxInterface(interfaceName, false)

	// lookup for the interface in tx interfaces
	rxIfs := plugin.XcIndexes.LookupNameByMetadata("TransmitInterface", interfaceName)
	for _, rxIf := range rxIfs {
		err = plugin.resolveRxInterface(rxIf, false)
	}

	return err
}

// resolveRxInterface creates/deletes 2sxconnect in XcIndexes that has not been created yet/need to be deleted
// and have the rx interface name matching with the provided argument
func (plugin *XConnectConfigurator) resolveRxInterface(rxIfName string, create bool) error {
	var err error

	_, meta, exists := plugin.XcIndexes.LookupIdx(rxIfName)
	if exists {
		meta := meta.(*XConnectMeta)
		if create {
			// the l2xconn needs to be created
			if !meta.configured {
				// not yet configured, configure now
				err = plugin.configureL2XConnectPair(rxIfName, meta.TransmitInterface)
				meta.configured = true
			}
		} else {
			// the l2xconn needs to be delted
			err = plugin.deleteL2XConnectPair(rxIfName, meta.TransmitInterface)
			// meta deleted in deleteL2XConnectPair
		}
	}

	return err
}

func (plugin *XConnectConfigurator) configureL2XConnectPair(rxIf, txIf string) error {
	log.DefaultLogger().Println("Configuring L2 xConnect pair", rxIf, txIf)

	// find interface idx-es
	receiveInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(rxIf)
	if !found {
		log.DefaultLogger().WithField("Interface", rxIf).Warn("Receive interface not found.")
		return fmt.Errorf("Receive interface '%s' not found", rxIf)
	}
	transmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(txIf)
	if !found {
		log.DefaultLogger().WithField("Interface", txIf).Warn("Transmit interface not found.")
		return fmt.Errorf("Transmit interface '%s' not found", txIf)
	}

	// configure l2xconnect
	err := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, transmitInterfaceIndex, plugin.vppChan)
	if err != nil {
		log.DefaultLogger().WithField("Error", err).Error("Failed to create l2xConnect")
		return err
	}

	return nil
}

func (plugin *XConnectConfigurator) deleteL2XConnectPair(rxIf, txIf string) error {
	log.DefaultLogger().Println("Deleting L2 xConnect pair", rxIf, txIf)

	// find interface idx-es
	receiveInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(rxIf)
	if !found {
		log.DefaultLogger().WithField("Interface", rxIf).Warn("Receive interface not found.")
		return fmt.Errorf("Receive interface '%s' not found", rxIf)
	}
	transmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(txIf)
	if !found {
		log.DefaultLogger().WithField("Interface", txIf).Warn("Transmit interface not found.")
		return fmt.Errorf("Transmit interface '%s' not found", txIf)
	}

	err := vppcalls.VppUnsetL2XConnect(receiveInterfaceIndex, transmitInterfaceIndex, plugin.vppChan)
	if err != nil {
		log.DefaultLogger().WithField("Error", err).Error("Failed to remove l2xConnect")
		return err
	}

	// unregister
	plugin.XcIndexes.UnregisterName(rxIf)
	log.DefaultLogger().WithFields(log.Fields{"RecIface": rxIf, "Idex": receiveInterfaceIndex}).Debug("XConnect pair unregistered.")

	return nil
}
<commit_msg>fixed l2xconn meta setting<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 l2plugin

import (
	"fmt"

	govppapi "git.fd.io/govpp.git/api"
	log "github.com/ligato/cn-infra/logging/logrus"
	"github.com/ligato/cn-infra/utils/safeclose"
	"github.com/ligato/vpp-agent/idxvpp"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/ifaceidx"
	l2ba "github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/bin_api/l2"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/model/l2"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/vppcalls"
	"github.com/ligato/vpp-agent/plugins/govppmux"
)

// XConnectConfigurator implements PluginHandlerVPP
type XConnectConfigurator struct {
	GoVppmux    *govppmux.GOVPPPlugin
	SwIfIndexes ifaceidx.SwIfIndex
	XcIndexes   idxvpp.NameToIdxRW
	XcIndexSeq  uint32
	vppChan     *govppapi.Channel
}

// XConnectMeta meta hold info about transmit interface
type XConnectMeta struct {
	TransmitInterface string
	configured        bool // true if already configured on VPP, false if still waiting for creation of the rx or tx interface
}

// Init members (channels...) and start go routines
func (plugin *XConnectConfigurator) Init() (err error) {

	log.DefaultLogger().Debug("Initializing L2 xConnect")

	// Init VPP API channel
	plugin.vppChan, err = plugin.GoVppmux.NewAPIChannel()
	if err != nil {
		return err
	}

	// check bin api message compatibility
	err = vppcalls.CheckMsgCompatibilityForL2XConnect(plugin.vppChan)
	if err != nil {
		return err
	}

	return nil
}

// Close GOVPP channel
func (plugin *XConnectConfigurator) Close() error {
	return safeclose.Close(plugin.vppChan)
}

// ConfigureXConnectPair process the NB config and propagates it to bin api calls
func (plugin *XConnectConfigurator) ConfigureXConnectPair(xConnectPairInput *l2.XConnectPairs_XConnectPair) error {
	log.DefaultLogger().Println("Configuring L2 xConnect pair", xConnectPairInput.ReceiveInterface)

	// Find interfaces
	receiveInterfaceIndex, _, rxFound := plugin.SwIfIndexes.LookupIdx(xConnectPairInput.ReceiveInterface)
	if !rxFound {
		log.DefaultLogger().WithField("Interface", xConnectPairInput.ReceiveInterface).Warn("Receive interface not found.")
	}
	transmitInterfaceIndex, _, txFound := plugin.SwIfIndexes.LookupIdx(xConnectPairInput.TransmitInterface)
	if !txFound {
		log.DefaultLogger().WithField("Interface", xConnectPairInput.TransmitInterface).Warn("Transmit interface not found.")
	}

	if rxFound && txFound {
		// can be configured now
		err := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, transmitInterfaceIndex, plugin.vppChan)
		if err != nil {
			log.DefaultLogger().WithField("Error", err).Error("Failed to create l2xConnect")
			return err
		}
	} else {
		log.DefaultLogger().Error("l2xConnect")
	}

	// Prepare meta
	meta := XConnectMeta{
		TransmitInterface: xConnectPairInput.TransmitInterface,
		configured:        rxFound && txFound,
	}

	// Register
	plugin.XcIndexes.RegisterName(xConnectPairInput.ReceiveInterface, plugin.XcIndexSeq, &meta)
	plugin.XcIndexSeq++

	return nil
}

// ModifyXConnectPair processes the NB config and propagates it to bin api calls
func (plugin *XConnectConfigurator) ModifyXConnectPair(newConfig *l2.XConnectPairs_XConnectPair, oldConfig *l2.XConnectPairs_XConnectPair) error {
	log.DefaultLogger().Println("Modifying L2 xConnect pair")

	// interfaces
	receiveInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(newConfig.ReceiveInterface)
	if !found {
		log.DefaultLogger().WithField("Interface", newConfig.ReceiveInterface).Error("Receive interface not found.")
		return nil
	}
	newTransmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(newConfig.TransmitInterface)
	if !found {
		log.DefaultLogger().WithField("Interface", newConfig.TransmitInterface).Error("New transmit interface not found.")
		return nil
	}
	oldTransmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(oldConfig.TransmitInterface)
	if !found {
		log.DefaultLogger().WithField("Interface", newConfig.TransmitInterface).Debug("Old transmit interface not found.")
		oldTransmitInterfaceIndex = 0
		// do not return, not an error
	}
	if oldTransmitInterfaceIndex == newTransmitInterfaceIndex {
		// nothing to update
		return nil
	} else if oldTransmitInterfaceIndex == 0 {
		// create new xConnect only
		err := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, newTransmitInterfaceIndex, plugin.vppChan)
		if err != nil {
			log.DefaultLogger().WithField("Error", err).Error("Failed to set l2xConnect")
			return err
		}
	} else {
		errDel := vppcalls.VppUnsetL2XConnect(receiveInterfaceIndex, oldTransmitInterfaceIndex, plugin.vppChan)
		if errDel != nil {
			log.DefaultLogger().WithField("Error", errDel).Error("Failed to remove l2xConnect")
			return errDel
		}
		errCreate := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, newTransmitInterfaceIndex, plugin.vppChan)
		if errCreate != nil {
			log.DefaultLogger().WithField("Error", errCreate).Error("Failed to set l2xConnect")
			return errCreate
		}
	}

	meta := XConnectMeta{
		TransmitInterface: newConfig.TransmitInterface,
	}
	plugin.XcIndexes.RegisterName(newConfig.ReceiveInterface, receiveInterfaceIndex, &meta)
	plugin.XcIndexSeq++

	return nil
}

// DeleteXConnectPair process the NB config and propagates it to bin api calls
func (plugin *XConnectConfigurator) DeleteXConnectPair(xConnectPairInput *l2.XConnectPairs_XConnectPair) error {
	return plugin.deleteL2XConnectPair(xConnectPairInput.ReceiveInterface, xConnectPairInput.TransmitInterface)
}

// LookupXConnectPairs registers missing l2 xConnect pairs
func (plugin *XConnectConfigurator) LookupXConnectPairs() error {
	req := &l2ba.L2XconnectDump{}
	reqContext := plugin.vppChan.SendMultiRequest(req)
	var index uint32 = 1
	for {
		msg := &l2ba.L2XconnectDetails{}
		stop, err := reqContext.ReceiveReply(msg)
		if err != nil {
			log.DefaultLogger().Error(err)
			return err
		}
		if stop {
			break
		}
		// Store name if missing
		_, _, found := plugin.XcIndexes.LookupName(index)
		xcIdentifier := string(msg.RxSwIfIndex)
		if !found {
			log.DefaultLogger().WithFields(log.Fields{"Name": xcIdentifier, "Index": index}).Debug("L2 xConnect pair registered.")
			plugin.XcIndexes.RegisterName(xcIdentifier, index, nil)
		} else {
			log.DefaultLogger().WithFields(log.Fields{"Name": xcIdentifier, "Index": index}).Debug("L2 xConnect pair already registered.")
		}
		index++
	}

	return nil
}

// ResolveCreatedInterface configures xconnect pairs that use the interface as rx or tx and have not been configured yet
func (plugin *XConnectConfigurator) ResolveCreatedInterface(interfaceName string, interfaceIndex uint32) error {
	log.DefaultLogger().Println("Resolving L2 xConnect pairs for created interface ", interfaceName)
	var err error

	// lookup for the interface in rx interfaces
	err = plugin.resolveRxInterface(interfaceName, true)

	// lookup for the interface in tx interfaces
	rxIfs := plugin.XcIndexes.LookupNameByMetadata("TransmitInterface", interfaceName)
	for _, rxIf := range rxIfs {
		err = plugin.resolveRxInterface(rxIf, true)
	}

	return err
}

// ResolveDeletedInterface deltes xconnect pairs that have not been deleted yet and use the interface as rx or tx
func (plugin *XConnectConfigurator) ResolveDeletedInterface(interfaceName string) error {
	log.DefaultLogger().Println("Resolving L2 xConnect pairs for deleted interface ", interfaceName)

	var err error

	// lookup for the interface in rx interfaces
	err = plugin.resolveRxInterface(interfaceName, false)

	// lookup for the interface in tx interfaces
	rxIfs := plugin.XcIndexes.LookupNameByMetadata("TransmitInterface", interfaceName)
	for _, rxIf := range rxIfs {
		err = plugin.resolveRxInterface(rxIf, false)
	}

	return err
}

// resolveRxInterface creates/deletes 2sxconnect in XcIndexes that has not been created yet/need to be deleted
// and have the rx interface name matching with the provided argument
func (plugin *XConnectConfigurator) resolveRxInterface(rxIfName string, create bool) error {
	var err error

	_, meta, exists := plugin.XcIndexes.LookupIdx(rxIfName)
	if exists {
		meta := meta.(*XConnectMeta)
		if create {
			// the l2xconn needs to be created
			if !meta.configured {
				// not yet configured, configure now
				err = plugin.configureL2XConnectPair(rxIfName, meta.TransmitInterface)
				meta.configured = true
			}
		} else {
			// the l2xconn needs to be delted
			err = plugin.deleteL2XConnectPair(rxIfName, meta.TransmitInterface)
			// meta deleted in deleteL2XConnectPair
		}
	}

	return err
}

func (plugin *XConnectConfigurator) configureL2XConnectPair(rxIf, txIf string) error {
	log.DefaultLogger().Println("Configuring L2 xConnect pair", rxIf, txIf)

	// find interface idx-es
	receiveInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(rxIf)
	if !found {
		log.DefaultLogger().WithField("Interface", rxIf).Warn("Receive interface not found.")
		return fmt.Errorf("Receive interface '%s' not found", rxIf)
	}
	transmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(txIf)
	if !found {
		log.DefaultLogger().WithField("Interface", txIf).Warn("Transmit interface not found.")
		return fmt.Errorf("Transmit interface '%s' not found", txIf)
	}

	// configure l2xconnect
	err := vppcalls.VppSetL2XConnect(receiveInterfaceIndex, transmitInterfaceIndex, plugin.vppChan)
	if err != nil {
		log.DefaultLogger().WithField("Error", err).Error("Failed to create l2xConnect")
		return err
	}

	return nil
}

func (plugin *XConnectConfigurator) deleteL2XConnectPair(rxIf, txIf string) error {
	log.DefaultLogger().Println("Deleting L2 xConnect pair", rxIf, txIf)

	// find interface idx-es
	receiveInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(rxIf)
	if !found {
		log.DefaultLogger().WithField("Interface", rxIf).Warn("Receive interface not found.")
		return fmt.Errorf("Receive interface '%s' not found", rxIf)
	}
	transmitInterfaceIndex, _, found := plugin.SwIfIndexes.LookupIdx(txIf)
	if !found {
		log.DefaultLogger().WithField("Interface", txIf).Warn("Transmit interface not found.")
		return fmt.Errorf("Transmit interface '%s' not found", txIf)
	}

	err := vppcalls.VppUnsetL2XConnect(receiveInterfaceIndex, transmitInterfaceIndex, plugin.vppChan)
	if err != nil {
		log.DefaultLogger().WithField("Error", err).Error("Failed to remove l2xConnect")
		return err
	}

	// unregister
	plugin.XcIndexes.UnregisterName(rxIf)
	log.DefaultLogger().WithFields(log.Fields{"RecIface": rxIf, "Idex": receiveInterfaceIndex}).Debug("XConnect pair unregistered.")

	return nil
}
<|endoftext|>


<commit_before>package v1

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/solefaucet/sole-server/errors"
	"github.com/solefaucet/sole-server/models"
)

/*
immediate:

0：非即时返利活动,处于待审核状态；
1：即时返利活动，需发放奖励给会员；
2：非即时返利活动，审核通过，重新回传，发放奖励给会员；
3：非即时返利活动，审核不通过，重新回传，不发放奖励；

errno:

offerwow-01: 出现空参数
offerwow-02: 网站id不存在
offerwow-03: uid会员不存在
offerwow-04: 已发放奖励的Eventid重复
offerwow-05: immediate=0
offerwow-06: immediate=3
*/

// offerwow const
const (
	offerwowWebsiteID     = "2626"
	offerwowImmediate0    = "0"
	offerwowImmediate1    = "1"
	offerwowImmediate2    = "2"
	offerwowImmediate3    = "3"
	offerwowStatusSuccess = "success"
	offerwowStatusFailure = "failure"
	offerwowErrno01       = "offerwow-01"
	offerwowErrno02       = "offerwow-02"
	offerwowErrno03       = "offerwow-03"
	offerwowErrno04       = "offerwow-04"
	offerwowErrno05       = "offerwow-05"
	offerwowErrno06       = "offerwow-06"
)

type offerwowPayload struct {
	UserID      int64   `form:"memberid"`
	Amount      float64 `form:"point"`
	EventID     string  `form:"eventid"`
	WebsiteID   string  `form:"websiteid"`
	Immediate   string  `form:"immediate"`
	ProgramName string  `form:"programname"`
	Sign        string  `form:"sign"` // NOTE: should be required in production
}

type offerwowResponse struct {
	UserID    int64
	Amount    float64
	EventID   string
	Immediate string
	Status    string
	Error     string
}

func (r offerwowResponse) MarshalJSON() ([]byte, error) {
	m := map[string]interface{}{
		"memberid":  fmt.Sprint(r.UserID),
		"point":     fmt.Sprint(r.Amount),
		"websiteid": offerwowWebsiteID,
		"eventid":   r.EventID,
		"Immediate": r.Immediate,
		"status":    r.Status,
	}
	if r.Error != "" {
		m["errno"] = r.Error
	}
	return json.Marshal(m)
}

// OfferwowCallback handles callback from offerwow
func OfferwowCallback(
	getUserByID dependencyGetUserByID,
	getOfferwowEventByID dependencyGetOfferwowEventByID,
	getSystemConfig dependencyGetSystemConfig,
	createOfferwowIncome dependencyCreateOfferwowIncome,
) gin.HandlerFunc {
	return func(c *gin.Context) {
		payload := offerwowPayload{}
		c.BindWith(&payload, binding.Form)

		responseAndLog := func(status, err string) {
			response := offerwowResponse{
				UserID:    payload.UserID,
				Amount:    payload.Amount,
				EventID:   payload.EventID,
				Immediate: payload.Immediate,
				Status:    status,
				Error:     err,
			}
			c.JSON(http.StatusOK, response)
			logrus.WithFields(logrus.Fields{
				"event":    models.EventOfferwowCallback,
				"query":    c.Request.URL.Query().Encode(),
				"payload":  payload,
				"response": response,
			}).Debug("get offerwow callback")
		}

		if payload.UserID == 0 || payload.Amount == 0 || payload.EventID == "" || payload.WebsiteID == "" || payload.Immediate == "" {
			responseAndLog(offerwowStatusFailure, offerwowErrno01)
			return
		}

		if payload.WebsiteID != offerwowWebsiteID {
			responseAndLog(offerwowStatusFailure, offerwowErrno02)
			return
		}

		// check if user exists
		user, err := getUserByID(payload.UserID)
		if err != nil {
			switch err {
			case errors.ErrNotFound:
				responseAndLog(offerwowStatusFailure, offerwowErrno03)
			default:
				c.AbortWithError(http.StatusInternalServerError, err)
			}
			return
		}

		// check if eventid duplicates
		if _, err := getOfferwowEventByID(payload.EventID); err != nil {
			switch err {
			case errors.ErrNotFound:
				responseAndLog(offerwowStatusFailure, offerwowErrno04)
			default:
				c.AbortWithError(http.StatusInternalServerError, err)
			}
			return
		}

		if payload.Immediate == offerwowImmediate0 {
			responseAndLog(offerwowStatusFailure, offerwowErrno05)
			return
		}

		if payload.Immediate == offerwowImmediate3 {
			responseAndLog(offerwowStatusFailure, offerwowErrno06)
			return
		}

		// create income offerwow
		income := models.Income{
			UserID:        user.ID,
			RefererID:     user.RefererID,
			Type:          models.IncomeTypeOfferwow,
			Income:        payload.Amount / 1e8,
			RefererIncome: getSystemConfig().RefererRewardRate * payload.Amount,
		}
		if err := createOfferwowIncome(income, payload.EventID); err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}

		responseAndLog(offerwowStatusSuccess, "")
	}
}
<commit_msg>Fix bug when validate existence of event<commit_after>package v1

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/solefaucet/sole-server/errors"
	"github.com/solefaucet/sole-server/models"
)

/*

0：非即时返利活动,处于待审核状态；
1：即时返利活动，需发放奖励给会员；
2：非即时返利活动，审核通过，重新回传，发放奖励给会员；
3：非即时返利活动，审核不通过，重新回传，不发放奖励；

errno:

offerwow-01: 出现空参数
offerwow-02: 网站id不存在
offerwow-03: uid会员不存在
offerwow-04: 已发放奖励的Eventid重复
offerwow-05: immediate=0
offerwow-06: immediate=3
*/

// offerwow const
const (
	offerwowWebsiteID     = "2626"
	offerwowImmediate0    = "0"
	offerwowImmediate1    = "1"
	offerwowImmediate2    = "2"
	offerwowImmediate3    = "3"
	offerwowStatusSuccess = "success"
	offerwowStatusFailure = "failure"
	offerwowErrno01       = "offerwow-01"
	offerwowErrno02       = "offerwow-02"
	offerwowErrno03       = "offerwow-03"
	offerwowErrno04       = "offerwow-04"
	offerwowErrno05       = "offerwow-05"
	offerwowErrno06       = "offerwow-06"
)

type offerwowPayload struct {
	UserID      int64   `form:"memberid"`
	Amount      float64 `form:"point"`
	EventID     string  `form:"eventid"`
	WebsiteID   string  `form:"websiteid"`
	Immediate   string  `form:"immediate"`
	ProgramName string  `form:"programname"`
	Sign        string  `form:"sign"` // NOTE: should be required in production
}

type offerwowResponse struct {
	UserID    int64
	Amount    float64
	EventID   string
	Immediate string
	Status    string
	Error     string
}

func (r offerwowResponse) MarshalJSON() ([]byte, error) {
	m := map[string]interface{}{
		"memberid":  fmt.Sprint(r.UserID),
		"point":     fmt.Sprint(r.Amount),
		"websiteid": offerwowWebsiteID,
		"eventid":   r.EventID,
		"Immediate": r.Immediate,
		"status":    r.Status,
	}
	if r.Error != "" {
		m["errno"] = r.Error
	}
	return json.Marshal(m)
}

// OfferwowCallback handles callback from offerwow
func OfferwowCallback(
	getUserByID dependencyGetUserByID,
	getOfferwowEventByID dependencyGetOfferwowEventByID,
	getSystemConfig dependencyGetSystemConfig,
	createOfferwowIncome dependencyCreateOfferwowIncome,
) gin.HandlerFunc {
	return func(c *gin.Context) {
		payload := offerwowPayload{}
		c.BindWith(&payload, binding.Form)

		responseAndLog := func(status, err string) {
			response := offerwowResponse{
				UserID:    payload.UserID,
				Amount:    payload.Amount,
				EventID:   payload.EventID,
				Immediate: payload.Immediate,
				Status:    status,
				Error:     err,
			}
			c.JSON(http.StatusOK, response)
			logrus.WithFields(logrus.Fields{
				"event":    models.EventOfferwowCallback,
				"query":    c.Request.URL.Query().Encode(),
				"payload":  payload,
				"response": response,
			}).Debug("get offerwow callback")
		}

		if payload.UserID == 0 || payload.Amount == 0 || payload.EventID == "" || payload.WebsiteID == "" || payload.Immediate == "" {
			responseAndLog(offerwowStatusFailure, offerwowErrno01)
			return
		}

		if payload.WebsiteID != offerwowWebsiteID {
			responseAndLog(offerwowStatusFailure, offerwowErrno02)
			return
		}

		// check if user exists
		user, err := getUserByID(payload.UserID)
		if err != nil {
			switch err {
			case errors.ErrNotFound:
				responseAndLog(offerwowStatusFailure, offerwowErrno03)
			default:
				c.AbortWithError(http.StatusInternalServerError, err)
			}
			return
		}

		// check if eventid duplicates
		_, err = getOfferwowEventByID(payload.EventID)
		switch err {
		case errors.ErrNotFound:
			// pass validation
		case nil:
			responseAndLog(offerwowStatusFailure, offerwowErrno04)
			return
		default:
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}

		if payload.Immediate == offerwowImmediate0 {
			responseAndLog(offerwowStatusFailure, offerwowErrno05)
			return
		}

		if payload.Immediate == offerwowImmediate3 {
			responseAndLog(offerwowStatusFailure, offerwowErrno06)
			return
		}

		// create income offerwow
		income := models.Income{
			UserID:        user.ID,
			RefererID:     user.RefererID,
			Type:          models.IncomeTypeOfferwow,
			Income:        payload.Amount / 1e8,
			RefererIncome: getSystemConfig().RefererRewardRate * payload.Amount,
		}
		if err := createOfferwowIncome(income, payload.EventID); err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}

		responseAndLog(offerwowStatusSuccess, "")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/cartland/go/fib"
)

func main() {
	f := fib.NewMemoizer()
	for i := 0; i < 20; i++ {
		fmt.Printf("f.Fib(%v) %v\n", i, f.Fib(i))
	}
}
<commit_msg>Add copyright<commit_after>/*
 * Copyright 2014 Chris Cartland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package main

import (
	"fmt"
	"github.com/cartland/go/fib"
)

func main() {
	f := fib.NewMemoizer()
	for i := 0; i < 20; i++ {
		fmt.Printf("f.Fib(%v) %v\n", i, f.Fib(i))
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package transferissue

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"
	"unicode"

	"github.com/shurcooL/githubv4"
	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/prow/github"
	"k8s.io/test-infra/prow/github/fakegithub"
)

const issuerNum = 1

func Test_handleTransfer(t *testing.T) {
	ts := []struct {
		name         string
		event        github.GenericCommentEvent
		expectError  bool
		errorMessage string
		comment      string
		fcFunc       func(client *fakegithub.FakeClient)
		tcFunc       func(client *testClient)
	}{
		{
			name:  "is a pr",
			event: github.GenericCommentEvent{IsPR: true},
		},
		{
			name:  "is not comment added",
			event: github.GenericCommentEvent{Action: github.GenericCommentActionDeleted},
		},
		{
			name: "multiple matches",
			event: github.GenericCommentEvent{
				Action: github.GenericCommentActionCreated,
				Body: `/transfer-issue kubectl
/transfer test-infra`,
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "org"}, Name: "repo"},
				User:    github.User{Login: "user"},
			},
			comment: "single destination",
		},
		{
			name: "no destination",
			event: github.GenericCommentEvent{
				Action:  github.GenericCommentActionCreated,
				Body:    "/transfer",
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "org"}, Name: "repo"},
				User:    github.User{Login: "user"},
			},
			comment: "single destination",
		},
		{
			name: "dest repo does not exist",
			event: github.GenericCommentEvent{
				Action:  github.GenericCommentActionCreated,
				Body:    "/transfer-issue fake",
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:    github.User{Login: "user"},
			},
			comment: "does not exist",
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.GetRepoError = errors.New("stub")
			},
		},
		{
			name: "not collaborator",
			event: github.GenericCommentEvent{
				Action:  github.GenericCommentActionCreated,
				Body:    "/transfer-issue test-infra",
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:    github.User{Login: "user"},
			},
			comment: "must be an org member",
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.OrgMembers["kubernetes"] = []string{}
			},
		},
		{
			name: "trims whitespace from user input",
			event: github.GenericCommentEvent{
				Action: github.GenericCommentActionCreated,
				Body:   "/transfer-issue test-infra\r",
				Number: issuerNum,
				Repo:   github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:   github.User{Login: "user"},
				NodeID: "fakeIssueNodeID",
			},
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.OrgMembers["kubernetes"] = []string{"user"}
			},
			tcFunc: func(c *testClient) {
				c.repoNodeID = "fakeRepoNodeID"
			},
		},
		{
			name: "happy path",
			event: github.GenericCommentEvent{
				Action: github.GenericCommentActionCreated,
				Body: `This belongs elsewhere
/transfer-issue test-infra
Thanks!`,
				Number: issuerNum,
				Repo:   github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:   github.User{Login: "user"},
				NodeID: "fakeIssueNodeID",
			},
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.OrgMembers["kubernetes"] = []string{"user"}
			},
			tcFunc: func(c *testClient) {
				c.repoNodeID = "fakeRepoNodeID"
			},
		},
	}

	for _, tc := range ts {
		t.Run(tc.name, func(t *testing.T) {
			fc := fakegithub.NewFakeClient()
			c := &testClient{fc: fc}
			if tc.tcFunc != nil {
				tc.tcFunc(c)
			}
			if tc.fcFunc != nil {
				tc.fcFunc(fc)
			}
			log := logrus.WithField("plugin", pluginName)
			err := handleTransfer(c, log, tc.event)
			if err != nil {
				if !tc.expectError {
					t.Fatalf("unexpected error: %v", err)
				}
				if m := err.Error(); !strings.Contains(m, tc.errorMessage) {
					t.Fatalf("expected error to contain: %s got: %v", tc.errorMessage, m)
				}
			}
			if err == nil && tc.expectError {
				t.Fatalf("expected error but did not produce")
			}
			if len(tc.comment) != 0 {
				if cm, ok := fc.IssueComments[tc.event.Number]; ok {
					if !strings.Contains(cm[0].Body, tc.comment) {
						t.Errorf("expected comment to contain: %s got: %s", tc.comment, cm[0].Body)
					}
				} else {
					t.Errorf("expected comment to contain: %s but no comment", tc.comment)
				}
			}
			if len(tc.comment) == 0 && len(fc.IssueComments[issuerNum]) != 0 {
				t.Errorf("unexpected comment: %v", fc.IssueComments[issuerNum])
			}
		})
	}
}

type testRoundTripper struct {
	rt func(*http.Request) (*http.Response, error)
}

func (rt testRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	return rt.rt(r)
}

type testClient struct {
	fc         *fakegithub.FakeClient
	repoNodeID string
}

func (t *testClient) GetRepo(org, name string) (github.FullRepo, error) {
	r := []rune(name)
	if lastChar := r[len(r)-1:][0]; unicode.IsSpace(lastChar) {
		return github.FullRepo{}, fmt.Errorf("failed creating new request: parse \"https://api.github.com/repos/%s/%s\\r\": net/url: invalid control character in URL", org, name)
	}
	repo, err := t.fc.GetRepo(org, name)
	if len(t.repoNodeID) != 0 {
		repo.NodeID = t.repoNodeID
	}
	return repo, err
}

func (t *testClient) CreateComment(org, repo string, number int, comment string) error {
	return t.fc.CreateComment(org, repo, number, comment)
}

func (t *testClient) IsMember(org, user string) (bool, error) {
	return t.fc.IsMember(org, user)
}

func (t *testClient) MutateWithGitHubAppsSupport(ctx context.Context, m interface{}, input githubv4.Input, vars map[string]interface{}, org string) error {
	mr := `{"data": { "transferIssue": { "issue": { "url": "https://kubernetes.io/fake" } } } }`

	gqlc := githubv4.NewClient(&http.Client{
		Transport: testRoundTripper{rt: func(r *http.Request) (*http.Response, error) {
			defer r.Body.Close()
			body, err := ioutil.ReadAll(r.Body)
			if err != nil {
				return nil, err
			}
			s := string(body)
			if !(strings.Contains(s, "fakeRepoNodeID") && strings.Contains(s, "fakeIssueNodeID")) {
				return nil, fmt.Errorf("unexpected request body: %s", s)
			}
			return &http.Response{StatusCode: http.StatusOK, Body: ioutil.NopCloser(bytes.NewBufferString(mr))}, nil
		}},
	})

	return gqlc.Mutate(ctx, m, input, vars)
}

func Test_transferIssue(t *testing.T) {
	c := &testClient{}
	issue, err := transferIssue(c, "k8s", "fakeRepoNodeID", "fakeIssueNodeID")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got := issue.TransferIssue.Issue.URL.String(); got != "https://kubernetes.io/fake" {
		t.Fatalf("unexpected url: %v", got)
	}
}
<commit_msg>Clean up prow transfer issue test<commit_after>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package transferissue

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"
	"unicode"

	"github.com/shurcooL/githubv4"
	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/prow/github"
	"k8s.io/test-infra/prow/github/fakegithub"
)

const issuerNum = 1

func Test_handleTransfer(t *testing.T) {
	ts := []struct {
		name         string
		event        github.GenericCommentEvent
		expectError  bool
		errorMessage string
		comment      string
		fcFunc       func(client *fakegithub.FakeClient)
		tcFunc       func(client *testClient)
	}{
		{
			name:  "is a pr",
			event: github.GenericCommentEvent{IsPR: true},
		},
		{
			name:  "is not comment added",
			event: github.GenericCommentEvent{Action: github.GenericCommentActionDeleted},
		},
		{
			name: "multiple matches",
			event: github.GenericCommentEvent{
				Action: github.GenericCommentActionCreated,
				Body: `/transfer-issue kubectl
/transfer test-infra`,
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "org"}, Name: "repo"},
				User:    github.User{Login: "user"},
			},
			comment: "single destination",
		},
		{
			name: "no destination",
			event: github.GenericCommentEvent{
				Action:  github.GenericCommentActionCreated,
				Body:    "/transfer",
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "org"}, Name: "repo"},
				User:    github.User{Login: "user"},
			},
			comment: "single destination",
		},
		{
			name: "dest repo does not exist",
			event: github.GenericCommentEvent{
				Action:  github.GenericCommentActionCreated,
				Body:    "/transfer-issue fake",
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:    github.User{Login: "user"},
			},
			comment: "does not exist",
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.GetRepoError = errors.New("stub")
			},
		},
		{
			name: "not collaborator",
			event: github.GenericCommentEvent{
				Action:  github.GenericCommentActionCreated,
				Body:    "/transfer-issue test-infra",
				HTMLURL: fmt.Sprintf("https://github.com/kubernetes/fake/issues/%d", issuerNum),
				Number:  issuerNum,
				Repo:    github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:    github.User{Login: "user"},
			},
			comment: "must be an org member",
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.OrgMembers["kubernetes"] = []string{}
			},
		},
		{
			name: "trims whitespace from user input",
			event: github.GenericCommentEvent{
				Action: github.GenericCommentActionCreated,
				Body:   "/transfer-issue test-infra\r",
				Number: issuerNum,
				Repo:   github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:   github.User{Login: "user"},
				NodeID: "fakeIssueNodeID",
			},
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.OrgMembers["kubernetes"] = []string{"user"}
			},
			tcFunc: func(c *testClient) {
				c.repoNodeID = "fakeRepoNodeID"
			},
		},
		{
			name: "happy path",
			event: github.GenericCommentEvent{
				Action: github.GenericCommentActionCreated,
				Body: `This belongs elsewhere
/transfer-issue test-infra
Thanks!`,
				Number: issuerNum,
				Repo:   github.Repo{Owner: github.User{Login: "kubernetes"}, Name: "kubectl"},
				User:   github.User{Login: "user"},
				NodeID: "fakeIssueNodeID",
			},
			fcFunc: func(fc *fakegithub.FakeClient) {
				fc.OrgMembers["kubernetes"] = []string{"user"}
			},
			tcFunc: func(c *testClient) {
				c.repoNodeID = "fakeRepoNodeID"
			},
		},
	}

	for _, tc := range ts {
		t.Run(tc.name, func(t *testing.T) {
			fc := fakegithub.NewFakeClient()
			c := &testClient{fc: fc}
			if tc.tcFunc != nil {
				tc.tcFunc(c)
			}
			if tc.fcFunc != nil {
				tc.fcFunc(fc)
			}
			log := logrus.WithField("plugin", pluginName)
			err := handleTransfer(c, log, tc.event)
			if err != nil {
				if !tc.expectError {
					t.Fatalf("unexpected error: %v", err)
				}
				if m := err.Error(); !strings.Contains(m, tc.errorMessage) {
					t.Fatalf("expected error to contain: %s got: %v", tc.errorMessage, m)
				}
			}
			if err == nil && tc.expectError {
				t.Fatalf("expected error but did not produce")
			}
			if len(tc.comment) != 0 {
				if cm, ok := fc.IssueComments[tc.event.Number]; ok {
					if !strings.Contains(cm[0].Body, tc.comment) {
						t.Errorf("expected comment to contain: %s got: %s", tc.comment, cm[0].Body)
					}
				} else {
					t.Errorf("expected comment to contain: %s but no comment", tc.comment)
				}
			}
			if len(tc.comment) == 0 && len(fc.IssueComments[issuerNum]) != 0 {
				t.Errorf("unexpected comment: %v", fc.IssueComments[issuerNum])
			}
		})
	}
}

type testRoundTripper struct {
	rt func(*http.Request) (*http.Response, error)
}

func (rt testRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	return rt.rt(r)
}

type testClient struct {
	fc         *fakegithub.FakeClient
	repoNodeID string
}

func (t *testClient) GetRepo(org, name string) (github.FullRepo, error) {
	r := []rune(name)
	if lastChar := r[len(r)-1]; unicode.IsSpace(lastChar) {
		return github.FullRepo{}, fmt.Errorf("failed creating new request: parse \"https://api.github.com/repos/%s/%s\\r\": net/url: invalid control character in URL", org, name)
	}
	repo, err := t.fc.GetRepo(org, name)
	if len(t.repoNodeID) != 0 {
		repo.NodeID = t.repoNodeID
	}
	return repo, err
}

func (t *testClient) CreateComment(org, repo string, number int, comment string) error {
	return t.fc.CreateComment(org, repo, number, comment)
}

func (t *testClient) IsMember(org, user string) (bool, error) {
	return t.fc.IsMember(org, user)
}

func (t *testClient) MutateWithGitHubAppsSupport(ctx context.Context, m interface{}, input githubv4.Input, vars map[string]interface{}, org string) error {
	mr := `{"data": { "transferIssue": { "issue": { "url": "https://kubernetes.io/fake" } } } }`

	gqlc := githubv4.NewClient(&http.Client{
		Transport: testRoundTripper{rt: func(r *http.Request) (*http.Response, error) {
			defer r.Body.Close()
			body, err := ioutil.ReadAll(r.Body)
			if err != nil {
				return nil, err
			}
			s := string(body)
			if !(strings.Contains(s, "fakeRepoNodeID") && strings.Contains(s, "fakeIssueNodeID")) {
				return nil, fmt.Errorf("unexpected request body: %s", s)
			}
			return &http.Response{StatusCode: http.StatusOK, Body: ioutil.NopCloser(bytes.NewBufferString(mr))}, nil
		}},
	})

	return gqlc.Mutate(ctx, m, input, vars)
}

func Test_transferIssue(t *testing.T) {
	c := &testClient{}
	issue, err := transferIssue(c, "k8s", "fakeRepoNodeID", "fakeIssueNodeID")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got := issue.TransferIssue.Issue.URL.String(); got != "https://kubernetes.io/fake" {
		t.Fatalf("unexpected url: %v", got)
	}
}
<|endoftext|>


<commit_before>package redis_test
<commit_msg>simples tests<commit_after>package redis
import (
	"testing"
)

func TestRedisSentinelPing(t *testing.T) {
	_, err := GetSetinelClient()
	if err != nil {
		t.Errorf("Erro no teste de conexão. %s", err.Error())
	}
}

func TestRedisPing(t *testing.T) {
	resp, err := PingSentinel()
	if err != nil {
		t.Errorf("Não deveria gerar erro. %s", err.Error())
	}

	if resp != "Resp(Str PONG)"{
		t.Errorf("ACE %s", resp)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.

package query

import (
	"net/url"
	"testing"
)

var (
	baseAddr     = "https://www.subdomain.tracker.com:80/"
	testInfoHash = "01234567890123456789"
	testPeerID   = "-TEST01-6wfG2wk6wWLc"

	ValidAnnounceArguments = []url.Values{
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "numwant": {"28"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "event": {"stopped"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "event": {"started"}, "numwant": {"13"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "no_peer_id": {"1"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}, "key": {"peerKey"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}, "key": {"peerKey"}, "trackerid": {"trackerId"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {"%3Ckey%3A+0x90%3E"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}, "key": {"peerKey"}, "trackerid": {"trackerId"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {"%3Ckey%3A+0x90%3E"}, "compact": {"1"}},
	}

	InvalidQueries = []string{
		baseAddr + "announce/?" + "info_hash=%0%a",
	}
)

func mapArrayEqual(boxed map[string][]string, unboxed map[string]string) bool {
	if len(boxed) != len(unboxed) {
		return false
	}

	for mapKey, mapVal := range boxed {
		// Always expect box to hold only one element
		if len(mapVal) != 1 || mapVal[0] != unboxed[mapKey] {
			return false
		}
	}

	return true
}

func TestValidQueries(t *testing.T) {
	for parseIndex, parseVal := range ValidAnnounceArguments {
		parsedQueryObj, err := New(baseAddr + "announce/?" + parseVal.Encode())
		if err != nil {
			t.Error(err)
		}

		if !mapArrayEqual(parseVal, parsedQueryObj.Params) {
			t.Errorf("Incorrect parse at item %d.\n Expected=%v\n Recieved=%v\n", parseIndex, parseVal, parsedQueryObj.Params)
		}
	}
}

func TestInvalidQueries(t *testing.T) {
	for parseIndex, parseStr := range InvalidQueries {
		parsedQueryObj, err := New(parseStr)
		if err == nil {
			t.Error("Should have produced error", parseIndex)
		}

		if parsedQueryObj != nil {
			t.Error("Should be nil after error", parsedQueryObj, parseIndex)
		}
	}
}

func BenchmarkParseQuery(b *testing.B) {
	for bCount := 0; bCount < b.N; bCount++ {
		for parseIndex, parseStr := range ValidAnnounceArguments {
			parsedQueryObj, err := New(baseAddr + "announce/?" + parseStr.Encode())
			if err != nil {
				b.Error(err, parseIndex)
				b.Log(parsedQueryObj)
			}
		}
	}
}

func BenchmarkURLParseQuery(b *testing.B) {
	for bCount := 0; bCount < b.N; bCount++ {
		for parseIndex, parseStr := range ValidAnnounceArguments {
			parsedQueryObj, err := url.ParseQuery(baseAddr + "announce/?" + parseStr.Encode())
			if err != nil {
				b.Error(err, parseIndex)
				b.Log(parsedQueryObj)
			}
		}
	}
}
<commit_msg>Add failing test that reproduces #63<commit_after>// Copyright 2015 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.

package query

import (
	"net/url"
	"testing"
)

var (
	baseAddr     = "https://www.subdomain.tracker.com:80/"
	testInfoHash = "01234567890123456789"
	testPeerID   = "-TEST01-6wfG2wk6wWLc"

	ValidAnnounceArguments = []url.Values{
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "numwant": {"28"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "event": {"stopped"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "ip": {"192.168.0.1"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "event": {"started"}, "numwant": {"13"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "no_peer_id": {"1"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}, "key": {"peerKey"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {testPeerID}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}, "key": {"peerKey"}, "trackerid": {"trackerId"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {"%3Ckey%3A+0x90%3E"}, "port": {"6881"}, "downloaded": {"1234"}, "left": {"4321"}, "compact": {"0"}, "no_peer_id": {"1"}, "key": {"peerKey"}, "trackerid": {"trackerId"}},
		url.Values{"info_hash": {testInfoHash}, "peer_id": {"%3Ckey%3A+0x90%3E"}, "compact": {"1"}},
		url.Values{"info_hash": {""}, "peer_id": {""}, "compact": {""}},
	}

	InvalidQueries = []string{
		baseAddr + "announce/?" + "info_hash=%0%a",
	}
)

func mapArrayEqual(boxed map[string][]string, unboxed map[string]string) bool {
	if len(boxed) != len(unboxed) {
		return false
	}

	for mapKey, mapVal := range boxed {
		// Always expect box to hold only one element
		if len(mapVal) != 1 || mapVal[0] != unboxed[mapKey] {
			return false
		}
	}

	return true
}

func TestValidQueries(t *testing.T) {
	for parseIndex, parseVal := range ValidAnnounceArguments {
		parsedQueryObj, err := New(baseAddr + "announce/?" + parseVal.Encode())
		if err != nil {
			t.Error(err)
		}

		if !mapArrayEqual(parseVal, parsedQueryObj.Params) {
			t.Errorf("Incorrect parse at item %d.\n Expected=%v\n Recieved=%v\n", parseIndex, parseVal, parsedQueryObj.Params)
		}
	}
}

func TestInvalidQueries(t *testing.T) {
	for parseIndex, parseStr := range InvalidQueries {
		parsedQueryObj, err := New(parseStr)
		if err == nil {
			t.Error("Should have produced error", parseIndex)
		}

		if parsedQueryObj != nil {
			t.Error("Should be nil after error", parsedQueryObj, parseIndex)
		}
	}
}

func BenchmarkParseQuery(b *testing.B) {
	for bCount := 0; bCount < b.N; bCount++ {
		for parseIndex, parseStr := range ValidAnnounceArguments {
			parsedQueryObj, err := New(baseAddr + "announce/?" + parseStr.Encode())
			if err != nil {
				b.Error(err, parseIndex)
				b.Log(parsedQueryObj)
			}
		}
	}
}

func BenchmarkURLParseQuery(b *testing.B) {
	for bCount := 0; bCount < b.N; bCount++ {
		for parseIndex, parseStr := range ValidAnnounceArguments {
			parsedQueryObj, err := url.ParseQuery(baseAddr + "announce/?" + parseStr.Encode())
			if err != nil {
				b.Error(err, parseIndex)
				b.Log(parsedQueryObj)
			}
		}
	}
}
<|endoftext|>


<commit_before>package imagestore

import (
	"bufio"
	"io"
	"os"
)

type LocalImageStore struct {
	storeRoot      string
	namePathMapper *NamePathMapper
}

func NewLocalImageStore(root string, mapper *NamePathMapper) *LocalImageStore {
	return &LocalImageStore{
		storeRoot:      root,
		namePathMapper: mapper,
	}
}

func (this *LocalImageStore) Exists(obj *StoreObject) (bool, error) {
	if _, err := os.Stat(this.toPath(obj)); os.IsNotExist(err) {
		return false, err
	}

	return true, nil
}

func (this *LocalImageStore) Save(src string, obj *StoreObject) (*StoreObject, error) {
	// open input file
	fi, err := os.Open(src)
	if err != nil {
		return nil, err
	}

	defer fi.Close()

	// make a read buffer
	r := bufio.NewReader(fi)

	// open output file
	this.createParent(obj)
	fo, err := os.Create(this.toPath(obj))
	if err != nil {
		return nil, err
	}

	defer fo.Close()

	// make a write buffer
	w := bufio.NewWriter(fo)

	// make a buffer to keep chunks that are read
	buf := make([]byte, 1024)
	for {
		// read a chunk
		n, err := r.Read(buf)
		if err != nil && err != io.EOF {
			return nil, err
		}

		if n == 0 {
			break
		}

		// write a chunk
		if _, err := w.Write(buf[:n]); err != nil {
			return nil, err
		}
	}

	if err = w.Flush(); err != nil {
		return nil, err
	}

	obj.Url = this.toPath(obj)
	return obj, nil
}

func (this *LocalImageStore) createParent(obj *StoreObject) {
	path := this.storeRoot + "/" + obj.Type

	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.Mkdir(path, 0777)
	}
}

func (this *LocalImageStore) toPath(obj *StoreObject) string {
	return this.storeRoot + "/" + obj.Type + "/" + obj.Name
}
<commit_msg>fix local store<commit_after>package imagestore

import (
	"bufio"
	"io"
	"os"
	"path"
)

type LocalImageStore struct {
	storeRoot      string
	namePathMapper *NamePathMapper
}

func NewLocalImageStore(root string, mapper *NamePathMapper) *LocalImageStore {
	return &LocalImageStore{
		storeRoot:      root,
		namePathMapper: mapper,
	}
}

func (this *LocalImageStore) Exists(obj *StoreObject) (bool, error) {
	if _, err := os.Stat(this.toPath(obj)); os.IsNotExist(err) {
		return false, err
	}

	return true, nil
}

func (this *LocalImageStore) Save(src string, obj *StoreObject) (*StoreObject, error) {
	// open input file
	fi, err := os.Open(src)
	if err != nil {
		return nil, err
	}

	defer fi.Close()

	// make a read buffer
	r := bufio.NewReader(fi)

	// open output file
	this.createParent(obj)
	fo, err := os.Create(this.toPath(obj))
	if err != nil {
		return nil, err
	}

	defer fo.Close()

	// make a write buffer
	w := bufio.NewWriter(fo)

	// make a buffer to keep chunks that are read
	buf := make([]byte, 1024)
	for {
		// read a chunk
		n, err := r.Read(buf)
		if err != nil && err != io.EOF {
			return nil, err
		}

		if n == 0 {
			break
		}

		// write a chunk
		if _, err := w.Write(buf[:n]); err != nil {
			return nil, err
		}
	}

	if err = w.Flush(); err != nil {
		return nil, err
	}

	obj.Url = this.toPath(obj)
	return obj, nil
}

func (this *LocalImageStore) createParent(obj *StoreObject) {
	path := path.Dir(this.toPath(obj))

	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.MkdirAll(path, 0777)
	}
}

func (this *LocalImageStore) toPath(obj *StoreObject) string {
	return this.storeRoot + "/" + this.namePathMapper.mapToPath(obj)
}
<|endoftext|>