<commit_before>package apns

import (
	"crypto/tls"
	"fmt"
	"log"
	"time"

	"code.google.com/p/go.net/context"
	"github.com/cenkalti/backoff"
)

// Sender sends notifications
type Sender struct {
	addr       string
	cert       *tls.Certificate
	conn       *conn
	notifc     chan *PushNotification
	prioNotifc *priochan
	respc      chan *PushNotificationRequestResponse
	readc      chan *readEvent
}

type readEvent struct {
	resp *ErrorResponse
	conn *conn
}

// NewSender creates a new Sender
func NewSender(ctx context.Context, addr string, cert *tls.Certificate) *Sender {
	s := &Sender{
		addr:       addr,
		cert:       cert,
		notifc:     make(chan *PushNotification),
		prioNotifc: newPriochan(),
		respc:      make(chan *PushNotificationRequestResponse),
		readc:      make(chan *readEvent),
	}

	s.prioNotifc.Add(s.notifc)

	go s.senderJob(ctx)

	return s
}

// Notifications returns the channel to which to send notifications
func (s *Sender) Notifications() chan *PushNotification {
	return s.notifc
}

// Responses returns the channel from which responses should be received
func (s *Sender) Responses() <-chan *PushNotificationRequestResponse {
	return s.respc
}

func (s *Sender) senderJob(ctx context.Context) {

	ticker := time.Tick(time.Second)

	for {
		select {
		case <-ctx.Done():
			if s.conn != nil {
				s.conn.Close()
			}
			s.prioNotifc.Close()
			return
		case ev := <-s.readc:
			s.handleRead(ev)
		case pn := <-s.prioNotifc.Receive():
			log.Printf("Sending notification %v", pn.Identifier)
			s.doSend(pn)
		case <-ticker:
			if s.conn != nil {
				s.conn.Expire()
			}
		}
	}
}

func (s *Sender) handleRead(ev *readEvent) {

	var pn *PushNotification
	var sent []*PushNotification
	conn := ev.conn

	conn.Close()
	if conn == s.conn {
		s.conn = nil
	}

	if resp := ev.resp; resp != nil {
		pn = conn.GetSentNotification(resp.Identifier)

		if pn == nil {
			log.Printf("Got a response for unknown notification %v", resp.Identifier)
		} else {
			log.Printf("Got a response for notification %v", resp.Identifier)
			s.respc <- &PushNotificationRequestResponse{
				Notification: pn,
				Response:     resp,
			}
		}
	}

	if pn != nil {
		sent = conn.GetSentNotificationsAfter(pn.Identifier)
	} else {
		sent = conn.GetSentNotifications()
	}

	// requeue notifications before anything sent to s.notifc
	c := make(chan *PushNotification)
	s.prioNotifc.Add(c)

	go func() {
		for _, pn := range sent {
			log.Printf("Requeuing notification %v", pn.Identifier)
			c <- pn
		}
		close(c)
	}()
}

func (s *Sender) doSend(pn *PushNotification) {

	for {
		s.connect()

		if connError, err := s.conn.Write(pn); err != nil {
			if connError {
				s.conn.Close()
				s.conn = nil
				fmt.Printf("%v; will retry", err)
			} else {
				fmt.Println(err)
			}
		} else {
			break
		}
	}
}

func (s *Sender) connect() {

	for s.conn == nil {
		var conn *conn
		var err error

		connect := func() error {
			log.Printf("Connecting to %v", s.addr)
			conn, err = newConn(s.addr, s.cert)
			if err != nil {
				log.Printf("Failed connecting to %v: %v; will retry", s.addr, err)
				return err
			}
			return nil
		}

		if backoff.Retry(connect, backoff.NewExponentialBackOff()) != nil {
			continue
		}

		log.Printf("Connected to %v", s.addr)

		go s.read(conn)

		s.conn = conn
	}
}

func (s *Sender) read(c *conn) {
	for {
		select {
		case <-c.Done():
			return
		case pnr := <-c.Read():
			s.readc <- &readEvent{pnr, c}
		}
	}
}
<commit_msg>fmt -> log<commit_after>package apns

import (
	"crypto/tls"
	"log"
	"time"

	"code.google.com/p/go.net/context"
	"github.com/cenkalti/backoff"
)

// Sender sends notifications
type Sender struct {
	addr       string
	cert       *tls.Certificate
	conn       *conn
	notifc     chan *PushNotification
	prioNotifc *priochan
	respc      chan *PushNotificationRequestResponse
	readc      chan *readEvent
}

type readEvent struct {
	resp *ErrorResponse
	conn *conn
}

// NewSender creates a new Sender
func NewSender(ctx context.Context, addr string, cert *tls.Certificate) *Sender {
	s := &Sender{
		addr:       addr,
		cert:       cert,
		notifc:     make(chan *PushNotification),
		prioNotifc: newPriochan(),
		respc:      make(chan *PushNotificationRequestResponse),
		readc:      make(chan *readEvent),
	}

	s.prioNotifc.Add(s.notifc)

	go s.senderJob(ctx)

	return s
}

// Notifications returns the channel to which to send notifications
func (s *Sender) Notifications() chan *PushNotification {
	return s.notifc
}

// Responses returns the channel from which responses should be received
func (s *Sender) Responses() <-chan *PushNotificationRequestResponse {
	return s.respc
}

func (s *Sender) senderJob(ctx context.Context) {

	ticker := time.Tick(time.Second)

	for {
		select {
		case <-ctx.Done():
			if s.conn != nil {
				s.conn.Close()
			}
			s.prioNotifc.Close()
			return
		case ev := <-s.readc:
			s.handleRead(ev)
		case pn := <-s.prioNotifc.Receive():
			log.Printf("Sending notification %v", pn.Identifier)
			s.doSend(pn)
		case <-ticker:
			if s.conn != nil {
				s.conn.Expire()
			}
		}
	}
}

func (s *Sender) handleRead(ev *readEvent) {

	var pn *PushNotification
	var sent []*PushNotification
	conn := ev.conn

	conn.Close()
	if conn == s.conn {
		s.conn = nil
	}

	if resp := ev.resp; resp != nil {
		pn = conn.GetSentNotification(resp.Identifier)

		if pn == nil {
			log.Printf("Got a response for unknown notification %v", resp.Identifier)
		} else {
			log.Printf("Got a response for notification %v", resp.Identifier)
			s.respc <- &PushNotificationRequestResponse{
				Notification: pn,
				Response:     resp,
			}
		}
	}

	if pn != nil {
		sent = conn.GetSentNotificationsAfter(pn.Identifier)
	} else {
		sent = conn.GetSentNotifications()
	}

	// requeue notifications before anything sent to s.notifc
	c := make(chan *PushNotification)
	s.prioNotifc.Add(c)

	go func() {
		for _, pn := range sent {
			log.Printf("Requeuing notification %v", pn.Identifier)
			c <- pn
		}
		close(c)
	}()
}

func (s *Sender) doSend(pn *PushNotification) {

	for {
		s.connect()

		if connError, err := s.conn.Write(pn); err != nil {
			if connError {
				s.conn.Close()
				s.conn = nil
				log.Printf("%v; will retry", err)
			} else {
				log.Println(err)
			}
		} else {
			break
		}
	}
}

func (s *Sender) connect() {

	for s.conn == nil {
		var conn *conn
		var err error

		connect := func() error {
			log.Printf("Connecting to %v", s.addr)
			conn, err = newConn(s.addr, s.cert)
			if err != nil {
				log.Printf("Failed connecting to %v: %v; will retry", s.addr, err)
				return err
			}
			return nil
		}

		if backoff.Retry(connect, backoff.NewExponentialBackOff()) != nil {
			continue
		}

		log.Printf("Connected to %v", s.addr)

		go s.read(conn)

		s.conn = conn
	}
}

func (s *Sender) read(c *conn) {
	for {
		select {
		case <-c.Done():
			return
		case pnr := <-c.Read():
			s.readc <- &readEvent{pnr, c}
		}
	}
}
<|endoftext|>


<commit_before>package cf_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/pivotal-cf-experimental/cf-test-helpers/cf"
)

var _ = Describe("NewUserContext", func() {

	var createUser = func() cf.UserContext {
		return cf.NewUserContext("http://FAKE_API.example.com", "FAKE_USERNAME", "FAKE_PASSWORD", "FAKE_ORG", "FAKE_SPACE")
	}

	It("returns a UserContext struct", func() {
		Expect(createUser()).To(BeAssignableToTypeOf(cf.UserContext{}))
	})

	It("sets UserContext.ApiUrl", func() {
		Expect(createUser().ApiUrl).To(Equal("http://FAKE_API.example.com"))
	})

	It("sets UserContext.name", func() {
		Expect(createUser().Username).To(Equal("FAKE_USERNAME"))
	})

	It("sets UserContext.password", func() {
		Expect(createUser().Password).To(Equal("FAKE_PASSWORD"))
	})

	It("sets UserContext.org", func() {
		Expect(createUser().Org).To(Equal("FAKE_ORG"))
	})

	It("sets UserContext.space", func() {
		Expect(createUser().Space).To(Equal("FAKE_SPACE"))
	})
})
<commit_msg>Fix spec descriptions Fix spec descriptions to match property names<commit_after>package cf_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/pivotal-cf-experimental/cf-test-helpers/cf"
)

var _ = Describe("NewUserContext", func() {

	var createUser = func() cf.UserContext {
		return cf.NewUserContext("http://FAKE_API.example.com", "FAKE_USERNAME", "FAKE_PASSWORD", "FAKE_ORG", "FAKE_SPACE")
	}

	It("returns a UserContext struct", func() {
		Expect(createUser()).To(BeAssignableToTypeOf(cf.UserContext{}))
	})

	It("sets UserContext.ApiUrl", func() {
		Expect(createUser().ApiUrl).To(Equal("http://FAKE_API.example.com"))
	})

	It("sets UserContext.Username", func() {
		Expect(createUser().Username).To(Equal("FAKE_USERNAME"))
	})

	It("sets UserContext.Password", func() {
		Expect(createUser().Password).To(Equal("FAKE_PASSWORD"))
	})

	It("sets UserContext.Org", func() {
		Expect(createUser().Org).To(Equal("FAKE_ORG"))
	})

	It("sets UserContext.Space", func() {
		Expect(createUser().Space).To(Equal("FAKE_SPACE"))
	})
})
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"net/url"

	"github.com/docker/engine-api/types"
)

// ContainerRemove kills and removes a container from the docker host.
func (cli *Client) ContainerRemove(options types.ContainerRemoveOptions) ([]string, error) {
	var warnings []string
	query := url.Values{}
	if options.RemoveVolumes {
		query.Set("v", "1")
	}
	if options.RemoveLinks {
		query.Set("link", "1")
	}

	if options.Force {
		query.Set("force", "1")
	}

	resp, err := cli.delete("/containers/"+options.ContainerID, query, nil)
	json.NewDecoder(resp.body).Decode(&warnings)
	ensureReaderClosed(resp)
	return warnings, err
}
<commit_msg>fix remove non-exist container panic<commit_after>package client

import (
	"encoding/json"
	"net/url"

	"github.com/docker/engine-api/types"
)

// ContainerRemove kills and removes a container from the docker host.
func (cli *Client) ContainerRemove(options types.ContainerRemoveOptions) ([]string, error) {
	var warnings []string
	query := url.Values{}
	if options.RemoveVolumes {
		query.Set("v", "1")
	}
	if options.RemoveLinks {
		query.Set("link", "1")
	}

	if options.Force {
		query.Set("force", "1")
	}

	resp, err := cli.delete("/containers/"+options.ContainerID, query, nil)
	if err == nil {
		json.NewDecoder(resp.body).Decode(&warnings)
	}
	ensureReaderClosed(resp)
	return warnings, err
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

func index(w http.ResponseWriter, r *http.Request) {
	var output string
	output = "MongoDumpServer v0.1"

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(output); err != nil {
		log.Println("Failed", err)
	}
}

func dumpCreate(w http.ResponseWriter, r *http.Request) {
	var target dumpTarget

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Println("Failed", err)
	}
	if err := r.Body.Close(); err != nil {
		log.Println("Failed", err)
	}
	if err := json.Unmarshal(body, &target); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(422) //unprocessable entity
		if err := json.NewEncoder(w).Encode(err); err != nil {
			log.Println("Failed", err)
		}
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode("Backup started successfully"); err != nil {
		log.Println("Failed to encode json", err)
	}

	go dumpStart(target)
}
<commit_msg>notify user if bucket not specified<commit_after>package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

