<commit_before>package appstore

import "encoding/json"

type numericString string

func (n *numericString) UnmarshalJSON(b []byte) error {
	var number json.Number
	if err := json.Unmarshal(b, &number); err != nil {
		return err
	}
	*n = numericString(number.String())
	return nil
}

type (
	// https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
	// The IAPRequest type has the request parameter
	IAPRequest struct {
		ReceiptData string `json:"receipt-data"`
		// Only used for receipts that contain auto-renewable subscriptions.
		Password string `json:"password,omitempty"`
		// Only used for iOS7 style app receipts that contain auto-renewable or non-renewing subscriptions.
		// If value is true, response includes only the latest renewal transaction for any subscriptions.
		ExcludeOldTransactions bool `json:"exclude-old-transactions"`
	}

	// The ReceiptCreationDate type indicates the date when the app receipt was created.
	ReceiptCreationDate struct {
		CreationDate    string `json:"receipt_creation_date"`
		CreationDateMS  string `json:"receipt_creation_date_ms"`
		CreationDatePST string `json:"receipt_creation_date_pst"`
	}

	// The RequestDate type indicates the date and time that the request was sent
	RequestDate struct {
		RequestDate    string `json:"request_date"`
		RequestDateMS  string `json:"request_date_ms"`
		RequestDatePST string `json:"request_date_pst"`
	}

	// The PurchaseDate type indicates the date and time that the item was purchased
	PurchaseDate struct {
		PurchaseDate    string `json:"purchase_date"`
		PurchaseDateMS  string `json:"purchase_date_ms"`
		PurchaseDatePST string `json:"purchase_date_pst"`
	}

	// The OriginalPurchaseDate type indicates the beginning of the subscription period
	OriginalPurchaseDate struct {
		OriginalPurchaseDate    string `json:"original_purchase_date"`
		OriginalPurchaseDateMS  string `json:"original_purchase_date_ms"`
		OriginalPurchaseDatePST string `json:"original_purchase_date_pst"`
	}

	// The ExpiresDate type indicates the expiration date for the subscription
	ExpiresDate struct {
		ExpiresDate    string `json:"expires_date"`
		ExpiresDateMS  string `json:"expires_date_ms"`
		ExpiresDatePST string `json:"expires_date_pst"`
	}

	// The CancellationDate type indicates the time and date of the cancellation by Apple customer support
	CancellationDate struct {
		CancellationDate    string `json:"cancellation_date"`
		CancellationDateMS  string `json:"cancellation_date_ms"`
		CancellationDatePST string `json:"cancellation_date_pst"`
	}

	// The InApp type has the receipt attributes
	InApp struct {
		Quantity              string `json:"quantity"`
		ProductID             string `json:"product_id"`
		TransactionID         string `json:"transaction_id"`
		OriginalTransactionID string `json:"original_transaction_id"`
		WebOrderLineItemID    string `json:"web_order_line_item_id"`

		IsTrialPeriod string `json:"is_trial_period"`
		ExpiresDate

		PurchaseDate
		OriginalPurchaseDate

		CancellationDate
		CancellationReason string `json:"cancellation_reason"`
	}

	// The Receipt type has whole data of receipt
	Receipt struct {
		ReceiptType                string        `json:"receipt_type"`
		AdamID                     int64         `json:"adam_id"`
		AppItemID                  numericString `json:"app_item_id"`
		BundleID                   string        `json:"bundle_id"`
		ApplicationVersion         string        `json:"application_version"`
		DownloadID                 int64         `json:"download_id"`
		VersionExternalIdentifier  numericString `json:"version_external_identifier"`
		OriginalApplicationVersion string        `json:"original_application_version"`
		InApp                      []InApp       `json:"in_app"`
		ReceiptCreationDate
		RequestDate
		OriginalPurchaseDate
	}

	// A pending renewal may refer to a renewal that is scheduled in the future or a renewal that failed in the past for some reason.
	PendingRenewalInfo struct {
		SubscriptionExpirationIntent   string `json:"expiration_intent"`
		SubscriptionAutoRenewProductID string `json:"auto_renew_product_id"`
		SubscriptionRetryFlag          string `json:"is_in_billing_retry_period"`
		SubscriptionAutoRenewStatus    string `json:"auto_renew_status"`
		SubscriptionPriceConsentStatus string `json:"price_consent_status"`
		ProductID                      string `json:"product_id"`
	}

	// The IAPResponse type has the response properties
	// We defined each field by the current IAP response, but some fields are not mentioned
	// in the following Apple's document;
	// https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html
	// If you get other types or fields from the IAP response, you should use the struct you defined.
	IAPResponse struct {
		Status             int                  `json:"status"`
		Environment        string               `json:"environment"`
		Receipt            Receipt              `json:"receipt"`
		LatestReceiptInfo  []InApp              `json:"latest_receipt_info"`
		LatestReceipt      string               `json:"latest_receipt"`
		PendingRenewalInfo []PendingRenewalInfo `json:"pending_renewal_info"`
		IsRetryable        bool                 `json:"is-retryable"`
	}

	// The HttpStatusResponse struct contains the status code returned by the store
	// Used as a workaround to detect when to hit the production appstore or sandbox appstore regardless of receipt type
	StatusResponse struct {
		Status int `json:"status"`
	}
)
<commit_msg>Add "omitempty" to some keys which need not to be returned<commit_after>package appstore

import "encoding/json"

type numericString string

func (n *numericString) UnmarshalJSON(b []byte) error {
	var number json.Number
	if err := json.Unmarshal(b, &number); err != nil {
		return err
	}
	*n = numericString(number.String())
	return nil
}

type (
	// https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
	// The IAPRequest type has the request parameter
	IAPRequest struct {
		ReceiptData string `json:"receipt-data"`
		// Only used for receipts that contain auto-renewable subscriptions.
		Password string `json:"password,omitempty"`
		// Only used for iOS7 style app receipts that contain auto-renewable or non-renewing subscriptions.
		// If value is true, response includes only the latest renewal transaction for any subscriptions.
		ExcludeOldTransactions bool `json:"exclude-old-transactions"`
	}

	// The ReceiptCreationDate type indicates the date when the app receipt was created.
	ReceiptCreationDate struct {
		CreationDate    string `json:"receipt_creation_date"`
		CreationDateMS  string `json:"receipt_creation_date_ms"`
		CreationDatePST string `json:"receipt_creation_date_pst"`
	}

	// The RequestDate type indicates the date and time that the request was sent
	RequestDate struct {
		RequestDate    string `json:"request_date"`
		RequestDateMS  string `json:"request_date_ms"`
		RequestDatePST string `json:"request_date_pst"`
	}

	// The PurchaseDate type indicates the date and time that the item was purchased
	PurchaseDate struct {
		PurchaseDate    string `json:"purchase_date"`
		PurchaseDateMS  string `json:"purchase_date_ms"`
		PurchaseDatePST string `json:"purchase_date_pst"`
	}

	// The OriginalPurchaseDate type indicates the beginning of the subscription period
	OriginalPurchaseDate struct {
		OriginalPurchaseDate    string `json:"original_purchase_date"`
		OriginalPurchaseDateMS  string `json:"original_purchase_date_ms"`
		OriginalPurchaseDatePST string `json:"original_purchase_date_pst"`
	}

	// The ExpiresDate type indicates the expiration date for the subscription
	ExpiresDate struct {
		ExpiresDate    string `json:"expires_date,omitempty"`
		ExpiresDateMS  string `json:"expires_date_ms,omitempty"`
		ExpiresDatePST string `json:"expires_date_pst,omitempty"`
	}

	// The CancellationDate type indicates the time and date of the cancellation by Apple customer support
	CancellationDate struct {
		CancellationDate    string `json:"cancellation_date,omitempty"`
		CancellationDateMS  string `json:"cancellation_date_ms,omitempty"`
		CancellationDatePST string `json:"cancellation_date_pst,omitempty"`
	}

	// The InApp type has the receipt attributes
	InApp struct {
		Quantity              string `json:"quantity"`
		ProductID             string `json:"product_id"`
		TransactionID         string `json:"transaction_id"`
		OriginalTransactionID string `json:"original_transaction_id"`
		WebOrderLineItemID    string `json:"web_order_line_item_id,omitempty"`

		IsTrialPeriod string `json:"is_trial_period"`
		ExpiresDate

		PurchaseDate
		OriginalPurchaseDate

		CancellationDate
		CancellationReason string `json:"cancellation_reason,omitempty"`
	}

	// The Receipt type has whole data of receipt
	Receipt struct {
		ReceiptType                string        `json:"receipt_type"`
		AdamID                     int64         `json:"adam_id"`
		AppItemID                  numericString `json:"app_item_id"`
		BundleID                   string        `json:"bundle_id"`
		ApplicationVersion         string        `json:"application_version"`
		DownloadID                 int64         `json:"download_id"`
		VersionExternalIdentifier  numericString `json:"version_external_identifier"`
		OriginalApplicationVersion string        `json:"original_application_version"`
		InApp                      []InApp       `json:"in_app"`
		ReceiptCreationDate
		RequestDate
		OriginalPurchaseDate
	}

	// A pending renewal may refer to a renewal that is scheduled in the future or a renewal that failed in the past for some reason.
	PendingRenewalInfo struct {
		SubscriptionExpirationIntent   string `json:"expiration_intent"`
		SubscriptionAutoRenewProductID string `json:"auto_renew_product_id"`
		SubscriptionRetryFlag          string `json:"is_in_billing_retry_period"`
		SubscriptionAutoRenewStatus    string `json:"auto_renew_status"`
		SubscriptionPriceConsentStatus string `json:"price_consent_status"`
		ProductID                      string `json:"product_id"`
	}

	// The IAPResponse type has the response properties
	// We defined each field by the current IAP response, but some fields are not mentioned
	// in the following Apple's document;
	// https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html
	// If you get other types or fields from the IAP response, you should use the struct you defined.
	IAPResponse struct {
		Status             int                  `json:"status"`
		Environment        string               `json:"environment"`
		Receipt            Receipt              `json:"receipt"`
		LatestReceiptInfo  []InApp              `json:"latest_receipt_info,omitempty"`
		LatestReceipt      string               `json:"latest_receipt,omitempty"`
		PendingRenewalInfo []PendingRenewalInfo `json:"pending_renewal_info,omitempty"`
		IsRetryable        bool                 `json:"is-retryable,omitempty"`
	}

	// The HttpStatusResponse struct contains the status code returned by the store
	// Used as a workaround to detect when to hit the production appstore or sandbox appstore regardless of receipt type
	StatusResponse struct {
		Status int `json:"status"`
	}
)
<|endoftext|>


<commit_before>package main

import (
	"github.com/dirkolbrich/gobacktest/pkg/backtest"
	"github.com/dirkolbrich/gobacktest/pkg/data"
)

func main() {
	// define symbols
	var symbols = []string{"TEST.DE"}

	// initiate new backtester and load symbols
	test := backtest.New()
	test.SetSymbols(symbols)

	// create data provider and load data into the backtest
	data := &data.BarEventFromCSVFileData{FileDir: "../testdata/test/"}
	data.Load(symbols)
	test.SetData(data)

	// set portfolio with initial cash and default size and risk manager
	portfolio := &backtest.Portfolio{}
	portfolio.SetInitialCash(10000)

	sizeManager := &backtest.Size{DefaultSize: 100, DefaultValue: 1000}
	portfolio.SetSizeManager(sizeManager)

	riskManager := &backtest.Risk{}
	portfolio.SetRiskManager(riskManager)

	test.SetPortfolio(portfolio)

	// create strategy provider and load into the backtest
	strategy := &backtest.BuyAndHoldStrategy{}
	test.SetStrategy(strategy)

	// create execution provider and load into the backtest
	exchange := &backtest.Exchange{Symbol: "TEST", ExchangeFee: 1.00}
	test.SetExchange(exchange)

	// choose a statisitc and load into the backtest
	statistic := &backtest.Statistic{}
	test.SetStatistic(statistic)

	// run the backtest
	test.Run()

}
<commit_msg>fix importet datahandler<commit_after>package main

