<commit_before>package dnsimple

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

type Record struct {
	Id       int
	Name     string
	Content  string
	DomainId int `json:"domain_id"`
}

type recordList struct {
	Record Record
}

type Domain struct {
	Id   int
	Name string
}

type domainList struct {
	Domain Domain
}

type DNSimpleClient struct {
	ApiToken    string
	Email       string
	DomainToken string
	HttpClient  *http.Client
}

func NewClient(apiToken, email string) *DNSimpleClient {
	return &DNSimpleClient{ApiToken: apiToken, Email: email, HttpClient: &http.Client{}}
}

func (client *DNSimpleClient) makeRequest(method, url string, body io.Reader) (*http.Request, error) {
	req, err := http.NewRequest(method, url, body)
	req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", client.Email, client.ApiToken))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	if err != nil {
		return nil, err
	}
	return req, nil
}

func (client *DNSimpleClient) sendRequest(method, url string, body io.Reader) (string, error) {
	req, err := client.makeRequest(method, url, body)
	if err != nil {
		return "", err
	}

	resp, err := client.HttpClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(responseBody), nil
}

func (client *DNSimpleClient) Record(domain, name string) (Record, error) {
	reqStr := fmt.Sprintf("https://dnsimple.com/domains/%s/records?name=%s", domain, name)

	body, err := client.sendRequest("GET", reqStr, nil)
	if err != nil {
		return Record{}, err
	}

	var records []recordList

	if err = json.Unmarshal([]byte(body), &records); err != nil {
		return Record{}, err
	}

	return records[0].Record, nil
}

func (client *DNSimpleClient) Domains() ([]Domain, error) {
	reqStr := "https://dnsimple.com/domains"

	body, err := client.sendRequest("GET", reqStr, nil)
	if err != nil {
		return []Domain{}, err
	}

	fmt.Println(body)
	var domainList []domainList

	if err = json.Unmarshal([]byte(body), &domainList); err != nil {
		return []Domain{}, err
	}

	domains := []Domain{}
	for _, domain := range domainList {
		domains = append(domains, domain.Domain)
	}

	return domains, nil
}

func (record *Record) UpdateIP(client *DNSimpleClient, IP string) error {
	// lame, but easy enough for now
	jsonPayload := fmt.Sprintf(`{"record": {"content": "%s"}}`, IP)
	url := fmt.Sprintf("https://dnsimple.com/domains/%d/records/%d", record.DomainId, record.Id)

	_, err := client.sendRequest("PUT", url, strings.NewReader(jsonPayload))
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Get a specific domain, by name<commit_after>package dnsimple

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

type Record struct {
	Id       int
	Name     string
	Content  string
	DomainId int `json:"domain_id"`
}

type recordList struct {
	Record Record
}

type Domain struct {
	Id   int
	Name string
}

type domainWrapper struct {
	Domain Domain
}

type DNSimpleClient struct {
	ApiToken    string
	Email       string
	DomainToken string
	HttpClient  *http.Client
}

func NewClient(apiToken, email string) *DNSimpleClient {
	return &DNSimpleClient{ApiToken: apiToken, Email: email, HttpClient: &http.Client{}}
}

func (client *DNSimpleClient) makeRequest(method, url string, body io.Reader) (*http.Request, error) {
	req, err := http.NewRequest(method, url, body)
	req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", client.Email, client.ApiToken))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	if err != nil {
		return nil, err
	}
	return req, nil
}

func (client *DNSimpleClient) sendRequest(method, url string, body io.Reader) (string, error) {
	req, err := client.makeRequest(method, url, body)
	if err != nil {
		return "", err
	}

	resp, err := client.HttpClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(responseBody), nil
}

func (client *DNSimpleClient) Record(domain, name string) (Record, error) {
	reqStr := fmt.Sprintf("https://dnsimple.com/domains/%s/records?name=%s", domain, name)

	body, err := client.sendRequest("GET", reqStr, nil)
	if err != nil {
		return Record{}, err
	}

	var records []recordList

	if err = json.Unmarshal([]byte(body), &records); err != nil {
		return Record{}, err
	}

	return records[0].Record, nil
}

func (client *DNSimpleClient) Domains() ([]Domain, error) {
	reqStr := "https://dnsimple.com/domains"

	body, err := client.sendRequest("GET", reqStr, nil)
	if err != nil {
		return []Domain{}, err
	}

	var domainList []domainWrapper

	if err = json.Unmarshal([]byte(body), &domainList); err != nil {
		return []Domain{}, err
	}

	domains := []Domain{}
	for _, domain := range domainList {
		domains = append(domains, domain.Domain)
	}

	return domains, nil
}

func (client *DNSimpleClient) Domain(domain string) (Domain, error) {
	reqStr := fmt.Sprintf("https://dnsimple.com/domains/%s", domain)

	body, err := client.sendRequest("GET", reqStr, nil)
	if err != nil {
		return Domain{}, err
	}

	wrappedDomain := domainWrapper{}

	if err = json.Unmarshal([]byte(body), &wrappedDomain); err != nil {
		return Domain{}, err
	}
	return wrappedDomain.Domain, nil
}