func index(w http.ResponseWriter, r *http.Request) {
	var output string
	output = "MongoDumpServer v0.1"

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(output); err != nil {
		log.Println("Failed", err)
	}
}

func dumpCreate(w http.ResponseWriter, r *http.Request) {
	var target dumpTarget
	var output string

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Println("Failed", err)
	}
	if err := r.Body.Close(); err != nil {
		log.Println("Failed", err)
	}
	if err := json.Unmarshal(body, &target); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(422) //unprocessable entity
		if err := json.NewEncoder(w).Encode(err); err != nil {
			log.Println("Failed", err)
		}
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if target.Bucket != "" {
		output = "Backup started successfully"
	} else {
		output = "Backup started successfully, dumping to null"
	}
	if err := json.NewEncoder(w).Encode(output); err != nil {
		log.Println("Failed to encode json", err)
	}

	go dumpStart(target)
}
<|endoftext|>


<commit_before>package kwiscale

import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strings"
)

// thanks Russ Cox - https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
// eq reports whether the first argument is equal to
// any of the remaining arguments.
func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

// request handler represents an handler
type IRequestHandler interface {
	Get()
	Post()
	Head()
	Delete()
	Put()
	Render(template string, context interface{})
	GetSession(name string) interface{}
	SetSession(name string, value interface{})

	setParams(w http.ResponseWriter, r *http.Request, u []string)
}

// object that will handler routes and request information
type RequestHandler struct {
	IRequestHandler
	Routes    []string
	Response  http.ResponseWriter
	Request   *http.Request
	UrlParams []string
	SessionId string
}

// method that set request and response object
func (this *RequestHandler) setParams(w http.ResponseWriter, r *http.Request, urlparams []string) {
	this.Response = w
	this.Request = r
	this.UrlParams = urlparams
}

// alias to http.Response.Write + type conversion from string to []byte
func (this *RequestHandler) Write(s string) {
	this.Response.Write([]byte(s))
}

// Render a template using override directive if any
func (this *RequestHandler) Render(tpl string, context interface{}) {

	content := getCachedTemplate(tpl)

	fm := template.FuncMap{
		"title": strings.Title,
	}

	re := regexp.MustCompile(`\{\{\s*override\s+"(.*)"\s*\}\}`)
	matches := re.FindAllStringSubmatch(content, -1)
	for len(matches) > 0 {
		for _, m := range matches {
			// The capture is in m[1]
			// The whole override line is m[0]
			over := getCachedTemplate(m[1])
			content = strings.Replace(content, m[0], string(over), -1)
		}
		matches = re.FindAllStringSubmatch(content, -1)
	}

	t, _ := template.New("main").Funcs(fm).Parse(content)
	t.Execute(this.Response, context)

}

// generate a session uuid
func (this *RequestHandler) GenSessionID() {

	f, _ := os.Open("/dev/urandom")
	b := make([]byte, 16)
	f.Read(b)
	f.Close()
	uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

	this.SessionId = uuid

}

func (this *RequestHandler) CheckSessid() {
	if id, err := this.Request.Cookie("SESSID"); err == nil {
		this.SessionId = id.Value
	} else {
		this.GenSessionID()
	}

	c := http.Cookie{
		Name:  "SESSID",
		Value: this.SessionId,
		Path:  "/",
	}

	http.SetCookie(this.Response, &c)
}

// get sessions
func (this *RequestHandler) GetSession(name string) interface{} {
	this.CheckSessid()
	if sessions == nil {
		sessions = make(map[string]map[string]interface{})
	}

	if s := sessions[this.SessionId]; s != nil {
		if r := s[name]; r != nil {
			return r
		}
	}

	return nil
}

func (this *RequestHandler) SetSession(name string, val interface{}) {

	this.CheckSessid()

	if sessions == nil {
		sessions = make(map[string]map[string]interface{})
	}

	s := sessions[this.SessionId]
	if s == nil {
		sessions[this.SessionId] = make(map[string]interface{})
		s = sessions[this.SessionId]
	}

	s[name] = val
}

// Redirect to given url
func (this *RequestHandler) Redirect(url string) {
	http.Redirect(this.Response, this.Request, url, http.StatusSeeOther)
}

// unset the entire session for the current request
func (this *RequestHandler) EmptySession() {
	delete(sessions, this.SessionId)
}
<commit_msg>No need to set "Routes" property now<commit_after>package kwiscale

import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strings"
)

// thanks Russ Cox - https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
// eq reports whether the first argument is equal to
// any of the remaining arguments.
func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

// request handler represents an handler
type IRequestHandler interface {
	Get()
	Post()
	Head()
	Delete()
	Put()
	Render(template string, context interface{})
	GetSession(name string) interface{}
	SetSession(name string, value interface{})

	setParams(w http.ResponseWriter, r *http.Request, u []string)
}

// object that will handler routes and request information
type RequestHandler struct {
	IRequestHandler
	Response  http.ResponseWriter
	Request   *http.Request
	UrlParams []string
	SessionId string
}

// method that set request and response object
func (this *RequestHandler) setParams(w http.ResponseWriter, r *http.Request, urlparams []string) {
	this.Response = w
	this.Request = r
	this.UrlParams = urlparams
}

// alias to http.Response.Write + type conversion from string to []byte
func (this *RequestHandler) Write(s string) {
	this.Response.Write([]byte(s))
}

// Render a template using override directive if any
func (this *RequestHandler) Render(tpl string, context interface{}) {

	content := getCachedTemplate(tpl)

	fm := template.FuncMap{
		"title": strings.Title,
	}

	re := regexp.MustCompile(`\{\{\s*override\s+"(.*)"\s*\}\}`)
	matches := re.FindAllStringSubmatch(content, -1)
	for len(matches) > 0 {
		for _, m := range matches {
			// The capture is in m[1]
			// The whole override line is m[0]
			over := getCachedTemplate(m[1])
			content = strings.Replace(content, m[0], string(over), -1)
		}
		matches = re.FindAllStringSubmatch(content, -1)
	}

	t, _ := template.New("main").Funcs(fm).Parse(content)
	t.Execute(this.Response, context)

}

// generate a session uuid
func (this *RequestHandler) GenSessionID() {

	f, _ := os.Open("/dev/urandom")
	b := make([]byte, 16)
	f.Read(b)
	f.Close()
	uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

	this.SessionId = uuid

}

func (this *RequestHandler) CheckSessid() {
	if id, err := this.Request.Cookie("SESSID"); err == nil {
		this.SessionId = id.Value
	} else {
		this.GenSessionID()
	}

	c := http.Cookie{
		Name:  "SESSID",
		Value: this.SessionId,
		Path:  "/",
	}

	http.SetCookie(this.Response, &c)
}

// get sessions
func (this *RequestHandler) GetSession(name string) interface{} {
	this.CheckSessid()
	if sessions == nil {
		sessions = make(map[string]map[string]interface{})
	}

	if s := sessions[this.SessionId]; s != nil {
		if r := s[name]; r != nil {
			return r
		}
	}

	return nil
}

func (this *RequestHandler) SetSession(name string, val interface{}) {

	this.CheckSessid()

	if sessions == nil {
		sessions = make(map[string]map[string]interface{})
	}

	s := sessions[this.SessionId]
	if s == nil {
		sessions[this.SessionId] = make(map[string]interface{})
		s = sessions[this.SessionId]
	}

	s[name] = val
}

// Redirect to given url
func (this *RequestHandler) Redirect(url string) {
	http.Redirect(this.Response, this.Request, url, http.StatusSeeOther)
}