import (
	"github.com/dirkolbrich/gobacktest/pkg/backtest"
	"github.com/dirkolbrich/gobacktest/pkg/data"
)

func main() {
	// define symbols
	var symbols = []string{"TEST.DE"}

	// initiate new backtester and load symbols
	test := backtest.New()
	test.SetSymbols(symbols)

	// create data provider and load data into the backtest
	data := &data.BarEventFromCSVFile{FileDir: "../testdata/test/"}
	data.Load(symbols)
	test.SetData(data)

	// set portfolio with initial cash and default size and risk manager
	portfolio := &backtest.Portfolio{}
	portfolio.SetInitialCash(10000)

	sizeManager := &backtest.Size{DefaultSize: 100, DefaultValue: 1000}
	portfolio.SetSizeManager(sizeManager)

	riskManager := &backtest.Risk{}
	portfolio.SetRiskManager(riskManager)

	test.SetPortfolio(portfolio)

	// create strategy provider and load into the backtest
	strategy := &backtest.BuyAndHoldStrategy{}
	test.SetStrategy(strategy)

	// create execution provider and load into the backtest
	exchange := &backtest.Exchange{Symbol: "TEST", ExchangeFee: 1.00}
	test.SetExchange(exchange)

	// choose a statisitc and load into the backtest
	statistic := &backtest.Statistic{}
	test.SetStatistic(statistic)

	// run the backtest
	test.Run()

}
<|endoftext|>


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

package quota

import (
	"log"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"
)

// map[minute][address] = current quota
type quotaMap struct {
	sync.RWMutex
	data     map[int64]map[uint32]uint64
	limit    uint64
	duration int64
}

func (q *quotaMap) Add(ip uint32, size uint64) bool {
	currentMinute := time.Now().Unix() / q.duration
	expiredQuotas := (time.Now().Unix() / q.duration) - 5
	for time := range q.data {
		if time < expiredQuotas {
			delete(q.data, time)
		}
	}
	log.Println(currentMinute)
	if _, ok := q.data[currentMinute]; !ok {
		q.data[currentMinute] = make(map[uint32]uint64)
	}
	currentData, _ := q.data[currentMinute][ip]
	q.data[currentMinute][ip] = currentData + size
	return false
}

// HttpQuotaHandler
type httpQuotaHandler struct {
	handler http.Handler
	quotas  *quotaMap
}

// ServeHTTP is an http.Handler ServeHTTP method
func (h *httpQuotaHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ipString := strings.Split(req.RemoteAddr, ":")[0]
	ipSplit := strings.Split(ipString, ".")
	q0, _ := strconv.Atoi(ipSplit[0])
	q1, _ := strconv.Atoi(ipSplit[1])
	q2, _ := strconv.Atoi(ipSplit[2])
	q3, _ := strconv.Atoi(ipSplit[3])
	longIP := uint32(q0)<<24 + uint32(q1)<<16 + uint32(q2)<<8 + uint32(q3)
	h.quotas.Add(longIP, uint64(req.ContentLength))
	log.Println("quota called")
	log.Println(h.quotas)
	h.handler.ServeHTTP(w, req)
}