func (record *Record) UpdateIP(client *DNSimpleClient, IP string) error {
	// lame, but easy enough for now
	jsonPayload := fmt.Sprintf(`{"record": {"content": "%s"}}`, IP)
	url := fmt.Sprintf("https://dnsimple.com/domains/%d/records/%d", record.DomainId, record.Id)

	_, err := client.sendRequest("PUT", url, strings.NewReader(jsonPayload))
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


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

package logrus

import (
	"fmt"
	"os"
	"sync"

	"regexp"

	"github.com/ligato/cn-infra/logging"
	"github.com/sirupsen/logrus"
)

var initialLogLvl = logrus.InfoLevel

func init() {
	if lvl, err := logrus.ParseLevel(os.Getenv("INITIAL_LOGLVL")); err == nil {
		initialLogLvl = lvl
		if err := setLevel(defaultLogger, lvl); err != nil {
			defaultLogger.Warnf("setting initialLogLvl = %q failed: %v", lvl.String(), err)
		} else {
			defaultLogger.Debugf("initialLogLvl = %q", lvl.String())
		}
	}
}

// NewLogRegistry is a constructor
func NewLogRegistry() logging.Registry {
	registry := &logRegistry{
		loggers:      new(sync.Map),
		logLevels:    make(map[string]logrus.Level),
		defaultLevel: initialLogLvl,
	}
	// put default logger
	registry.putLoggerToMapping(defaultLogger)
	return registry
}

// logRegistry contains logger map and rwlock guarding access to it
type logRegistry struct {
	// loggers holds mapping of logger instances indexed by their names
	loggers *sync.Map
	// logLevels store map of log levels for logger names
	logLevels map[string]logrus.Level
	// defaultLevel is used if logger level is not set
	defaultLevel logrus.Level
}

var validLoggerName = regexp.MustCompile(`^[a-zA-Z0-9.-]+$`).MatchString

func checkLoggerName(name string) error {
	if !validLoggerName(name) {
		return fmt.Errorf("logger name can contain only alphanum characters, dash and comma")
	}
	return nil
}

// NewLogger creates new named Logger instance. Name can be subsequently used to
// refer the logger in registry.
func (lr *logRegistry) NewLogger(name string) logging.Logger {
	existingLogger := lr.getLoggerFromMapping(name)
	if existingLogger != nil {
		panic(fmt.Errorf("logger with name '%s' already exists", name))
	}
	if err := checkLoggerName(name); err != nil {
		panic(err)
	}

	logger := NewLogger(name)

	// set initial logger level
	if lvl, ok := lr.logLevels[name]; ok {
		setLevel(logger, lvl)
	} else {
		setLevel(logger, lr.defaultLevel)
	}

	lr.putLoggerToMapping(logger)
	return logger
}

// ListLoggers returns a map (loggerName => log level)
func (lr *logRegistry) ListLoggers() map[string]string {
	list := make(map[string]string)

	var wasErr error

	lr.loggers.Range(func(k, v interface{}) bool {
		key, ok := k.(string)
		if !ok {
			wasErr = fmt.Errorf("cannot cast log map key to string")
			// false stops the iteration
			return false
		}
		value, ok := v.(*Logger)
		if !ok {
			wasErr = fmt.Errorf("cannot cast log value to Logger obj")
			return false
		}
		list[key] = value.GetLevel().String()
		return true
	})

	// throw panic outside of logger.Range()
	if wasErr != nil {
		panic(wasErr)
	}

	return list
}

func setLevel(logVal logging.Logger, lvl logrus.Level) error {
	if logVal == nil {
		return fmt.Errorf("logger %q not found", logVal)
	}
	defaultLogger.Debugln("set logger level:", logVal.GetName(), "->", lvl.String())
	switch lvl {
	case logrus.DebugLevel:
		logVal.SetLevel(logging.DebugLevel)
	case logrus.InfoLevel:
		logVal.SetLevel(logging.InfoLevel)
	case logrus.WarnLevel:
		logVal.SetLevel(logging.WarnLevel)
	case logrus.ErrorLevel:
		logVal.SetLevel(logging.ErrorLevel)
	case logrus.PanicLevel:
		logVal.SetLevel(logging.PanicLevel)
	case logrus.FatalLevel:
		logVal.SetLevel(logging.FatalLevel)
	}
	return nil
}

// SetLevel modifies log level of selected logger in the registry
func (lr *logRegistry) SetLevel(logger, level string) error {
	lvl, err := logrus.ParseLevel(level)
	if err != nil {
		return err
	}
	if logger == "default" {
		lr.defaultLevel = lvl
		return nil
	}
	lr.logLevels[logger] = lvl
	logVal := lr.getLoggerFromMapping(logger)
	if logVal != nil {
		return setLevel(logVal, lvl)
	}
	return nil
}

// GetLevel returns the currently set log level of the logger
func (lr *logRegistry) GetLevel(logger string) (string, error) {
	logVal := lr.getLoggerFromMapping(logger)
	if logVal == nil {
		return "", fmt.Errorf("logger %s not found", logger)
	}
	return logVal.GetLevel().String(), nil
}

// Lookup returns a logger instance identified by name from registry
func (lr *logRegistry) Lookup(loggerName string) (logger logging.Logger, found bool) {
	loggerInt, found := lr.loggers.Load(loggerName)
	if !found {
		return nil, false
	}
	logger, ok := loggerInt.(*Logger)
	if ok {
		return logger, found
	}
	panic(fmt.Errorf("cannot cast log value to Logger obj"))
}

// ClearRegistry removes all loggers except the default one from registry
func (lr *logRegistry) ClearRegistry() {
	var wasErr error

	// range over logger map and store keys
	lr.loggers.Range(func(k, v interface{}) bool {
		key, ok := k.(string)
		if !ok {
			wasErr = fmt.Errorf("cannot cast log map key to string")
			// false stops the iteration
			return false
		}
		if key != DefaultLoggerName {
			lr.loggers.Delete(key)
		}
		return true
	})

	if wasErr != nil {
		panic(wasErr)
	}
}

// putLoggerToMapping writes logger into map of named loggers
func (lr *logRegistry) putLoggerToMapping(logger *Logger) {
	lr.loggers.Store(logger.name, logger)
}

// getLoggerFromMapping returns a logger by its name
func (lr *logRegistry) getLoggerFromMapping(logger string) *Logger {
	loggerVal, found := lr.loggers.Load(logger)
	if !found {
		return nil
	}
	log, ok := loggerVal.(*Logger)
	if ok {
		return log
	}
	panic("cannot cast log value to Logger obj")

}
<commit_msg>Omit logging message about setting log level on init<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package logrus

import (
	"fmt"
	"os"
	"sync"

	"regexp"

	"github.com/ligato/cn-infra/logging"
	"github.com/sirupsen/logrus"
)

var initialLogLvl = logrus.InfoLevel

func init() {
	if lvl, err := logrus.ParseLevel(os.Getenv("INITIAL_LOGLVL")); err == nil {
		initialLogLvl = lvl
		if err := setLevel(defaultLogger, lvl); err != nil {
			defaultLogger.Warnf("setting initial log level to %v failed: %v", lvl.String(), err)
		} else {
			defaultLogger.Debugf("initial log level: %v", lvl.String())
		}
	}
}

// NewLogRegistry is a constructor
func NewLogRegistry() logging.Registry {
	registry := &logRegistry{
		loggers:      new(sync.Map),
		logLevels:    make(map[string]logrus.Level),
		defaultLevel: initialLogLvl,
	}
	// put default logger
	registry.putLoggerToMapping(defaultLogger)
	return registry
}

// logRegistry contains logger map and rwlock guarding access to it
type logRegistry struct {
	// loggers holds mapping of logger instances indexed by their names
	loggers *sync.Map
	// logLevels store map of log levels for logger names
	logLevels map[string]logrus.Level
	// defaultLevel is used if logger level is not set
	defaultLevel logrus.Level
}

var validLoggerName = regexp.MustCompile(`^[a-zA-Z0-9.-]+$`).MatchString

func checkLoggerName(name string) error {
	if !validLoggerName(name) {
		return fmt.Errorf("logger name can contain only alphanum characters, dash and comma")
	}
	return nil
}

// NewLogger creates new named Logger instance. Name can be subsequently used to
// refer the logger in registry.
func (lr *logRegistry) NewLogger(name string) logging.Logger {
	if existingLogger := lr.getLoggerFromMapping(name); existingLogger != nil {
		panic(fmt.Errorf("logger with name '%s' already exists", name))
	}
	if err := checkLoggerName(name); err != nil {
		panic(err)
	}

	logger := NewLogger(name)

	// set initial logger level
	if lvl, ok := lr.logLevels[name]; ok {
		setLevel(logger, lvl)
	} else {
		setLevel(logger, lr.defaultLevel)
	}

	lr.putLoggerToMapping(logger)
	return logger
}

// ListLoggers returns a map (loggerName => log level)
func (lr *logRegistry) ListLoggers() map[string]string {
	list := make(map[string]string)

	var wasErr error

	lr.loggers.Range(func(k, v interface{}) bool {
		key, ok := k.(string)
		if !ok {
			wasErr = fmt.Errorf("cannot cast log map key to string")
			// false stops the iteration
			return false
		}
		value, ok := v.(*Logger)
		if !ok {
			wasErr = fmt.Errorf("cannot cast log value to Logger obj")
			return false
		}
		list[key] = value.GetLevel().String()
		return true
	})

	// throw panic outside of logger.Range()
	if wasErr != nil {
		panic(wasErr)
	}

	return list
}

func setLevel(logVal logging.Logger, lvl logrus.Level) error {
	if logVal == nil {
		return fmt.Errorf("logger %q not found", logVal)
	}
	switch lvl {
	case logrus.DebugLevel:
		logVal.SetLevel(logging.DebugLevel)
	case logrus.InfoLevel:
		logVal.SetLevel(logging.InfoLevel)
	case logrus.WarnLevel:
		logVal.SetLevel(logging.WarnLevel)
	case logrus.ErrorLevel:
		logVal.SetLevel(logging.ErrorLevel)
	case logrus.PanicLevel:
		logVal.SetLevel(logging.PanicLevel)
	case logrus.FatalLevel:
		logVal.SetLevel(logging.FatalLevel)
	}
	return nil
}

// SetLevel modifies log level of selected logger in the registry
func (lr *logRegistry) SetLevel(logger, level string) error {
	lvl, err := logrus.ParseLevel(level)
	if err != nil {
		return err
	}
	if logger == "default" {
		lr.defaultLevel = lvl
		return nil
	}
	lr.logLevels[logger] = lvl
	logVal := lr.getLoggerFromMapping(logger)
	if logVal != nil {
		defaultLogger.Debugf("setting logger level: %v -> %v", logVal.GetName(), lvl.String())
		return setLevel(logVal, lvl)
	}
	return nil
}

// GetLevel returns the currently set log level of the logger
func (lr *logRegistry) GetLevel(logger string) (string, error) {
	logVal := lr.getLoggerFromMapping(logger)
	if logVal == nil {
		return "", fmt.Errorf("logger %s not found", logger)
	}
	return logVal.GetLevel().String(), nil
}

// Lookup returns a logger instance identified by name from registry
func (lr *logRegistry) Lookup(loggerName string) (logger logging.Logger, found bool) {
	loggerInt, found := lr.loggers.Load(loggerName)
	if !found {
		return nil, false
	}
	logger, ok := loggerInt.(*Logger)
	if ok {
		return logger, found
	}
	panic(fmt.Errorf("cannot cast log value to Logger obj"))
}

// ClearRegistry removes all loggers except the default one from registry
func (lr *logRegistry) ClearRegistry() {
	var wasErr error

	// range over logger map and store keys
	lr.loggers.Range(func(k, v interface{}) bool {
		key, ok := k.(string)
		if !ok {
			wasErr = fmt.Errorf("cannot cast log map key to string")
			// false stops the iteration
			return false
		}
		if key != DefaultLoggerName {
			lr.loggers.Delete(key)
		}
		return true
	})

	if wasErr != nil {
		panic(wasErr)
	}
}

// putLoggerToMapping writes logger into map of named loggers
func (lr *logRegistry) putLoggerToMapping(logger *Logger) {
	lr.loggers.Store(logger.name, logger)
}

// getLoggerFromMapping returns a logger by its name
func (lr *logRegistry) getLoggerFromMapping(logger string) *Logger {
	loggerVal, found := lr.loggers.Load(logger)
	if !found {
		return nil
	}
	log, ok := loggerVal.(*Logger)
	if ok {
		return log
	}
	panic("cannot cast log value to Logger obj")

}
<|endoftext|>


<commit_before>package isolated

import (
	"os"
	"regexp"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("v3-set-droplet command", func() {
	var (
		orgName   string
		spaceName string
		appName   string
	)

	BeforeEach(func() {
		Skip("don't run in the pipeline until cf-deployment master supports it")

		orgName = helpers.NewOrgName()
		spaceName = helpers.NewSpaceName()
		appName = helpers.PrefixedRandomName("app")
	})

	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("v3-set-droplet", "--help")

				Eventually(session.Out).Should(Say("NAME:"))
				Eventually(session.Out).Should(Say("v3-set-droplet - Set the droplet used to run an app"))
				Eventually(session.Out).Should(Say("USAGE:"))
				Eventually(session.Out).Should(Say("cf v3-set-droplet -n APP_NAME -d DROPLET_GUID"))
				Eventually(session.Out).Should(Say("OPTIONS:"))
				Eventually(session.Out).Should(Say("--name, -n\\s+The application name to which to assign the droplet"))
				Eventually(session.Out).Should(Say("--droplet-guid, -d\\s+The guid of the droplet to use"))

				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when no flags are given", func() {
		It("displays incorrect usage", func() {
			session := helpers.CF("v3-set-droplet")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required flags `-d, --droplet-guid' and `-n, --name' were not specified"))
			Eventually(session.Out).Should(Say("NAME:"))

			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the name flag is missing", func() {
		It("displays incorrect usage", func() {
			session := helpers.CF("v3-set-droplet", "--droplet-guid", "some-droplet-guid")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required flag `-n, --name' was not specified"))
			Eventually(session.Out).Should(Say("NAME:"))

			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the package GUID flag is missing", func() {
		It("displays incorrect usage", func() {
			session := helpers.CF("v3-set-droplet", "--name", "some-app")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required flag `-d, --droplet-guid' was not specified"))
			Eventually(session.Out).Should(Say("NAME:"))

			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set\\. Use 'cf login' or 'cf api' to target an endpoint\\."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in\\. Use 'cf login' to log in\\."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no org set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
			})

			It("fails with no org targeted error message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org\\."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
				helpers.TargetOrg(ReadOnlyOrg)
			})

			It("fails with no space targeted error message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space\\."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		BeforeEach(func() {
			setupCF(orgName, spaceName)
		})

		FContext("when the app exists", func() {
			var dropletGUID string

			BeforeEach(func() {
				var packageGUID string
				Eventually(helpers.CF("v3-create-app", "--name", appName)).Should(Exit(0))

				prevDir, err := os.Getwd()
				Expect(err).ToNot(HaveOccurred())

				helpers.WithHelloWorldApp(func(appDir string) {
					err := os.Chdir(appDir)
					Expect(err).ToNot(HaveOccurred())

					pkgSession := helpers.CF("v3-create-package", "--name", appName)
					Eventually(pkgSession).Should(Exit(0))
					regex, err := regexp.Compile(`package guid: (.+)`)
					Expect(err).ToNot(HaveOccurred())
					matches := regex.FindStringSubmatch(string(pkgSession.Out.Contents()))
					Expect(matches).To(HaveLen(2))

					packageGUID = matches[1]
				})

				err = os.Chdir(prevDir)
				Expect(err).ToNot(HaveOccurred())

				stageSession := helpers.CF("v3-stage", "--name", appName, "--package-guid", packageGUID)
				Eventually(stageSession).Should(Exit(0))

				regex, err := regexp.Compile(`droplet: (.+)`)
				Expect(err).ToNot(HaveOccurred())
				matches := regex.FindStringSubmatch(string(stageSession.Out.Contents()))
				Expect(matches).To(HaveLen(2))

				dropletGUID = matches[1]
			})

			It("sets the droplet for the app", func() {
				userName, _ := helpers.GetCredentials()

				session := helpers.CF("v3-set-droplet", "-n", appName, "-d", dropletGUID)
				Eventually(session.Out).Should(Say("Setting app %s to droplet %s in org %s / space %s as %s\\.\\.\\.", appName, dropletGUID, orgName, spaceName, userName))
				Eventually(session.Out).Should(Say("OK"))

				Eventually(session).Should(Exit(0))
			})

			Context("when the app does not exist", func() {
				It("displays app not found and exits 1", func() {
					invalidAppName := "invalid-app-name"
					session := helpers.CF("v3-set-droplet", "-n", invalidAppName, "-d", dropletGUID)
					userName, _ := helpers.GetCredentials()

					Eventually(session.Out).Should(Say("Setting app %s to droplet %s in org %s / space %s as %s\\.\\.\\.", invalidAppName, dropletGUID, orgName, spaceName, userName))
					Eventually(session.Err).Should(Say("App %s not found", invalidAppName))
					Eventually(session.Out).Should(Say("FAILED"))

					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the droplet does not exist", func() {
				It("displays droplet not found and exits 1", func() {
					invalidDropletGUID := "some-droplet-guid"
					session := helpers.CF("v3-set-droplet", "-n", appName, "-d", invalidDropletGUID)
					userName, _ := helpers.GetCredentials()

					Eventually(session.Out).Should(Say("Setting app %s to droplet %s in org %s / space %s as %s\\.\\.\\.", appName, invalidDropletGUID, orgName, spaceName, userName))
					Eventually(session.Err).Should(Say("Unable to assign current droplet\\. Ensure the droplet exists and belongs to this app\\."))
					Eventually(session.Out).Should(Say("FAILED"))
					Eventually(session).Should(Exit(1))
				})
			})
		})
	})
})
<commit_msg>remove focus<commit_after>package isolated

import (
	"os"
	"regexp"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("v3-set-droplet command", func() {
	var (
		orgName   string
		spaceName string
		appName   string
	)

	BeforeEach(func() {
		Skip("don't run in the pipeline until cf-deployment master supports it")

		orgName = helpers.NewOrgName()
		spaceName = helpers.NewSpaceName()
		appName = helpers.PrefixedRandomName("app")
	})

	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("v3-set-droplet", "--help")

				Eventually(session.Out).Should(Say("NAME:"))
				Eventually(session.Out).Should(Say("v3-set-droplet - Set the droplet used to run an app"))
				Eventually(session.Out).Should(Say("USAGE:"))
				Eventually(session.Out).Should(Say("cf v3-set-droplet -n APP_NAME -d DROPLET_GUID"))
				Eventually(session.Out).Should(Say("OPTIONS:"))
				Eventually(session.Out).Should(Say("--name, -n\\s+The application name to which to assign the droplet"))
				Eventually(session.Out).Should(Say("--droplet-guid, -d\\s+The guid of the droplet to use"))

				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when no flags are given", func() {
		It("displays incorrect usage", func() {
			session := helpers.CF("v3-set-droplet")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required flags `-d, --droplet-guid' and `-n, --name' were not specified"))
			Eventually(session.Out).Should(Say("NAME:"))

			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the name flag is missing", func() {
		It("displays incorrect usage", func() {
			session := helpers.CF("v3-set-droplet", "--droplet-guid", "some-droplet-guid")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required flag `-n, --name' was not specified"))
			Eventually(session.Out).Should(Say("NAME:"))

			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the package GUID flag is missing", func() {
		It("displays incorrect usage", func() {
			session := helpers.CF("v3-set-droplet", "--name", "some-app")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required flag `-d, --droplet-guid' was not specified"))
			Eventually(session.Out).Should(Say("NAME:"))

			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set\\. Use 'cf login' or 'cf api' to target an endpoint\\."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in\\. Use 'cf login' to log in\\."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no org set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
			})

			It("fails with no org targeted error message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org\\."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
				helpers.TargetOrg(ReadOnlyOrg)
			})

			It("fails with no space targeted error message", func() {
				session := helpers.CF("v3-set-droplet", "--name", appName, "--droplet-guid", "some-droplet-guid")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space\\."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		BeforeEach(func() {
			setupCF(orgName, spaceName)
		})

		Context("when the app exists", func() {
			var dropletGUID string

			BeforeEach(func() {
				var packageGUID string
				Eventually(helpers.CF("v3-create-app", "--name", appName)).Should(Exit(0))

				prevDir, err := os.Getwd()
				Expect(err).ToNot(HaveOccurred())

				helpers.WithHelloWorldApp(func(appDir string) {
					err := os.Chdir(appDir)
					Expect(err).ToNot(HaveOccurred())

					pkgSession := helpers.CF("v3-create-package", "--name", appName)
					Eventually(pkgSession).Should(Exit(0))
					regex, err := regexp.Compile(`package guid: (.+)`)
					Expect(err).ToNot(HaveOccurred())
					matches := regex.FindStringSubmatch(string(pkgSession.Out.Contents()))
					Expect(matches).To(HaveLen(2))

					packageGUID = matches[1]
				})

				err = os.Chdir(prevDir)
				Expect(err).ToNot(HaveOccurred())

				stageSession := helpers.CF("v3-stage", "--name", appName, "--package-guid", packageGUID)
				Eventually(stageSession).Should(Exit(0))

				regex, err := regexp.Compile(`droplet: (.+)`)
				Expect(err).ToNot(HaveOccurred())
				matches := regex.FindStringSubmatch(string(stageSession.Out.Contents()))
				Expect(matches).To(HaveLen(2))

				dropletGUID = matches[1]
			})

			It("sets the droplet for the app", func() {
				userName, _ := helpers.GetCredentials()

				session := helpers.CF("v3-set-droplet", "-n", appName, "-d", dropletGUID)
				Eventually(session.Out).Should(Say("Setting app %s to droplet %s in org %s / space %s as %s\\.\\.\\.", appName, dropletGUID, orgName, spaceName, userName))
				Eventually(session.Out).Should(Say("OK"))

				Eventually(session).Should(Exit(0))
			})

			Context("when the app does not exist", func() {
				It("displays app not found and exits 1", func() {
					invalidAppName := "invalid-app-name"
					session := helpers.CF("v3-set-droplet", "-n", invalidAppName, "-d", dropletGUID)
					userName, _ := helpers.GetCredentials()

					Eventually(session.Out).Should(Say("Setting app %s to droplet %s in org %s / space %s as %s\\.\\.\\.", invalidAppName, dropletGUID, orgName, spaceName, userName))
					Eventually(session.Err).Should(Say("App %s not found", invalidAppName))
					Eventually(session.Out).Should(Say("FAILED"))

					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the droplet does not exist", func() {
				It("displays droplet not found and exits 1", func() {
					invalidDropletGUID := "some-droplet-guid"
					session := helpers.CF("v3-set-droplet", "-n", appName, "-d", invalidDropletGUID)
					userName, _ := helpers.GetCredentials()

					Eventually(session.Out).Should(Say("Setting app %s to droplet %s in org %s / space %s as %s\\.\\.\\.", appName, invalidDropletGUID, orgName, spaceName, userName))
					Eventually(session.Err).Should(Say("Unable to assign current droplet\\. Ensure the droplet exists and belongs to this app\\."))
					Eventually(session.Out).Should(Say("FAILED"))
					Eventually(session).Should(Exit(1))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>// +build linux,cgo,!agent

package db

import (
	"database/sql"
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/suite"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

const fixtures string = `
    INSERT INTO instances (node_id, name, architecture, type, project_id) VALUES (1, 'thename', 1, 1, 1);
    INSERT INTO profiles (name, project_id) VALUES ('theprofile', 1);
    INSERT INTO instances_profiles (instance_id, profile_id) VALUES (1, 2);
    INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'thekey', 'thevalue');
    INSERT INTO instances_devices (instance_id, name, type) VALUES (1, 'somename', 1);
    INSERT INTO instances_devices_config (key, value, instance_device_id) VALUES ('configkey', 'configvalue', 1);
    INSERT INTO images (fingerprint, filename, size, architecture, creation_date, expiry_date, upload_date, auto_update, project_id) VALUES ('fingerprint', 'filename', 1024, 0,  1431547174,  1431547175,  1431547176, 1, 1);
    INSERT INTO images_aliases (name, image_id, description, project_id) VALUES ('somealias', 1, 'some description', 1);
    INSERT INTO images_properties (image_id, type, key, value) VALUES (1, 0, 'thekey', 'some value');
    INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'thekey', 'thevalue');
    INSERT INTO profiles_devices (profile_id, name, type) VALUES (2, 'devicename', 1);
    INSERT INTO profiles_devices_config (profile_device_id, key, value) VALUES (1, 'devicekey', 'devicevalue');
    `

type dbTestSuite struct {
	suite.Suite

	dir     string
	db      *Cluster
	cleanup func()
}

func (s *dbTestSuite) SetupTest() {
	s.db, s.cleanup = s.CreateTestDb()

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err := tx.Exec(fixtures)
	s.Nil(err)
}

func (s *dbTestSuite) TearDownTest() {
	s.cleanup()
}

// Initialize a test in-memory DB.
func (s *dbTestSuite) CreateTestDb() (*Cluster, func()) {
	var err error

	// Setup logging if main() hasn't been called/when testing
	if logger.Log == nil {
		logger.Log, err = logging.GetLogger("", "", true, true, nil)
		s.Nil(err)
	}

	db, cleanup := NewTestCluster(s.T().(*testing.T))
	return db, cleanup
}

// Enter a transaction on the test in-memory DB.
func (s *dbTestSuite) CreateTestTx() (*sql.Tx, func()) {
	tx, err := s.db.DB().Begin()
	s.Nil(err)
	commit := func() {
		s.Nil(tx.Commit())
	}
	return tx, commit
}

func TestDBTestSuite(t *testing.T) {
	suite.Run(t, new(dbTestSuite))
}

func (s *dbTestSuite) Test_deleting_a_container_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the container we just created.
	statements = `DELETE FROM instances WHERE name = 'thename';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err, "Error deleting container!")

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the profile association!")

	// Make sure there are 0 containers_config entries left.
	statements = `SELECT count(*) FROM instances_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_config!")

	// Make sure there are 0 containers_devices entries left.
	statements = `SELECT count(*) FROM instances_devices;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices!")

	// Make sure there are 0 containers_devices_config entries left.
	statements = `SELECT count(*) FROM instances_devices_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices_config!")
}

func (s *dbTestSuite) Test_deleting_a_profile_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the profile we just created.
	statements = `DELETE FROM profiles WHERE name = 'theprofile';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles WHERE profile_id = 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the container association!")

	// Make sure there are 0 profiles_devices entries left.
	statements = `SELECT count(*) FROM profiles_devices WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices!")

	// Make sure there are 0 profiles_config entries left.
	statements = `SELECT count(*) FROM profiles_config WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_config! There are %d left")

	// Make sure there are 0 profiles_devices_config entries left.
	statements = `SELECT count(*) FROM profiles_devices_config WHERE profile_device_id == 3;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices_config!")
}

func (s *dbTestSuite) Test_deleting_an_image_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the image we just created.
	statements = `DELETE FROM images;`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)
	// Make sure there are 0 images_aliases entries left.
	statements = `SELECT count(*) FROM images_aliases;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the image alias association!")

	// Make sure there are 0 images_properties entries left.
	statements = `SELECT count(*) FROM images_properties;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the related images_properties!")
}

func (s *dbTestSuite) Test_ImageGet_finds_image_for_fingerprint() {
	var err error
	var result *api.Image

	_, result, err = s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)
	s.NotNil(result)
	s.Equal(result.Filename, "filename")
	s.Equal(result.CreatedAt.UTC(), time.Unix(1431547174, 0).UTC())
	s.Equal(result.ExpiresAt.UTC(), time.Unix(1431547175, 0).UTC())
	s.Equal(result.UploadedAt.UTC(), time.Unix(1431547176, 0).UTC())
}

func (s *dbTestSuite) Test_ImageGet_for_missing_fingerprint() {
	var err error

	_, _, err = s.db.ImageGet("default", "unknown", false, false)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageExists_true() {
	var err error

	exists, err := s.db.ImageExists("default", "fingerprint")
	s.Nil(err)
	s.True(exists)
}

func (s *dbTestSuite) Test_ImageExists_false() {
	var err error

	exists, err := s.db.ImageExists("default", "foobar")
	s.Nil(err)
	s.False(exists)
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_exists() {
	var err error

	_, alias, err := s.db.ImageAliasGet("default", "somealias", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_does_not_exists() {
	var err error

	_, _, err = s.db.ImageAliasGet("default", "whatever", true)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageAliasAdd() {
	var err error

	err = s.db.ImageAliasAdd("default", "Chaosphere", 1, "Someone will like the name")
	s.Nil(err)

	_, alias, err := s.db.ImageAliasGet("default", "Chaosphere", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	fingerprint, err := s.db.ImageSourceGetCachedFingerprint("server.remote", "simplestreams", "test", "container", 0)
	s.Nil(err)
	s.Equal(fingerprint, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint_no_match() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	_, err = s.db.ImageSourceGetCachedFingerprint("server.remote", "lxd", "test", "container", 0)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ContainerConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ContainerConfig(1)
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_dbProfileConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ProfileConfig("default", "theprofile")
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_ContainerProfiles() {
	var err error
	var result []string
	var expected []string

	expected = []string{"theprofile"}
	result, err = s.db.ContainerProfiles(1)
	s.Nil(err)

	for i := range expected {
		s.Equal(expected[i], result[i],
			fmt.Sprintf("Mismatching contents for profile list: %s != %s", result[i], expected[i]))
	}
}

func (s *dbTestSuite) Test_dbDevices_profiles() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "theprofile", true)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "devicekey": "devicevalue"}
	subresult = result["devicename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %v != %v", key, subresult[key], value))
	}
}

func (s *dbTestSuite) Test_dbDevices_containers() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "thename", false)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "configkey": "configvalue"}
	subresult = result["somename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, subresult[key], value))
	}
}
<commit_msg>lxd/db: Revert 3da5aea1 fix, since in turn testify reverted the change<commit_after>// +build linux,cgo,!agent

package db

import (
	"database/sql"
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/suite"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

const fixtures string = `
    INSERT INTO instances (node_id, name, architecture, type, project_id) VALUES (1, 'thename', 1, 1, 1);
    INSERT INTO profiles (name, project_id) VALUES ('theprofile', 1);
    INSERT INTO instances_profiles (instance_id, profile_id) VALUES (1, 2);
    INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'thekey', 'thevalue');
    INSERT INTO instances_devices (instance_id, name, type) VALUES (1, 'somename', 1);
    INSERT INTO instances_devices_config (key, value, instance_device_id) VALUES ('configkey', 'configvalue', 1);
    INSERT INTO images (fingerprint, filename, size, architecture, creation_date, expiry_date, upload_date, auto_update, project_id) VALUES ('fingerprint', 'filename', 1024, 0,  1431547174,  1431547175,  1431547176, 1, 1);
    INSERT INTO images_aliases (name, image_id, description, project_id) VALUES ('somealias', 1, 'some description', 1);
    INSERT INTO images_properties (image_id, type, key, value) VALUES (1, 0, 'thekey', 'some value');
    INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'thekey', 'thevalue');
    INSERT INTO profiles_devices (profile_id, name, type) VALUES (2, 'devicename', 1);
    INSERT INTO profiles_devices_config (profile_device_id, key, value) VALUES (1, 'devicekey', 'devicevalue');
    `

type dbTestSuite struct {
	suite.Suite

	dir     string
	db      *Cluster
	cleanup func()
}

func (s *dbTestSuite) SetupTest() {
	s.db, s.cleanup = s.CreateTestDb()

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err := tx.Exec(fixtures)
	s.Nil(err)
}

func (s *dbTestSuite) TearDownTest() {
	s.cleanup()
}

// Initialize a test in-memory DB.
func (s *dbTestSuite) CreateTestDb() (*Cluster, func()) {
	var err error

	// Setup logging if main() hasn't been called/when testing
	if logger.Log == nil {
		logger.Log, err = logging.GetLogger("", "", true, true, nil)
		s.Nil(err)
	}

	db, cleanup := NewTestCluster(s.T())
	return db, cleanup
}

// Enter a transaction on the test in-memory DB.
func (s *dbTestSuite) CreateTestTx() (*sql.Tx, func()) {
	tx, err := s.db.DB().Begin()
	s.Nil(err)
	commit := func() {
		s.Nil(tx.Commit())
	}
	return tx, commit
}

func TestDBTestSuite(t *testing.T) {
	suite.Run(t, new(dbTestSuite))
}

func (s *dbTestSuite) Test_deleting_a_container_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the container we just created.
	statements = `DELETE FROM instances WHERE name = 'thename';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err, "Error deleting container!")

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the profile association!")

	// Make sure there are 0 containers_config entries left.
	statements = `SELECT count(*) FROM instances_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_config!")

	// Make sure there are 0 containers_devices entries left.
	statements = `SELECT count(*) FROM instances_devices;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices!")

	// Make sure there are 0 containers_devices_config entries left.
	statements = `SELECT count(*) FROM instances_devices_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices_config!")
}

func (s *dbTestSuite) Test_deleting_a_profile_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the profile we just created.
	statements = `DELETE FROM profiles WHERE name = 'theprofile';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles WHERE profile_id = 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the container association!")

	// Make sure there are 0 profiles_devices entries left.
	statements = `SELECT count(*) FROM profiles_devices WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices!")

	// Make sure there are 0 profiles_config entries left.
	statements = `SELECT count(*) FROM profiles_config WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_config! There are %d left")

	// Make sure there are 0 profiles_devices_config entries left.
	statements = `SELECT count(*) FROM profiles_devices_config WHERE profile_device_id == 3;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices_config!")
}

func (s *dbTestSuite) Test_deleting_an_image_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the image we just created.
	statements = `DELETE FROM images;`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)
	// Make sure there are 0 images_aliases entries left.
	statements = `SELECT count(*) FROM images_aliases;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the image alias association!")

	// Make sure there are 0 images_properties entries left.
	statements = `SELECT count(*) FROM images_properties;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the related images_properties!")
}

func (s *dbTestSuite) Test_ImageGet_finds_image_for_fingerprint() {
	var err error
	var result *api.Image

	_, result, err = s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)
	s.NotNil(result)
	s.Equal(result.Filename, "filename")
	s.Equal(result.CreatedAt.UTC(), time.Unix(1431547174, 0).UTC())
	s.Equal(result.ExpiresAt.UTC(), time.Unix(1431547175, 0).UTC())
	s.Equal(result.UploadedAt.UTC(), time.Unix(1431547176, 0).UTC())
}

func (s *dbTestSuite) Test_ImageGet_for_missing_fingerprint() {
	var err error

	_, _, err = s.db.ImageGet("default", "unknown", false, false)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageExists_true() {
	var err error

	exists, err := s.db.ImageExists("default", "fingerprint")
	s.Nil(err)
	s.True(exists)
}

func (s *dbTestSuite) Test_ImageExists_false() {
	var err error

	exists, err := s.db.ImageExists("default", "foobar")
	s.Nil(err)
	s.False(exists)
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_exists() {
	var err error

	_, alias, err := s.db.ImageAliasGet("default", "somealias", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_does_not_exists() {
	var err error

	_, _, err = s.db.ImageAliasGet("default", "whatever", true)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageAliasAdd() {
	var err error

	err = s.db.ImageAliasAdd("default", "Chaosphere", 1, "Someone will like the name")
	s.Nil(err)

	_, alias, err := s.db.ImageAliasGet("default", "Chaosphere", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	fingerprint, err := s.db.ImageSourceGetCachedFingerprint("server.remote", "simplestreams", "test", "container", 0)
	s.Nil(err)
	s.Equal(fingerprint, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint_no_match() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	_, err = s.db.ImageSourceGetCachedFingerprint("server.remote", "lxd", "test", "container", 0)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ContainerConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ContainerConfig(1)
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_dbProfileConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ProfileConfig("default", "theprofile")
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_ContainerProfiles() {
	var err error
	var result []string
	var expected []string

	expected = []string{"theprofile"}
	result, err = s.db.ContainerProfiles(1)
	s.Nil(err)

	for i := range expected {
		s.Equal(expected[i], result[i],
			fmt.Sprintf("Mismatching contents for profile list: %s != %s", result[i], expected[i]))
	}
}

func (s *dbTestSuite) Test_dbDevices_profiles() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "theprofile", true)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "devicekey": "devicevalue"}
	subresult = result["devicename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %v != %v", key, subresult[key], value))
	}
}

func (s *dbTestSuite) Test_dbDevices_containers() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "thename", false)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "configkey": "configvalue"}
	subresult = result["somename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, subresult[key], value))
	}
}
<|endoftext|>


<commit_before>package lxhttpclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gogo/protobuf/proto"
	"github.com/layer-x/layerx-commons/lxerrors"
	"io/ioutil"
	"net/http"
	"strings"
)

var DefaultRetries = 5

type client struct {
	c *http.Client
}

func newClient() *client {
	return &client{
		c: http.DefaultClient,
	}
}

var emptyBytes []byte

func Get(url string, path string, headers map[string]string) (*http.Response, []byte, error) {
	return getWithRetries(url, path, headers, DefaultRetries)
}

func getWithRetries(url string, path string, headers map[string]string, retries int) (*http.Response, []byte, error) {
	resp, respBytes, err := func() (*http.Response, []byte, error) {
		completeURL := parseURL(url, path)
		request, err := http.NewRequest("GET", completeURL, nil)
		if err != nil {
			return nil, emptyBytes, lxerrors.New("error generating get request", err)
		}
		for key, value := range headers {
			request.Header.Add(key, value)
		}
		resp, err := newClient().c.Do(request)
		if err != nil {
			return resp, emptyBytes, lxerrors.New("error performing get request", err)
		}
		respBytes, err := ioutil.ReadAll(resp.Body)
		if resp.Body != nil {
			defer resp.Body.Close()
		}
		if err != nil {
			return resp, emptyBytes, lxerrors.New("error reading get response", err)
		}

		return resp, respBytes, nil
	}()
	if err != nil && retries > 0 {
		return getWithRetries(url, path, headers, retries-1)
	}
	return resp, respBytes, err
}

func Post(url string, path string, headers map[string]string, message interface{}) (*http.Response, []byte, error) {
	return postWithRetries(url, path, headers, message, DefaultRetries)
}

func postWithRetries(url string, path string, headers map[string]string, message interface{}, retries int) (*http.Response, []byte, error) {
	resp, respBytes, err := func() (*http.Response, []byte, error) {
		switch message.(type) {
		case proto.Message:
			return postPB(url, path, headers, message.(proto.Message))
		default:
			_, err := json.Marshal(message)
			if err != nil {
				return nil, emptyBytes, lxerrors.New("message was not of expected type `json` or `protobuf`", err)
			}
			return postJson(url, path, headers, message)
		}
	}()
	if err != nil && retries > 0 {
		return postWithRetries(url, path, headers, message, retries-1)
	}
	return resp, respBytes, err
}

func postPB(url string, path string, headers map[string]string, pb proto.Message) (*http.Response, []byte, error) {
	data, err := proto.Marshal(pb)
	if err != nil {
		return nil, emptyBytes, lxerrors.New("could not proto.Marshal mesasge", err)
	}
	return postData(url, path, headers, data)
}

func postJson(url string, path string, headers map[string]string, jsonStruct interface{}) (*http.Response, []byte, error) {
	//err has already been caught
	data, _ := json.Marshal(jsonStruct)
	return postData(url, path, headers, data)
}

func postData(url string, path string, headers map[string]string, data []byte) (*http.Response, []byte, error) {
	completeURL := parseURL(url, path)
	request, err := http.NewRequest("POST", completeURL, bytes.NewReader(data))
	if err != nil {
		return nil, emptyBytes, lxerrors.New("error generating post request", err)
	}
	for key, value := range headers {
		request.Header.Add(key, value)
	}
	resp, err := newClient().c.Do(request)
	if err != nil {
		return resp, emptyBytes, lxerrors.New("error performing post request", err)
	}
	respBytes, err := ioutil.ReadAll(resp.Body)
	if resp.Body != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return resp, emptyBytes, lxerrors.New("error reading post response", err)
	}

	return resp, respBytes, nil
}

func parseURL(url string, path string) string {
	if !strings.HasPrefix(url, "http://") || !strings.HasPrefix(url, "https://") {
		url = fmt.Sprintf("http://%s", url)
	}
	if strings.HasSuffix(url, "/") {
		url = strings.TrimSuffix(url, "/")
	}
	if strings.HasPrefix(path, "/") {
		path = strings.TrimPrefix(path, "/")
	}
	return fmt.Sprintf("%s/%s", url, path)
}
<commit_msg>add sending byte buffer<commit_after>package lxhttpclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gogo/protobuf/proto"
	"github.com/layer-x/layerx-commons/lxerrors"
	"io/ioutil"
	"net/http"
	"strings"
)

var DefaultRetries = 5

type client struct {
	c *http.Client
}

func newClient() *client {
	return &client{
		c: http.DefaultClient,
	}
}

var emptyBytes []byte

func Get(url string, path string, headers map[string]string) (*http.Response, []byte, error) {
	return getWithRetries(url, path, headers, DefaultRetries)
}

func getWithRetries(url string, path string, headers map[string]string, retries int) (*http.Response, []byte, error) {
	resp, respBytes, err := func() (*http.Response, []byte, error) {
		completeURL := parseURL(url, path)
		request, err := http.NewRequest("GET", completeURL, nil)
		if err != nil {
			return nil, emptyBytes, lxerrors.New("error generating get request", err)
		}
		for key, value := range headers {
			request.Header.Add(key, value)
		}
		resp, err := newClient().c.Do(request)
		if err != nil {
			return resp, emptyBytes, lxerrors.New("error performing get request", err)
		}
		respBytes, err := ioutil.ReadAll(resp.Body)
		if resp.Body != nil {
			defer resp.Body.Close()
		}
		if err != nil {
			return resp, emptyBytes, lxerrors.New("error reading get response", err)
		}

		return resp, respBytes, nil
	}()
	if err != nil && retries > 0 {
		return getWithRetries(url, path, headers, retries-1)
	}
	return resp, respBytes, err
}

func Post(url string, path string, headers map[string]string, message interface{}) (*http.Response, []byte, error) {
	return postWithRetries(url, path, headers, message, DefaultRetries)
}

func postWithRetries(url string, path string, headers map[string]string, message interface{}, retries int) (*http.Response, []byte, error) {
	resp, respBytes, err := func() (*http.Response, []byte, error) {
		switch message.(type) {
		case proto.Message:
			return postPB(url, path, headers, message.(proto.Message))
		case *bytes.Buffer:
			return postBuffer(url, path, headers, message.(*bytes.Buffer))
		default:
			_, err := json.Marshal(message)
			if err != nil {
				return nil, emptyBytes, lxerrors.New("message was not of expected type `json` or `protobuf`", err)
			}
			return postJson(url, path, headers, message)
		}
	}()
	if err != nil && retries > 0 {
		return postWithRetries(url, path, headers, message, retries-1)
	}
	return resp, respBytes, err
}

func postPB(url string, path string, headers map[string]string, pb proto.Message) (*http.Response, []byte, error) {
	data, err := proto.Marshal(pb)
	if err != nil {
		return nil, emptyBytes, lxerrors.New("could not proto.Marshal mesasge", err)
	}
	return postData(url, path, headers, data)
}

func postBuffer(url string, path string, headers map[string]string, buffer *bytes.Buffer) (*http.Response, []byte, error) {
	completeURL := parseURL(url, path)
	request, err := http.NewRequest("POST", completeURL, buffer)
	if err != nil {
		return nil, emptyBytes, lxerrors.New("error generating post request", err)
	}
	for key, value := range headers {
		request.Header.Add(key, value)
	}
	resp, err := newClient().c.Do(request)
	if err != nil {
		return resp, emptyBytes, lxerrors.New("error performing post request", err)
	}
	respBytes, err := ioutil.ReadAll(resp.Body)
	if resp.Body != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return resp, emptyBytes, lxerrors.New("error reading post response", err)
	}

	return resp, respBytes, nil
}

func postJson(url string, path string, headers map[string]string, jsonStruct interface{}) (*http.Response, []byte, error) {
	//err has already been caught
	data, _ := json.Marshal(jsonStruct)
	return postData(url, path, headers, data)
}

func postData(url string, path string, headers map[string]string, data []byte) (*http.Response, []byte, error) {
	completeURL := parseURL(url, path)
	request, err := http.NewRequest("POST", completeURL, bytes.NewReader(data))
	if err != nil {
		return nil, emptyBytes, lxerrors.New("error generating post request", err)
	}
	for key, value := range headers {
		request.Header.Add(key, value)
	}
	resp, err := newClient().c.Do(request)
	if err != nil {
		return resp, emptyBytes, lxerrors.New("error performing post request", err)
	}
	respBytes, err := ioutil.ReadAll(resp.Body)
	if resp.Body != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return resp, emptyBytes, lxerrors.New("error reading post response", err)
	}

	return resp, respBytes, nil
}

func parseURL(url string, path string) string {
	if !strings.HasPrefix(url, "http://") || !strings.HasPrefix(url, "https://") {
		url = fmt.Sprintf("http://%s", url)
	}
	if strings.HasSuffix(url, "/") {
		url = strings.TrimSuffix(url, "/")
	}
	if strings.HasPrefix(path, "/") {
		path = strings.TrimPrefix(path, "/")
	}
	return fmt.Sprintf("%s/%s", url, path)
}
<|endoftext|>


<commit_before>package timeout

import "time"

type Timeout interface {
	Reset() bool
	Cancel() bool
}

type responseChanType chan bool
type controlChanType chan responseChanType

type timeout struct {
	resetChan  controlChanType
	cancelChan controlChanType
}

// New creates a Timeout, which calls timeoutFunc after duration.
// It can be reset or cancelled.
func New(duration time.Duration, timeoutFunc func()) Timeout {
	timeout := &timeout{
		resetChan:  make(controlChanType),
		cancelChan: make(controlChanType),
	}

	go func() {
	ActiveLoop:
		for {
			select {
			case <-time.After(duration):
				timeoutFunc()
				break ActiveLoop
			case responseChan := <-timeout.resetChan:
				responseChan <- true
			case responseChan := <-timeout.cancelChan:
				responseChan <- true
				break ActiveLoop
			}
		}

		// now that the timeout has been triggered or cancelled, Reset and Cancel will be returning false
		for {
			select {
			case responseChan := <-timeout.resetChan:
				responseChan <- false
			case responseChan := <-timeout.cancelChan:
				responseChan <- false
			}
		}
	}()

	return timeout
}

func (self *timeout) Reset() bool {
	responseChan := make(responseChanType)

	self.resetChan <- responseChan

	return <-responseChan
}

func (self *timeout) Cancel() bool {
	responseChan := make(responseChanType)

	self.cancelChan <- responseChan

	return <-responseChan
}
<commit_msg>Fix golint errors for timeout.go<commit_after>package timeout

import "time"

// Timeout is an interface for objects that facilitate managing active timeouts, allowing resetting and canceling
type Timeout interface {
	Reset() bool
	Cancel() bool
}

type responseChanType chan bool
type controlChanType chan responseChanType

type timeout struct {
	resetChan  controlChanType
	cancelChan controlChanType
}

// New creates a Timeout, which calls timeoutFunc after duration.
// It can be reset or cancelled.
func New(duration time.Duration, timeoutFunc func()) Timeout {
	timeout := &timeout{
		resetChan:  make(controlChanType),
		cancelChan: make(controlChanType),
	}

	go func() {
	ActiveLoop:
		for {
			select {
			case <-time.After(duration):
				timeoutFunc()
				break ActiveLoop
			case responseChan := <-timeout.resetChan:
				responseChan <- true
			case responseChan := <-timeout.cancelChan:
				responseChan <- true
				break ActiveLoop
			}
		}

		// now that the timeout has been triggered or cancelled, Reset and Cancel will be returning false
		for {
			select {
			case responseChan := <-timeout.resetChan:
				responseChan <- false
			case responseChan := <-timeout.cancelChan:
				responseChan <- false
			}
		}
	}()

	return timeout
}

func (t *timeout) Reset() bool {
	responseChan := make(responseChanType)

	t.resetChan <- responseChan

	return <-responseChan
}

func (t *timeout) Cancel() bool {
	responseChan := make(responseChanType)

	t.cancelChan <- responseChan

	return <-responseChan
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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 collector handles the command-line, configuration, and runs the OC collector.
package service

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"syscall"
	"testing"

	"github.com/prometheus/common/expfmt"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.opentelemetry.io/otel/trace"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/config/configparser"
	"go.opentelemetry.io/collector/config/configunmarshaler"
	"go.opentelemetry.io/collector/internal/testutil"
	"go.opentelemetry.io/collector/service/defaultcomponents"
	"go.opentelemetry.io/collector/service/internal/builder"
	"go.opentelemetry.io/collector/service/parserprovider"
)

func TestCollector_Start(t *testing.T) {
	factories, err := defaultcomponents.Components()
	require.NoError(t, err)

	loggingHookCalled := false
	hook := func(entry zapcore.Entry) error {
		loggingHookCalled = true
		return nil
	}

	col, err := New(CollectorSettings{
		BuildInfo:      component.DefaultBuildInfo(),
		Factories:      factories,
		LoggingOptions: []zap.Option{zap.Hooks(hook)},
	})
	require.NoError(t, err)

	const testPrefix = "a_test"
	metricsPort := testutil.GetAvailablePort(t)
	cmd := NewCommand(col)
	cmd.SetArgs([]string{
		"--config=testdata/otelcol-config.yaml",
		"--metrics-addr=localhost:" + strconv.FormatUint(uint64(metricsPort), 10),
		"--metrics-prefix=" + testPrefix,
	})

	colDone := make(chan struct{})
	go func() {
		defer close(colDone)
		assert.NoError(t, cmd.Execute())
	}()

	assert.Equal(t, Starting, <-col.GetStateChannel())
	assert.Equal(t, Running, <-col.GetStateChannel())
	assert.Equal(t, col.logger, col.GetLogger())
	assert.True(t, loggingHookCalled)

	// All labels added to all collector metrics by default are listed below.
	// These labels are hard coded here in order to avoid inadvertent changes:
	// at this point changing labels should be treated as a breaking changing
	// and requires a good justification. The reason is that changes to metric
	// names or labels can break alerting, dashboards, etc that are used to
	// monitor the Collector in production deployments.
	mandatoryLabels := []string{
		"service_instance_id",
	}
	assertMetrics(t, testPrefix, metricsPort, mandatoryLabels)

	assertZPages(t)

	// Trigger another configuration load.
	require.NoError(t, col.reloadService(context.Background()))

	col.signalsChannel <- syscall.SIGTERM
	<-colDone
	assert.Equal(t, Closing, <-col.GetStateChannel())
	assert.Equal(t, Closed, <-col.GetStateChannel())
}

type mockColTelemetry struct{}

func (tel *mockColTelemetry) init(chan<- error, uint64, *zap.Logger) error {
	return nil
}

func (tel *mockColTelemetry) shutdown() error {
	return errors.New("err1")
}

func TestCollector_ReportError(t *testing.T) {
	// use a mock AppTelemetry struct to return an error on shutdown
	preservedAppTelemetry := collectorTelemetry
	collectorTelemetry = &mockColTelemetry{}
	defer func() { collectorTelemetry = preservedAppTelemetry }()

	factories, err := defaultcomponents.Components()
	require.NoError(t, err)

	col, err := New(CollectorSettings{BuildInfo: component.DefaultBuildInfo(), Factories: factories})
	require.NoError(t, err)

	cmd := NewCommand(col)
	cmd.SetArgs([]string{"--config=testdata/otelcol-config-minimal.yaml"})

	colDone := make(chan struct{})
	go func() {
		defer close(colDone)
		assert.EqualError(t, cmd.Execute(), "failed to shutdown collector telemetry: err1")
	}()

	assert.Equal(t, Starting, <-col.GetStateChannel())
	assert.Equal(t, Running, <-col.GetStateChannel())
	col.service.ReportFatalError(errors.New("err2"))
	<-colDone
	assert.Equal(t, Closing, <-col.GetStateChannel())
	assert.Equal(t, Closed, <-col.GetStateChannel())
}

func TestCollector_StartAsGoRoutine(t *testing.T) {
	factories, err := defaultcomponents.Components()
	require.NoError(t, err)

	set := CollectorSettings{
		BuildInfo:      component.DefaultBuildInfo(),
		Factories:      factories,
		ParserProvider: new(minimalParserLoader),
	}
	col, err := New(set)
	require.NoError(t, err)

	colDone := make(chan struct{})
	go func() {
		defer close(colDone)
		colErr := col.Run(context.Background())
		if colErr != nil {
			err = colErr
		}
	}()

	assert.Equal(t, Starting, <-col.GetStateChannel())
	assert.Equal(t, Running, <-col.GetStateChannel())

	col.Shutdown()
	col.Shutdown()
	<-colDone
	assert.Equal(t, Closing, <-col.GetStateChannel())
	assert.Equal(t, Closed, <-col.GetStateChannel())
}

func assertMetrics(t *testing.T, prefix string, metricsPort uint16, mandatoryLabels []string) {
	client := &http.Client{}
	resp, err := client.Get(fmt.Sprintf("http://localhost:%d/metrics", metricsPort))
	require.NoError(t, err)

	defer resp.Body.Close()
	reader := bufio.NewReader(resp.Body)

	var parser expfmt.TextParser
	parsed, err := parser.TextToMetricFamilies(reader)
	require.NoError(t, err)

	for metricName, metricFamily := range parsed {
		// require is used here so test fails with a single message.
		require.True(
			t,
			strings.HasPrefix(metricName, prefix),
			"expected prefix %q but string starts with %q",
			prefix,
			metricName[:len(prefix)+1]+"...")

		for _, metric := range metricFamily.Metric {
			var labelNames []string
			for _, labelPair := range metric.Label {
				labelNames = append(labelNames, *labelPair.Name)
			}

			for _, mandatoryLabel := range mandatoryLabels {
				// require is used here so test fails with a single message.
				require.Contains(t, labelNames, mandatoryLabel, "mandatory label %q not present", mandatoryLabel)
			}
		}
	}
}

func assertZPages(t *testing.T) {
	paths := []string{
		"/debug/tracez",
		// TODO: enable this when otel-metrics is used and this page is available.
		// "/debug/rpcz",
		"/debug/pipelinez",
		"/debug/servicez",
		"/debug/extensionz",
	}

	const defaultZPagesPort = "55679"

	testZPagePathFn := func(t *testing.T, path string) {
		client := &http.Client{}
		resp, err := client.Get("http://localhost:" + defaultZPagesPort + path)
		if !assert.NoError(t, err, "error retrieving zpage at %q", path) {
			return
		}
		assert.Equal(t, http.StatusOK, resp.StatusCode, "unsuccessful zpage %q GET", path)
		assert.NoError(t, resp.Body.Close())
	}

	for _, path := range paths {
		testZPagePathFn(t, path)
	}
}

type minimalParserLoader struct{}

func (*minimalParserLoader) Get(context.Context) (*configparser.ConfigMap, error) {
	configStr := `
receivers:
  otlp:
    protocols:
      grpc:

exporters:
  otlp:
    endpoint: "localhost:4317"

processors:
  batch:

extensions:

service:
  extensions:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp]
`
	return configparser.NewConfigMapFromBuffer(strings.NewReader(configStr))
}

func (*minimalParserLoader) Close(context.Context) error {
	return nil
}

type errParserLoader struct {
	err error
}

func (epl *errParserLoader) Get(context.Context) (*configparser.ConfigMap, error) {
	return nil, epl.err
}

func (epl *errParserLoader) Close(context.Context) error {
	return nil
}

func TestCollector_reloadService(t *testing.T) {
	factories, err := defaultcomponents.Components()
	require.NoError(t, err)
	ctx := context.Background()
	sentinelError := errors.New("sentinel error")

	tests := []struct {
		name           string
		parserProvider parserprovider.ParserProvider
		service        *service
	}{
		{
			name:           "first_load_err",
			parserProvider: &errParserLoader{err: sentinelError},
		},
		{
			name:           "retire_service_ok_load_err",
			parserProvider: &errParserLoader{err: sentinelError},
			service: &service{
				logger:          zap.NewNop(),
				builtExporters:  builder.Exporters{},
				builtPipelines:  builder.BuiltPipelines{},
				builtReceivers:  builder.Receivers{},
				builtExtensions: builder.Extensions{},
			},
		},
		{
			name:           "retire_service_ok_load_ok",
			parserProvider: new(minimalParserLoader),
			service: &service{
				logger:          zap.NewNop(),
				builtExporters:  builder.Exporters{},
				builtPipelines:  builder.BuiltPipelines{},
				builtReceivers:  builder.Receivers{},
				builtExtensions: builder.Extensions{},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			col := Collector{
				set: CollectorSettings{
					ParserProvider:    tt.parserProvider,
					ConfigUnmarshaler: configunmarshaler.NewDefault(),
					Factories:         factories,
				},
				logger:         zap.NewNop(),
				tracerProvider: trace.NewNoopTracerProvider(),
				service:        tt.service,
			}

			err := col.reloadService(ctx)

			if err != nil {
				assert.ErrorIs(t, err, sentinelError)
				return
			}

			// If successful need to shutdown active service.
			assert.NoError(t, col.service.Shutdown(ctx))
		})
	}
}
<commit_msg>Use in-memory provider instead of custom provider (#4089)<commit_after>// Copyright The OpenTelemetry 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 collector handles the command-line, configuration, and runs the OC collector.
package service

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"syscall"
	"testing"

	"github.com/prometheus/common/expfmt"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.opentelemetry.io/otel/trace"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/config/configparser"
	"go.opentelemetry.io/collector/config/configunmarshaler"
	"go.opentelemetry.io/collector/internal/testutil"
	"go.opentelemetry.io/collector/service/defaultcomponents"
	"go.opentelemetry.io/collector/service/internal/builder"
	"go.opentelemetry.io/collector/service/parserprovider"
)

const configStr = `
receivers:
  otlp:
    protocols:
      grpc:
exporters:
  otlp:
    endpoint: "localhost:4317"
processors:
  batch:
extensions:
service:
  extensions:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp]
`

func TestCollector_Start(t *testing.T) {
	factories, err := defaultcomponents.Components()
	require.NoError(t, err)

	loggingHookCalled := false
	hook := func(entry zapcore.Entry) error {
		loggingHookCalled = true
		return nil
	}

	col, err := New(CollectorSettings{
		BuildInfo:      component.DefaultBuildInfo(),
		Factories:      factories,
		LoggingOptions: []zap.Option{zap.Hooks(hook)},
	})
	require.NoError(t, err)

	const testPrefix = "a_test"
	metricsPort := testutil.GetAvailablePort(t)
	cmd := NewCommand(col)
	cmd.SetArgs([]string{
		"--config=testdata/otelcol-config.yaml",
		"--metrics-addr=localhost:" + strconv.FormatUint(uint64(metricsPort), 10),
		"--metrics-prefix=" + testPrefix,
	})

	colDone := make(chan struct{})
	go func() {
		defer close(colDone)
		assert.NoError(t, cmd.Execute())
	}()

	assert.Equal(t, Starting, <-col.GetStateChannel())
	assert.Equal(t, Running, <-col.GetStateChannel())
	assert.Equal(t, col.logger, col.GetLogger())
	assert.True(t, loggingHookCalled)

	// All labels added to all collector metrics by default are listed below.
	// These labels are hard coded here in order to avoid inadvertent changes:
	// at this point changing labels should be treated as a breaking changing
	// and requires a good justification. The reason is that changes to metric
	// names or labels can break alerting, dashboards, etc that are used to
	// monitor the Collector in production deployments.
	mandatoryLabels := []string{
		"service_instance_id",
	}
	assertMetrics(t, testPrefix, metricsPort, mandatoryLabels)

	assertZPages(t)

	// Trigger another configuration load.
	require.NoError(t, col.reloadService(context.Background()))

	col.signalsChannel <- syscall.SIGTERM
	<-colDone
	assert.Equal(t, Closing, <-col.GetStateChannel())
	assert.Equal(t, Closed, <-col.GetStateChannel())
}

type mockColTelemetry struct{}

func (tel *mockColTelemetry) init(chan<- error, uint64, *zap.Logger) error {
	return nil
}

func (tel *mockColTelemetry) shutdown() error {
	return errors.New("err1")
}

func TestCollector_ReportError(t *testing.T) {
	// use a mock AppTelemetry struct to return an error on shutdown
	preservedAppTelemetry := collectorTelemetry
	collectorTelemetry = &mockColTelemetry{}
	defer func() { collectorTelemetry = preservedAppTelemetry }()

	factories, err := defaultcomponents.Components()
	require.NoError(t, err)

	col, err := New(CollectorSettings{BuildInfo: component.DefaultBuildInfo(), Factories: factories})
	require.NoError(t, err)

	cmd := NewCommand(col)
	cmd.SetArgs([]string{"--config=testdata/otelcol-config-minimal.yaml"})

	colDone := make(chan struct{})
	go func() {
		defer close(colDone)
		assert.EqualError(t, cmd.Execute(), "failed to shutdown collector telemetry: err1")
	}()

	assert.Equal(t, Starting, <-col.GetStateChannel())
	assert.Equal(t, Running, <-col.GetStateChannel())
	col.service.ReportFatalError(errors.New("err2"))
	<-colDone
	assert.Equal(t, Closing, <-col.GetStateChannel())
	assert.Equal(t, Closed, <-col.GetStateChannel())
}

func TestCollector_StartAsGoRoutine(t *testing.T) {
	factories, err := defaultcomponents.Components()
	require.NoError(t, err)

	set := CollectorSettings{
		BuildInfo:      component.DefaultBuildInfo(),
		Factories:      factories,
		ParserProvider: parserprovider.NewInMemory(strings.NewReader(configStr)),
	}
	col, err := New(set)
	require.NoError(t, err)

	colDone := make(chan struct{})
	go func() {
		defer close(colDone)
		colErr := col.Run(context.Background())
		if colErr != nil {
			err = colErr
		}
	}()

	assert.Equal(t, Starting, <-col.GetStateChannel())
	assert.Equal(t, Running, <-col.GetStateChannel())

	col.Shutdown()
	col.Shutdown()
	<-colDone
	assert.Equal(t, Closing, <-col.GetStateChannel())
	assert.Equal(t, Closed, <-col.GetStateChannel())
}

func assertMetrics(t *testing.T, prefix string, metricsPort uint16, mandatoryLabels []string) {
	client := &http.Client{}
	resp, err := client.Get(fmt.Sprintf("http://localhost:%d/metrics", metricsPort))
	require.NoError(t, err)

	defer resp.Body.Close()
	reader := bufio.NewReader(resp.Body)

	var parser expfmt.TextParser
	parsed, err := parser.TextToMetricFamilies(reader)
	require.NoError(t, err)

	for metricName, metricFamily := range parsed {
		// require is used here so test fails with a single message.
		require.True(
			t,
			strings.HasPrefix(metricName, prefix),
			"expected prefix %q but string starts with %q",
			prefix,
			metricName[:len(prefix)+1]+"...")

		for _, metric := range metricFamily.Metric {
			var labelNames []string
			for _, labelPair := range metric.Label {
				labelNames = append(labelNames, *labelPair.Name)
			}

			for _, mandatoryLabel := range mandatoryLabels {
				// require is used here so test fails with a single message.
				require.Contains(t, labelNames, mandatoryLabel, "mandatory label %q not present", mandatoryLabel)
			}
		}
	}
}

func assertZPages(t *testing.T) {
	paths := []string{
		"/debug/tracez",
		// TODO: enable this when otel-metrics is used and this page is available.
		// "/debug/rpcz",
		"/debug/pipelinez",
		"/debug/servicez",
		"/debug/extensionz",
	}

	const defaultZPagesPort = "55679"

	testZPagePathFn := func(t *testing.T, path string) {
		client := &http.Client{}
		resp, err := client.Get("http://localhost:" + defaultZPagesPort + path)
		if !assert.NoError(t, err, "error retrieving zpage at %q", path) {
			return
		}
		assert.Equal(t, http.StatusOK, resp.StatusCode, "unsuccessful zpage %q GET", path)
		assert.NoError(t, resp.Body.Close())
	}

	for _, path := range paths {
		testZPagePathFn(t, path)
	}
}

type errParserLoader struct {
	err error
}

func (epl *errParserLoader) Get(context.Context) (*configparser.ConfigMap, error) {
	return nil, epl.err
}

func (epl *errParserLoader) Close(context.Context) error {
	return nil
}

func TestCollector_reloadService(t *testing.T) {
	factories, err := defaultcomponents.Components()
	require.NoError(t, err)
	ctx := context.Background()
	sentinelError := errors.New("sentinel error")

	tests := []struct {
		name           string
		parserProvider parserprovider.ParserProvider
		service        *service
	}{
		{
			name:           "first_load_err",
			parserProvider: &errParserLoader{err: sentinelError},
		},
		{
			name:           "retire_service_ok_load_err",
			parserProvider: &errParserLoader{err: sentinelError},
			service: &service{
				logger:          zap.NewNop(),
				builtExporters:  builder.Exporters{},
				builtPipelines:  builder.BuiltPipelines{},
				builtReceivers:  builder.Receivers{},
				builtExtensions: builder.Extensions{},
			},
		},
		{
			name:           "retire_service_ok_load_ok",
			parserProvider: parserprovider.NewInMemory(strings.NewReader(configStr)),
			service: &service{
				logger:          zap.NewNop(),
				builtExporters:  builder.Exporters{},
				builtPipelines:  builder.BuiltPipelines{},
				builtReceivers:  builder.Receivers{},
				builtExtensions: builder.Extensions{},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			col := Collector{
				set: CollectorSettings{
					ParserProvider:    tt.parserProvider,
					ConfigUnmarshaler: configunmarshaler.NewDefault(),
					Factories:         factories,
				},
				logger:         zap.NewNop(),
				tracerProvider: trace.NewNoopTracerProvider(),
				service:        tt.service,
			}

			err := col.reloadService(ctx)

			if err != nil {
				assert.ErrorIs(t, err, sentinelError)
				return
			}

			// If successful need to shutdown active service.
			assert.NoError(t, col.service.Shutdown(ctx))
		})
	}
}
<|endoftext|>


<commit_before>package filereciversrv
import (
	"net/http"
	"strconv"
	"io/ioutil"
	"log"
	"encoding/base64"
	"crypto/rand"
	"fmt"
	"os"
	"dicomsend/http_receiver"
	"godownloader/monitor"
	"encoding/json"
)

const htmlData = ""
const FlushDiskSize = 1024 * 1024

func genUid() string {
	b := make([]byte, 16)
	rand.Read(b)
	return fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
type Upst struct {
	Uid      string
	Progress int
}

func sep() string {
	st := strconv.QuoteRune(os.PathSeparator)
	st = st[1 : len(st) - 1]
	return st
}
type UpSrv struct {
drs map[string]*monitor.MonitoredWorker
}

func (srv *UpSrv) Start(listenPort int) error {
	srv.drs=make(map[string]*monitor.MonitoredWorker)
	http.HandleFunc("/", srv.Redirect)
	http.HandleFunc("/index.html", srv.index)
	http.HandleFunc("/upload_dicom", srv.uploadDicom)
	http.HandleFunc("/progress_upload.js", srv.progressJson)
	if err := http.ListenAndServe(":" + strconv.Itoa(listenPort), nil); err != nil {
		return err
	}
	return nil
}
func (srv *UpSrv) Redirect(responseWriter http.ResponseWriter, request *http.Request) {
	http.Redirect(responseWriter, request, "/index.html", 301)
}

func (srv *UpSrv) index(rwr http.ResponseWriter, req *http.Request) {
	rwr.Header().Set("Content-Type: text/html", "*")
	content, err := ioutil.ReadFile("index.html")
	if err != nil {
		log.Println("warning: start page not found, return included page")
		val, _ := base64.StdEncoding.DecodeString(htmlData)
		rwr.Write(val)
		return
	}
	rwr.Write(content)
}

func dummyOnFileDownload(path string)error {
	log.Println("info: i do some thing with file", path)
	return nil
}

func (srv *UpSrv)uploadDicom(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if fr, err := httpreciver.CreateReciver(w, r, dummyOnFileDownload); err != nil {
		http.Error(w, "error: can't create reciver", http.StatusInternalServerError)
	}else {
		mw := monitor.MonitoredWorker{Itw:fr}
		srv.drs[mw.GetId()]=&mw
		mw.Start()
		mw.Wait()
		log.Println(mw.GetState())
	}
	log.Println("info: finish upload")
}

func (srv *UpSrv) progressJson(rwr http.ResponseWriter, req *http.Request) {
	defer req.Body.Close()
	rwr.Header().Set("Access-Control-Allow-Origin", "*")
	jbs := make([]Upst, 0, len(srv.drs))
	for ind, i := range srv.drs {
		prs, _ := i.GetProgress().(int)
		st := Upst{Uid:ind, Progress:prs}
		jbs = append(jbs, st)
	}
	js, err := json.Marshal(jbs)
	if err != nil {
		http.Error(rwr, err.Error(), http.StatusInternalServerError)
		return
	}
	rwr.Write(js)

}<commit_msg>cosmetic fix<commit_after>package filereciversrv
import (
	"net/http"
	"strconv"
	"io/ioutil"
	"log"
	"encoding/base64"
	"crypto/rand"
	"fmt"
	"os"
	"dicomsend/http_receiver"
	"godownloader/monitor"
	"encoding/json"
)

const htmlData = ""
const FlushDiskSize = 1024 * 1024

func genUid() string {
	b := make([]byte, 16)
	rand.Read(b)
	return fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
type Upst struct {
	Uid      string
	Progress int
}

func sep() string {
	st := strconv.QuoteRune(os.PathSeparator)
	st = st[1 : len(st) - 1]
	return st
}
type UpSrv struct {
	drs map[string]*monitor.MonitoredWorker
}

func (srv *UpSrv) Start(listenPort int) error {
	srv.drs = make(map[string]*monitor.MonitoredWorker)
	http.HandleFunc("/", srv.Redirect)
	http.HandleFunc("/index.html", srv.index)
	http.HandleFunc("/upload_dicom", srv.uploadDicom)
	http.HandleFunc("/progress_upload.js", srv.progressJson)
	if err := http.ListenAndServe(":" + strconv.Itoa(listenPort), nil); err != nil {
		return err
	}
	return nil
}
func (srv *UpSrv) Redirect(responseWriter http.ResponseWriter, request *http.Request) {
	http.Redirect(responseWriter, request, "/index.html", 301)
}

func (srv *UpSrv) index(rwr http.ResponseWriter, req *http.Request) {
	rwr.Header().Set("Content-Type: text/html", "*")
	content, err := ioutil.ReadFile("index.html")
	if err != nil {
		log.Println("warning: start page not found, return included page")
		val, _ := base64.StdEncoding.DecodeString(htmlData)
		rwr.Write(val)
		return
	}
	rwr.Write(content)
}

func dummyOnFileDownload(path string) error {
	log.Println("info: i do some thing with file", path)
	return nil
}

func (srv *UpSrv)uploadDicom(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if fr, err := httpreciver.CreateReciver(w, r, dummyOnFileDownload); err != nil {
		http.Error(w, "error: can't create reciver", http.StatusInternalServerError)

	}else {
		mw := monitor.MonitoredWorker{Itw:fr}
		srv.drs[mw.GetId()] = &mw
		mw.Start()
		mw.Wait()
		log.Println(mw.GetState())
	}
	log.Println("info: finish upload")
}

func (srv *UpSrv) progressJson(rwr http.ResponseWriter, req *http.Request) {
	defer req.Body.Close()
	rwr.Header().Set("Access-Control-Allow-Origin", "*")
	jbs := make([]Upst, 0, len(srv.drs))
	for ind, i := range srv.drs {
		if i.GetState() != monitor.Running {
			prs, _ := i.GetProgress().(int)
			st := Upst{Uid:ind, Progress:prs}
			jbs = append(jbs, st)
		}else {
			delete(srv.drs, ind)
		}

	}
	js, err := json.Marshal(jbs)
	if err != nil {
		http.Error(rwr, err.Error(), http.StatusInternalServerError)
		return
	}
	rwr.Write(js)

}<|endoftext|>