// unset the entire session for the current request
func (this *RequestHandler) EmptySession() {
	delete(sessions, this.SessionId)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

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

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

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

package lib

import (
	"context"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/onsi/ginkgo"
	corev1 "k8s.io/api/core/v1"
	apierrs "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	pkgTest "knative.dev/pkg/test"
	"knative.dev/pkg/test/prow"

	"knative.dev/eventing/pkg/utils"

	// Mysteriously required to support GCP auth (required by k8s libs).
	// Apparently just importing it is enough. @_@ side effects @_@.
	// https://github.com/kubernetes/client-go/issues/242
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
)

const (
	podLogsDir         = "pod-logs"
	testPullSecretName = "kn-eventing-test-pull-secret"
	MaxNamespaceSkip   = 20
	MaxRetries         = 5
	RetrySleepDuration = 2 * time.Second
)

var (
	nsMutex        sync.Mutex
	namespaceCount int
	ReuseNamespace bool
)

// ComponentsTestRunner is used to run tests against different eventing components.
type ComponentsTestRunner struct {
	ComponentFeatureMap map[metav1.TypeMeta][]Feature
	ComponentsToTest    []metav1.TypeMeta
	componentOptions    map[metav1.TypeMeta][]SetupClientOption
	ComponentName       string
	ComponentNamespace  string
}

// RunTests will use all components that support the given feature, to run
// a test for the testFunc.
func (tr *ComponentsTestRunner) RunTests(
	t *testing.T,
	feature Feature,
	testFunc func(st *testing.T, component metav1.TypeMeta),
) {
	for _, component := range tr.ComponentsToTest {
		// If a component is not present in the map, then assume it has all properties. This is so an
		// unknown component (e.g. a Channel) can be specified via a dedicated flag (e.g. --channels) and have tests run.
		// TODO Use a flag to specify the features of the flag based component, rather than assuming
		// it supports all features.
		features, present := tr.ComponentFeatureMap[component]
		if !present || contains(features, feature) {
			t.Run(fmt.Sprintf("%s-%s", component.Kind, component.APIVersion), func(st *testing.T) {
				testFunc(st, component)
			})
		}
	}
}

// RunTestsWithComponentOptions will use all components that support the given
// feature, to run a test for the testFunc while passing the component specific
// SetupClientOptions to testFunc. You should used this method instead of
// RunTests if you have used AddComponentSetupClientOption to add some component
// specific initialization code. If strict is set to true, tests will not run
// for components that don't exist in the ComponentFeatureMap.
func (tr *ComponentsTestRunner) RunTestsWithComponentOptions(
	t *testing.T,
	feature Feature,
	strict bool,
	testFunc func(st *testing.T, component metav1.TypeMeta,
		options ...SetupClientOption),
) {
	t.Parallel()
	for _, c := range tr.ComponentsToTest {
		component := c
		features, present := tr.ComponentFeatureMap[component]
		subTestName := fmt.Sprintf("%s-%s", component.Kind, component.APIVersion)
		t.Run(subTestName, func(st *testing.T) {
			// If in strict mode and a component is not present in the map, then
			// don't run the tests
			if !strict || (present && contains(features, feature)) {
				testFunc(st, component, tr.componentOptions[component]...)
			} else {
				st.Skipf("Skipping component %s since it did not "+
					"match the feature %s and we are in strict mode", subTestName, feature)
			}
		})
	}
}

// AddComponentSetupClientOption adds a SetupClientOption that should only run when
// component gets selected to run. This should be used when there's an expensive
// initialization code should take place conditionally (e.g. create an instance
// of a source or a channel) as opposed to other cheap initialization code that
// is safe to be called in all cases (e.g. installation of a CRD)
func (tr *ComponentsTestRunner) AddComponentSetupClientOption(component metav1.TypeMeta,
	options ...SetupClientOption) {
	if tr.componentOptions == nil {
		tr.componentOptions = make(map[metav1.TypeMeta][]SetupClientOption)
	}
	if _, ok := tr.componentOptions[component]; !ok {
		tr.componentOptions[component] = make([]SetupClientOption, 0)
	}
	tr.componentOptions[component] = append(tr.componentOptions[component], options...)
}

func contains(features []Feature, feature Feature) bool {
	for _, f := range features {
		if f == feature {
			return true
		}
	}
	return false
}

// SetupClientOption does further setup for the Client. It can be used if other projects
// need to do extra setups to run the tests we expose as test helpers.
type SetupClientOption func(*Client)

// SetupClientOptionNoop is a SetupClientOption that does nothing.
var SetupClientOptionNoop SetupClientOption = func(*Client) {
	// nothing
}

// GSetup creates
// - the client objects needed in the e2e tests,
// - the namespace hosting all objects needed by the test
func GSetup(t ginkgo.GinkgoTInterface, options ...SetupClientOption) *Client {
	client, err := CreateNamespacedClient(t)
	if err != nil {
		t.Fatal("Couldn't initialize clients:", err)
	}

	// If namespaces are re-used the pull-secret is supposed to be created in advance.
	if !ReuseNamespace {
		SetupServiceAccount(t, client)
		SetupPullSecret(t, client)
		CreateRBACPodsGetEventsAll(client, client.Namespace)
		CreateRBACPodsEventsGetListWatch(client, client.Namespace+"-eventwatcher")
	}

	// Run further setups for the client.
	for _, option := range options {
		option(client)
	}

	return client
}

// Setup creates
// - the client objects needed in the e2e tests,
// - the namespace hosting all objects needed by the test
func Setup(t ginkgo.GinkgoTInterface, runInParallel bool, options ...SetupClientOption) *Client {
	client := GSetup(t, options...)

	// Run the test case in parallel if needed.
	if runInParallel {
		t.Parallel()
	}

	return client
}

func CreateNamespacedClient(t ginkgo.GinkgoTInterface) (*Client, error) {
	ns := ""
	// Try next MaxNamespaceSkip namespaces before giving up. This should address the issue with
	// development cycles when namespaces from previous runs were not cleaned properly.
	for i := 0; i < MaxNamespaceSkip; i++ {
		ns = NextNamespace()
		client, err := NewClient(
			pkgTest.Flags.Kubeconfig,
			pkgTest.Flags.Cluster,
			ns,
			t)
		if err != nil {
			return nil, err
		}
		if ReuseNamespace {
			// Re-using existing namespace, no need to create it.
			// The namespace is supposed to be created in advance.
			return client, nil
		} else {
			// The test is supposed to create a new test namespace for itself.
			// Keep trying until we find a namespace that doesn't exist yet.
			if err := CreateNamespaceWithRetry(client, ns); err != nil {
				if apierrs.IsAlreadyExists(err) {
					continue
				}
				return nil, err
			}
		}
		return client, nil
	}
	return nil, errors.New("unable to find available namespace")
}

// NextNamespace returns the next unique namespace.
func NextNamespace() string {
	ns := os.Getenv("EVENTING_E2E_NAMESPACE")
	if ns == "" {
		ns = "eventing-e2e"
	}
	return fmt.Sprintf("%s%d", ns, GetNextNamespaceId())
}

// GetNextNamespaceId return the next unique ID for the next namespace.
func GetNextNamespaceId() int {
	nsMutex.Lock()
	defer nsMutex.Unlock()
	current := namespaceCount
	namespaceCount++
	return current
}

// CreateNamespaceWithRetry creates the given namespace with retries.
func CreateNamespaceWithRetry(client *Client, namespace string) error {
	var (
		retries int
		err     error
	)
	for retries < MaxRetries {
		nsSpec := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
		if _, err = client.Kube.CoreV1().Namespaces().
			Create(context.Background(), nsSpec, metav1.CreateOptions{}); err == nil || apierrs.IsAlreadyExists(err) {
			return err
		}
		retries++
		time.Sleep(RetrySleepDuration)
	}
	return err
}

// TearDown will delete created names using clients.
func TearDown(client *Client) {
	// Dump the events in the namespace
	el, err := client.Kube.CoreV1().Events(client.Namespace).List(context.Background(), metav1.ListOptions{})
	if err != nil {
		client.T.Logf("Could not list events in the namespace %q: %v", client.Namespace, err)
	} else {
		// Elements has to be ordered first
		items := el.Items
		sort.SliceStable(items, func(i, j int) bool {
			// Some events might not contain last timestamp, in that case we fallback to event time
			iTime := items[i].LastTimestamp.Time
			if iTime.IsZero() {
				iTime = items[i].EventTime.Time
			}

			jTime := items[j].LastTimestamp.Time
			if jTime.IsZero() {
				jTime = items[j].EventTime.Time
			}

			return iTime.Before(jTime)
		})

		for _, e := range items {
			client.T.Log(formatEvent(&e))
		}
	}

	// If the test is run by CI, export the pod logs in the namespace to the artifacts directory,
	// which will then be uploaded to GCS after the test job finishes.
	if prow.IsCI() && client.T.Failed() {
		dir := filepath.Join(prow.GetLocalArtifactsDir(), podLogsDir)
		client.T.Logf("Export logs in %q to %q", client.Namespace, dir)
		if err := client.ExportLogs(dir); err != nil {
			client.T.Logf("Error in exporting logs: %v", err)
		}
	}

	if err := client.runCleanup(); err != nil {
		client.T.Logf("Cleanup error: %+v", err)
	}

	client.Tracker.Clean(true)
	// If we're reusing existing namespaces leave the deletion to the creator.
	if !ReuseNamespace {
		if err := DeleteNameSpace(client); err != nil {
			client.T.Logf("Could not delete the namespace %q: %v", client.Namespace, err)
		}
	}
}

func formatEvent(e *corev1.Event) string {
	return strings.Join([]string{`Event{`,
		`ObjectMeta:` + strings.Replace(strings.Replace(e.ObjectMeta.String(), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1),
		`InvolvedObject:` + strings.Replace(strings.Replace(e.InvolvedObject.String(), "ObjectReference", "ObjectReference", 1), `&`, ``, 1),
		`Reason:` + e.Reason,
		`Message:` + e.Message,
		`Source:` + strings.Replace(strings.Replace(e.Source.String(), "EventSource", "EventSource", 1), `&`, ``, 1),
		`FirstTimestamp:` + e.FirstTimestamp.String(),
		`LastTimestamp:` + e.LastTimestamp.String(),
		`Count:` + fmt.Sprintf("%d", e.Count),
		`Type:` + e.Type,
		`EventTime:` + e.EventTime.String(),
		`Series:` + strings.Replace(e.Series.String(), "EventSeries", "EventSeries", 1),
		`Action:` + e.Action,
		`Related:` + strings.Replace(e.Related.String(), "ObjectReference", "ObjectReference", 1),
		`ReportingController:` + e.ReportingController,
		`ReportingInstance:` + e.ReportingInstance,
		`}`,
	}, "\n")
}

// SetupServiceAccount creates a new namespace if it does not exist.
func SetupServiceAccount(t ginkgo.GinkgoTInterface, client *Client) {
	// https://github.com/kubernetes/kubernetes/issues/66689
	// We can only start creating pods after the default ServiceAccount is created by the kube-controller-manager.
	err := waitForServiceAccountExists(client, "default", client.Namespace)
	if err != nil {
		t.Fatal("The default ServiceAccount was not created for the Namespace:", client.Namespace)
	}
}

// SetupPullSecret sets up kn-eventing-test-pull-secret on the client namespace.
func SetupPullSecret(t ginkgo.GinkgoTInterface, client *Client) {
	// If the "default" Namespace has a secret called
	// "kn-eventing-test-pull-secret" then use that as the ImagePullSecret
	// on the "default" ServiceAccount in this new Namespace.
	// This is needed for cases where the images are in a private registry.
	_, err := utils.CopySecret(client.Kube.CoreV1(), "default", testPullSecretName, client.Namespace, "default")
	if err != nil && !apierrs.IsNotFound(err) {
		t.Fatalf("error copying the secret into ns %q: %s", client.Namespace, err)
	}
}

// waitForServiceAccountExists waits until the ServiceAccount exists.
func waitForServiceAccountExists(client *Client, name, namespace string) error {
	return wait.PollImmediate(1*time.Second, 2*time.Minute, func() (bool, error) {
		sas := client.Kube.CoreV1().ServiceAccounts(namespace)
		if _, err := sas.Get(context.Background(), name, metav1.GetOptions{}); err == nil {
			return true, nil
		}
		return false, nil
	})
}

// DeleteNameSpace deletes the namespace that has the given name.
func DeleteNameSpace(client *Client) error {
	_, err := client.Kube.CoreV1().Namespaces().Get(context.Background(), client.Namespace, metav1.GetOptions{})
	if err == nil || !apierrs.IsNotFound(err) {
		return client.Kube.CoreV1().Namespaces().Delete(context.Background(), client.Namespace, metav1.DeleteOptions{})
	}
	return err
}
<commit_msg>Test runner: Increase MaxNamespaceSkip (#5706)<commit_after>/*
Copyright 2019 The Knative Authors

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

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

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

package lib

import (
	"context"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/onsi/ginkgo"
	corev1 "k8s.io/api/core/v1"
	apierrs "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	pkgTest "knative.dev/pkg/test"
	"knative.dev/pkg/test/prow"

	"knative.dev/eventing/pkg/utils"

	// Mysteriously required to support GCP auth (required by k8s libs).
	// Apparently just importing it is enough. @_@ side effects @_@.
	// https://github.com/kubernetes/client-go/issues/242
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
)

const (
	podLogsDir         = "pod-logs"
	testPullSecretName = "kn-eventing-test-pull-secret"
	MaxNamespaceSkip   = 50
	MaxRetries         = 5
	RetrySleepDuration = 2 * time.Second
)

var (
	nsMutex        sync.Mutex
	namespaceCount int
	ReuseNamespace bool
)

// ComponentsTestRunner is used to run tests against different eventing components.
type ComponentsTestRunner struct {
	ComponentFeatureMap map[metav1.TypeMeta][]Feature
	ComponentsToTest    []metav1.TypeMeta
	componentOptions    map[metav1.TypeMeta][]SetupClientOption
	ComponentName       string
	ComponentNamespace  string
}

// RunTests will use all components that support the given feature, to run
// a test for the testFunc.
func (tr *ComponentsTestRunner) RunTests(
	t *testing.T,
	feature Feature,
	testFunc func(st *testing.T, component metav1.TypeMeta),
) {
	for _, component := range tr.ComponentsToTest {
		// If a component is not present in the map, then assume it has all properties. This is so an
		// unknown component (e.g. a Channel) can be specified via a dedicated flag (e.g. --channels) and have tests run.
		// TODO Use a flag to specify the features of the flag based component, rather than assuming
		// it supports all features.
		features, present := tr.ComponentFeatureMap[component]
		if !present || contains(features, feature) {
			t.Run(fmt.Sprintf("%s-%s", component.Kind, component.APIVersion), func(st *testing.T) {
				testFunc(st, component)
			})
		}
	}
}

// RunTestsWithComponentOptions will use all components that support the given
// feature, to run a test for the testFunc while passing the component specific
// SetupClientOptions to testFunc. You should used this method instead of
// RunTests if you have used AddComponentSetupClientOption to add some component
// specific initialization code. If strict is set to true, tests will not run
// for components that don't exist in the ComponentFeatureMap.
func (tr *ComponentsTestRunner) RunTestsWithComponentOptions(
	t *testing.T,
	feature Feature,
	strict bool,
	testFunc func(st *testing.T, component metav1.TypeMeta,
		options ...SetupClientOption),
) {
	t.Parallel()
	for _, c := range tr.ComponentsToTest {
		component := c
		features, present := tr.ComponentFeatureMap[component]
		subTestName := fmt.Sprintf("%s-%s", component.Kind, component.APIVersion)
		t.Run(subTestName, func(st *testing.T) {
			// If in strict mode and a component is not present in the map, then
			// don't run the tests
			if !strict || (present && contains(features, feature)) {
				testFunc(st, component, tr.componentOptions[component]...)
			} else {
				st.Skipf("Skipping component %s since it did not "+
					"match the feature %s and we are in strict mode", subTestName, feature)
			}
		})
	}
}

// AddComponentSetupClientOption adds a SetupClientOption that should only run when
// component gets selected to run. This should be used when there's an expensive
// initialization code should take place conditionally (e.g. create an instance
// of a source or a channel) as opposed to other cheap initialization code that
// is safe to be called in all cases (e.g. installation of a CRD)
func (tr *ComponentsTestRunner) AddComponentSetupClientOption(component metav1.TypeMeta,
	options ...SetupClientOption) {
	if tr.componentOptions == nil {
		tr.componentOptions = make(map[metav1.TypeMeta][]SetupClientOption)
	}
	if _, ok := tr.componentOptions[component]; !ok {
		tr.componentOptions[component] = make([]SetupClientOption, 0)
	}
	tr.componentOptions[component] = append(tr.componentOptions[component], options...)
}

func contains(features []Feature, feature Feature) bool {
	for _, f := range features {
		if f == feature {
			return true
		}
	}
	return false
}

// SetupClientOption does further setup for the Client. It can be used if other projects
// need to do extra setups to run the tests we expose as test helpers.
type SetupClientOption func(*Client)

// SetupClientOptionNoop is a SetupClientOption that does nothing.
var SetupClientOptionNoop SetupClientOption = func(*Client) {
	// nothing
}

// GSetup creates
// - the client objects needed in the e2e tests,
// - the namespace hosting all objects needed by the test
func GSetup(t ginkgo.GinkgoTInterface, options ...SetupClientOption) *Client {
	client, err := CreateNamespacedClient(t)
	if err != nil {
		t.Fatal("Couldn't initialize clients:", err)
	}

	// If namespaces are re-used the pull-secret is supposed to be created in advance.
	if !ReuseNamespace {
		SetupServiceAccount(t, client)
		SetupPullSecret(t, client)
		CreateRBACPodsGetEventsAll(client, client.Namespace)
		CreateRBACPodsEventsGetListWatch(client, client.Namespace+"-eventwatcher")
	}

	// Run further setups for the client.
	for _, option := range options {
		option(client)
	}

	return client
}

// Setup creates
// - the client objects needed in the e2e tests,
// - the namespace hosting all objects needed by the test
func Setup(t ginkgo.GinkgoTInterface, runInParallel bool, options ...SetupClientOption) *Client {
	client := GSetup(t, options...)

	// Run the test case in parallel if needed.
	if runInParallel {
		t.Parallel()
	}

	return client
}

func CreateNamespacedClient(t ginkgo.GinkgoTInterface) (*Client, error) {
	ns := ""
	// Try next MaxNamespaceSkip namespaces before giving up. This should address the issue with
	// development cycles when namespaces from previous runs were not cleaned properly.
	for i := 0; i < MaxNamespaceSkip; i++ {
		ns = NextNamespace()
		client, err := NewClient(
			pkgTest.Flags.Kubeconfig,
			pkgTest.Flags.Cluster,
			ns,
			t)
		if err != nil {
			return nil, err
		}
		if ReuseNamespace {
			// Re-using existing namespace, no need to create it.
			// The namespace is supposed to be created in advance.
			return client, nil
		} else {
			// The test is supposed to create a new test namespace for itself.
			// Keep trying until we find a namespace that doesn't exist yet.
			if err := CreateNamespaceWithRetry(client, ns); err != nil {
				if apierrs.IsAlreadyExists(err) {
					continue
				}
				return nil, err
			}
		}
		return client, nil
	}
	return nil, errors.New("unable to find available namespace")
}

// NextNamespace returns the next unique namespace.
func NextNamespace() string {
	ns := os.Getenv("EVENTING_E2E_NAMESPACE")
	if ns == "" {
		ns = "eventing-e2e"
	}
	return fmt.Sprintf("%s%d", ns, GetNextNamespaceId())
}

// GetNextNamespaceId return the next unique ID for the next namespace.
func GetNextNamespaceId() int {
	nsMutex.Lock()
	defer nsMutex.Unlock()
	current := namespaceCount
	namespaceCount++
	return current
}

// CreateNamespaceWithRetry creates the given namespace with retries.
func CreateNamespaceWithRetry(client *Client, namespace string) error {
	var (
		retries int
		err     error
	)
	for retries < MaxRetries {
		nsSpec := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
		if _, err = client.Kube.CoreV1().Namespaces().
			Create(context.Background(), nsSpec, metav1.CreateOptions{}); err == nil || apierrs.IsAlreadyExists(err) {
			return err
		}
		retries++
		time.Sleep(RetrySleepDuration)
	}
	return err
}

// TearDown will delete created names using clients.
func TearDown(client *Client) {
	// Dump the events in the namespace
	el, err := client.Kube.CoreV1().Events(client.Namespace).List(context.Background(), metav1.ListOptions{})
	if err != nil {
		client.T.Logf("Could not list events in the namespace %q: %v", client.Namespace, err)
	} else {
		// Elements has to be ordered first
		items := el.Items
		sort.SliceStable(items, func(i, j int) bool {
			// Some events might not contain last timestamp, in that case we fallback to event time
			iTime := items[i].LastTimestamp.Time
			if iTime.IsZero() {
				iTime = items[i].EventTime.Time
			}

			jTime := items[j].LastTimestamp.Time
			if jTime.IsZero() {
				jTime = items[j].EventTime.Time
			}

			return iTime.Before(jTime)
		})

		for _, e := range items {
			client.T.Log(formatEvent(&e))
		}
	}

	// If the test is run by CI, export the pod logs in the namespace to the artifacts directory,
	// which will then be uploaded to GCS after the test job finishes.
	if prow.IsCI() && client.T.Failed() {
		dir := filepath.Join(prow.GetLocalArtifactsDir(), podLogsDir)
		client.T.Logf("Export logs in %q to %q", client.Namespace, dir)
		if err := client.ExportLogs(dir); err != nil {
			client.T.Logf("Error in exporting logs: %v", err)
		}
	}

	if err := client.runCleanup(); err != nil {
		client.T.Logf("Cleanup error: %+v", err)
	}

	client.Tracker.Clean(true)
	// If we're reusing existing namespaces leave the deletion to the creator.
	if !ReuseNamespace {
		if err := DeleteNameSpace(client); err != nil {
			client.T.Logf("Could not delete the namespace %q: %v", client.Namespace, err)
		}
	}
}

func formatEvent(e *corev1.Event) string {
	return strings.Join([]string{`Event{`,
		`ObjectMeta:` + strings.Replace(strings.Replace(e.ObjectMeta.String(), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1),
		`InvolvedObject:` + strings.Replace(strings.Replace(e.InvolvedObject.String(), "ObjectReference", "ObjectReference", 1), `&`, ``, 1),
		`Reason:` + e.Reason,
		`Message:` + e.Message,
		`Source:` + strings.Replace(strings.Replace(e.Source.String(), "EventSource", "EventSource", 1), `&`, ``, 1),
		`FirstTimestamp:` + e.FirstTimestamp.String(),
		`LastTimestamp:` + e.LastTimestamp.String(),
		`Count:` + fmt.Sprintf("%d", e.Count),
		`Type:` + e.Type,
		`EventTime:` + e.EventTime.String(),
		`Series:` + strings.Replace(e.Series.String(), "EventSeries", "EventSeries", 1),
		`Action:` + e.Action,
		`Related:` + strings.Replace(e.Related.String(), "ObjectReference", "ObjectReference", 1),
		`ReportingController:` + e.ReportingController,
		`ReportingInstance:` + e.ReportingInstance,
		`}`,
	}, "\n")
}

// SetupServiceAccount creates a new namespace if it does not exist.
func SetupServiceAccount(t ginkgo.GinkgoTInterface, client *Client) {
	// https://github.com/kubernetes/kubernetes/issues/66689
	// We can only start creating pods after the default ServiceAccount is created by the kube-controller-manager.
	err := waitForServiceAccountExists(client, "default", client.Namespace)
	if err != nil {
		t.Fatal("The default ServiceAccount was not created for the Namespace:", client.Namespace)
	}
}

// SetupPullSecret sets up kn-eventing-test-pull-secret on the client namespace.
func SetupPullSecret(t ginkgo.GinkgoTInterface, client *Client) {
	// If the "default" Namespace has a secret called
	// "kn-eventing-test-pull-secret" then use that as the ImagePullSecret
	// on the "default" ServiceAccount in this new Namespace.
	// This is needed for cases where the images are in a private registry.
	_, err := utils.CopySecret(client.Kube.CoreV1(), "default", testPullSecretName, client.Namespace, "default")
	if err != nil && !apierrs.IsNotFound(err) {
		t.Fatalf("error copying the secret into ns %q: %s", client.Namespace, err)
	}
}

// waitForServiceAccountExists waits until the ServiceAccount exists.
func waitForServiceAccountExists(client *Client, name, namespace string) error {
	return wait.PollImmediate(1*time.Second, 2*time.Minute, func() (bool, error) {
		sas := client.Kube.CoreV1().ServiceAccounts(namespace)
		if _, err := sas.Get(context.Background(), name, metav1.GetOptions{}); err == nil {
			return true, nil
		}
		return false, nil
	})
}

// DeleteNameSpace deletes the namespace that has the given name.
func DeleteNameSpace(client *Client) error {
	_, err := client.Kube.CoreV1().Namespaces().Get(context.Background(), client.Namespace, metav1.GetOptions{})
	if err == nil || !apierrs.IsNotFound(err) {
		return client.Kube.CoreV1().Namespaces().Delete(context.Background(), client.Namespace, metav1.DeleteOptions{})
	}
	return err
}
<|endoftext|>


<commit_before>package billing_test

import (
	"fmt"
	"testing"

	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/billing"
	billingMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/billing"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil/assert"
)

func TestUpdateDefinitions(t *testing.T) {
	tests := []struct {
		billing.Definition
		Expected  map[string]interface{}
		ShouldErr bool
	}{{
		Definition: billing.Definition{
			Name:           "test-def",
			Value:          "test-val",
			UpdateGroupReq: "staff",
		},
		Expected: map[string]interface{}{
			"name":             "test-def",
			"value":            "test-val",
			"update_group_req": "staff",
		},
	}, {
		ShouldErr: true,
	}}

	for i, test := range tests {
		testName := testutil.Name(i)
		rts := testutil.RequestTestSpec{
			Method:        "PUT",
			Endpoint:      lib.BillingEndpoint,
			URL:           fmt.Sprintf("/api/v1/definitions/%s", test.Name),
			AssertRequest: assert.BodyUnmarshalEqual(test.Expected),
			Response:      nil,
		}
		rts.Run(t, testName, true, func(client lib.Client) {
			err := billingMethods.UpdateDefinition(client, test.Definition)
			if test.ShouldErr {
				assert.NotEqual(t, testName, nil, err)
			} else {
				assert.Equal(t, testName, nil, err)
			}
		})
	}
}
<commit_msg>Set NoVerify on the error-y TestUpdateDefinition case<commit_after>package billing_test

import (
	"fmt"
	"testing"

	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/billing"
	billingMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/billing"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil/assert"
)

func TestUpdateDefinitions(t *testing.T) {
	tests := []struct {
		Name       string
		Definition billing.Definition
		Expected   map[string]interface{}
		ShouldErr  bool
	}{{
		Name: "works",
		Definition: billing.Definition{
			Name:           "test-def",
			Value:          "test-val",
			UpdateGroupReq: "staff",
		},
		Expected: map[string]interface{}{
			"name":             "test-def",
			"value":            "test-val",
			"update_group_req": "staff",
		},
	}, {
		Name:      "Errors when blank definition provided",
		ShouldErr: true,
	}}

	for _, test := range tests {
		t.Run(test.Name, func(t *testing.T) {
			rts := testutil.RequestTestSpec{
				Method:        "PUT",
				Endpoint:      lib.BillingEndpoint,
				URL:           fmt.Sprintf("/api/v1/definitions/%s", test.Definition.Name),
				AssertRequest: assert.BodyUnmarshalEqual(test.Expected),
				Response:      nil,
				NoVerify:      test.ShouldErr,
			}
			rts.Run(t, "", true, func(client lib.Client) {
				err := billingMethods.UpdateDefinition(client, test.Definition)
				if test.ShouldErr {
					assert.NotEqual(t, "", nil, err)
				} else {
					assert.Equal(t, "", nil, err)
				}
			})
		})
	}
}
<|endoftext|>


<commit_before>package immortal

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

func TestDaemonNewCtl(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtl")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		Cwd: dir,
		ctl: dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	if _, err = os.Stat(filepath.Join(dir, "lock")); err != nil {
		t.Fatal(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lockOnce)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestDaemonNewCtlErr(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtlErr")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cwd, err := os.Getwd()
	if err != nil {
		t.Error(err)
	}
	defer os.Chdir(cwd)
	if err := os.Chdir(dir); err != nil {
		t.Error(err)
	}
	os.Chmod(dir, 0000)
	cfg := &Config{
		ctl: dir,
	}
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestDaemonNewCtlCwd(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrlCwd")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cwd, err := os.Getwd()
	if err != nil {
		t.Error(err)
	}
	defer os.Chdir(cwd)
	if err := os.Chdir(dir); err != nil {
		t.Error(err)
	}
	cfg := &Config{
		ctl: dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Error(err)
	}
	if _, err = os.Stat(filepath.Join(dir, "lock")); err != nil {
		t.Fatal(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lockOnce)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestBadUid(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestBadUid")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "uid", Gid: "0"},
		ctl:     dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadGid(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestBadGid")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "0", Gid: "gid"},
		ctl:     dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestUser(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestUser")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "0", Gid: "0"},
		ctl:     dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadWritePidParent(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestBadWritePidParent")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Parent: "/dev/null/parent.pid",
		},
		ctl: dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/parent.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestBadWritePidChild(t *testing.T) {
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Child: "/dev/null/child.pid",
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/child.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestHelperProcessSignalsUDOT(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	fmt.Println("5D675098-45D7-4089-A72C-3628713EA5BA")
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	select {
	case <-c:
		os.Exit(1)
	case <-time.After(10 * time.Second):
		os.Exit(0)
	}
}

func TestSignalsUDOT(t *testing.T) {
	sdir, err := ioutil.TempDir("", "TestSignalsUDOT")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(sdir)
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	tmpfile, err := ioutil.TempFile("", "TestLogFile")
	if err != nil {
		t.Error(err)
	}
	defer os.Remove(tmpfile.Name()) // clean up
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSignalsUDOT", "--"},
		Cwd:     parentDir,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
		},
		Log: Log{
			File: tmpfile.Name(),
		},
		ctl: sdir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}

	np := NewProcess(cfg)
	expect(t, 0, np.Pid())
	p, err := d.Run(np)
	if err != nil {
		t.Error(err)
	}

	// create socket
	if err := d.Listen(); err != nil {
		t.Fatal(err)
	}

	// check pids
	if pid, err := d.ReadPidFile(filepath.Join(parentDir, "parent.pid")); err != nil {
		t.Error(err)
	} else {
		expect(t, os.Getpid(), pid)
	}
	if pid, err := d.ReadPidFile(filepath.Join(parentDir, "child.pid")); err != nil {
		t.Error(err, pid)
	} else {
		expect(t, p.Pid(), pid)
	}

	// check lock
	if _, err = os.Stat(filepath.Join(sdir, "immortal.sock")); err != nil {
		t.Fatal(err)
	}

	status := &Status{}
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "", status); err != nil {
		t.Fatal(err)
	}

	// http socket client
	// test "k", process should restart and get a new pid
	t.Log("testing k")
	expect(t, p.Pid(), status.Pid)

	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/k", status); err != nil {
		t.Fatal(err)
	}
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: killed", err.Error())
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}

	if status.Pid == p.Pid() {
		t.Fatalf("Expecting a new pid")
	}

	// $ pgrep -fl TestHelperProcessSignalsUDO
	// PID _test/immortal.test -test.run=TestHelperProcessSignalsUDOT --

	// test "d", (keep it down and don't restart)
	t.Log("testing d")
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/d", status); err != nil {
		t.Fatal(err)
	}
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: terminated", err.Error())
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}

	// test "u"
	t.Log("testing up")
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/up", status); err != nil {
		t.Fatal(err)
	}
	<-d.run
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}

	// test "once", process should not restart after going down
	t.Log("testing once")
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/o", status); err != nil {
		t.Fatal(err)
	}
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/k", status); err != nil {
		t.Fatal(err)
	}
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: killed", err.Error())
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}

	// test "u"
	t.Log("testing u")
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/u", status); err != nil {
		t.Fatal(err)
	}
	<-d.run
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	oldPid := p.Pid()

	// test "t"
	t.Log("testing t")
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/t", status); err != nil {
		t.Fatal(err)
	}
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: terminated", err.Error())

	// restart to get new pid
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	if oldPid == p.Pid() {
		t.Fatal("Expecting a new pid")
	}
	if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/kill", status); err != nil {
		t.Fatal(err)
	}
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: killed", err.Error())

	// test after
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}

	select {
	case err := <-p.errch:
		expect(t, "signal: killed", err.Error())
	case <-time.After(1 * time.Second):
		if err := GetJSON(filepath.Join(sdir, "immortal.sock"), "/signal/kill", status); err != nil {
			t.Fatal(err)
		}
	}

	// test log content
	t.Log("testing logfile")
	content, err := ioutil.ReadFile(tmpfile.Name())
	if err != nil {
		t.Fatal(err)
	}
	lines := strings.Split(string(content), "\n")
	expect(t, true, strings.HasSuffix(lines[0], "5D675098-45D7-4089-A72C-3628713EA5BA"))
}
<commit_msg>GetStatus and SendSignal using ctl<commit_after>package immortal

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