// Handler implements quotas
func Handler(h http.Handler, limit int64) http.Handler {
	return &httpQuotaHandler{
		handler: h,
		quotas: &quotaMap{
			data:     make(map[int64]map[uint32]uint64),
			limit:    uint64(limit),
			duration: int64(60),
		},
	}
}
<commit_msg>Use standard functions to achieve byteorder converstion<commit_after>/*
 * Minimalist Object Storage, (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package quota

import (
	"encoding/binary"
	"log"
	"net"
	"net/http"
	"sync"
	"time"
)

// map[minute][address] = current quota
type quotaMap struct {
	sync.RWMutex
	data     map[int64]map[uint32]uint64
	limit    uint64
	duration int64
}

func (q *quotaMap) Add(ip uint32, size uint64) bool {
	currentMinute := time.Now().Unix() / q.duration
	expiredQuotas := (time.Now().Unix() / q.duration) - 5
	for time := range q.data {
		if time < expiredQuotas {
			delete(q.data, time)
		}
	}
	log.Println(currentMinute)
	if _, ok := q.data[currentMinute]; !ok {
		q.data[currentMinute] = make(map[uint32]uint64)
	}
	currentData, _ := q.data[currentMinute][ip]
	q.data[currentMinute][ip] = currentData + size
	return false
}

// HttpQuotaHandler
type httpQuotaHandler struct {
	handler http.Handler
	quotas  *quotaMap
}

type longIP struct {
	net.IP
}

// []byte to uint32 representation
func (p longIP) IptoUint32() uint32 {
	ip := p.To4()
	if ip == nil {
		return 0
	}
	// golang net.IP is BigEndian
	return binary.BigEndian.Uint32([]byte(ip))
}

// any uint32 back to IP representation
func uint32ToIP(ip uint32) net.IP {
	addr := net.IP{0, 0, 0, 0}
	binary.BigEndian.PutUint32(addr, ip)
	return addr
}

// ServeHTTP is an http.Handler ServeHTTP method
func (h *httpQuotaHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	host, _, _ := net.SplitHostPort(req.RemoteAddr)
	log.Println(host)

	longIP := longIP{net.ParseIP(host)}
	h.quotas.Add(longIP.IptoUint32(), uint64(req.ContentLength))

	log.Println("quota called")
	log.Println(h.quotas)
	h.handler.ServeHTTP(w, req)
}

// Handler implements quotas
func Handler(h http.Handler, limit int64) http.Handler {
	return &httpQuotaHandler{
		handler: h,
		quotas: &quotaMap{
			data:     make(map[int64]map[uint32]uint64),
			limit:    uint64(limit),
			duration: int64(60),
		},
	}
}
<|endoftext|>


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

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"sync/atomic"

	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/httpstream"
	"k8s.io/apimachinery/pkg/util/httpstream/spdy"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/proxy"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/transport"
	apiregistrationapi "k8s.io/kube-aggregator/pkg/apis/apiregistration"
)

// proxyHandler provides a http.Handler which will proxy traffic to locations
// specified by items implementing Redirector.
type proxyHandler struct {
	// localDelegate is used to satisfy local APIServices
	localDelegate http.Handler

	// proxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
	// this to confirm the proxy's identity
	proxyClientCert []byte
	proxyClientKey  []byte
	proxyTransport  *http.Transport

	// Endpoints based routing to map from cluster IP to routable IP
	serviceResolver ServiceResolver

	handlingInfo atomic.Value
}

type proxyHandlingInfo struct {
	// local indicates that this APIService is locally satisfied
	local bool

	// restConfig holds the information for building a roundtripper
	restConfig *restclient.Config
	// transportBuildingError is an error produced while building the transport.  If this
	// is non-nil, it will be reported to clients.
	transportBuildingError error
	// proxyRoundTripper is the re-useable portion of the transport.  It does not vary with any request.
	proxyRoundTripper http.RoundTripper
	// serviceName is the name of the service this handler proxies to
	serviceName string
	// namespace is the namespace the service lives in
	serviceNamespace string
	// serviceAvailable indicates this APIService is available or not
	serviceAvailable bool
}

func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	value := r.handlingInfo.Load()
	if value == nil {
		r.localDelegate.ServeHTTP(w, req)
		return
	}
	handlingInfo := value.(proxyHandlingInfo)
	if handlingInfo.local {
		if r.localDelegate == nil {
			http.Error(w, "", http.StatusNotFound)
			return
		}
		r.localDelegate.ServeHTTP(w, req)
		return
	}

	if !handlingInfo.serviceAvailable {
		http.Error(w, "service unavailable", http.StatusServiceUnavailable)
		return
	}

	if handlingInfo.transportBuildingError != nil {
		http.Error(w, handlingInfo.transportBuildingError.Error(), http.StatusInternalServerError)
		return
	}

	user, ok := genericapirequest.UserFrom(req.Context())
	if !ok {
		http.Error(w, "missing user", http.StatusInternalServerError)
		return
	}

	// write a new location based on the existing request pointed at the target service
	location := &url.URL{}
	location.Scheme = "https"
	rloc, err := r.serviceResolver.ResolveEndpoint(handlingInfo.serviceNamespace, handlingInfo.serviceName)
	if err != nil {
		glog.Errorf("error resolving %s/%s: %v", handlingInfo.serviceNamespace, handlingInfo.serviceName, err)
		http.Error(w, "service unavailable", http.StatusServiceUnavailable)
		return
	}
	location.Host = rloc.Host
	location.Path = req.URL.Path
	location.RawQuery = req.URL.Query().Encode()

	// WithContext creates a shallow clone of the request with the new context.
	newReq := req.WithContext(context.Background())
	newReq.Header = utilnet.CloneHeader(req.Header)
	newReq.URL = location

	if handlingInfo.proxyRoundTripper == nil {
		http.Error(w, "", http.StatusNotFound)
		return
	}

	// we need to wrap the roundtripper in another roundtripper which will apply the front proxy headers
	proxyRoundTripper, upgrade, err := maybeWrapForConnectionUpgrades(handlingInfo.restConfig, handlingInfo.proxyRoundTripper, req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), user.GetGroups(), user.GetExtra(), proxyRoundTripper)

	// if we are upgrading, then the upgrade path tries to use this request with the TLS config we provide, but it does
	// NOT use the roundtripper.  Its a direct call that bypasses the round tripper.  This means that we have to
	// attach the "correct" user headers to the request ahead of time.  After the initial upgrade, we'll be back
	// at the roundtripper flow, so we only have to muck with this request, but we do have to do it.
	if upgrade {
		transport.SetAuthProxyHeaders(newReq, user.GetName(), user.GetGroups(), user.GetExtra())
	}

	handler := proxy.NewUpgradeAwareHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w})
	handler.ServeHTTP(w, newReq)
}

// maybeWrapForConnectionUpgrades wraps the roundtripper for upgrades.  The bool indicates if it was wrapped
func maybeWrapForConnectionUpgrades(restConfig *restclient.Config, rt http.RoundTripper, req *http.Request) (http.RoundTripper, bool, error) {
	if !httpstream.IsUpgradeRequest(req) {
		return rt, false, nil
	}

	tlsConfig, err := restclient.TLSConfigFor(restConfig)
	if err != nil {
		return nil, true, err
	}
	followRedirects := utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StreamingProxyRedirects)
	upgradeRoundTripper := spdy.NewRoundTripper(tlsConfig, followRedirects)
	wrappedRT, err := restclient.HTTPWrappersForConfig(restConfig, upgradeRoundTripper)
	if err != nil {
		return nil, true, err
	}

	return wrappedRT, true, nil
}

// responder implements rest.Responder for assisting a connector in writing objects or errors.
type responder struct {
	w http.ResponseWriter
}

// TODO this should properly handle content type negotiation
// if the caller asked for protobuf and you write JSON bad things happen.
func (r *responder) Object(statusCode int, obj runtime.Object) {
	responsewriters.WriteRawJSON(statusCode, obj, r.w)
}

func (r *responder) Error(_ http.ResponseWriter, _ *http.Request, err error) {
	http.Error(r.w, err.Error(), http.StatusInternalServerError)
}

// these methods provide locked access to fields

func (r *proxyHandler) updateAPIService(apiService *apiregistrationapi.APIService) {
	if apiService.Spec.Service == nil {
		r.handlingInfo.Store(proxyHandlingInfo{local: true})
		return
	}

	newInfo := proxyHandlingInfo{
		restConfig: &restclient.Config{
			TLSClientConfig: restclient.TLSClientConfig{
				Insecure:   apiService.Spec.InsecureSkipTLSVerify,
				ServerName: apiService.Spec.Service.Name + "." + apiService.Spec.Service.Namespace + ".svc",
				CertData:   r.proxyClientCert,
				KeyData:    r.proxyClientKey,
				CAData:     apiService.Spec.CABundle,
			},
		},
		serviceName:      apiService.Spec.Service.Name,
		serviceNamespace: apiService.Spec.Service.Namespace,
		serviceAvailable: apiregistrationapi.IsAPIServiceConditionTrue(apiService, apiregistrationapi.Available),
	}
	newInfo.proxyRoundTripper, newInfo.transportBuildingError = restclient.TransportFor(newInfo.restConfig)
	if newInfo.transportBuildingError == nil && r.proxyTransport != nil && r.proxyTransport.Dial != nil {
		switch transport := newInfo.proxyRoundTripper.(type) {
		case *http.Transport:
			transport.Dial = r.proxyTransport.Dial
		default:
			newInfo.transportBuildingError = fmt.Errorf("unable to set dialer for %s/%s as rest transport is of type %T", apiService.Spec.Service.Namespace, apiService.Spec.Service.Name, newInfo.proxyRoundTripper)
			glog.Warning(newInfo.transportBuildingError.Error())
		}
	}
	r.handlingInfo.Store(newInfo)
}
<commit_msg>Use Dial with context<commit_after>/*
Copyright 2016 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 apiserver

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"sync/atomic"

	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/httpstream"
	"k8s.io/apimachinery/pkg/util/httpstream/spdy"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/proxy"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/transport"
	apiregistrationapi "k8s.io/kube-aggregator/pkg/apis/apiregistration"
)

// proxyHandler provides a http.Handler which will proxy traffic to locations
// specified by items implementing Redirector.
type proxyHandler struct {
	// localDelegate is used to satisfy local APIServices
	localDelegate http.Handler

	// proxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
	// this to confirm the proxy's identity
	proxyClientCert []byte
	proxyClientKey  []byte
	proxyTransport  *http.Transport

	// Endpoints based routing to map from cluster IP to routable IP
	serviceResolver ServiceResolver

	handlingInfo atomic.Value
}

type proxyHandlingInfo struct {
	// local indicates that this APIService is locally satisfied
	local bool

	// restConfig holds the information for building a roundtripper
	restConfig *restclient.Config
	// transportBuildingError is an error produced while building the transport.  If this
	// is non-nil, it will be reported to clients.
	transportBuildingError error
	// proxyRoundTripper is the re-useable portion of the transport.  It does not vary with any request.
	proxyRoundTripper http.RoundTripper
	// serviceName is the name of the service this handler proxies to
	serviceName string
	// namespace is the namespace the service lives in
	serviceNamespace string
	// serviceAvailable indicates this APIService is available or not
	serviceAvailable bool
}

func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	value := r.handlingInfo.Load()
	if value == nil {
		r.localDelegate.ServeHTTP(w, req)
		return
	}
	handlingInfo := value.(proxyHandlingInfo)
	if handlingInfo.local {
		if r.localDelegate == nil {
			http.Error(w, "", http.StatusNotFound)
			return
		}
		r.localDelegate.ServeHTTP(w, req)
		return
	}

	if !handlingInfo.serviceAvailable {
		http.Error(w, "service unavailable", http.StatusServiceUnavailable)
		return
	}

	if handlingInfo.transportBuildingError != nil {
		http.Error(w, handlingInfo.transportBuildingError.Error(), http.StatusInternalServerError)
		return
	}

	user, ok := genericapirequest.UserFrom(req.Context())
	if !ok {
		http.Error(w, "missing user", http.StatusInternalServerError)
		return
	}

	// write a new location based on the existing request pointed at the target service
	location := &url.URL{}
	location.Scheme = "https"
	rloc, err := r.serviceResolver.ResolveEndpoint(handlingInfo.serviceNamespace, handlingInfo.serviceName)
	if err != nil {
		glog.Errorf("error resolving %s/%s: %v", handlingInfo.serviceNamespace, handlingInfo.serviceName, err)
		http.Error(w, "service unavailable", http.StatusServiceUnavailable)
		return
	}
	location.Host = rloc.Host
	location.Path = req.URL.Path
	location.RawQuery = req.URL.Query().Encode()

	// WithContext creates a shallow clone of the request with the new context.
	newReq := req.WithContext(context.Background())
	newReq.Header = utilnet.CloneHeader(req.Header)
	newReq.URL = location

	if handlingInfo.proxyRoundTripper == nil {
		http.Error(w, "", http.StatusNotFound)
		return
	}

	// we need to wrap the roundtripper in another roundtripper which will apply the front proxy headers
	proxyRoundTripper, upgrade, err := maybeWrapForConnectionUpgrades(handlingInfo.restConfig, handlingInfo.proxyRoundTripper, req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), user.GetGroups(), user.GetExtra(), proxyRoundTripper)

	// if we are upgrading, then the upgrade path tries to use this request with the TLS config we provide, but it does
	// NOT use the roundtripper.  Its a direct call that bypasses the round tripper.  This means that we have to
	// attach the "correct" user headers to the request ahead of time.  After the initial upgrade, we'll be back
	// at the roundtripper flow, so we only have to muck with this request, but we do have to do it.
	if upgrade {
		transport.SetAuthProxyHeaders(newReq, user.GetName(), user.GetGroups(), user.GetExtra())
	}

	handler := proxy.NewUpgradeAwareHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w})
	handler.ServeHTTP(w, newReq)
}

// maybeWrapForConnectionUpgrades wraps the roundtripper for upgrades.  The bool indicates if it was wrapped
func maybeWrapForConnectionUpgrades(restConfig *restclient.Config, rt http.RoundTripper, req *http.Request) (http.RoundTripper, bool, error) {
	if !httpstream.IsUpgradeRequest(req) {
		return rt, false, nil
	}

	tlsConfig, err := restclient.TLSConfigFor(restConfig)
	if err != nil {
		return nil, true, err
	}
	followRedirects := utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StreamingProxyRedirects)
	upgradeRoundTripper := spdy.NewRoundTripper(tlsConfig, followRedirects)
	wrappedRT, err := restclient.HTTPWrappersForConfig(restConfig, upgradeRoundTripper)
	if err != nil {
		return nil, true, err
	}

	return wrappedRT, true, nil
}

// responder implements rest.Responder for assisting a connector in writing objects or errors.
type responder struct {
	w http.ResponseWriter
}

// TODO this should properly handle content type negotiation
// if the caller asked for protobuf and you write JSON bad things happen.
func (r *responder) Object(statusCode int, obj runtime.Object) {
	responsewriters.WriteRawJSON(statusCode, obj, r.w)
}

func (r *responder) Error(_ http.ResponseWriter, _ *http.Request, err error) {
	http.Error(r.w, err.Error(), http.StatusInternalServerError)
}

// these methods provide locked access to fields

func (r *proxyHandler) updateAPIService(apiService *apiregistrationapi.APIService) {
	if apiService.Spec.Service == nil {
		r.handlingInfo.Store(proxyHandlingInfo{local: true})
		return
	}

	newInfo := proxyHandlingInfo{
		restConfig: &restclient.Config{
			TLSClientConfig: restclient.TLSClientConfig{
				Insecure:   apiService.Spec.InsecureSkipTLSVerify,
				ServerName: apiService.Spec.Service.Name + "." + apiService.Spec.Service.Namespace + ".svc",
				CertData:   r.proxyClientCert,
				KeyData:    r.proxyClientKey,
				CAData:     apiService.Spec.CABundle,
			},
		},
		serviceName:      apiService.Spec.Service.Name,
		serviceNamespace: apiService.Spec.Service.Namespace,
		serviceAvailable: apiregistrationapi.IsAPIServiceConditionTrue(apiService, apiregistrationapi.Available),
	}
	newInfo.proxyRoundTripper, newInfo.transportBuildingError = restclient.TransportFor(newInfo.restConfig)
	if newInfo.transportBuildingError == nil && r.proxyTransport != nil && r.proxyTransport.DialContext != nil {
		switch transport := newInfo.proxyRoundTripper.(type) {
		case *http.Transport:
			transport.DialContext = r.proxyTransport.DialContext
		default:
			newInfo.transportBuildingError = fmt.Errorf("unable to set dialer for %s/%s as rest transport is of type %T", apiService.Spec.Service.Namespace, apiService.Spec.Service.Name, newInfo.proxyRoundTripper)
			glog.Warning(newInfo.transportBuildingError.Error())
		}
	}
	r.handlingInfo.Store(newInfo)
}
<|endoftext|>


<commit_before>package v1

import (
	"k8s.io/kubernetes/pkg/conversion"
	"k8s.io/kubernetes/pkg/runtime"

	oapi "github.com/openshift/origin/pkg/api"
	newer "github.com/openshift/origin/pkg/build/api"
	buildutil "github.com/openshift/origin/pkg/build/util"
	imageapi "github.com/openshift/origin/pkg/image/api"
)

func Convert_v1_BuildConfig_To_api_BuildConfig(in *BuildConfig, out *newer.BuildConfig, s conversion.Scope) error {
	if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
		return err
	}

	newTriggers := []newer.BuildTriggerPolicy{}
	// strip off any default imagechange triggers where the buildconfig's
	// "from" is not an ImageStreamTag, because those triggers
	// will never be invoked.
	imageRef := buildutil.GetInputReference(out.Spec.Strategy)
	hasIST := imageRef != nil && imageRef.Kind == "ImageStreamTag"
	for _, trigger := range out.Spec.Triggers {
		if trigger.Type != newer.ImageChangeBuildTriggerType {
			newTriggers = append(newTriggers, trigger)
			continue
		}
		if (trigger.ImageChange == nil || trigger.ImageChange.From == nil) && !hasIST {
			continue
		}
		newTriggers = append(newTriggers, trigger)
	}
	out.Spec.Triggers = newTriggers
	return nil
}

func Convert_v1_SourceBuildStrategy_To_api_SourceBuildStrategy(in *SourceBuildStrategy, out *newer.SourceBuildStrategy, s conversion.Scope) error {
	if err := autoConvert_v1_SourceBuildStrategy_To_api_SourceBuildStrategy(in, out, s); err != nil {
		return err
	}
	switch in.From.Kind {
	case "ImageStream":
		out.From.Kind = "ImageStreamTag"
		out.From.Name = imageapi.JoinImageStreamTag(in.From.Name, "")
	}
	return nil
}

func Convert_v1_DockerBuildStrategy_To_api_DockerBuildStrategy(in *DockerBuildStrategy, out *newer.DockerBuildStrategy, s conversion.Scope) error {
	if err := autoConvert_v1_DockerBuildStrategy_To_api_DockerBuildStrategy(in, out, s); err != nil {
		return err
	}
	if in.From != nil {
		switch in.From.Kind {
		case "ImageStream":
			out.From.Kind = "ImageStreamTag"
			out.From.Name = imageapi.JoinImageStreamTag(in.From.Name, "")
		}
	}
	return nil
}

func Convert_v1_CustomBuildStrategy_To_api_CustomBuildStrategy(in *CustomBuildStrategy, out *newer.CustomBuildStrategy, s conversion.Scope) error {
	if err := autoConvert_v1_CustomBuildStrategy_To_api_CustomBuildStrategy(in, out, s); err != nil {
		return err
	}
	switch in.From.Kind {
	case "ImageStream":
		out.From.Kind = "ImageStreamTag"
		out.From.Name = imageapi.JoinImageStreamTag(in.From.Name, "")
	}
	return nil
}

func Convert_v1_BuildOutput_To_api_BuildOutput(in *BuildOutput, out *newer.BuildOutput, s conversion.Scope) error {
	if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
		return err
	}
	if in.To != nil && (in.To.Kind == "ImageStream" || len(in.To.Kind) == 0) {
		out.To.Kind = "ImageStreamTag"
		out.To.Name = imageapi.JoinImageStreamTag(in.To.Name, "")
	}
	return nil
}

func Convert_v1_BuildTriggerPolicy_To_api_BuildTriggerPolicy(in *BuildTriggerPolicy, out *newer.BuildTriggerPolicy, s conversion.Scope) error {
	if err := autoConvert_v1_BuildTriggerPolicy_To_api_BuildTriggerPolicy(in, out, s); err != nil {
		return err
	}

	switch in.Type {
	case ImageChangeBuildTriggerTypeDeprecated:
		out.Type = newer.ImageChangeBuildTriggerType
	case GenericWebHookBuildTriggerTypeDeprecated:
		out.Type = newer.GenericWebHookBuildTriggerType
	case GitHubWebHookBuildTriggerTypeDeprecated:
		out.Type = newer.GitHubWebHookBuildTriggerType
	}
	return nil
}

func Convert_api_SourceRevision_To_v1_SourceRevision(in *newer.SourceRevision, out *SourceRevision, s conversion.Scope) error {
	if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
		return err
	}
	out.Type = BuildSourceGit
	return nil
}

func Convert_api_BuildSource_To_v1_BuildSource(in *newer.BuildSource, out *BuildSource, s conversion.Scope) error {
	if err := autoConvert_api_BuildSource_To_v1_BuildSource(in, out, s); err != nil {
		return err
	}
	switch {
	// it is legal for a buildsource to have both a git+dockerfile source, but in v1 that was represented
	// as type git.
	case in.Git != nil:
		out.Type = BuildSourceGit
	// it is legal for a buildsource to have both a binary+dockerfile source, but in v1 that was represented
	// as type binary.
	case in.Binary != nil:
		out.Type = BuildSourceBinary
	case in.Dockerfile != nil:
		out.Type = BuildSourceDockerfile
	case len(in.Images) > 0:
		out.Type = BuildSourceImage
	default:
		out.Type = BuildSourceNone
	}
	return nil
}

func Convert_api_BuildStrategy_To_v1_BuildStrategy(in *newer.BuildStrategy, out *BuildStrategy, s conversion.Scope) error {
	if err := autoConvert_api_BuildStrategy_To_v1_BuildStrategy(in, out, s); err != nil {
		return err
	}
	switch {
	case in.SourceStrategy != nil:
		out.Type = SourceBuildStrategyType
	case in.DockerStrategy != nil:
		out.Type = DockerBuildStrategyType
	case in.CustomStrategy != nil:
		out.Type = CustomBuildStrategyType
	case in.JenkinsPipelineStrategy != nil:
		out.Type = JenkinsPipelineBuildStrategyType
	default:
		out.Type = ""
	}
	return nil
}

func addConversionFuncs(scheme *runtime.Scheme) {
	err := scheme.AddDefaultingFuncs(
		func(config *BuildConfigSpec) {
			if len(config.RunPolicy) == 0 {
				config.RunPolicy = BuildRunPolicySerial
			}
		},
		func(source *BuildSource) {
			if (source != nil) && (source.Type == BuildSourceBinary) && (source.Binary == nil) {
				source.Binary = &BinaryBuildSource{}
			}
		},
		func(strategy *BuildStrategy) {
			if (strategy != nil) && (strategy.Type == DockerBuildStrategyType) && (strategy.DockerStrategy == nil) {
				strategy.DockerStrategy = &DockerBuildStrategy{}
			}
		},
		func(obj *SourceBuildStrategy) {
			if len(obj.From.Kind) == 0 {
				obj.From.Kind = "ImageStreamTag"
			}
		},
		func(obj *DockerBuildStrategy) {
			if obj.From != nil && len(obj.From.Kind) == 0 {
				obj.From.Kind = "ImageStreamTag"
			}
		},
		func(obj *CustomBuildStrategy) {
			if len(obj.From.Kind) == 0 {
				obj.From.Kind = "ImageStreamTag"
			}
		},
		func(obj *BuildTriggerPolicy) {
			if obj.Type == ImageChangeBuildTriggerType && obj.ImageChange == nil {
				obj.ImageChange = &ImageChangeTrigger{}
			}
		},
	)
	if err != nil {
		panic(err)
	}

	scheme.AddConversionFuncs(
		Convert_v1_BuildConfig_To_api_BuildConfig,
		Convert_api_BuildConfig_To_v1_BuildConfig,
		Convert_v1_SourceBuildStrategy_To_api_SourceBuildStrategy,
		Convert_api_SourceBuildStrategy_To_v1_SourceBuildStrategy,
		Convert_v1_DockerBuildStrategy_To_api_DockerBuildStrategy,
		Convert_api_DockerBuildStrategy_To_v1_DockerBuildStrategy,
		Convert_v1_CustomBuildStrategy_To_api_CustomBuildStrategy,
		Convert_api_CustomBuildStrategy_To_v1_CustomBuildStrategy,
		Convert_v1_BuildOutput_To_api_BuildOutput,
		Convert_api_BuildOutput_To_v1_BuildOutput,
		Convert_v1_BuildTriggerPolicy_To_api_BuildTriggerPolicy,
		Convert_api_BuildTriggerPolicy_To_v1_BuildTriggerPolicy,
		Convert_v1_SourceRevision_To_api_SourceRevision,
		Convert_api_SourceRevision_To_v1_SourceRevision,
		Convert_v1_BuildSource_To_api_BuildSource,
		Convert_api_BuildSource_To_v1_BuildSource,
		Convert_v1_BuildStrategy_To_api_BuildStrategy,
		Convert_api_BuildStrategy_To_v1_BuildStrategy,
	)

	if err := scheme.AddFieldLabelConversionFunc("v1", "Build",
		oapi.GetFieldLabelConversionFunc(newer.BuildToSelectableFields(&newer.Build{}), map[string]string{"name": "metadata.name"}),
	); err != nil {
		panic(err)
	}

	if err := scheme.AddFieldLabelConversionFunc("v1", "BuildConfig",
		oapi.GetFieldLabelConversionFunc(newer.BuildConfigToSelectableFields(&newer.BuildConfig{}), map[string]string{"name": "metadata.name"}),
	); err != nil {
		panic(err)
	}
}
<commit_msg>migrate use of s.DefaultConvert to autoConvert<commit_after>package v1

import (
	"k8s.io/kubernetes/pkg/conversion"
	"k8s.io/kubernetes/pkg/runtime"

	oapi "github.com/openshift/origin/pkg/api"
	newer "github.com/openshift/origin/pkg/build/api"
	buildutil "github.com/openshift/origin/pkg/build/util"
	imageapi "github.com/openshift/origin/pkg/image/api"
)

func Convert_v1_BuildConfig_To_api_BuildConfig(in *BuildConfig, out *newer.BuildConfig, s conversion.Scope) error {
	if err := autoConvert_v1_BuildConfig_To_api_BuildConfig(in, out, s); err != nil {
		return err
	}

	newTriggers := []newer.BuildTriggerPolicy{}
	// strip off any default imagechange triggers where the buildconfig's
	// "from" is not an ImageStreamTag, because those triggers
	// will never be invoked.
	imageRef := buildutil.GetInputReference(out.Spec.Strategy)
	hasIST := imageRef != nil && imageRef.Kind == "ImageStreamTag"
	for _, trigger := range out.Spec.Triggers {
		if trigger.Type != newer.ImageChangeBuildTriggerType {
			newTriggers = append(newTriggers, trigger)
			continue
		}
		if (trigger.ImageChange == nil || trigger.ImageChange.From == nil) && !hasIST {
			continue
		}
		newTriggers = append(newTriggers, trigger)
	}
	out.Spec.Triggers = newTriggers
	return nil
}

func Convert_v1_SourceBuildStrategy_To_api_SourceBuildStrategy(in *SourceBuildStrategy, out *newer.SourceBuildStrategy, s conversion.Scope) error {
	if err := autoConvert_v1_SourceBuildStrategy_To_api_SourceBuildStrategy(in, out, s); err != nil {
		return err
	}
	switch in.From.Kind {
	case "ImageStream":
		out.From.Kind = "ImageStreamTag"
		out.From.Name = imageapi.JoinImageStreamTag(in.From.Name, "")
	}
	return nil
}

func Convert_v1_DockerBuildStrategy_To_api_DockerBuildStrategy(in *DockerBuildStrategy, out *newer.DockerBuildStrategy, s conversion.Scope) error {
	if err := autoConvert_v1_DockerBuildStrategy_To_api_DockerBuildStrategy(in, out, s); err != nil {
		return err
	}
	if in.From != nil {
		switch in.From.Kind {
		case "ImageStream":
			out.From.Kind = "ImageStreamTag"
			out.From.Name = imageapi.JoinImageStreamTag(in.From.Name, "")
		}
	}
	return nil
}

func Convert_v1_CustomBuildStrategy_To_api_CustomBuildStrategy(in *CustomBuildStrategy, out *newer.CustomBuildStrategy, s conversion.Scope) error {
	if err := autoConvert_v1_CustomBuildStrategy_To_api_CustomBuildStrategy(in, out, s); err != nil {
		return err
	}
	switch in.From.Kind {
	case "ImageStream":
		out.From.Kind = "ImageStreamTag"
		out.From.Name = imageapi.JoinImageStreamTag(in.From.Name, "")
	}
	return nil
}

func Convert_v1_BuildOutput_To_api_BuildOutput(in *BuildOutput, out *newer.BuildOutput, s conversion.Scope) error {
	if err := autoConvert_v1_BuildOutput_To_api_BuildOutput(in, out, s); err != nil {
		return err
	}
	if in.To != nil && (in.To.Kind == "ImageStream" || len(in.To.Kind) == 0) {
		out.To.Kind = "ImageStreamTag"
		out.To.Name = imageapi.JoinImageStreamTag(in.To.Name, "")
	}
	return nil
}

func Convert_v1_BuildTriggerPolicy_To_api_BuildTriggerPolicy(in *BuildTriggerPolicy, out *newer.BuildTriggerPolicy, s conversion.Scope) error {
	if err := autoConvert_v1_BuildTriggerPolicy_To_api_BuildTriggerPolicy(in, out, s); err != nil {
		return err
	}

	switch in.Type {
	case ImageChangeBuildTriggerTypeDeprecated:
		out.Type = newer.ImageChangeBuildTriggerType
	case GenericWebHookBuildTriggerTypeDeprecated:
		out.Type = newer.GenericWebHookBuildTriggerType
	case GitHubWebHookBuildTriggerTypeDeprecated:
		out.Type = newer.GitHubWebHookBuildTriggerType
	}
	return nil
}

func Convert_api_SourceRevision_To_v1_SourceRevision(in *newer.SourceRevision, out *SourceRevision, s conversion.Scope) error {
	if err := autoConvert_api_SourceRevision_To_v1_SourceRevision(in, out, s); err != nil {
		return err
	}
	out.Type = BuildSourceGit
	return nil
}

func Convert_api_BuildSource_To_v1_BuildSource(in *newer.BuildSource, out *BuildSource, s conversion.Scope) error {
	if err := autoConvert_api_BuildSource_To_v1_BuildSource(in, out, s); err != nil {
		return err
	}
	switch {
	// it is legal for a buildsource to have both a git+dockerfile source, but in v1 that was represented
	// as type git.
	case in.Git != nil:
		out.Type = BuildSourceGit
	// it is legal for a buildsource to have both a binary+dockerfile source, but in v1 that was represented
	// as type binary.
	case in.Binary != nil:
		out.Type = BuildSourceBinary
	case in.Dockerfile != nil:
		out.Type = BuildSourceDockerfile
	case len(in.Images) > 0:
		out.Type = BuildSourceImage
	default:
		out.Type = BuildSourceNone
	}
	return nil
}

func Convert_api_BuildStrategy_To_v1_BuildStrategy(in *newer.BuildStrategy, out *BuildStrategy, s conversion.Scope) error {
	if err := autoConvert_api_BuildStrategy_To_v1_BuildStrategy(in, out, s); err != nil {
		return err
	}
	switch {
	case in.SourceStrategy != nil:
		out.Type = SourceBuildStrategyType
	case in.DockerStrategy != nil:
		out.Type = DockerBuildStrategyType
	case in.CustomStrategy != nil:
		out.Type = CustomBuildStrategyType
	case in.JenkinsPipelineStrategy != nil:
		out.Type = JenkinsPipelineBuildStrategyType
	default:
		out.Type = ""
	}
	return nil
}

func addConversionFuncs(scheme *runtime.Scheme) {
	err := scheme.AddDefaultingFuncs(
		func(config *BuildConfigSpec) {
			if len(config.RunPolicy) == 0 {
				config.RunPolicy = BuildRunPolicySerial
			}
		},
		func(source *BuildSource) {
			if (source != nil) && (source.Type == BuildSourceBinary) && (source.Binary == nil) {
				source.Binary = &BinaryBuildSource{}
			}
		},
		func(strategy *BuildStrategy) {
			if (strategy != nil) && (strategy.Type == DockerBuildStrategyType) && (strategy.DockerStrategy == nil) {
				strategy.DockerStrategy = &DockerBuildStrategy{}
			}
		},
		func(obj *SourceBuildStrategy) {
			if len(obj.From.Kind) == 0 {
				obj.From.Kind = "ImageStreamTag"
			}
		},
		func(obj *DockerBuildStrategy) {
			if obj.From != nil && len(obj.From.Kind) == 0 {
				obj.From.Kind = "ImageStreamTag"
			}
		},
		func(obj *CustomBuildStrategy) {
			if len(obj.From.Kind) == 0 {
				obj.From.Kind = "ImageStreamTag"
			}
		},
		func(obj *BuildTriggerPolicy) {
			if obj.Type == ImageChangeBuildTriggerType && obj.ImageChange == nil {
				obj.ImageChange = &ImageChangeTrigger{}
			}
		},
	)
	if err != nil {
		panic(err)
	}

	scheme.AddConversionFuncs(
		Convert_v1_BuildConfig_To_api_BuildConfig,
		Convert_api_BuildConfig_To_v1_BuildConfig,
		Convert_v1_SourceBuildStrategy_To_api_SourceBuildStrategy,
		Convert_api_SourceBuildStrategy_To_v1_SourceBuildStrategy,
		Convert_v1_DockerBuildStrategy_To_api_DockerBuildStrategy,
		Convert_api_DockerBuildStrategy_To_v1_DockerBuildStrategy,
		Convert_v1_CustomBuildStrategy_To_api_CustomBuildStrategy,
		Convert_api_CustomBuildStrategy_To_v1_CustomBuildStrategy,
		Convert_v1_BuildOutput_To_api_BuildOutput,
		Convert_api_BuildOutput_To_v1_BuildOutput,
		Convert_v1_BuildTriggerPolicy_To_api_BuildTriggerPolicy,
		Convert_api_BuildTriggerPolicy_To_v1_BuildTriggerPolicy,
		Convert_v1_SourceRevision_To_api_SourceRevision,
		Convert_api_SourceRevision_To_v1_SourceRevision,
		Convert_v1_BuildSource_To_api_BuildSource,
		Convert_api_BuildSource_To_v1_BuildSource,
		Convert_v1_BuildStrategy_To_api_BuildStrategy,
		Convert_api_BuildStrategy_To_v1_BuildStrategy,
	)

	if err := scheme.AddFieldLabelConversionFunc("v1", "Build",
		oapi.GetFieldLabelConversionFunc(newer.BuildToSelectableFields(&newer.Build{}), map[string]string{"name": "metadata.name"}),
	); err != nil {
		panic(err)
	}

	if err := scheme.AddFieldLabelConversionFunc("v1", "BuildConfig",
		oapi.GetFieldLabelConversionFunc(newer.BuildConfigToSelectableFields(&newer.BuildConfig{}), map[string]string{"name": "metadata.name"}),
	); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 featureflag implements simple feature-flagging.
// Feature flags can become an anti-pattern if abused.
// We should try to use them for two use-cases:
// * `Preview` feature flags enable a piece of functionality we haven't yet fully baked.  The user needs to 'opt-in'.
//   We expect these flags to be removed at some time.  Normally these will default to false.
// * Escape-hatch feature flags turn off a default that we consider risky (e.g. pre-creating DNS records).
//   This lets us ship a behaviour, and if we encounter unusual circumstances in the field, we can
//   allow the user to turn the behaviour off.  Normally these will default to true.
package featureflag

import (
	"os"
	"strings"
	"sync"
)

func Bool(b bool) *bool {
	return &b
}

// DNSPreCreate controls whether we pre-create DNS records.
var DNSPreCreate = New("DNSPreCreate", Bool(true))

var flags = make(map[string]*FeatureFlag)
var flagsMutex sync.Mutex

var initFlags sync.Once

type FeatureFlag struct {
	Key          string
	enabled      *bool
	defaultValue *bool
}

func (f *FeatureFlag) Enabled() bool {
	if f.enabled != nil {
		return *f.enabled
	}
	if f.defaultValue != nil {
		return *f.defaultValue
	}
	return false
}

func ParseFlags(f string) {
	f = strings.TrimSpace(f)
	for _, s := range strings.Split(f, ",") {
		s = strings.TrimSpace(s)
		if s == "" {
			continue
		}
		enabled := true
		var ff *FeatureFlag
		if s[0] == '+' || s[0] == '-' {
			ff = New(s[1:], nil)
			if s[0] == '-' {
				enabled = false
			}
		} else {
			ff = New(s, nil)
		}
		ff.enabled = &enabled
	}
}

func readEnv() {
	ParseFlags(os.Getenv("KOPS_FEATURE_FLAGS"))
}

func New(key string, defaultValue *bool) *FeatureFlag {
	initFlags.Do(readEnv)

	flagsMutex.Lock()
	defer flagsMutex.Unlock()

	f := flags[key]
	if f == nil {
		f = &FeatureFlag{
			Key: key,
		}
		flags[key] = f
	}

	if f.defaultValue == nil {
		f.defaultValue = defaultValue
	}

	return f
}
<commit_msg>Fix feature flags potential deadlock<commit_after>/*
Copyright 2016 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 featureflag implements simple feature-flagging.
// Feature flags can become an anti-pattern if abused.
// We should try to use them for two use-cases:
// * `Preview` feature flags enable a piece of functionality we haven't yet fully baked.  The user needs to 'opt-in'.
//   We expect these flags to be removed at some time.  Normally these will default to false.
// * Escape-hatch feature flags turn off a default that we consider risky (e.g. pre-creating DNS records).
//   This lets us ship a behaviour, and if we encounter unusual circumstances in the field, we can
//   allow the user to turn the behaviour off.  Normally these will default to true.
package featureflag

import (
	"github.com/golang/glog"
	"os"
	"strings"
	"sync"
)

func Bool(b bool) *bool {
	return &b
}

// DNSPreCreate controls whether we pre-create DNS records.
var DNSPreCreate = New("DNSPreCreate", Bool(true))

var flags = make(map[string]*FeatureFlag)
var flagsMutex sync.Mutex

func init() {
	ParseFlags(os.Getenv("KOPS_FEATURE_FLAGS"))
}

type FeatureFlag struct {
	Key          string
	enabled      *bool
	defaultValue *bool
}

func (f *FeatureFlag) Enabled() bool {
	if f.enabled != nil {
		return *f.enabled
	}
	if f.defaultValue != nil {
		return *f.defaultValue
	}
	return false
}

func ParseFlags(f string) {
	f = strings.TrimSpace(f)
	for _, s := range strings.Split(f, ",") {
		s = strings.TrimSpace(s)
		if s == "" {
			continue
		}
		enabled := true
		var ff *FeatureFlag
		if s[0] == '+' || s[0] == '-' {
			ff = New(s[1:], nil)
			if s[0] == '-' {
				enabled = false
			}
		} else {
			ff = New(s, nil)
		}
		glog.Infof("FeatureFlag %q=%v", ff.Key, enabled)
		ff.enabled = &enabled
	}
}

func New(key string, defaultValue *bool) *FeatureFlag {
	flagsMutex.Lock()
	defer flagsMutex.Unlock()

	f := flags[key]
	if f == nil {
		f = &FeatureFlag{
			Key: key,
		}
		flags[key] = f
	}

	if f.defaultValue == nil {
		f.defaultValue = defaultValue
	}

	return f
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"testing"
	"time"

	"github.com/globalsign/mgo/bson"

	"github.com/mgodatagen/rg"
)

var (
	source               = rg.NewRandSource()
	sd, _                = time.Parse(time.RFC3339, "2010-01-01T00:00:00-00:00")
	ed, _                = time.Parse(time.RFC3339, "2016-01-01T00:00:00-00:00")
	eg                   = rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 8}
	constArr             = []interface{}{"2012-10-10", "2012-12-12", "2014-01-01", "2016-05-05"}
	stringGenerator      = &rg.StringGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 0}, MinLength: 2, MaxLength: 5}
	int32Generator       = &rg.Int32Generator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 2}, Min: 0, Max: 100}
	int64Generator       = &rg.Int64Generator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 3}, Min: 0, Max: 100}
	float64Generator     = &rg.Float64Generator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 4}, Mean: 0, StdDev: 50}
	dateGenerator        = &rg.DateGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 7}, StartDate: sd.Unix(), Delta: (ed.Unix() - sd.Unix())}
	boolGenerator        = &rg.BoolGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 1}}
	binaryGenerator      = &rg.BinaryDataGenerator{EmptyGenerator: eg, MinLength: 30, MaxLength: 30}
	positionGenerator    = &rg.PositionGenerator{EmptyGenerator: eg}
	arrayGeneratorString = &rg.ArrayGenerator{EmptyGenerator: eg, Size: 10, Generator: stringGenerator}
	arrayGeneratorBool   = &rg.ArrayGenerator{EmptyGenerator: eg, Size: 10, Generator: boolGenerator}
	autoIncrGenerator    = &rg.AutoIncrementGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 3}, Counter: 0}
	objectIDGenerator    = &rg.ObjectIDGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 5}}
	refGenerator         = &rg.RefGenerator{EmptyGenerator: eg, ID: 1, Generator: objectIDGenerator}
	fromArrayGenerator   = &rg.FromArrayGenerator{EmptyGenerator: eg, Array: constArr, Size: int32(len(constArr)), Index: -1}
)

type expected struct {
	ID          bson.ObjectId `json:"_id"`
	Date        time.Time     `json:"date"`
	Data        []byte        `json:"data"`
	Dt          string        `json:"dt"`
	Name        string        `json:"name"`
	Count32     int32         `json:"count32"`
	Count64     int64         `json:"count64"`
	Float       float64       `json:"float"`
	Verified    bool          `json:"verified"`
	FirstArray  [3]string     `json:"firstArray"`
	Nb          int           `json:"nb"`
	Pos         [2]float32    `json:"pos"`
	Cs          cst           `json:"cst"`
	FirstObject obj           `json:"firstObject"`
}
type obj struct {
	K  int    `json:"k"`
	Nm string `json:"nm"`
}
type cst struct {
	Key1 string `json:"key1"`
	Key2 int32  `json:"key2"`
}

func getGeneratorFromFile(shortNames bool) (rg.Generator, error) {
	file, err := ioutil.ReadFile("samples/config.json")
	if err != nil {
		return nil, fmt.Errorf("File error: %v", err.Error())
	}
	var collectionList []Collection
	err = json.Unmarshal(file, &collectionList)
	if err != nil {
		return nil, fmt.Errorf("JSON error: %v", err.Error())
	}
	generators, err := rg.NewGeneratorsFromMap(collectionList[0].Content, shortNames)
	if err != nil {
		return nil, fmt.Errorf("Config error: %v", err.Error())
	}
	eg := rg.EmptyGenerator{K: "", NullPercentage: 0, T: 6}
	return &rg.ArrayGenerator{EmptyGenerator: eg,
		Size:      1000,
		Generator: &rg.ObjectGenerator{EmptyGenerator: eg, Generators: generators}}, nil
}

func BenchmarkExists(b *testing.B) {
	for n := 0; n < b.N; n++ {
		stringGenerator.Exists(source)
	}
}

func BenchmarkRandomString(b *testing.B) {
	for n := 0; n < b.N; n++ {
		stringGenerator.Value(source)
	}
}

func BenchmarkRandomInt32(b *testing.B) {
	for n := 0; n < b.N; n++ {
		int32Generator.Value(source)
	}
}
func BenchmarkRandomInt64(b *testing.B) {
	for n := 0; n < b.N; n++ {
		int64Generator.Value(source)
	}
}
func BenchmarkRandomFloat64(b *testing.B) {
	for n := 0; n < b.N; n++ {
		float64Generator.Value(source)
	}
}
func BenchmarkRandomDate(b *testing.B) {
	for n := 0; n < b.N; n++ {
		dateGenerator.Value(source)
	}
}

func BenchmarkRandomBool(b *testing.B) {
	for n := 0; n < b.N; n++ {
		boolGenerator.Value(source)
	}
}

func BenchmarkRandomBinaryData(b *testing.B) {
	for n := 0; n < b.N; n++ {
		binaryGenerator.Value(source)
	}
}
func BenchmarkRandomPosition(b *testing.B) {
	for n := 0; n < b.N; n++ {
		positionGenerator.Value(source)
	}
}
func BenchmarkRandomArray(b *testing.B) {
	var list []string
	for n := 0; n < b.N; n++ {
		list = arrayGeneratorString.Value(source).([]string)
	}
	_ = list[0]

}
func BenchmarkRandomArray1(b *testing.B) {
	var list []bool
	for n := 0; n < b.N; n++ {
		list = arrayGeneratorBool.Value(source).([]bool)
	}
	_ = list[0]
}
func BenchmarkAutoIncrement(b *testing.B) {
	for n := 0; n < b.N; n++ {
		autoIncrGenerator.Value(source)
	}
}
func BenchmarkRefGenerator(b *testing.B) {
	for n := 0; n < b.N; n++ {
		refGenerator.Value(source)
	}
}

func BenchmarkFromArray(b *testing.B) {
	for n := 0; n < b.N; n++ {
		fromArrayGenerator.Value(source)
	}
}

func BenchmarkJSONGeneration(b *testing.B) {
	generator, err := getGeneratorFromFile(false)
	if err != nil {
		b.Error(err.Error())
	}
	docList := generator.Value(source).([]bson.M)
	bsonBytes, err := bson.Marshal(docList[0])
	if err != nil {
		fmt.Printf("marshaling failed, %s\n", err.Error())
	}
	// on each generation, 1000 docs are generated
	b.SetBytes(int64(len(bsonBytes)) * 1000)
	for n := 0; n < b.N; n++ {
		docList = generator.Value(source).([]bson.M)
	}
}

func BenchmarkJSONGenerationShortNames(b *testing.B) {
	generator, err := getGeneratorFromFile(true)
	if err != nil {
		b.Error(err.Error())
	}
	docList := generator.Value(source).([]bson.M)
	bsonBytes, err := bson.Marshal(docList[0])
	if err != nil {
		fmt.Printf("marshaling failed, %s\n", err.Error())
	}
	// on each generation, 1000 docs are generated
	b.SetBytes(int64(len(bsonBytes)) * 1000)
	for n := 0; n < b.N; n++ {
		docList = generator.Value(source).([]bson.M)
	}
}

func TestKey(t *testing.T) {
	if stringGenerator.Key() != "key" {
		t.Error("wrong key returned")
	}
}
func TestExists(t *testing.T) {
	tc := 0
	fc := 0
	for i := 0; i < 1000; i++ {
		if stringGenerator.Exists(source) {
			tc++
		} else {
			fc++
		}
	}
	if fc > 150 || fc < 50 {
		t.Errorf("Error to big, should accept 5 percent, but got  %v percent", fc/10)
	}

}
func TestValueString(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := stringGenerator.Value(source).(string)
		if int32(len(v)) > stringGenerator.MaxLength || int32(len(v)) < stringGenerator.MinLength {
			t.Error("wrong string size")
		}
	}
}

func TestValueBool(t *testing.T) {
	v := boolGenerator.Value(source).(bool)
	if v != true && v != false {
		t.Error("wrong value for bool generator")
	}
}

func TestInt32Value(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := int32Generator.Value(source).(int32)
		if v > int32Generator.Max || v < int32Generator.Min {
			t.Error("int32 not within correct bounds")
		}
	}
}

func TestInt64Value(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := int64Generator.Value(source).(int64)
		if v > int64Generator.Max || v < int64Generator.Min {
			t.Error("int64 not within correct bounds")
		}
	}
}
func TestFloat64Value(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := float64Generator.Value(source).(float64)
		if v > (float64Generator.Mean+float64Generator.StdDev) || v < (float64Generator.Mean-float64Generator.StdDev) {
			t.Error("float64 not within correct bounds")
		}
	}
}
func TestDateValue(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := dateGenerator.Value(source).(time.Time)
		if v.After(ed) || v.Before(sd) {
			t.Error("Date not within correct bounds")
		}
	}
}
func TestBinaryDataValue(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := binaryGenerator.Value(source).([]byte)
		if int32(len(v)) > binaryGenerator.MaxLength || int32(len(v)) < binaryGenerator.MinLength {
			t.Error("wrong string size")
		}
	}
}

func TestPositionValue(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := positionGenerator.Value(source).([2]float32)
		if v[0] < -90 || v[0] > 90 {
			t.Errorf("wrong value for longitude: %v", v[0])
		}
		if v[1] < -180 || v[1] > 180 {
			t.Errorf("wrong value for latitiude: %v", v[1])
		}
	}
}
func TestStringArrayValue(t *testing.T) {
	v := arrayGeneratorString.Value(source).([]string)
	if len(v) != arrayGeneratorString.Size {
		t.Errorf("wrong aray size, expected %v, got %v", arrayGeneratorString.Size, len(v))
	}
}

func TestAutoIncrementValue(t *testing.T) {
	var v int64
	for i := 0; i < 100; i++ {
		v = autoIncrGenerator.Value(source).(int64)
	}
	if v != 100 {
		t.Errorf("wrong value for autoincrement field, expected 100, got %v", v)
	}
}
func TestFromArrayValue(t *testing.T) {
	var v string
	for i := 0; i < 100; i++ {
		v = fromArrayGenerator.Value(source).(string)
		ok := false
		for j := range constArr {
			if constArr[j] == v {
				ok = true
			}
		}
		if !ok {
			t.Errorf("wrong value for fromArray field, %s is not in %v", v, constArr)
		}
	}
}
func TestGeneratedDoc(t *testing.T) {
	var exp expected
	generator, err := getGeneratorFromFile(false)
	if err != nil {
		t.Error(err.Error())
	}
	docList := generator.Value(source).([]bson.M)
	for _, doc := range docList {
		bsonBytes, err := bson.Marshal(doc)
		if err != nil {
			t.Errorf("Couldn't marshal generated documenT: %s", err.Error())
		}
		err = bson.Unmarshal(bsonBytes, &exp)
		if err != nil {
			t.Errorf("Couldn't unmarshal generated documenT: %s", err.Error())
		}
	}
}
<commit_msg>fix ineffassign warning<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"testing"
	"time"

	"github.com/globalsign/mgo/bson"

	"github.com/mgodatagen/rg"
)

var (
	source               = rg.NewRandSource()
	sd, _                = time.Parse(time.RFC3339, "2010-01-01T00:00:00-00:00")
	ed, _                = time.Parse(time.RFC3339, "2016-01-01T00:00:00-00:00")
	eg                   = rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 8}
	constArr             = []interface{}{"2012-10-10", "2012-12-12", "2014-01-01", "2016-05-05"}
	stringGenerator      = &rg.StringGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 0}, MinLength: 2, MaxLength: 5}
	int32Generator       = &rg.Int32Generator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 2}, Min: 0, Max: 100}
	int64Generator       = &rg.Int64Generator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 3}, Min: 0, Max: 100}
	float64Generator     = &rg.Float64Generator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 4}, Mean: 0, StdDev: 50}
	dateGenerator        = &rg.DateGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 7}, StartDate: sd.Unix(), Delta: (ed.Unix() - sd.Unix())}
	boolGenerator        = &rg.BoolGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 1}}
	binaryGenerator      = &rg.BinaryDataGenerator{EmptyGenerator: eg, MinLength: 30, MaxLength: 30}
	positionGenerator    = &rg.PositionGenerator{EmptyGenerator: eg}
	arrayGeneratorString = &rg.ArrayGenerator{EmptyGenerator: eg, Size: 10, Generator: stringGenerator}
	arrayGeneratorBool   = &rg.ArrayGenerator{EmptyGenerator: eg, Size: 10, Generator: boolGenerator}
	autoIncrGenerator    = &rg.AutoIncrementGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 3}, Counter: 0}
	objectIDGenerator    = &rg.ObjectIDGenerator{EmptyGenerator: rg.EmptyGenerator{K: "key", NullPercentage: 100, T: 5}}
	refGenerator         = &rg.RefGenerator{EmptyGenerator: eg, ID: 1, Generator: objectIDGenerator}
	fromArrayGenerator   = &rg.FromArrayGenerator{EmptyGenerator: eg, Array: constArr, Size: int32(len(constArr)), Index: -1}
)

type expected struct {
	ID          bson.ObjectId `json:"_id"`
	Date        time.Time     `json:"date"`
	Data        []byte        `json:"data"`
	Dt          string        `json:"dt"`
	Name        string        `json:"name"`
	Count32     int32         `json:"count32"`
	Count64     int64         `json:"count64"`
	Float       float64       `json:"float"`
	Verified    bool          `json:"verified"`
	FirstArray  [3]string     `json:"firstArray"`
	Nb          int           `json:"nb"`
	Pos         [2]float32    `json:"pos"`
	Cs          cst           `json:"cst"`
	FirstObject obj           `json:"firstObject"`
}
type obj struct {
	K  int    `json:"k"`
	Nm string `json:"nm"`
}
type cst struct {
	Key1 string `json:"key1"`
	Key2 int32  `json:"key2"`
}

func getGeneratorFromFile(shortNames bool) (rg.Generator, error) {
	file, err := ioutil.ReadFile("samples/config.json")
	if err != nil {
		return nil, fmt.Errorf("File error: %v", err.Error())
	}
	var collectionList []Collection
	err = json.Unmarshal(file, &collectionList)
	if err != nil {
		return nil, fmt.Errorf("JSON error: %v", err.Error())
	}
	generators, err := rg.NewGeneratorsFromMap(collectionList[0].Content, shortNames)
	if err != nil {
		return nil, fmt.Errorf("Config error: %v", err.Error())
	}
	eg := rg.EmptyGenerator{K: "", NullPercentage: 0, T: 6}
	return &rg.ArrayGenerator{EmptyGenerator: eg,
		Size:      1000,
		Generator: &rg.ObjectGenerator{EmptyGenerator: eg, Generators: generators}}, nil
}

func BenchmarkExists(b *testing.B) {
	for n := 0; n < b.N; n++ {
		stringGenerator.Exists(source)
	}
}

func BenchmarkRandomString(b *testing.B) {
	for n := 0; n < b.N; n++ {
		stringGenerator.Value(source)
	}
}

func BenchmarkRandomInt32(b *testing.B) {
	for n := 0; n < b.N; n++ {
		int32Generator.Value(source)
	}
}
func BenchmarkRandomInt64(b *testing.B) {
	for n := 0; n < b.N; n++ {
		int64Generator.Value(source)
	}
}
func BenchmarkRandomFloat64(b *testing.B) {
	for n := 0; n < b.N; n++ {
		float64Generator.Value(source)
	}
}
func BenchmarkRandomDate(b *testing.B) {
	for n := 0; n < b.N; n++ {
		dateGenerator.Value(source)
	}
}

func BenchmarkRandomBool(b *testing.B) {
	for n := 0; n < b.N; n++ {
		boolGenerator.Value(source)
	}
}

func BenchmarkRandomBinaryData(b *testing.B) {
	for n := 0; n < b.N; n++ {
		binaryGenerator.Value(source)
	}
}
func BenchmarkRandomPosition(b *testing.B) {
	for n := 0; n < b.N; n++ {
		positionGenerator.Value(source)
	}
}
func BenchmarkRandomArray(b *testing.B) {
	var list []string
	for n := 0; n < b.N; n++ {
		list = arrayGeneratorString.Value(source).([]string)
	}
	_ = list[0]

}
func BenchmarkRandomArray1(b *testing.B) {
	var list []bool
	for n := 0; n < b.N; n++ {
		list = arrayGeneratorBool.Value(source).([]bool)
	}
	_ = list[0]
}
func BenchmarkAutoIncrement(b *testing.B) {
	for n := 0; n < b.N; n++ {
		autoIncrGenerator.Value(source)
	}
}
func BenchmarkRefGenerator(b *testing.B) {
	for n := 0; n < b.N; n++ {
		refGenerator.Value(source)
	}
}

func BenchmarkFromArray(b *testing.B) {
	for n := 0; n < b.N; n++ {
		fromArrayGenerator.Value(source)
	}
}

func BenchmarkJSONGeneration(b *testing.B) {
	generator, err := getGeneratorFromFile(false)
	if err != nil {
		b.Error(err.Error())
	}
	docList := generator.Value(source).([]bson.M)
	bsonBytes, err := bson.Marshal(docList[0])
	if err != nil {
		fmt.Printf("marshaling failed, %s\n", err.Error())
	}
	// on each generation, 1000 docs are generated
	b.SetBytes(int64(len(bsonBytes)) * 1000)
	for n := 0; n < b.N; n++ {
		docList = generator.Value(source).([]bson.M)
	}
	_ = docList[0]
}

func BenchmarkJSONGenerationShortNames(b *testing.B) {
	generator, err := getGeneratorFromFile(true)
	if err != nil {
		b.Error(err.Error())
	}
	docList := generator.Value(source).([]bson.M)
	bsonBytes, err := bson.Marshal(docList[0])
	if err != nil {
		fmt.Printf("marshaling failed, %s\n", err.Error())
	}
	// on each generation, 1000 docs are generated
	b.SetBytes(int64(len(bsonBytes)) * 1000)
	for n := 0; n < b.N; n++ {
		docList = generator.Value(source).([]bson.M)
	}
	_ = docList[0]
}

func TestKey(t *testing.T) {
	if stringGenerator.Key() != "key" {
		t.Error("wrong key returned")
	}
}
func TestExists(t *testing.T) {
	tc := 0
	fc := 0
	for i := 0; i < 1000; i++ {
		if stringGenerator.Exists(source) {
			tc++
		} else {
			fc++
		}
	}
	if fc > 150 || fc < 50 {
		t.Errorf("Error to big, should accept 5 percent, but got  %v percent", fc/10)
	}

}
func TestValueString(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := stringGenerator.Value(source).(string)
		if int32(len(v)) > stringGenerator.MaxLength || int32(len(v)) < stringGenerator.MinLength {
			t.Error("wrong string size")
		}
	}
}

func TestValueBool(t *testing.T) {
	v := boolGenerator.Value(source).(bool)
	if v != true && v != false {
		t.Error("wrong value for bool generator")
	}
}

func TestInt32Value(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := int32Generator.Value(source).(int32)
		if v > int32Generator.Max || v < int32Generator.Min {
			t.Error("int32 not within correct bounds")
		}
	}
}

func TestInt64Value(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := int64Generator.Value(source).(int64)
		if v > int64Generator.Max || v < int64Generator.Min {
			t.Error("int64 not within correct bounds")
		}
	}
}
func TestFloat64Value(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := float64Generator.Value(source).(float64)
		if v > (float64Generator.Mean+float64Generator.StdDev) || v < (float64Generator.Mean-float64Generator.StdDev) {
			t.Error("float64 not within correct bounds")
		}
	}
}
func TestDateValue(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := dateGenerator.Value(source).(time.Time)
		if v.After(ed) || v.Before(sd) {
			t.Error("Date not within correct bounds")
		}
	}
}
func TestBinaryDataValue(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := binaryGenerator.Value(source).([]byte)
		if int32(len(v)) > binaryGenerator.MaxLength || int32(len(v)) < binaryGenerator.MinLength {
			t.Error("wrong string size")
		}
	}
}

func TestPositionValue(t *testing.T) {
	for i := 0; i < 1000; i++ {
		v := positionGenerator.Value(source).([2]float32)
		if v[0] < -90 || v[0] > 90 {
			t.Errorf("wrong value for longitude: %v", v[0])
		}
		if v[1] < -180 || v[1] > 180 {
			t.Errorf("wrong value for latitiude: %v", v[1])
		}
	}
}
func TestStringArrayValue(t *testing.T) {
	v := arrayGeneratorString.Value(source).([]string)
	if len(v) != arrayGeneratorString.Size {
		t.Errorf("wrong aray size, expected %v, got %v", arrayGeneratorString.Size, len(v))
	}
}

func TestAutoIncrementValue(t *testing.T) {
	var v int64
	for i := 0; i < 100; i++ {
		v = autoIncrGenerator.Value(source).(int64)
	}
	if v != 100 {
		t.Errorf("wrong value for autoincrement field, expected 100, got %v", v)
	}
}
func TestFromArrayValue(t *testing.T) {
	var v string
	for i := 0; i < 100; i++ {
		v = fromArrayGenerator.Value(source).(string)
		ok := false
		for j := range constArr {
			if constArr[j] == v {
				ok = true
			}
		}
		if !ok {
			t.Errorf("wrong value for fromArray field, %s is not in %v", v, constArr)
		}
	}
}
func TestGeneratedDoc(t *testing.T) {
	var exp expected
	generator, err := getGeneratorFromFile(false)
	if err != nil {
		t.Error(err.Error())
	}
	docList := generator.Value(source).([]bson.M)
	for _, doc := range docList {
		bsonBytes, err := bson.Marshal(doc)
		if err != nil {
			t.Errorf("Couldn't marshal generated documenT: %s", err.Error())
		}
		err = bson.Unmarshal(bsonBytes, &exp)
		if err != nil {
			t.Errorf("Couldn't unmarshal generated documenT: %s", err.Error())
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC 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 partial

import (
	"bytes"
	"io"
	"sync"

	"github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/types"
	"github.com/google/go-containerregistry/pkg/v1/v1util"
)

// UncompressedLayer represents the bare minimum interface a natively
// uncompressed layer must implement for us to produce a v1.Layer
type UncompressedLayer interface {
	// DiffID returns the Hash of the uncompressed layer.
	DiffID() (v1.Hash, error)

	// Uncompressed returns an io.ReadCloser for the uncompressed layer contents.
	Uncompressed() (io.ReadCloser, error)
}

// uncompressedLayerExtender implements v1.Image using the uncompressed base properties.
type uncompressedLayerExtender struct {
	UncompressedLayer
	// TODO(mattmoor): Memoize size/hash so that the methods aren't twice as
	// expensive as doing this manually.
}

// Compressed implements v1.Layer
func (ule *uncompressedLayerExtender) Compressed() (io.ReadCloser, error) {
	u, err := ule.Uncompressed()
	if err != nil {
		return nil, err
	}
	return v1util.GzipReadCloser(u)
}

// Digest implements v1.Layer
func (ule *uncompressedLayerExtender) Digest() (v1.Hash, error) {
	r, err := ule.Compressed()
	if err != nil {
		return v1.Hash{}, err
	}
	defer r.Close()
	h, _, err := v1.SHA256(r)
	return h, err
}

// Size implements v1.Layer
func (ule *uncompressedLayerExtender) Size() (int64, error) {
	r, err := ule.Compressed()
	if err != nil {
		return -1, err
	}
	defer r.Close()
	_, i, err := v1.SHA256(r)
	return i, err
}

// UncompressedToLayer fills in the missing methods from an UncompressedLayer so that it implements v1.Layer
func UncompressedToLayer(ul UncompressedLayer) (v1.Layer, error) {
	return &uncompressedLayerExtender{ul}, nil
}

// UncompressedImageCore represents the bare minimum interface a natively
// uncompressed image must implement for us to produce a v1.Image
type UncompressedImageCore interface {
	imageCore

	// LayerByDiffID is a variation on the v1.Image method, which returns
	// an UncompressedLayer instead.
	LayerByDiffID(v1.Hash) (UncompressedLayer, error)
}

// UncompressedToImage fills in the missing methods from an UncompressedImageCore so that it implements v1.Image.
func UncompressedToImage(uic UncompressedImageCore) (v1.Image, error) {
	return &uncompressedImageExtender{
		UncompressedImageCore: uic,
	}, nil
}

// uncompressedImageExtender implements v1.Image by extending UncompressedImageCore with the
// appropriate methods computed from the minimal core.
type uncompressedImageExtender struct {
	UncompressedImageCore

	lock     sync.Mutex
	manifest *v1.Manifest
}

// Assert that our extender type completes the v1.Image interface
var _ v1.Image = (*uncompressedImageExtender)(nil)

// BlobSet implements v1.Image
func (i *uncompressedImageExtender) BlobSet() (map[v1.Hash]struct{}, error) {
	return BlobSet(i)
}

// Digest implements v1.Image
func (i *uncompressedImageExtender) Digest() (v1.Hash, error) {
	return Digest(i)
}

// Manifest implements v1.Image
func (i *uncompressedImageExtender) Manifest() (*v1.Manifest, error) {
	i.lock.Lock()
	defer i.lock.Unlock()
	if i.manifest != nil {
		return i.manifest, nil
	}

	b, err := i.RawConfigFile()
	if err != nil {
		return nil, err
	}

	cfgHash, cfgSize, err := v1.SHA256(bytes.NewReader(b))
	if err != nil {
		return nil, err
	}

	m := &v1.Manifest{
		SchemaVersion: 2,
		MediaType:     types.DockerManifestSchema2,
		Config: v1.Descriptor{
			MediaType: types.DockerConfigJSON,
			Size:      cfgSize,
			Digest:    cfgHash,
		},
	}

	ls, err := i.Layers()
	if err != nil {
		return nil, err
	}

	m.Layers = make([]v1.Descriptor, len(ls))
	for i, l := range ls {
		sz, err := l.Size()
		if err != nil {
			return nil, err
		}
		h, err := l.Digest()
		if err != nil {
			return nil, err
		}

		m.Layers[i] = v1.Descriptor{
			MediaType: types.DockerLayer,
			Size:      sz,
			Digest:    h,
		}
	}

	i.manifest = m
	return i.manifest, nil
}

// RawManifest implements v1.Image
func (i *uncompressedImageExtender) RawManifest() ([]byte, error) {
	return RawManifest(i)
}

// ConfigName implements v1.Image
func (i *uncompressedImageExtender) ConfigName() (v1.Hash, error) {
	return ConfigName(i)
}

// ConfigFile implements v1.Image
func (i *uncompressedImageExtender) ConfigFile() (*v1.ConfigFile, error) {
	return ConfigFile(i)
}

// Layers implements v1.Image
func (i *uncompressedImageExtender) Layers() ([]v1.Layer, error) {
	diffIDs, err := DiffIDs(i)
	if err != nil {
		return nil, err
	}
	ls := make([]v1.Layer, 0, len(diffIDs))
	for _, h := range diffIDs {
		l, err := i.LayerByDiffID(h)
		if err != nil {
			return nil, err
		}
		ls = append(ls, l)
	}
	return ls, nil
}

// LayerByDiffID implements v1.Image
func (i *uncompressedImageExtender) LayerByDiffID(diffID v1.Hash) (v1.Layer, error) {
	ul, err := i.UncompressedImageCore.LayerByDiffID(diffID)
	if err != nil {
		return nil, err
	}
	return UncompressedToLayer(ul)
}

// LayerByDigest implements v1.Image
func (i *uncompressedImageExtender) LayerByDigest(h v1.Hash) (v1.Layer, error) {
	// Support returning the ConfigFile when asked for its hash.
	if cfgName, err := i.ConfigName(); err != nil {
		return nil, err
	} else if cfgName == h {
		return ConfigLayer(i)
	}

	diffID, err := BlobToDiffID(i, h)
	if err != nil {
		return nil, err
	}
	return i.LayerByDiffID(diffID)
}
<commit_msg>Memoize size/hash for uncompressedLayerExtender (#270)<commit_after>// Copyright 2018 Google LLC 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 partial

import (
	"bytes"
	"io"
	"sync"

	"github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/types"
	"github.com/google/go-containerregistry/pkg/v1/v1util"
)

// UncompressedLayer represents the bare minimum interface a natively
// uncompressed layer must implement for us to produce a v1.Layer
type UncompressedLayer interface {
	// DiffID returns the Hash of the uncompressed layer.
	DiffID() (v1.Hash, error)

	// Uncompressed returns an io.ReadCloser for the uncompressed layer contents.
	Uncompressed() (io.ReadCloser, error)
}

// uncompressedLayerExtender implements v1.Image using the uncompressed base properties.
type uncompressedLayerExtender struct {
	UncompressedLayer
	// Memoize size/hash so that the methods aren't twice as
	// expensive as doing this manually.
	hash          v1.Hash
	size          int64
	hashSizeError error
	once          sync.Once
}

// Compressed implements v1.Layer
func (ule *uncompressedLayerExtender) Compressed() (io.ReadCloser, error) {
	u, err := ule.Uncompressed()
	if err != nil {
		return nil, err
	}
	return v1util.GzipReadCloser(u)
}

// Digest implements v1.Layer
func (ule *uncompressedLayerExtender) Digest() (v1.Hash, error) {
	ule.calcSizeHash()
	return ule.hash, ule.hashSizeError
}

// Size implements v1.Layer
func (ule *uncompressedLayerExtender) Size() (int64, error) {
	ule.calcSizeHash()
	return ule.size, ule.hashSizeError
}

func (ule *uncompressedLayerExtender) calcSizeHash() {
	ule.once.Do(func() {
		var r io.ReadCloser
		r, ule.hashSizeError = ule.Compressed()
		if ule.hashSizeError != nil {
			return
		}
		defer r.Close()
		ule.hash, ule.size, ule.hashSizeError = v1.SHA256(r)
	})
}

// UncompressedToLayer fills in the missing methods from an UncompressedLayer so that it implements v1.Layer
func UncompressedToLayer(ul UncompressedLayer) (v1.Layer, error) {
	return &uncompressedLayerExtender{UncompressedLayer: ul}, nil
}

// UncompressedImageCore represents the bare minimum interface a natively
// uncompressed image must implement for us to produce a v1.Image
type UncompressedImageCore interface {
	imageCore

	// LayerByDiffID is a variation on the v1.Image method, which returns
	// an UncompressedLayer instead.
	LayerByDiffID(v1.Hash) (UncompressedLayer, error)
}

// UncompressedToImage fills in the missing methods from an UncompressedImageCore so that it implements v1.Image.
func UncompressedToImage(uic UncompressedImageCore) (v1.Image, error) {
	return &uncompressedImageExtender{
		UncompressedImageCore: uic,
	}, nil
}

// uncompressedImageExtender implements v1.Image by extending UncompressedImageCore with the
// appropriate methods computed from the minimal core.
type uncompressedImageExtender struct {
	UncompressedImageCore

	lock     sync.Mutex
	manifest *v1.Manifest
}

// Assert that our extender type completes the v1.Image interface
var _ v1.Image = (*uncompressedImageExtender)(nil)

// BlobSet implements v1.Image
func (i *uncompressedImageExtender) BlobSet() (map[v1.Hash]struct{}, error) {
	return BlobSet(i)
}

// Digest implements v1.Image
func (i *uncompressedImageExtender) Digest() (v1.Hash, error) {
	return Digest(i)
}

// Manifest implements v1.Image
func (i *uncompressedImageExtender) Manifest() (*v1.Manifest, error) {
	i.lock.Lock()
	defer i.lock.Unlock()
	if i.manifest != nil {
		return i.manifest, nil
	}

	b, err := i.RawConfigFile()
	if err != nil {
		return nil, err
	}

	cfgHash, cfgSize, err := v1.SHA256(bytes.NewReader(b))
	if err != nil {
		return nil, err
	}

	m := &v1.Manifest{
		SchemaVersion: 2,
		MediaType:     types.DockerManifestSchema2,
		Config: v1.Descriptor{
			MediaType: types.DockerConfigJSON,
			Size:      cfgSize,
			Digest:    cfgHash,
		},
	}

	ls, err := i.Layers()
	if err != nil {
		return nil, err
	}

	m.Layers = make([]v1.Descriptor, len(ls))
	for i, l := range ls {
		sz, err := l.Size()
		if err != nil {
			return nil, err
		}
		h, err := l.Digest()
		if err != nil {
			return nil, err
		}

		m.Layers[i] = v1.Descriptor{
			MediaType: types.DockerLayer,
			Size:      sz,
			Digest:    h,
		}
	}

	i.manifest = m
	return i.manifest, nil
}

// RawManifest implements v1.Image
func (i *uncompressedImageExtender) RawManifest() ([]byte, error) {
	return RawManifest(i)
}

// ConfigName implements v1.Image
func (i *uncompressedImageExtender) ConfigName() (v1.Hash, error) {
	return ConfigName(i)
}

// ConfigFile implements v1.Image
func (i *uncompressedImageExtender) ConfigFile() (*v1.ConfigFile, error) {
	return ConfigFile(i)
}

// Layers implements v1.Image
func (i *uncompressedImageExtender) Layers() ([]v1.Layer, error) {
	diffIDs, err := DiffIDs(i)
	if err != nil {
		return nil, err
	}
	ls := make([]v1.Layer, 0, len(diffIDs))
	for _, h := range diffIDs {
		l, err := i.LayerByDiffID(h)
		if err != nil {
			return nil, err
		}
		ls = append(ls, l)
	}
	return ls, nil
}

// LayerByDiffID implements v1.Image
func (i *uncompressedImageExtender) LayerByDiffID(diffID v1.Hash) (v1.Layer, error) {
	ul, err := i.UncompressedImageCore.LayerByDiffID(diffID)
	if err != nil {
		return nil, err
	}
	return UncompressedToLayer(ul)
}

// LayerByDigest implements v1.Image
func (i *uncompressedImageExtender) LayerByDigest(h v1.Hash) (v1.Layer, error) {
	// Support returning the ConfigFile when asked for its hash.
	if cfgName, err := i.ConfigName(); err != nil {
		return nil, err
	} else if cfgName == h {
		return ConfigLayer(i)
	}

	diffID, err := BlobToDiffID(i, h)
	if err != nil {
		return nil, err
	}
	return i.LayerByDiffID(diffID)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All rights reserved.

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

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

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

package iscsi

import (
	"os"
	"testing"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
)

func TestCanSupport(t *testing.T) {
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	if plug.Name() != "kubernetes.io/iscsi" {
		t.Errorf("Wrong name: %s", plug.Name())
	}
}

type fakeDiskManager struct{}

func (fake *fakeDiskManager) MakeGlobalPDName(disk iscsiDisk) string {
	return "/tmp/fake_iscsi_path"
}
func (fake *fakeDiskManager) AttachDisk(disk iscsiDisk) error {
	globalPath := disk.manager.MakeGlobalPDName(disk)
	err := os.MkdirAll(globalPath, 0750)
	if err != nil {
		return err
	}
	return nil
}

func (fake *fakeDiskManager) DetachDisk(disk iscsiDisk, mntPath string) error {
	globalPath := disk.manager.MakeGlobalPDName(disk)
	err := os.RemoveAll(globalPath)
	if err != nil {
		return err
	}
	return nil
}

func TestPlugin(t *testing.T) {
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	spec := &api.Volume{
		Name: "vol1",
		VolumeSource: api.VolumeSource{
			ISCSI: &api.ISCSIVolumeSource{
				TargetPortal: "127.0.0.1:3260",
				IQN:          "iqn.2014-12.server:storage.target01",
				FSType:       "ext4",
				Lun:          0,
			},
		},
	}
	builder, err := plug.(*ISCSIPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakeDiskManager{}, &mount.FakeMounter{})
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder: %v")
	}

	path := builder.GetPath()
	if path != "/tmp/fake/pods/poduid/volumes/kubernetes.io~iscsi/vol1" {
		t.Errorf("Got unexpected path: %s", path)
	}

	if err := builder.SetUp(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}

	cleaner, err := plug.(*ISCSIPlugin).newCleanerInternal("vol1", types.UID("poduid"), &fakeDiskManager{}, &mount.FakeMounter{})
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}
	if cleaner == nil {
		t.Errorf("Got a nil Cleaner: %v")
	}

	if err := cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err == nil {
		t.Errorf("TearDown() failed, volume path still exists: %s", path)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}
}
<commit_msg>iscsi Test: Add explicit check for attach and detach calls.<commit_after>/*
Copyright 2015 Google Inc. All rights reserved.

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

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

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

package iscsi

import (
	"os"
	"testing"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
)

func TestCanSupport(t *testing.T) {
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	if plug.Name() != "kubernetes.io/iscsi" {
		t.Errorf("Wrong name: %s", plug.Name())
	}
}

type fakeDiskManager struct {
	attachCalled bool
	detachCalled bool
}

func (fake *fakeDiskManager) MakeGlobalPDName(disk iscsiDisk) string {
	return "/tmp/fake_iscsi_path"
}
func (fake *fakeDiskManager) AttachDisk(disk iscsiDisk) error {
	globalPath := disk.manager.MakeGlobalPDName(disk)
	err := os.MkdirAll(globalPath, 0750)
	if err != nil {
		return err
	}
	// Simulate the global mount so that the fakeMounter returns the
	// expected number of mounts for the attached disk.
	disk.mounter.Mount(globalPath, globalPath, disk.fsType, 0, "")

	fake.attachCalled = true
	return nil
}

func (fake *fakeDiskManager) DetachDisk(disk iscsiDisk, mntPath string) error {
	globalPath := disk.manager.MakeGlobalPDName(disk)
	err := os.RemoveAll(globalPath)
	if err != nil {
		return err
	}
	fake.detachCalled = true
	return nil
}

func TestPlugin(t *testing.T) {
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	spec := &api.Volume{
		Name: "vol1",
		VolumeSource: api.VolumeSource{
			ISCSI: &api.ISCSIVolumeSource{
				TargetPortal: "127.0.0.1:3260",
				IQN:          "iqn.2014-12.server:storage.target01",
				FSType:       "ext4",
				Lun:          0,
			},
		},
	}
	fakeManager := &fakeDiskManager{}
	fakeMounter := &mount.FakeMounter{}
	builder, err := plug.(*ISCSIPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), fakeManager, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder: %v")
	}

	path := builder.GetPath()
	if path != "/tmp/fake/pods/poduid/volumes/kubernetes.io~iscsi/vol1" {
		t.Errorf("Got unexpected path: %s", path)
	}

	if err := builder.SetUp(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}
	if !fakeManager.attachCalled {
		t.Errorf("Attach was not called")
	}

	fakeManager = &fakeDiskManager{}
	cleaner, err := plug.(*ISCSIPlugin).newCleanerInternal("vol1", types.UID("poduid"), fakeManager, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}
	if cleaner == nil {
		t.Errorf("Got a nil Cleaner: %v")
	}

	if err := cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err == nil {
		t.Errorf("TearDown() failed, volume path still exists: %s", path)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}
	if !fakeManager.detachCalled {
		t.Errorf("Detach was not called")
	}
}
<|endoftext|>