func TestDaemonNewCtl(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtl")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		Cwd: dir,
		ctl: dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	if _, err = os.Stat(filepath.Join(dir, "lock")); err != nil {
		t.Fatal(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lockOnce)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestDaemonNewCtlErr(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtlErr")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cwd, err := os.Getwd()
	if err != nil {
		t.Error(err)
	}
	defer os.Chdir(cwd)
	if err := os.Chdir(dir); err != nil {
		t.Error(err)
	}
	os.Chmod(dir, 0000)
	cfg := &Config{
		ctl: dir,
	}
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestDaemonNewCtlCwd(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrlCwd")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cwd, err := os.Getwd()
	if err != nil {
		t.Error(err)
	}
	defer os.Chdir(cwd)
	if err := os.Chdir(dir); err != nil {
		t.Error(err)
	}
	cfg := &Config{
		ctl: dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Error(err)
	}
	if _, err = os.Stat(filepath.Join(dir, "lock")); err != nil {
		t.Fatal(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lockOnce)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestBadUid(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestBadUid")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "uid", Gid: "0"},
		ctl:     dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadGid(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestBadGid")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "0", Gid: "gid"},
		ctl:     dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestUser(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestUser")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "0", Gid: "0"},
		ctl:     dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadWritePidParent(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestBadWritePidParent")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Parent: "/dev/null/parent.pid",
		},
		ctl: dir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/parent.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestBadWritePidChild(t *testing.T) {
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Child: "/dev/null/child.pid",
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/child.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestHelperProcessSignalsUDOT(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	fmt.Println("5D675098-45D7-4089-A72C-3628713EA5BA")
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	select {
	case <-c:
		os.Exit(1)
	case <-time.After(10 * time.Second):
		os.Exit(0)
	}
}

func TestSignalsUDOT(t *testing.T) {
	sdir, err := ioutil.TempDir("", "TestSignalsUDOT")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(sdir)
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	tmpfile, err := ioutil.TempFile("", "TestLogFile")
	if err != nil {
		t.Error(err)
	}
	defer os.Remove(tmpfile.Name()) // clean up
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSignalsUDOT", "--"},
		Cwd:     parentDir,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
		},
		Log: Log{
			File: tmpfile.Name(),
		},
		ctl: sdir,
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}

	np := NewProcess(cfg)
	expect(t, 0, np.Pid())
	p, err := d.Run(np)
	if err != nil {
		t.Error(err)
	}

	// create socket
	if err := d.Listen(); err != nil {
		t.Fatal(err)
	}

	// check pids
	if pid, err := d.ReadPidFile(filepath.Join(parentDir, "parent.pid")); err != nil {
		t.Error(err)
	} else {
		expect(t, os.Getpid(), pid)
	}
	if pid, err := d.ReadPidFile(filepath.Join(parentDir, "child.pid")); err != nil {
		t.Error(err, pid)
	} else {
		expect(t, p.Pid(), pid)
	}

	// check lock
	if _, err = os.Stat(filepath.Join(sdir, "immortal.sock")); err != nil {
		t.Fatal(err)
	}

	status := &Status{}
	ctl := &Controller{}
	signalResponse := &SignalResponse{}
	if status, err = ctl.GetStatus(filepath.Join(sdir, "immortal.sock")); err != nil {
		t.Fatal(err)
	}
	expect(t, "_test/immortal.test -test.run=TestHelperProcessSignalsUDOT --", status.Cmd)
	expect(t, 1, int(status.Count))

	// http socket client
	// test "k", process should restart and get a new pid
	t.Log("testing k")
	expect(t, p.Pid(), status.Pid)

	if signalResponse, err = ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "k"); err != nil {
		t.Fatal(err)
	}
	expect(t, "", signalResponse.Err)

	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: killed", err.Error())
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}

	if status.Pid == p.Pid() {
		t.Fatalf("Expecting a new pid")
	}

	// $ pgrep -fl TestHelperProcessSignalsUDO
	// PID _test/immortal.test -test.run=TestHelperProcessSignalsUDOT --

	// test "d", (keep it down and don't restart)
	t.Log("testing d")
	if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "d"); err != nil {
		t.Fatal(err)
	}
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: terminated", err.Error())
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}

	// test "u"
	t.Log("testing up")
	if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "up"); err != nil {
		t.Fatal(err)
	}
	<-d.run
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}

	// test "once", process should not restart after going down
	t.Log("testing once")
	if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "o"); err != nil {
		t.Fatal(err)
	}
	if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "k"); err != nil {
		t.Fatal(err)
	}
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: killed", err.Error())
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}

	if status, err = ctl.GetStatus(filepath.Join(sdir, "immortal.sock")); err != nil {
		t.Fatal(err)
	}
	expect(t, 3, int(status.Count))

	// test "u"
	t.Log("testing u")
	if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "u"); err != nil {
		t.Fatal(err)
	}
	<-d.run
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	oldPid := p.Pid()

	// test "t"
	t.Log("testing t")
	if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "t"); err != nil {
		t.Fatal(err)
	}
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: terminated", err.Error())

	// restart to get new pid
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	if oldPid == p.Pid() {
		t.Fatal("Expecting a new pid")
	}
	if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "kill"); err != nil {
		t.Fatal(err)
	}
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lockOnce)
	expect(t, "signal: killed", err.Error())

	// test after
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}

	select {
	case err := <-p.errch:
		expect(t, "signal: killed", err.Error())
	case <-time.After(1 * time.Second):
		if _, err := ctl.SendSignal(filepath.Join(sdir, "immortal.sock"), "kill"); err != nil {
			t.Fatal(err)
		}
	}

	if status, err = ctl.GetStatus(filepath.Join(sdir, "immortal.sock")); err != nil {
		t.Fatal(err)
	}
	expect(t, 6, int(status.Count))

	// test log content
	t.Log("testing logfile")
	content, err := ioutil.ReadFile(tmpfile.Name())
	if err != nil {
		t.Fatal(err)
	}
	lines := strings.Split(string(content), "\n")
	expect(t, true, strings.HasSuffix(lines[0], "5D675098-45D7-4089-A72C-3628713EA5BA"))
}
<|endoftext|>


<commit_before>package bootstrap

import (
	"fmt"
	"gnd.la/template/assets"
	"gnd.la/util/semver"
)

const (
	bootstrapCSSFmt              = "//netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap.min.css"
	bootstrapCSSNoIconsFmt       = "//netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap.no-icons.min.css"
	bootstrapCSSNoIconsLegacyFmt = "//netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap-combined.no-icons.min.css"
	bootstrapCSSThemeFmt         = "http://netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap-theme.min.css"
	bootstrapJSFmt               = "//netdna.bootstrapcdn.com/bootstrap/%s/js/bootstrap.min.js"
	fontAwesomeFmt               = "//netdna.bootstrapcdn.com/font-awesome/%s/css/font-awesome.min.css"
)

func bootstrapParser(m *assets.Manager, names []string, options assets.Options) ([]*assets.Asset, error) {
	if len(names) > 1 {
		return nil, fmt.Errorf("invalid bootstrap declaration \"%s\": must include only a version number", names)
	}
	bsV := names[0]
	bsVersion, err := semver.Parse(bsV)
	if err != nil || bsVersion.PreRelease != "" || bsVersion.Build != "" {
		return nil, fmt.Errorf("invalid bootstrap version %q", bsV)
	}
	if bsVersion.Major != 2 && bsVersion.Major != 3 {
		return nil, fmt.Errorf("only bootstrap versions 2.x and 3.x are supported")
	}
	var as []*assets.Asset
	if options.BoolOpt("fontawesome") {
		faV := options.StringOpt("fontawesome")
		if faV == "" {
			return nil, fmt.Errorf("please, specify a font awesome version")
		}
		faVersion, err := semver.Parse(faV)
		if err != nil || faVersion.PreRelease != "" || faVersion.Build != "" {
			return nil, fmt.Errorf("invalid font awesome version %q", faV)
		}
		if faVersion.Major != 3 && faVersion.Major != 4 {
			return nil, fmt.Errorf("only font awesome versions 3.x and 4.x are supported")
		}
		format := bootstrapCSSFmt
		if bsVersion.Major == 2 {
			format = bootstrapCSSNoIconsLegacyFmt
		} else if faVersion.Major == 3 {
			if bsVersion.Major >= 3 && (bsVersion.Minor > 0 || bsVersion.Patch > 0) {
				return nil, fmt.Errorf("can't use bootstrap > 3.0.0 with font awesome 3 (bootstrapcdn does not provide the files)")
			} else {
				format = bootstrapCSSNoIconsFmt
			}
		}
		as = append(as, assets.CSS(fmt.Sprintf(format, bsV)))
		as = append(as, assets.CSS(fmt.Sprintf(fontAwesomeFmt, faV)))
	} else {
		as = append(as, assets.CSS(fmt.Sprintf(bootstrapCSSFmt, bsV)))
	}
	if options.BoolOpt("theme") && bsVersion.Major == 3 {
		as = append(as, assets.CSS(fmt.Sprintf(bootstrapCSSThemeFmt, bsV)))
	}
	// Required for IE8 support
	html5Shiv := assets.Script("https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js")
	respondJs := assets.Script("https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js")
	cond := &assets.Condition{Comparison: assets.ComparisonLessThan, Version: 9}
	html5Shiv.Condition = cond
	respondJs.Condition = cond
	as = append(as, html5Shiv, respondJs)
	if !options.BoolOpt("nojs") {
		as = append(as, assets.Script(fmt.Sprintf("bootstrap-%s.js", bsV)))
	}
	return as, nil
}

func fontAwesomeParser(m *assets.Manager, version string, opts assets.Options) ([]*assets.Asset, error) {
	return []*assets.Asset{assets.CSS(fmt.Sprintf(fontAwesomeFmt, version))}, nil
}

func init() {
	assets.Register("bootstrap", bootstrapParser)
	assets.Register("fontawesome", assets.SingleParser(fontAwesomeParser))
}
<commit_msg>Fix bootstrap JS asset URL<commit_after>package bootstrap

import (
	"fmt"
	"gnd.la/template/assets"
	"gnd.la/util/semver"
)

const (
	bootstrapCSSFmt              = "//netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap.min.css"
	bootstrapCSSNoIconsFmt       = "//netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap.no-icons.min.css"
	bootstrapCSSNoIconsLegacyFmt = "//netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap-combined.no-icons.min.css"
	bootstrapCSSThemeFmt         = "http://netdna.bootstrapcdn.com/bootstrap/%s/css/bootstrap-theme.min.css"
	bootstrapJSFmt               = "//netdna.bootstrapcdn.com/bootstrap/%s/js/bootstrap.min.js"
	fontAwesomeFmt               = "//netdna.bootstrapcdn.com/font-awesome/%s/css/font-awesome.min.css"
)

func bootstrapParser(m *assets.Manager, names []string, options assets.Options) ([]*assets.Asset, error) {
	if len(names) > 1 {
		return nil, fmt.Errorf("invalid bootstrap declaration \"%s\": must include only a version number", names)
	}
	bsV := names[0]
	bsVersion, err := semver.Parse(bsV)
	if err != nil || bsVersion.PreRelease != "" || bsVersion.Build != "" {
		return nil, fmt.Errorf("invalid bootstrap version %q", bsV)
	}
	if bsVersion.Major != 2 && bsVersion.Major != 3 {
		return nil, fmt.Errorf("only bootstrap versions 2.x and 3.x are supported")
	}
	var as []*assets.Asset
	if options.BoolOpt("fontawesome") {
		faV := options.StringOpt("fontawesome")
		if faV == "" {
			return nil, fmt.Errorf("please, specify a font awesome version")
		}
		faVersion, err := semver.Parse(faV)
		if err != nil || faVersion.PreRelease != "" || faVersion.Build != "" {
			return nil, fmt.Errorf("invalid font awesome version %q", faV)
		}
		if faVersion.Major != 3 && faVersion.Major != 4 {
			return nil, fmt.Errorf("only font awesome versions 3.x and 4.x are supported")
		}
		format := bootstrapCSSFmt
		if bsVersion.Major == 2 {
			format = bootstrapCSSNoIconsLegacyFmt
		} else if faVersion.Major == 3 {
			if bsVersion.Major >= 3 && (bsVersion.Minor > 0 || bsVersion.Patch > 0) {
				return nil, fmt.Errorf("can't use bootstrap > 3.0.0 with font awesome 3 (bootstrapcdn does not provide the files)")
			} else {
				format = bootstrapCSSNoIconsFmt
			}
		}
		as = append(as, assets.CSS(fmt.Sprintf(format, bsV)))
		as = append(as, assets.CSS(fmt.Sprintf(fontAwesomeFmt, faV)))
	} else {
		as = append(as, assets.CSS(fmt.Sprintf(bootstrapCSSFmt, bsV)))
	}
	if options.BoolOpt("theme") && bsVersion.Major == 3 {
		as = append(as, assets.CSS(fmt.Sprintf(bootstrapCSSThemeFmt, bsV)))
	}
	// Required for IE8 support
	html5Shiv := assets.Script("https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js")
	respondJs := assets.Script("https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js")
	cond := &assets.Condition{Comparison: assets.ComparisonLessThan, Version: 9}
	html5Shiv.Condition = cond
	respondJs.Condition = cond
	as = append(as, html5Shiv, respondJs)
	if !options.BoolOpt("nojs") {
		as = append(as, assets.Script(fmt.Sprintf(bootstrapJSFmt, bsV)))
	}
	return as, nil
}

func fontAwesomeParser(m *assets.Manager, version string, opts assets.Options) ([]*assets.Asset, error) {
	return []*assets.Asset{assets.CSS(fmt.Sprintf(fontAwesomeFmt, version))}, nil
}

func init() {
	assets.Register("bootstrap", bootstrapParser)
	assets.Register("fontawesome", assets.SingleParser(fontAwesomeParser))
}
<|endoftext|>


<commit_before>package bot

import (
	"bytes"
	"encoding/base64"
	"flag"
	"fmt"
	"image/png"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/lnxjedi/robot"
	"github.com/pquerna/otp/totp"
)

func processCLI(usage string) {
	cliArgs := flag.Args()
	command := cliArgs[0]

	var fileName string
	var encodeBinary bool
	var encodeBase64 bool

	encFlags := flag.NewFlagSet("encrypt", flag.ExitOnError)
	encFlags.StringVar(&fileName, "file", "", "file to encrypt (or - for stdout)")
	encFlags.StringVar(&fileName, "f", "", "")
	encFlags.BoolVar(&encodeBinary, "binary", false, "binary dump (defauts to base64 encoded)")
	encFlags.BoolVar(&encodeBinary, "b", false, "")
	encFlags.Usage = func() {
		fmt.Println("Usage: gopherbot encrypt [options] [string to encrypt]\n\nOptions:")
		encFlags.PrintDefaults()
	}

	decFlags := flag.NewFlagSet("decrypt", flag.ExitOnError)
	decFlags.StringVar(&fileName, "file", "", "file to decrypt (or - for stdin)")
	decFlags.StringVar(&fileName, "f", "", "")
	decFlags.BoolVar(&encodeBinary, "binary", false, "")
	decFlags.BoolVar(&encodeBinary, "b", false, "")
	decFlags.Usage = func() {
		fmt.Println("Usage: gopherbot decrypt [options] [string to decrypt]\n\nOptions:")
		decFlags.PrintDefaults()
	}

	totpFlags := flag.NewFlagSet("gentotp", flag.ExitOnError)
	totpFlags.Usage = func() {
		fmt.Println("Usage: gopherbot gentotp <username>\n")
	}

	fetchFlags := flag.NewFlagSet("fetch", flag.ExitOnError)
	fetchFlags.BoolVar(&encodeBase64, "base64", false, "encode memory as base64")
	fetchFlags.BoolVar(&encodeBase64, "b", false, "")
	fetchFlags.Usage = func() {
		fmt.Println("Usage: gopherbot fetch [options] <memory to fetch>\n\nOptions:")
		fetchFlags.PrintDefaults()
	}

	switch command {
	case "encrypt":
		encFlags.Parse(cliArgs[1:])
		if len(fileName) == 0 && len(encFlags.Args()) != 1 {
			encFlags.Usage()
			return
		}
		cliEncrypt(encFlags.Arg(0), fileName, encodeBinary)
	case "decrypt":
		decFlags.Parse(cliArgs[1:])
		if len(fileName) == 0 && len(decFlags.Args()) != 1 {
			decFlags.Usage()
			return
		}
		cliDecrypt(decFlags.Arg(0), fileName)
	case "gentotp":
		totpFlags.Parse(cliArgs[1:])
		if len(totpFlags.Args()) == 0 || len(totpFlags.Arg(0)) == 0 {
			totpFlags.Usage()
			return
		}
		cliTOTPgen(totpFlags.Arg(0))
	case "fetch":
		fetchFlags.Parse(cliArgs[1:])
		if len(fetchFlags.Args()) == 0 || len(fetchFlags.Arg(0)) == 0 {
			fetchFlags.Usage()
			return
		}
		cliFetch(fetchFlags.Arg(0), encodeBase64)
	case "init":
		if len(cliArgs) < 2 {
			fmt.Println("Usage: gopherbot init <protocol>")
			return
		}
		if _, err := os.Stat("answerfile.txt"); err == nil {
			fmt.Println("Not over-writing existing 'answerfile.txt'")
			return
		}
		ansFile := filepath.Join(installPath, "resources", "answerfiles", cliArgs[1]+".txt")
		if _, err := os.Stat(ansFile); err != nil {
			fmt.Printf("Protocol answerfile template not found: %s\n", ansFile)
			return
		}
		var ansBytes []byte
		var err error
		if ansBytes, err = ioutil.ReadFile(ansFile); err != nil {
			fmt.Printf("Reading '%s': %v", ansFile, err)
			return
		}
		if err = ioutil.WriteFile("answerfile.txt", ansBytes, 0600); err != nil {
			fmt.Printf("Writing 'answerfile.txt': %v", err)
			return
		}
		if _, err := os.Stat("gopherbot"); err == nil {
			fmt.Println("Edit 'answerfile.txt' and re-run gopherbot with no arguments to generate your robot.")
		} else {
			exeFile := filepath.Join(installPath, "gopherbot")
			err := os.Symlink(exeFile, "gopherbot")
			if err != nil {
				fmt.Println("Unable to create symlink for 'gopherbot'")
				fmt.Println("Edit 'answerfile.txt' and re-run gopherbot with no arguments to generate your robot.")
			} else {
				fmt.Println("Edit 'answerfile.txt' and run './gopherbot' with no arguments to generate your robot.")
			}
		}
	case "store":
		if len(cliArgs) < 2 {
			fmt.Println("Usage: gopherbot store <key> [filename]")
			return
		}
		file := "-"
		if len(cliArgs) == 3 {
			file = cliArgs[2]
		}
		cliStore(cliArgs[1], file)
	case "list":
		cliList()
	case "delete":
		if len(cliArgs) != 2 {
			fmt.Println("Usage: gopherbot delete <key>")
			return
		}
		cliDelete(cliArgs[1])
	case "version":
		fmt.Printf("Version %s, commit: %s\n", botVersion.Version, botVersion.Commit)
	default:
		fmt.Printf("Invalid command/option(s): %s, %q\n", cliArgs[0], cliArgs[1:])
		fmt.Println(usage)
		flag.PrintDefaults()
	}
}

func cliTOTPgen(user string) {
	if !cryptKey.initialized {
		fmt.Println("Encryption not initialized")
		os.Exit(1)
	}
	key, err := totp.Generate(totp.GenerateOpts{
		Issuer:      currentCfg.botinfo.FullName,
		AccountName: user,
	})
	if err != nil {
		fmt.Printf("Error generating TOTP: %v\n", err)
		os.Exit(1)
	}
	secStr := key.Secret()
	fmt.Printf("Secret for %s: %s\n", user, secStr)
	ct, err := encrypt([]byte(secStr), cryptKey.key)
	if err != nil {
		fmt.Printf("Error encrypting: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("Encrypted secret for config: \"%s\": \"{{ decrypt \"%s\" }}\"\n", user, base64.StdEncoding.EncodeToString(ct))
	var buf bytes.Buffer
	img, imgerr := key.Image(400, 400)
	if imgerr != nil {
		fmt.Printf("Error generating image: %v\n", imgerr)
		os.Exit(1)
	}
	png.Encode(&buf, img)
	ferr := os.WriteFile(fmt.Sprintf("%s.png", user), buf.Bytes(), 0644)
	if ferr != nil {
		fmt.Printf("Error writing '%s.png': %v\n", user, imgerr)
		os.Exit(1)
	}
	fmt.Printf("Wrote '%s.png'\n", user)
}

func cliEncrypt(item, file string, binary bool) {
	if !cryptKey.initialized {
		fmt.Println("Encryption not initialized")
		os.Exit(1)
	}
	if len(file) > 0 {
		var fc []byte
		var err error
		if file == "-" {
			fc, err = ioutil.ReadAll(os.Stdin)
		} else {
			fc, err = ioutil.ReadFile(file)
		}
		if err != nil {
			fmt.Printf("Error reading file: %v\n", err)
			os.Exit(1)
		}
		ct, err := encrypt(fc, cryptKey.key)
		if err != nil {
			fmt.Printf("Error encrypting: %v\n", err)
			os.Exit(1)
		}
		if binary {
			os.Stdout.Write(ct)
		} else {
			WriteBase64(os.Stdout, &ct)
		}
		return
	}
	if len(item) > 0 {
		ct, err := encrypt([]byte(item), cryptKey.key)
		if err != nil {
			fmt.Printf("Error encrypting: %v\n", err)
			os.Exit(1)
		}
		if binary {
			os.Stdout.Write(ct)
		} else {
			fmt.Println(base64.StdEncoding.EncodeToString(ct))
		}
		return
	}
	os.Stderr.Write([]byte("Ingoring zero-length item\n"))
	os.Exit(1)
}

func cliDecrypt(item, file string) {
	if !cryptKey.initialized {
		fmt.Println("Encryption not initialized")
		os.Exit(1)
	}
	if len(file) > 0 {
		var ct *[]byte
		var err error
		if file == "-" {
			ct, err = ReadBinary(os.Stdin)
		} else {
			ct, err = ReadBinaryFile(file)
		}
		if err != nil {
			fmt.Printf("Error reading file: %v\n", err)
			os.Exit(1)
		}
		pt, err := decrypt(*ct, cryptKey.key)
		if err != nil {
			fmt.Printf("Error decrypting: %v\n", err)
		}
		os.Stdout.Write(pt)
		return
	}
	if len(item) > 0 {
		eb, err := base64.StdEncoding.DecodeString(item)
		if err != nil {
			fmt.Printf("Decoding base64: %v\n", err)
			os.Exit(1)
		}
		value, err := decrypt(eb, cryptKey.key)
		if err != nil {
			fmt.Printf("Error decrypting: %v\n", err)
			os.Exit(1)
		}
		fmt.Println(string(value))
		return
	}
	os.Stderr.Write([]byte("Ingoring zero-length item\n"))
	os.Exit(1)
}

func cliFetch(item string, b64 bool) {
	_, datum, exists, ret := getDatum(item, false)
	if ret != robot.Ok {
		fmt.Printf("Retrieving datum: %v\n", ret)
		os.Exit(1)
	}
	if !exists {
		fmt.Println("Item not found")
		os.Exit(1)
	}
	if b64 {
		encoder := base64.NewEncoder(base64.StdEncoding, os.Stdout)
		encoder.Write(*datum)
		os.Stdout.Write([]byte("\n"))
		return
	}
	os.Stdout.Write(*datum)
	os.Stdout.Write([]byte("\n"))
}

func cliStore(key, file string) {
	var fc []byte
	var err error
	if file == "-" {
		fc, err = ioutil.ReadAll(os.Stdin)
	} else {
		fc, err = ioutil.ReadFile(file)
	}
	if err != nil {
		fmt.Printf("Error reading file: %v\n", err)
		os.Exit(1)
	}
	tok, _, _, ret := checkout(key, true)
	if ret != robot.Ok {
		fmt.Printf("Getting token: %s\n", ret)
		return
	}
	ret = update(key, tok, &fc)
	if ret != robot.Ok {
		fmt.Printf("Storing datum: %s\n", ret)
		return
	}
	fmt.Println("Stored")
}

func cliList() {
	brain := interfaces.brain
	list, err := brain.List()
	if err != nil {
		fmt.Printf("Listing memories: %v\n", err)
		return
	}
	if len(list) > 0 {
		for _, memory := range list {
			fmt.Println(memory)
		}
		return
	}
	fmt.Println("No memories found")
}

func cliDelete(key string) {
	brain := interfaces.brain
	err := brain.Delete(key)
	if err != nil {
		fmt.Printf("Deleting memory: %v\n", err)
		return
	}
	fmt.Println("Deleted")
}
<commit_msg>You can't read from stdout<commit_after>package bot

import (
	"bytes"
	"encoding/base64"
	"flag"
	"fmt"
	"image/png"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/lnxjedi/robot"
	"github.com/pquerna/otp/totp"
)

func processCLI(usage string) {
	cliArgs := flag.Args()
	command := cliArgs[0]

	var fileName string
	var encodeBinary bool
	var encodeBase64 bool

	encFlags := flag.NewFlagSet("encrypt", flag.ExitOnError)
	encFlags.StringVar(&fileName, "file", "", "file to encrypt (or - for stdin)")
	encFlags.StringVar(&fileName, "f", "", "")
	encFlags.BoolVar(&encodeBinary, "binary", false, "binary dump (defauts to base64 encoded)")
	encFlags.BoolVar(&encodeBinary, "b", false, "")
	encFlags.Usage = func() {
		fmt.Println("Usage: gopherbot encrypt [options] [string to encrypt]\n\nOptions:")
		encFlags.PrintDefaults()
	}

	decFlags := flag.NewFlagSet("decrypt", flag.ExitOnError)
	decFlags.StringVar(&fileName, "file", "", "file to decrypt (or - for stdin)")
	decFlags.StringVar(&fileName, "f", "", "")
	decFlags.BoolVar(&encodeBinary, "binary", false, "")
	decFlags.BoolVar(&encodeBinary, "b", false, "")
	decFlags.Usage = func() {
		fmt.Println("Usage: gopherbot decrypt [options] [string to decrypt]\n\nOptions:")
		decFlags.PrintDefaults()
	}

	totpFlags := flag.NewFlagSet("gentotp", flag.ExitOnError)
	totpFlags.Usage = func() {
		fmt.Println("Usage: gopherbot gentotp <username>\n")
	}

	fetchFlags := flag.NewFlagSet("fetch", flag.ExitOnError)
	fetchFlags.BoolVar(&encodeBase64, "base64", false, "encode memory as base64")
	fetchFlags.BoolVar(&encodeBase64, "b", false, "")
	fetchFlags.Usage = func() {
		fmt.Println("Usage: gopherbot fetch [options] <memory to fetch>\n\nOptions:")
		fetchFlags.PrintDefaults()
	}

	switch command {
	case "encrypt":
		encFlags.Parse(cliArgs[1:])
		if len(fileName) == 0 && len(encFlags.Args()) != 1 {
			encFlags.Usage()
			return
		}
		cliEncrypt(encFlags.Arg(0), fileName, encodeBinary)
	case "decrypt":
		decFlags.Parse(cliArgs[1:])
		if len(fileName) == 0 && len(decFlags.Args()) != 1 {
			decFlags.Usage()
			return
		}
		cliDecrypt(decFlags.Arg(0), fileName)
	case "gentotp":
		totpFlags.Parse(cliArgs[1:])
		if len(totpFlags.Args()) == 0 || len(totpFlags.Arg(0)) == 0 {
			totpFlags.Usage()
			return
		}
		cliTOTPgen(totpFlags.Arg(0))
	case "fetch":
		fetchFlags.Parse(cliArgs[1:])
		if len(fetchFlags.Args()) == 0 || len(fetchFlags.Arg(0)) == 0 {
			fetchFlags.Usage()
			return
		}
		cliFetch(fetchFlags.Arg(0), encodeBase64)
	case "init":
		if len(cliArgs) < 2 {
			fmt.Println("Usage: gopherbot init <protocol>")
			return
		}
		if _, err := os.Stat("answerfile.txt"); err == nil {
			fmt.Println("Not over-writing existing 'answerfile.txt'")
			return
		}
		ansFile := filepath.Join(installPath, "resources", "answerfiles", cliArgs[1]+".txt")
		if _, err := os.Stat(ansFile); err != nil {
			fmt.Printf("Protocol answerfile template not found: %s\n", ansFile)
			return
		}
		var ansBytes []byte
		var err error
		if ansBytes, err = ioutil.ReadFile(ansFile); err != nil {
			fmt.Printf("Reading '%s': %v", ansFile, err)
			return
		}
		if err = ioutil.WriteFile("answerfile.txt", ansBytes, 0600); err != nil {
			fmt.Printf("Writing 'answerfile.txt': %v", err)
			return
		}
		if _, err := os.Stat("gopherbot"); err == nil {
			fmt.Println("Edit 'answerfile.txt' and re-run gopherbot with no arguments to generate your robot.")
		} else {
			exeFile := filepath.Join(installPath, "gopherbot")
			err := os.Symlink(exeFile, "gopherbot")
			if err != nil {
				fmt.Println("Unable to create symlink for 'gopherbot'")
				fmt.Println("Edit 'answerfile.txt' and re-run gopherbot with no arguments to generate your robot.")
			} else {
				fmt.Println("Edit 'answerfile.txt' and run './gopherbot' with no arguments to generate your robot.")
			}
		}
	case "store":
		if len(cliArgs) < 2 {
			fmt.Println("Usage: gopherbot store <key> [filename]")
			return
		}
		file := "-"
		if len(cliArgs) == 3 {
			file = cliArgs[2]
		}
		cliStore(cliArgs[1], file)
	case "list":
		cliList()
	case "delete":
		if len(cliArgs) != 2 {
			fmt.Println("Usage: gopherbot delete <key>")
			return
		}
		cliDelete(cliArgs[1])
	case "version":
		fmt.Printf("Version %s, commit: %s\n", botVersion.Version, botVersion.Commit)
	default:
		fmt.Printf("Invalid command/option(s): %s, %q\n", cliArgs[0], cliArgs[1:])
		fmt.Println(usage)
		flag.PrintDefaults()
	}
}

func cliTOTPgen(user string) {
	if !cryptKey.initialized {
		fmt.Println("Encryption not initialized")
		os.Exit(1)
	}
	key, err := totp.Generate(totp.GenerateOpts{
		Issuer:      currentCfg.botinfo.FullName,
		AccountName: user,
	})
	if err != nil {
		fmt.Printf("Error generating TOTP: %v\n", err)
		os.Exit(1)
	}
	secStr := key.Secret()
	fmt.Printf("Secret for %s: %s\n", user, secStr)
	ct, err := encrypt([]byte(secStr), cryptKey.key)
	if err != nil {
		fmt.Printf("Error encrypting: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("Encrypted secret for config: \"%s\": \"{{ decrypt \"%s\" }}\"\n", user, base64.StdEncoding.EncodeToString(ct))
	var buf bytes.Buffer
	img, imgerr := key.Image(400, 400)
	if imgerr != nil {
		fmt.Printf("Error generating image: %v\n", imgerr)
		os.Exit(1)
	}
	png.Encode(&buf, img)
	ferr := os.WriteFile(fmt.Sprintf("%s.png", user), buf.Bytes(), 0644)
	if ferr != nil {
		fmt.Printf("Error writing '%s.png': %v\n", user, imgerr)
		os.Exit(1)
	}
	fmt.Printf("Wrote '%s.png'\n", user)
}

func cliEncrypt(item, file string, binary bool) {
	if !cryptKey.initialized {
		fmt.Println("Encryption not initialized")
		os.Exit(1)
	}
	if len(file) > 0 {
		var fc []byte
		var err error
		if file == "-" {
			fc, err = ioutil.ReadAll(os.Stdin)
		} else {
			fc, err = ioutil.ReadFile(file)
		}
		if err != nil {
			fmt.Printf("Error reading file: %v\n", err)
			os.Exit(1)
		}
		ct, err := encrypt(fc, cryptKey.key)
		if err != nil {
			fmt.Printf("Error encrypting: %v\n", err)
			os.Exit(1)
		}
		if binary {
			os.Stdout.Write(ct)
		} else {
			WriteBase64(os.Stdout, &ct)
		}
		return
	}
	if len(item) > 0 {
		ct, err := encrypt([]byte(item), cryptKey.key)
		if err != nil {
			fmt.Printf("Error encrypting: %v\n", err)
			os.Exit(1)
		}
		if binary {
			os.Stdout.Write(ct)
		} else {
			fmt.Println(base64.StdEncoding.EncodeToString(ct))
		}
		return
	}
	os.Stderr.Write([]byte("Ingoring zero-length item\n"))
	os.Exit(1)
}

func cliDecrypt(item, file string) {
	if !cryptKey.initialized {
		fmt.Println("Encryption not initialized")
		os.Exit(1)
	}
	if len(file) > 0 {
		var ct *[]byte
		var err error
		if file == "-" {
			ct, err = ReadBinary(os.Stdin)
		} else {
			ct, err = ReadBinaryFile(file)
		}
		if err != nil {
			fmt.Printf("Error reading file: %v\n", err)
			os.Exit(1)
		}
		pt, err := decrypt(*ct, cryptKey.key)
		if err != nil {
			fmt.Printf("Error decrypting: %v\n", err)
		}
		os.Stdout.Write(pt)
		return
	}
	if len(item) > 0 {
		eb, err := base64.StdEncoding.DecodeString(item)
		if err != nil {
			fmt.Printf("Decoding base64: %v\n", err)
			os.Exit(1)
		}
		value, err := decrypt(eb, cryptKey.key)
		if err != nil {
			fmt.Printf("Error decrypting: %v\n", err)
			os.Exit(1)
		}
		fmt.Println(string(value))
		return
	}
	os.Stderr.Write([]byte("Ingoring zero-length item\n"))
	os.Exit(1)
}

func cliFetch(item string, b64 bool) {
	_, datum, exists, ret := getDatum(item, false)
	if ret != robot.Ok {
		fmt.Printf("Retrieving datum: %v\n", ret)
		os.Exit(1)
	}
	if !exists {
		fmt.Println("Item not found")
		os.Exit(1)
	}
	if b64 {
		encoder := base64.NewEncoder(base64.StdEncoding, os.Stdout)
		encoder.Write(*datum)
		os.Stdout.Write([]byte("\n"))
		return
	}
	os.Stdout.Write(*datum)
	os.Stdout.Write([]byte("\n"))
}

func cliStore(key, file string) {
	var fc []byte
	var err error
	if file == "-" {
		fc, err = ioutil.ReadAll(os.Stdin)
	} else {
		fc, err = ioutil.ReadFile(file)
	}
	if err != nil {
		fmt.Printf("Error reading file: %v\n", err)
		os.Exit(1)
	}
	tok, _, _, ret := checkout(key, true)
	if ret != robot.Ok {
		fmt.Printf("Getting token: %s\n", ret)
		return
	}
	ret = update(key, tok, &fc)
	if ret != robot.Ok {
		fmt.Printf("Storing datum: %s\n", ret)
		return
	}
	fmt.Println("Stored")
}

func cliList() {
	brain := interfaces.brain
	list, err := brain.List()
	if err != nil {
		fmt.Printf("Listing memories: %v\n", err)
		return
	}
	if len(list) > 0 {
		for _, memory := range list {
			fmt.Println(memory)
		}
		return
	}
	fmt.Println("No memories found")
}

func cliDelete(key string) {
	brain := interfaces.brain
	err := brain.Delete(key)
	if err != nil {
		fmt.Printf("Deleting memory: %v\n", err)
		return
	}
	fmt.Println("Deleted")
}
<|endoftext|>


<commit_before>// Copyright 2014 Docker authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the DOCKER-LICENSE file.

package docker

import (
	"encoding/binary"
	"errors"
	"io"
)

const (
	stdWriterPrefixLen = 8
	stdWriterFdIndex   = 0
	stdWriterSizeIndex = 4
)

var errInvalidStdHeader = errors.New("Unrecognized input header")

func stdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) {
	var (
		buf       = make([]byte, 32*1024+stdWriterPrefixLen+1)
		bufLen    = len(buf)
		nr, nw    int
		er, ew    error
		out       io.Writer
		frameSize int
	)
	for {
		for nr < stdWriterPrefixLen {
			var nr2 int
			nr2, er = src.Read(buf[nr:])
			if er == io.EOF {
				if nr < stdWriterPrefixLen && nr2 < stdWriterPrefixLen {
					return written, nil
				}
				nr += nr2
				break
			} else if er != nil {
				return 0, er
			}
			nr += nr2
		}
		switch buf[stdWriterFdIndex] {
		case 0:
			fallthrough
		case 1:
			out = dstout
		case 2:
			out = dsterr
		default:
			return 0, errInvalidStdHeader
		}
		frameSize = int(binary.BigEndian.Uint32(buf[stdWriterSizeIndex : stdWriterSizeIndex+4]))
		if frameSize+stdWriterPrefixLen > bufLen {
			buf = append(buf, make([]byte, frameSize+stdWriterPrefixLen-len(buf)+1)...)
			bufLen = len(buf)
		}
		for nr < frameSize+stdWriterPrefixLen {
			var nr2 int
			nr2, er = src.Read(buf[nr:])
			if er == io.EOF {
				if nr == 0 {
					return written, nil
				}
				nr += nr2
				break
			} else if er != nil {
				return 0, er
			}
			nr += nr2
		}
		bound := frameSize + stdWriterPrefixLen
		if bound > nr {
			bound = nr
		}
		nw, ew = out.Write(buf[stdWriterPrefixLen:bound])
		if nw > 0 {
			written += int64(nw)
		}
		if ew != nil {
			return 0, ew
		}
		if nw != frameSize {
			return written, io.ErrShortWrite
		}
		copy(buf, buf[frameSize+stdWriterPrefixLen:])
		nr -= frameSize + stdWriterPrefixLen
	}
}
<commit_msg>stdcopy: simplify switch statement<commit_after>// Copyright 2014 Docker authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the DOCKER-LICENSE file.

package docker

import (
	"encoding/binary"
	"errors"
	"io"
)

const (
	stdWriterPrefixLen = 8
	stdWriterFdIndex   = 0
	stdWriterSizeIndex = 4
)

var errInvalidStdHeader = errors.New("Unrecognized input header")

func stdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) {
	var (
		buf       = make([]byte, 32*1024+stdWriterPrefixLen+1)
		bufLen    = len(buf)
		nr, nw    int
		er, ew    error
		out       io.Writer
		frameSize int
	)
	for {
		for nr < stdWriterPrefixLen {
			var nr2 int
			nr2, er = src.Read(buf[nr:])
			if er == io.EOF {
				if nr < stdWriterPrefixLen && nr2 < stdWriterPrefixLen {
					return written, nil
				}
				nr += nr2
				break
			} else if er != nil {
				return 0, er
			}
			nr += nr2
		}
		switch buf[stdWriterFdIndex] {
		case 0, 1:
			out = dstout
		case 2:
			out = dsterr
		default:
			return 0, errInvalidStdHeader
		}
		frameSize = int(binary.BigEndian.Uint32(buf[stdWriterSizeIndex : stdWriterSizeIndex+4]))
		if frameSize+stdWriterPrefixLen > bufLen {
			buf = append(buf, make([]byte, frameSize+stdWriterPrefixLen-len(buf)+1)...)
			bufLen = len(buf)
		}
		for nr < frameSize+stdWriterPrefixLen {
			var nr2 int
			nr2, er = src.Read(buf[nr:])
			if er == io.EOF {
				if nr == 0 {
					return written, nil
				}
				nr += nr2
				break
			} else if er != nil {
				return 0, er
			}
			nr += nr2
		}
		bound := frameSize + stdWriterPrefixLen
		if bound > nr {
			bound = nr
		}
		nw, ew = out.Write(buf[stdWriterPrefixLen:bound])
		if nw > 0 {
			written += int64(nw)
		}
		if ew != nil {
			return 0, ew
		}
		if nw != frameSize {
			return written, io.ErrShortWrite
		}
		copy(buf, buf[frameSize+stdWriterPrefixLen:])
		nr -= frameSize + stdWriterPrefixLen
	}
}
<|endoftext|>


<commit_before>package golib

import (
	"github.com/lunixbochs/vtclean"
	"golang.org/x/text/unicode/norm"
)

func StringLength(str string) (strlen int) {
	str = vtclean.Clean(str, false)
	var ia norm.Iter
	ia.InitString(norm.NFKD, str)
	for ; !ia.Done(); ia.Next() {
		strlen += 1
	}
	// Alternative:
	// strlen = utf8.RuneCountInString(str)
	return
}
<commit_msg>Added function to get substring of utf8-string with possible escape characters and color codes.<commit_after>package golib

import (
	"bytes"

	"github.com/lunixbochs/vtclean"
	"golang.org/x/text/unicode/norm"
)

// Return the number of normalized utf8-runes within the cleaned string.
// Clean means no terminal escape characters and no color codes.
func StringLength(str string) (strlen int) {
	str = vtclean.Clean(str, false)
	var ia norm.Iter
	ia.InitString(norm.NFKD, str)
	for ; !ia.Done(); ia.Next() {
		strlen += 1
	}
	// Alternative:
	// strlen = utf8.RuneCountInString(str)
	return
}

// iFrom and iTo are indices to normalized utf8-runes within the cleaned string.
// Clean means no terminal escape characters and no color codes.
func Substring(str string, iFrom int, iTo int) string {
	var ia norm.Iter

	// Find the start in the input string
	from := 0
	ia.InitString(norm.NFKD, str)
	buf := bytes.NewBuffer(make([]byte, 0, len(str)))
	numRunes := 0
	cleanedLen := 0
	for !ia.Done() {
		from = ia.Pos()
		cleaned := vtclean.Clean(buf.String(), false)
		if len(cleaned) > cleanedLen {
			cleanedLen = len(cleaned)
			numRunes++
		}
		if numRunes >= iFrom {
			break
		}
		part := ia.Next()
		buf.Write(part)
	}

	iLen := iTo - iFrom
	str = str[from:]
	possibleColor := false

	// Find the end in the input string
	to := len(str)
	ia.InitString(norm.NFKD, str)
	buf.Reset()
	numRunes = 0
	cleanedLen = 0
	for !ia.Done() {
		part := ia.Next()
		buf.Write(part)
		to = ia.Pos()
		bufStr := buf.String()
		cleaned := vtclean.Clean(bufStr, false)
		if len(cleaned) > cleanedLen {
			cleanedLen = len(cleaned)
			numRunes++
		}
		if len(cleaned) != len(bufStr) {
			possibleColor = true
		}
		if numRunes >= iLen {
			break
		}
	}

	str = str[:to]
	if possibleColor {
		// Might contain color codes, make sure to disable colors at the end
		str = str + "\033[0m"
	}
	return str
}
<|endoftext|>