<commit_before>package tusd_test

import (
	"bytes"
	"net/http"
	"strings"
	"testing"

	"github.com/golang/mock/gomock"

	. "github.com/tus/tusd"
)

func TestPost(t *testing.T) {
	SubTest(t, "Create", func(t *testing.T, store *MockFullDataStore) {
		store.EXPECT().NewUpload(FileInfo{
			Size: 300,
			MetaData: map[string]string{
				"foo": "hello",
				"bar": "world",
			},
		}).Return("foo", nil)

		handler, _ := NewHandler(Config{
			DataStore: store,
			BasePath:  "/files/",
		})

		(&httpTest{
			Method: "POST",
			ReqHeader: map[string]string{
				"Tus-Resumable":   "1.0.0",
				"Upload-Length":   "300",
				"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
			},
			Code: http.StatusCreated,
			ResHeader: map[string]string{
				"Location": "http://tus.io/files/foo",
			},
		}).Run(handler, t)
	})

	SubTest(t, "CreateExceedingMaxSizeFail", func(t *testing.T, store *MockFullDataStore) {
		handler, _ := NewHandler(Config{
			MaxSize:   400,
			DataStore: store,
			BasePath:  "/files/",
		})

		(&httpTest{
			Name:   "Exceeding MaxSize",
			Method: "POST",
			ReqHeader: map[string]string{
				"Tus-Resumable":   "1.0.0",
				"Upload-Length":   "500",
				"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
			},
			Code: http.StatusRequestEntityTooLarge,
		}).Run(handler, t)
	})

	SubTest(t, "ForwardHeaders", func(t *testing.T, store *MockFullDataStore) {
		SubTest(t, "IgnoreXForwarded", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Host":  "foo.com",
					"X-Forwarded-Proto": "https",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "http://tus.io/files/foo",
				},
			}).Run(handler, t)
		})

		SubTest(t, "RespectXForwarded", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore:               store,
				BasePath:                "/files/",
				RespectForwardedHeaders: true,
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Host":  "foo.com",
					"X-Forwarded-Proto": "https",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "https://foo.com/files/foo",
				},
			}).Run(handler, t)
		})

		SubTest(t, "RespectForwarded", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore:               store,
				BasePath:                "/files/",
				RespectForwardedHeaders: true,
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Host":  "bar.com",
					"X-Forwarded-Proto": "http",
					"Forwarded":         "proto=https,host=foo.com",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "https://foo.com/files/foo",
				},
			}).Run(handler, t)
		})

		SubTest(t, "FilterForwardedProtocol", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore:               store,
				BasePath:                "/files/",
				RespectForwardedHeaders: true,
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Proto": "aaa",
					"Forwarded":         "proto=bbb",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "http://tus.io/files/foo",
				},
			}).Run(handler, t)
		})
	})

	SubTest(t, "WithUpload", func(t *testing.T, store *MockFullDataStore) {
		SubTest(t, "Create", func(t *testing.T, store *MockFullDataStore) {
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()
			locker := NewMockLocker(ctrl)

			gomock.InOrder(
				store.EXPECT().NewUpload(FileInfo{
					Size: 300,
					MetaData: map[string]string{
						"foo": "hello",
						"bar": "world",
					},
				}).Return("foo", nil),
				locker.EXPECT().LockUpload("foo"),
				store.EXPECT().WriteChunk("foo", int64(0), NewReaderMatcher("hello")).Return(int64(5), nil),
				locker.EXPECT().UnlockUpload("foo"),
			)

			composer := NewStoreComposer()
			composer.UseCore(store)
			composer.UseLocker(locker)

			handler, _ := NewHandler(Config{
				StoreComposer: composer,
				BasePath:      "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":   "1.0.0",
					"Upload-Length":   "300",
					"Content-Type":    "application/offset+octet-stream",
					"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
				},
				ReqBody: strings.NewReader("hello"),
				Code:    http.StatusCreated,
				ResHeader: map[string]string{
					"Location":      "http://tus.io/files/foo",
					"Upload-Offset": "5",
				},
			}).Run(handler, t)
		})

		SubTest(t, "CreateExceedingUploadSize", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable": "1.0.0",
					"Upload-Length": "300",
					"Content-Type":  "application/offset+octet-stream",
				},
				ReqBody: bytes.NewReader(make([]byte, 400)),
				Code:    http.StatusRequestEntityTooLarge,
			}).Run(handler, t)
		})

		SubTest(t, "IncorrectContentType", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Name:   "Incorrect content type",
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable": "1.0.0",
					"Upload-Length": "300",
					"Content-Type":  "application/false",
				},
				ReqBody: strings.NewReader("hello"),
				Code:    http.StatusCreated,
				ResHeader: map[string]string{
					"Location":      "http://tus.io/files/foo",
					"Upload-Offset": "",
				},
			}).Run(handler, t)
		})

		SubTest(t, "UploadToFinalUpload", func(t *testing.T, store *MockFullDataStore) {
			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable": "1.0.0",
					"Upload-Length": "300",
					"Content-Type":  "application/offset+octet-stream",
					"Upload-Concat": "final; http://tus.io/files/a http://tus.io/files/b",
				},
				ReqBody: strings.NewReader("hello"),
				Code:    http.StatusForbidden,
			}).Run(handler, t)
		})
	})
}
<commit_msg>Add test for absolute base paths<commit_after>package tusd_test

import (
	"bytes"
	"net/http"
	"strings"
	"testing"

	"github.com/golang/mock/gomock"

	. "github.com/tus/tusd"
)

func TestPost(t *testing.T) {
	SubTest(t, "Create", func(t *testing.T, store *MockFullDataStore) {
		store.EXPECT().NewUpload(FileInfo{
			Size: 300,
			MetaData: map[string]string{
				"foo": "hello",
				"bar": "world",
			},
		}).Return("foo", nil)

		handler, _ := NewHandler(Config{
			DataStore: store,
			BasePath:  "https://buy.art/files/",
		})

		(&httpTest{
			Method: "POST",
			ReqHeader: map[string]string{
				"Tus-Resumable":   "1.0.0",
				"Upload-Length":   "300",
				"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
			},
			Code: http.StatusCreated,
			ResHeader: map[string]string{
				"Location": "https://buy.art/files/foo",
			},
		}).Run(handler, t)
	})

	SubTest(t, "CreateExceedingMaxSizeFail", func(t *testing.T, store *MockFullDataStore) {
		handler, _ := NewHandler(Config{
			MaxSize:   400,
			DataStore: store,
			BasePath:  "/files/",
		})

		(&httpTest{
			Name:   "Exceeding MaxSize",
			Method: "POST",
			ReqHeader: map[string]string{
				"Tus-Resumable":   "1.0.0",
				"Upload-Length":   "500",
				"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
			},
			Code: http.StatusRequestEntityTooLarge,
		}).Run(handler, t)
	})

	SubTest(t, "ForwardHeaders", func(t *testing.T, store *MockFullDataStore) {
		SubTest(t, "IgnoreXForwarded", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Host":  "foo.com",
					"X-Forwarded-Proto": "https",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "http://tus.io/files/foo",
				},
			}).Run(handler, t)
		})

		SubTest(t, "RespectXForwarded", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore:               store,
				BasePath:                "/files/",
				RespectForwardedHeaders: true,
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Host":  "foo.com",
					"X-Forwarded-Proto": "https",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "https://foo.com/files/foo",
				},
			}).Run(handler, t)
		})

		SubTest(t, "RespectForwarded", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore:               store,
				BasePath:                "/files/",
				RespectForwardedHeaders: true,
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Host":  "bar.com",
					"X-Forwarded-Proto": "http",
					"Forwarded":         "proto=https,host=foo.com",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "https://foo.com/files/foo",
				},
			}).Run(handler, t)
		})

		SubTest(t, "FilterForwardedProtocol", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore:               store,
				BasePath:                "/files/",
				RespectForwardedHeaders: true,
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":     "1.0.0",
					"Upload-Length":     "300",
					"X-Forwarded-Proto": "aaa",
					"Forwarded":         "proto=bbb",
				},
				Code: http.StatusCreated,
				ResHeader: map[string]string{
					"Location": "http://tus.io/files/foo",
				},
			}).Run(handler, t)
		})
	})

	SubTest(t, "WithUpload", func(t *testing.T, store *MockFullDataStore) {
		SubTest(t, "Create", func(t *testing.T, store *MockFullDataStore) {
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()
			locker := NewMockLocker(ctrl)

			gomock.InOrder(
				store.EXPECT().NewUpload(FileInfo{
					Size: 300,
					MetaData: map[string]string{
						"foo": "hello",
						"bar": "world",
					},
				}).Return("foo", nil),
				locker.EXPECT().LockUpload("foo"),
				store.EXPECT().WriteChunk("foo", int64(0), NewReaderMatcher("hello")).Return(int64(5), nil),
				locker.EXPECT().UnlockUpload("foo"),
			)

			composer := NewStoreComposer()
			composer.UseCore(store)
			composer.UseLocker(locker)

			handler, _ := NewHandler(Config{
				StoreComposer: composer,
				BasePath:      "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable":   "1.0.0",
					"Upload-Length":   "300",
					"Content-Type":    "application/offset+octet-stream",
					"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
				},
				ReqBody: strings.NewReader("hello"),
				Code:    http.StatusCreated,
				ResHeader: map[string]string{
					"Location":      "http://tus.io/files/foo",
					"Upload-Offset": "5",
				},
			}).Run(handler, t)
		})

		SubTest(t, "CreateExceedingUploadSize", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable": "1.0.0",
					"Upload-Length": "300",
					"Content-Type":  "application/offset+octet-stream",
				},
				ReqBody: bytes.NewReader(make([]byte, 400)),
				Code:    http.StatusRequestEntityTooLarge,
			}).Run(handler, t)
		})

		SubTest(t, "IncorrectContentType", func(t *testing.T, store *MockFullDataStore) {
			store.EXPECT().NewUpload(FileInfo{
				Size:     300,
				MetaData: map[string]string{},
			}).Return("foo", nil)

			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Name:   "Incorrect content type",
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable": "1.0.0",
					"Upload-Length": "300",
					"Content-Type":  "application/false",
				},
				ReqBody: strings.NewReader("hello"),
				Code:    http.StatusCreated,
				ResHeader: map[string]string{
					"Location":      "http://tus.io/files/foo",
					"Upload-Offset": "",
				},
			}).Run(handler, t)
		})

		SubTest(t, "UploadToFinalUpload", func(t *testing.T, store *MockFullDataStore) {
			handler, _ := NewHandler(Config{
				DataStore: store,
				BasePath:  "/files/",
			})

			(&httpTest{
				Method: "POST",
				ReqHeader: map[string]string{
					"Tus-Resumable": "1.0.0",
					"Upload-Length": "300",
					"Content-Type":  "application/offset+octet-stream",
					"Upload-Concat": "final; http://tus.io/files/a http://tus.io/files/b",
				},
				ReqBody: strings.NewReader("hello"),
				Code:    http.StatusForbidden,
			}).Run(handler, t)
		})
	})
}
<|endoftext|>


<commit_before>package eval

import (
	"fmt"
	"os"

	"github.com/elves/elvish/parse"
)

// Op is an operation on an EvalCtx.
type Op struct {
	Func       OpFunc
	Begin, End int
}

type OpFunc func(*EvalCtx)

func (op Op) Exec(ec *EvalCtx) {
	ec.begin, ec.end = op.Begin, op.End
	op.Func(ec)
}

func (cp *compiler) chunk(n *parse.Chunk) OpFunc {
	ops := cp.pipelineOps(n.Pipelines)

	return func(ec *EvalCtx) {
		for _, op := range ops {
			op.Exec(ec)
		}
	}
}

const pipelineChanBufferSize = 32

func (cp *compiler) pipeline(n *parse.Pipeline) OpFunc {
	ops := cp.formOps(n.Forms)

	return func(ec *EvalCtx) {
		var nextIn *Port

		errorChans := make([]chan Error, len(ops))

		// For each form, create a dedicated evalCtx and run asynchronously
		for i, op := range ops {
			newEc := ec.fork(fmt.Sprintf("form op %v", op))
			if i > 0 {
				newEc.ports[0] = nextIn
			}
			if i < len(ops)-1 {
				// Each internal port pair consists of a (byte) pipe pair and a
				// channel.
				// os.Pipe sets O_CLOEXEC, which is what we want.
				reader, writer, e := os.Pipe()
				if e != nil {
					ec.errorf("failed to create pipe: %s", e)
				}
				ch := make(chan Value, pipelineChanBufferSize)
				newEc.ports[1] = &Port{
					File: writer, Chan: ch, CloseFile: true, CloseChan: true}
				nextIn = &Port{
					File: reader, Chan: ch, CloseFile: true, CloseChan: false}
			}
			thisOp := op
			errorChans[i] = make(chan Error)
			thisErrorChan := errorChans[i]
			go func() {
				err := newEc.PEval(thisOp)
				// Logger.Printf("closing ports of %s", newEc.context)
				ClosePorts(newEc.ports)
				thisErrorChan <- Error{err}
			}()
		}

		// Wait for all forms to finish and collect error returns.
		errors := make([]Error, len(ops))
		for i, errorChan := range errorChans {
			errors[i] = <-errorChan
		}

		throwCompositeError(errors)
	}
}

func throwCompositeError(errors []Error) {
	if !allok(errors) {
		if len(errors) == 1 {
			throw(errors[0].Inner)
		} else {
			throw(MultiError{errors})
		}
	}
}

func (cp *compiler) form(n *parse.Form) OpFunc {
	var saveVarsOps []LValuesOp
	var assignmentOps []Op
	if len(n.Assignments) > 0 {
		assignmentOps = cp.assignmentOps(n.Assignments)
		if n.Head == nil {
			// Permanent assignment.
			return func(ec *EvalCtx) {
				for _, op := range assignmentOps {
					op.Exec(ec)
				}
			}
		} else {
			for _, a := range n.Assignments {
				v, r := cp.lvaluesOp(a.Dst)
				saveVarsOps = append(saveVarsOps, v, r)
			}
		}
	}

	if n.Control != nil {
		if len(n.Args) > 0 {
			cp.errorpf(n.Args[0].Begin(), n.Args[len(n.Args)-1].End(), "control structure takes no arguments")
		}
		redirOps := cp.redirOps(n.Redirs)
		controlOp := cp.controlOp(n.Control)
		return func(ec *EvalCtx) {
			for _, redirOp := range redirOps {
				redirOp.Exec(ec)
			}
			controlOp.Exec(ec)
		}
	}

	headStr, ok := oneString(n.Head)
	if ok {
		compileForm, ok := builtinSpecials[headStr]
		if ok {
			// special form
			return compileForm(cp, n)
		}
		// Ignore the output. If a matching function exists it will be
		// captured and eventually the Evaler executes it. If not, nothing
		// happens here and the Evaler executes an external command.
		cp.registerVariableGet(FnPrefix + headStr)
		// XXX Dynamic head names should always refer to external commands
	}
	headOp := cp.compoundOp(n.Head)
	argOps := cp.compoundOps(n.Args)
	// TODO: n.NamedArgs
	redirOps := cp.redirOps(n.Redirs)
	// TODO: n.ErrorRedir

	begin, end := n.Begin(), n.End()
	// ec here is always a subevaler created in compiler.pipeline, so it can
	// be safely modified.
	return func(ec *EvalCtx) {
		// Temporary assignment.
		var saveVars []Variable
		var saveVals []Value
		if len(saveVarsOps) > 0 {
			// There is a temporary assignment.
			// Save variables.
			for _, op := range saveVarsOps {
				saveVars = append(saveVars, op.Exec(ec)...)
			}
			for _, v := range saveVars {
				saveVals = append(saveVals, v.Get())
				Logger.Printf("saved %s = %s", v, v.Get())
			}
			// Do assignment.
			for _, op := range assignmentOps {
				op.Exec(ec)
			}
		}

		// head
		headValues := headOp.Exec(ec)
		ec.must(headValues, "head of command", headOp.Begin, headOp.End).mustLen(1)
		headFn := mustFn(headValues[0])

		// args
		var args []Value
		for _, argOp := range argOps {
			args = append(args, argOp.Exec(ec)...)
		}

		// redirs
		for _, redirOp := range redirOps {
			redirOp.Exec(ec)
		}

		ec.begin, ec.end = begin, end
		headFn.Call(ec, args)

		if len(saveVars) > 0 {
			// Restore variables.
			for i, v := range saveVars {
				val := saveVals[i]
				if val == nil {
					// XXX Old value is nonexistent. We should delete the
					// variable. However, since the compiler now doesn't delete
					// it, we don't delete it in the evaler either.
					val = String("")
				}
				v.Set(val)
			}
		}
	}
}

func (cp *compiler) control(n *parse.Control) OpFunc {
	switch n.Kind {
	case parse.IfControl:
		condOps := cp.errorCaptureOps(n.Conditions)
		bodyOps := cp.chunkOps(n.Bodies)
		var elseOp Op
		if n.ElseBody != nil {
			elseOp = cp.chunkOp(n.ElseBody)
		}
		return func(ec *EvalCtx) {
			for i, condOp := range condOps {
				if condOp.Exec(ec)[0].(Error).Inner == nil {
					bodyOps[i].Exec(ec)
					return
				}
			}
			if elseOp.Func != nil {
				elseOp.Exec(ec)
			}
		}
	case parse.WhileControl:
		condOp := cp.errorCaptureOp(n.Condition)
		bodyOp := cp.chunkOp(n.Body)
		return func(ec *EvalCtx) {
			for condOp.Exec(ec)[0].(Error).Inner == nil {
				ex := ec.PEval(bodyOp)
				if ex == Continue {
					// do nothing
				} else if ex == Break {
					break
				} else if ex != nil {
					throw(ex)
				}
			}
		}
	case parse.ForControl:
		iteratorOp, restOp := cp.lvaluesOp(n.Iterator)
		if restOp.Func != nil {
			cp.errorpf(restOp.Begin, restOp.End, "may not use @rest in iterator")
		}
		valuesOp := cp.arrayOp(n.Array)
		bodyOp := cp.chunkOp(n.Body)
		return func(ec *EvalCtx) {
			iterator := iteratorOp.Exec(ec)
			values := valuesOp.Exec(ec)
			for _, v := range values {
				set(ec, iterator, nil, []Value{v})
				ex := ec.PEval(bodyOp)
				if ex == Continue {
					// do nothing
				} else if ex == Break {
					break
				} else if ex != nil {
					throw(ex)
				}
			}
		}
	case parse.BeginControl:
		return cp.chunk(n.Body)
	default:
		cp.errorpf(n.Begin(), n.End(), "unknown ControlKind %s, compiler bug", n.Kind)
		panic("unreachable")
	}
}

func (cp *compiler) assignment(n *parse.Assignment) OpFunc {
	variablesOp, restOp := cp.lvaluesOp(n.Dst)
	valuesOp := cp.compoundOp(n.Src)

	return func(ec *EvalCtx) {
		set(ec, variablesOp.Exec(ec), restOp.Exec(ec), valuesOp.Exec(ec))
	}
}

func (cp *compiler) literal(n *parse.Primary, msg string) string {
	switch n.Type {
	case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
		return n.Value
	default:
		cp.compiling(n)
		cp.errorf(msg)
		return "" // not reached
	}
}

const defaultFileRedirPerm = 0644

// redir compiles a Redir into a op.
func (cp *compiler) redir(n *parse.Redir) OpFunc {
	var dstOp ValuesOp
	if n.Dest != nil {
		dstOp = cp.compoundOp(n.Dest)
	}
	srcOp := cp.compoundOp(n.Source)
	sourceIsFd := n.SourceIsFd
	mode := n.Mode
	flag := makeFlag(mode)

	return func(ec *EvalCtx) {
		var dst int
		if dstOp.Func == nil {
			// use default dst fd
			switch mode {
			case parse.Read:
				dst = 0
			case parse.Write, parse.ReadWrite, parse.Append:
				dst = 1
			default:
				// XXX should report parser bug
				panic("bad RedirMode; parser bug")
			}
		} else {
			// dst must be a valid fd
			dst = ec.must(dstOp.Exec(ec), "FD", dstOp.Begin, dstOp.End).mustOneNonNegativeInt()
		}

		ec.growPorts(dst + 1)
		// Logger.Printf("closing old port %d of %s", dst, ec.context)
		ec.ports[dst].Close()

		srcMust := ec.must(srcOp.Exec(ec), "redirection source", srcOp.Begin, srcOp.End)
		if sourceIsFd {
			src := string(srcMust.mustOneStr())
			if src == "-" {
				// close
				ec.ports[dst] = &Port{}
			} else {
				fd := srcMust.zerothMustNonNegativeInt()
				ec.ports[dst] = ec.ports[fd].Fork()
			}
		} else {
			switch src := srcMust.mustOne().(type) {
			case String:
				f, err := os.OpenFile(string(src), flag, defaultFileRedirPerm)
				if err != nil {
					ec.errorf("failed to open file %s: %s", src.Repr(NoPretty), err)
				}
				ec.ports[dst] = &Port{
					File: f, Chan: make(chan Value),
					CloseFile: true, CloseChan: true,
				}
			case File:
				ec.ports[dst] = &Port{
					File: src.inner, Chan: make(chan Value),
					CloseFile: false, CloseChan: true,
				}
			case Pipe:
				var f *os.File
				switch mode {
				case parse.Read:
					f = src.r
				case parse.Write:
					f = src.w
				default:
					cp.errorf("can only use < or > with pipes")
				}
				ec.ports[dst] = &Port{
					File: f, Chan: make(chan Value),
					CloseFile: false, CloseChan: true,
				}
			default:
				srcMust.error("string or file", "%s", src.Kind())
			}
		}
	}
}
<commit_msg>Use defer to restore variables in temporary assignment.<commit_after>package eval

import (
	"fmt"
	"os"

	"github.com/elves/elvish/parse"
)

// Op is an operation on an EvalCtx.
type Op struct {
	Func       OpFunc
	Begin, End int
}

type OpFunc func(*EvalCtx)

func (op Op) Exec(ec *EvalCtx) {
	ec.begin, ec.end = op.Begin, op.End
	op.Func(ec)
}

func (cp *compiler) chunk(n *parse.Chunk) OpFunc {
	ops := cp.pipelineOps(n.Pipelines)

	return func(ec *EvalCtx) {
		for _, op := range ops {
			op.Exec(ec)
		}
	}
}

const pipelineChanBufferSize = 32

func (cp *compiler) pipeline(n *parse.Pipeline) OpFunc {
	ops := cp.formOps(n.Forms)

	return func(ec *EvalCtx) {
		var nextIn *Port

		errorChans := make([]chan Error, len(ops))

		// For each form, create a dedicated evalCtx and run asynchronously
		for i, op := range ops {
			newEc := ec.fork(fmt.Sprintf("form op %v", op))
			if i > 0 {
				newEc.ports[0] = nextIn
			}
			if i < len(ops)-1 {
				// Each internal port pair consists of a (byte) pipe pair and a
				// channel.
				// os.Pipe sets O_CLOEXEC, which is what we want.
				reader, writer, e := os.Pipe()
				if e != nil {
					ec.errorf("failed to create pipe: %s", e)
				}
				ch := make(chan Value, pipelineChanBufferSize)
				newEc.ports[1] = &Port{
					File: writer, Chan: ch, CloseFile: true, CloseChan: true}
				nextIn = &Port{
					File: reader, Chan: ch, CloseFile: true, CloseChan: false}
			}
			thisOp := op
			errorChans[i] = make(chan Error)
			thisErrorChan := errorChans[i]
			go func() {
				err := newEc.PEval(thisOp)
				// Logger.Printf("closing ports of %s", newEc.context)
				ClosePorts(newEc.ports)
				thisErrorChan <- Error{err}
			}()
		}

		// Wait for all forms to finish and collect error returns.
		errors := make([]Error, len(ops))
		for i, errorChan := range errorChans {
			errors[i] = <-errorChan
		}

		throwCompositeError(errors)
	}
}

func throwCompositeError(errors []Error) {
	if !allok(errors) {
		if len(errors) == 1 {
			throw(errors[0].Inner)
		} else {
			throw(MultiError{errors})
		}
	}
}

func (cp *compiler) form(n *parse.Form) OpFunc {
	var saveVarsOps []LValuesOp
	var assignmentOps []Op
	if len(n.Assignments) > 0 {
		assignmentOps = cp.assignmentOps(n.Assignments)
		if n.Head == nil {
			// Permanent assignment.
			return func(ec *EvalCtx) {
				for _, op := range assignmentOps {
					op.Exec(ec)
				}
			}
		} else {
			for _, a := range n.Assignments {
				v, r := cp.lvaluesOp(a.Dst)
				saveVarsOps = append(saveVarsOps, v, r)
			}
		}
	}

	if n.Control != nil {
		if len(n.Args) > 0 {
			cp.errorpf(n.Args[0].Begin(), n.Args[len(n.Args)-1].End(), "control structure takes no arguments")
		}
		redirOps := cp.redirOps(n.Redirs)
		controlOp := cp.controlOp(n.Control)
		return func(ec *EvalCtx) {
			for _, redirOp := range redirOps {
				redirOp.Exec(ec)
			}
			controlOp.Exec(ec)
		}
	}

	headStr, ok := oneString(n.Head)
	if ok {
		compileForm, ok := builtinSpecials[headStr]
		if ok {
			// special form
			return compileForm(cp, n)
		}
		// Ignore the output. If a matching function exists it will be
		// captured and eventually the Evaler executes it. If not, nothing
		// happens here and the Evaler executes an external command.
		cp.registerVariableGet(FnPrefix + headStr)
		// XXX Dynamic head names should always refer to external commands
	}
	headOp := cp.compoundOp(n.Head)
	argOps := cp.compoundOps(n.Args)
	// TODO: n.NamedArgs
	redirOps := cp.redirOps(n.Redirs)
	// TODO: n.ErrorRedir

	begin, end := n.Begin(), n.End()
	// ec here is always a subevaler created in compiler.pipeline, so it can
	// be safely modified.
	return func(ec *EvalCtx) {
		// Temporary assignment.
		if len(saveVarsOps) > 0 {
			// There is a temporary assignment.
			// Save variables.
			var saveVars []Variable
			var saveVals []Value
			for _, op := range saveVarsOps {
				saveVars = append(saveVars, op.Exec(ec)...)
			}
			for _, v := range saveVars {
				val := v.Get()
				saveVals = append(saveVals, val)
				Logger.Printf("saved %s = %s", v, val)
			}
			// Do assignment.
			for _, op := range assignmentOps {
				op.Exec(ec)
			}
			// Defer variable restoration. Will be executed even if an error
			// occurs when evaling other part of the form.
			defer func() {
				for i, v := range saveVars {
					val := saveVals[i]
					if val == nil {
						// XXX Old value is nonexistent. We should delete the
						// variable. However, since the compiler now doesn't delete
						// it, we don't delete it in the evaler either.
						val = String("")
					}
					v.Set(val)
					Logger.Printf("restored %s = %s", v, val)
				}
			}()
		}

		// head
		headValues := headOp.Exec(ec)
		ec.must(headValues, "head of command", headOp.Begin, headOp.End).mustLen(1)
		headFn := mustFn(headValues[0])

		// args
		var args []Value
		for _, argOp := range argOps {
			args = append(args, argOp.Exec(ec)...)
		}

		// redirs
		for _, redirOp := range redirOps {
			redirOp.Exec(ec)
		}

		ec.begin, ec.end = begin, end
		headFn.Call(ec, args)
	}
}

func (cp *compiler) control(n *parse.Control) OpFunc {
	switch n.Kind {
	case parse.IfControl:
		condOps := cp.errorCaptureOps(n.Conditions)
		bodyOps := cp.chunkOps(n.Bodies)
		var elseOp Op
		if n.ElseBody != nil {
			elseOp = cp.chunkOp(n.ElseBody)
		}
		return func(ec *EvalCtx) {
			for i, condOp := range condOps {
				if condOp.Exec(ec)[0].(Error).Inner == nil {
					bodyOps[i].Exec(ec)
					return
				}
			}
			if elseOp.Func != nil {
				elseOp.Exec(ec)
			}
		}
	case parse.WhileControl:
		condOp := cp.errorCaptureOp(n.Condition)
		bodyOp := cp.chunkOp(n.Body)
		return func(ec *EvalCtx) {
			for condOp.Exec(ec)[0].(Error).Inner == nil {
				ex := ec.PEval(bodyOp)
				if ex == Continue {
					// do nothing
				} else if ex == Break {
					break
				} else if ex != nil {
					throw(ex)
				}
			}
		}
	case parse.ForControl:
		iteratorOp, restOp := cp.lvaluesOp(n.Iterator)
		if restOp.Func != nil {
			cp.errorpf(restOp.Begin, restOp.End, "may not use @rest in iterator")
		}
		valuesOp := cp.arrayOp(n.Array)
		bodyOp := cp.chunkOp(n.Body)
		return func(ec *EvalCtx) {
			iterator := iteratorOp.Exec(ec)
			values := valuesOp.Exec(ec)
			for _, v := range values {
				set(ec, iterator, nil, []Value{v})
				ex := ec.PEval(bodyOp)
				if ex == Continue {
					// do nothing
				} else if ex == Break {
					break
				} else if ex != nil {
					throw(ex)
				}
			}
		}
	case parse.BeginControl:
		return cp.chunk(n.Body)
	default:
		cp.errorpf(n.Begin(), n.End(), "unknown ControlKind %s, compiler bug", n.Kind)
		panic("unreachable")
	}
}

func (cp *compiler) assignment(n *parse.Assignment) OpFunc {
	variablesOp, restOp := cp.lvaluesOp(n.Dst)
	valuesOp := cp.compoundOp(n.Src)

	return func(ec *EvalCtx) {
		set(ec, variablesOp.Exec(ec), restOp.Exec(ec), valuesOp.Exec(ec))
	}
}

func (cp *compiler) literal(n *parse.Primary, msg string) string {
	switch n.Type {
	case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
		return n.Value
	default:
		cp.compiling(n)
		cp.errorf(msg)
		return "" // not reached
	}
}

const defaultFileRedirPerm = 0644

// redir compiles a Redir into a op.
func (cp *compiler) redir(n *parse.Redir) OpFunc {
	var dstOp ValuesOp
	if n.Dest != nil {
		dstOp = cp.compoundOp(n.Dest)
	}
	srcOp := cp.compoundOp(n.Source)
	sourceIsFd := n.SourceIsFd
	mode := n.Mode
	flag := makeFlag(mode)

	return func(ec *EvalCtx) {
		var dst int
		if dstOp.Func == nil {
			// use default dst fd
			switch mode {
			case parse.Read:
				dst = 0
			case parse.Write, parse.ReadWrite, parse.Append:
				dst = 1
			default:
				// XXX should report parser bug
				panic("bad RedirMode; parser bug")
			}
		} else {
			// dst must be a valid fd
			dst = ec.must(dstOp.Exec(ec), "FD", dstOp.Begin, dstOp.End).mustOneNonNegativeInt()
		}

		ec.growPorts(dst + 1)
		// Logger.Printf("closing old port %d of %s", dst, ec.context)
		ec.ports[dst].Close()

		srcMust := ec.must(srcOp.Exec(ec), "redirection source", srcOp.Begin, srcOp.End)
		if sourceIsFd {
			src := string(srcMust.mustOneStr())
			if src == "-" {
				// close
				ec.ports[dst] = &Port{}
			} else {
				fd := srcMust.zerothMustNonNegativeInt()
				ec.ports[dst] = ec.ports[fd].Fork()
			}
		} else {
			switch src := srcMust.mustOne().(type) {
			case String:
				f, err := os.OpenFile(string(src), flag, defaultFileRedirPerm)
				if err != nil {
					ec.errorf("failed to open file %s: %s", src.Repr(NoPretty), err)
				}
				ec.ports[dst] = &Port{
					File: f, Chan: make(chan Value),
					CloseFile: true, CloseChan: true,
				}
			case File:
				ec.ports[dst] = &Port{
					File: src.inner, Chan: make(chan Value),
					CloseFile: false, CloseChan: true,
				}
			case Pipe:
				var f *os.File
				switch mode {
				case parse.Read:
					f = src.r
				case parse.Write:
					f = src.w
				default:
					cp.errorf("can only use < or > with pipes")
				}
				ec.ports[dst] = &Port{
					File: f, Chan: make(chan Value),
					CloseFile: false, CloseChan: true,
				}
			default:
				srcMust.error("string or file", "%s", src.Kind())
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2014 Boldly Go Ventures

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package predicate

// X represents a value to be evaluated by a Predicate.
type X interface{}

type Predicate interface {
	P(X) bool
}

type PredicateFunc func(X) bool

func (p PredicateFunc) P(x X) bool {
	return p(x)
}

func True() Predicate {
	return PredicateFunc(func(x X) bool {
		return true
	})
}

func False() Predicate {
	return PredicateFunc(func(x X) bool {
		return false
	})
}

func And(s []Predicate) Predicate {
	return PredicateFunc(func(x X) bool {
		for _, p := range s {
			if !p.P(x) {
				return false
			}
		}

		return true
	})
}
<commit_msg>Added Or<commit_after>/*
The MIT License (MIT)

Copyright (c) 2014 Boldly Go Ventures

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package predicate

// X represents a value to be evaluated by a Predicate.
type X interface{}

type Predicate interface {
	P(X) bool
}

type PredicateFunc func(X) bool

func (p PredicateFunc) P(x X) bool {
	return p(x)
}

func True() Predicate {
	return PredicateFunc(func(x X) bool {
		return true
	})
}

func False() Predicate {
	return PredicateFunc(func(x X) bool {
		return false
	})
}

func And(s []Predicate) Predicate {
	return PredicateFunc(func(x X) bool {
		for _, p := range s {
			if !p.P(x) {
				return false
			}
		}

		return true
	})
}

func Or(s []Predicate) Predicate {
	return PredicateFunc(func(x X) bool {
		for _, p := range s {
			if p.P(x) {
				return true
			}
		}

		return false
	})
}
<|endoftext|>


<commit_before>package system

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	httpd "github.com/rqlite/rqlite/http"
	"github.com/rqlite/rqlite/store"
)

// Node represents a node under test.
type Node struct {
	APIAddr  string
	RaftAddr string
	Dir      string
	Store    *store.Store
	Service  *httpd.Service
}

// SameAs returns true if this node is the same as o node.
func (n *Node) SameAs(o *Node) bool {
	return n.RaftAddr == o.RaftAddr
}

// Deprovision shuts down and removes all resources associated with the node.
func (n *Node) Deprovision() {
	n.Store.Close(false)
	n.Service.Close()
	os.RemoveAll(n.Dir)
}

// WaitForLeader blocks for up to 10 seconds until the node detects a leader.
func (n *Node) WaitForLeader() (string, error) {
	return n.Store.WaitForLeader(10 * time.Second)
}

// Execute executes a single statement against the node.
func (n *Node) Execute(stmt string) (string, error) {
	return n.ExecuteMulti([]string{stmt})
}

// ExecuteMulti executes multiple statements against the node.
func (n *Node) ExecuteMulti(stmts []string) (string, error) {
	j, err := json.Marshal(stmts)
	if err != nil {
		return "", err
	}
	return n.postExecute(string(j))
}

// Query runs a single query against the node.
func (n *Node) Query(stmt string) (string, error) {
	v, _ := url.Parse("http://" + n.APIAddr + "/db/query")
	v.RawQuery = url.Values{"q": []string{stmt}}.Encode()

	resp, err := http.Get(v.String())
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// Join instructs this node to join the leader.
func (n *Node) Join(leader *Node) error {
	b, err := json.Marshal(map[string]string{"addr": n.RaftAddr})
	if err != nil {
		return err
	}

	// Attempt to join leader
	resp, err := http.Post("http://"+leader.APIAddr+"/join", "application-type/json", bytes.NewReader(b))
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("failed to join, leader returned: %s", resp.Status)
	}
	defer resp.Body.Close()
	return nil
}

// ConfirmRedirect confirms that the node responds with a redirect to the given host.
func (n *Node) ConfirmRedirect(host string) bool {
	v, _ := url.Parse("http://" + n.APIAddr + "/db/query")
	v.RawQuery = url.Values{"q": []string{`SELECT * FROM foo`}}.Encode()

	resp, err := http.Get(v.String())
	if err != nil {
		return false
	}
	defer resp.Body.Close()
	fmt.Println(resp.StatusCode)
	if resp.StatusCode != http.StatusMovedPermanently {
		return false
	}
	if resp.Header.Get("location") != host {
		return false
	}
	return true
}

func (n *Node) postExecute(stmt string) (string, error) {
	resp, err := http.Post("http://"+n.APIAddr+"/db/execute", "application/json", strings.NewReader(stmt))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// Cluster represents a cluster of nodes.
type Cluster []*Node

// Leader returns the leader node of a cluster.
func (c Cluster) Leader() (*Node, error) {
	l, err := c[0].WaitForLeader()
	if err != nil {
		return nil, err
	}
	return c.FindNodeByRaftAddr(l)
}

// WaitForNewLeader waits for the leader to change from the node passed in.
func (c Cluster) WaitForNewLeader(old *Node) (*Node, error) {
	timer := time.NewTimer(30 * time.Second)
	defer timer.Stop()
	ticker := time.NewTicker(100 * time.Millisecond)
	defer ticker.Stop()

	for {
		select {
		case <-timer.C:
			return nil, fmt.Errorf("timed out waiting for new leader")
		case <-ticker.C:
			l, err := c.Leader()
			if err != nil {
				continue
			}
			if !l.SameAs(old) {
				return l, nil
			}
		}
	}
}

// Followers returns the slide of nodes in the cluster that are followers.
func (c Cluster) Followers() ([]*Node, error) {
	n, err := c[0].WaitForLeader()
	if err != nil {
		return nil, err
	}
	leader, err := c.FindNodeByRaftAddr(n)
	if err != nil {
		return nil, err
	}

	var followers []*Node
	for _, n := range c {
		if n != leader {
			followers = append(followers, n)
		}
	}
	return followers, nil
}

// RemoveNode removes the given node from the cluster.
func (c Cluster) RemoveNode(node *Node) {
	for i, n := range c {
		if n.RaftAddr == node.RaftAddr {
			c = append(c[:i], c[i+1:]...)
			return
		}
	}
}

// FindNodeByRaftAddr returns the node with the given Raft address.
func (c Cluster) FindNodeByRaftAddr(addr string) (*Node, error) {
	for _, n := range c {
		if n.RaftAddr == addr {
			return n, nil
		}
	}
	return nil, fmt.Errorf("node not found")
}

// Deprovision deprovisions every node in the cluster.
func (c Cluster) Deprovision() {
	for _, n := range c {
		n.Deprovision()
	}
}

func mustNewNode(enableSingle bool) *Node {
	node := &Node{
		Dir: mustTempDir(),
	}

	dbConf := store.NewDBConfig("", false)
	node.Store = store.New(dbConf, node.Dir, mustMockTransport("localhost:0"))
	if err := node.Store.Open(enableSingle); err != nil {
		node.Deprovision()
		panic(fmt.Sprintf("failed to open store: %s", err.Error()))
	}
	node.RaftAddr = node.Store.Addr().String()

	node.Service = httpd.New("localhost:0", node.Store, nil)
	if err := node.Service.Start(); err != nil {
		node.Deprovision()
		panic(fmt.Sprintf("failed to start HTTP server: %s", err.Error()))
	}
	node.APIAddr = node.Service.Addr().String()

	return node
}

func mustNewLeaderNode() *Node {
	node := mustNewNode(true)
	if _, err := node.WaitForLeader(); err != nil {
		node.Deprovision()
		panic("node never became leader")
	}
	return node
}

type mockTransport struct {
	ln net.Listener
}

func mustMockTransport(addr string) *mockTransport {
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		panic("failed to create new transport")
	}
	return &mockTransport{ln}
}

func (m *mockTransport) Dial(addr string, timeout time.Duration) (net.Conn, error) {
	return net.DialTimeout("tcp", addr, timeout)
}

func (m *mockTransport) Accept() (net.Conn, error) { return m.ln.Accept() }

func (m *mockTransport) Close() error { return m.ln.Close() }

func (m *mockTransport) Addr() net.Addr { return m.ln.Addr() }

func mustTempDir() string {
	var err error
	path, err := ioutil.TempDir("", "rqlilte-system-test-")
	if err != nil {
		panic("failed to create temp dir")
	}
	return path
}
<commit_msg>Add system test helper function Remove()<commit_after>package system

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	httpd "github.com/rqlite/rqlite/http"
	"github.com/rqlite/rqlite/store"
)

// Node represents a node under test.
type Node struct {
	APIAddr  string
	RaftAddr string
	Dir      string
	Store    *store.Store
	Service  *httpd.Service
}

// SameAs returns true if this node is the same as o node.
func (n *Node) SameAs(o *Node) bool {
	return n.RaftAddr == o.RaftAddr
}

// Deprovision shuts down and removes all resources associated with the node.
func (n *Node) Deprovision() {
	n.Store.Close(false)
	n.Service.Close()
	os.RemoveAll(n.Dir)
}

// WaitForLeader blocks for up to 10 seconds until the node detects a leader.
func (n *Node) WaitForLeader() (string, error) {
	return n.Store.WaitForLeader(10 * time.Second)
}

// Execute executes a single statement against the node.
func (n *Node) Execute(stmt string) (string, error) {
	return n.ExecuteMulti([]string{stmt})
}

// ExecuteMulti executes multiple statements against the node.
func (n *Node) ExecuteMulti(stmts []string) (string, error) {
	j, err := json.Marshal(stmts)
	if err != nil {
		return "", err
	}
	return n.postExecute(string(j))
}

// Query runs a single query against the node.
func (n *Node) Query(stmt string) (string, error) {
	v, _ := url.Parse("http://" + n.APIAddr + "/db/query")
	v.RawQuery = url.Values{"q": []string{stmt}}.Encode()

	resp, err := http.Get(v.String())
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// Join instructs this node to join the leader.
func (n *Node) Join(leader *Node) error {
	b, err := json.Marshal(map[string]string{"addr": n.RaftAddr})
	if err != nil {
		return err
	}

	// Attempt to join leader
	resp, err := http.Post("http://"+leader.APIAddr+"/join", "application-type/json", bytes.NewReader(b))
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("failed to join, leader returned: %s", resp.Status)
	}
	defer resp.Body.Close()
	return nil
}

// ConfirmRedirect confirms that the node responds with a redirect to the given host.
func (n *Node) ConfirmRedirect(host string) bool {
	v, _ := url.Parse("http://" + n.APIAddr + "/db/query")
	v.RawQuery = url.Values{"q": []string{`SELECT * FROM foo`}}.Encode()

	resp, err := http.Get(v.String())
	if err != nil {
		return false
	}
	defer resp.Body.Close()
	fmt.Println(resp.StatusCode)
	if resp.StatusCode != http.StatusMovedPermanently {
		return false
	}
	if resp.Header.Get("location") != host {
		return false
	}
	return true
}

func (n *Node) postExecute(stmt string) (string, error) {
	resp, err := http.Post("http://"+n.APIAddr+"/db/execute", "application/json", strings.NewReader(stmt))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// Cluster represents a cluster of nodes.
type Cluster []*Node

// Leader returns the leader node of a cluster.
func (c Cluster) Leader() (*Node, error) {
	l, err := c[0].WaitForLeader()
	if err != nil {
		return nil, err
	}
	return c.FindNodeByRaftAddr(l)
}

// WaitForNewLeader waits for the leader to change from the node passed in.
func (c Cluster) WaitForNewLeader(old *Node) (*Node, error) {
	timer := time.NewTimer(30 * time.Second)
	defer timer.Stop()
	ticker := time.NewTicker(100 * time.Millisecond)
	defer ticker.Stop()

	for {
		select {
		case <-timer.C:
			return nil, fmt.Errorf("timed out waiting for new leader")
		case <-ticker.C:
			l, err := c.Leader()
			if err != nil {
				continue
			}
			if !l.SameAs(old) {
				return l, nil
			}
		}
	}
}

// Followers returns the slide of nodes in the cluster that are followers.
func (c Cluster) Followers() ([]*Node, error) {
	n, err := c[0].WaitForLeader()
	if err != nil {
		return nil, err
	}
	leader, err := c.FindNodeByRaftAddr(n)
	if err != nil {
		return nil, err
	}

	var followers []*Node
	for _, n := range c {
		if n != leader {
			followers = append(followers, n)
		}
	}
	return followers, nil
}

// RemoveNode removes the given node from the list of nodes representing
// a cluster.
func (c Cluster) RemoveNode(node *Node) {
	for i, n := range c {
		if n.RaftAddr == node.RaftAddr {
			c = append(c[:i], c[i+1:]...)
			return
		}
	}
}

// FindNodeByRaftAddr returns the node with the given Raft address.
func (c Cluster) FindNodeByRaftAddr(addr string) (*Node, error) {
	for _, n := range c {
		if n.RaftAddr == addr {
			return n, nil
		}
	}
	return nil, fmt.Errorf("node not found")
}

// Deprovision deprovisions every node in the cluster.
func (c Cluster) Deprovision() {
	for _, n := range c {
		n.Deprovision()
	}
}

// Remove tells the cluster at n to remove the node at addr. Assumes n is the leader.
func Remove(n *Node, addr string) error {
	b, err := json.Marshal(map[string]string{"addr": addr})
	if err != nil {
		return err
	}

	// Attempt to remove node from leader.
	resp, err := http.Post("http://"+n.APIAddr+"/remove", "application-type/json", bytes.NewReader(b))
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("failed to remove node, leader returned: %s", resp.Status)
	}
	defer resp.Body.Close()
	return nil
}

func mustNewNode(enableSingle bool) *Node {
	node := &Node{
		Dir: mustTempDir(),
	}

	dbConf := store.NewDBConfig("", false)
	node.Store = store.New(dbConf, node.Dir, mustMockTransport("localhost:0"))
	if err := node.Store.Open(enableSingle); err != nil {
		node.Deprovision()
		panic(fmt.Sprintf("failed to open store: %s", err.Error()))
	}
	node.RaftAddr = node.Store.Addr().String()

	node.Service = httpd.New("localhost:0", node.Store, nil)
	if err := node.Service.Start(); err != nil {
		node.Deprovision()
		panic(fmt.Sprintf("failed to start HTTP server: %s", err.Error()))
	}
	node.APIAddr = node.Service.Addr().String()

	return node
}

func mustNewLeaderNode() *Node {
	node := mustNewNode(true)
	if _, err := node.WaitForLeader(); err != nil {
		node.Deprovision()
		panic("node never became leader")
	}
	return node
}

type mockTransport struct {
	ln net.Listener
}

func mustMockTransport(addr string) *mockTransport {
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		panic("failed to create new transport")
	}
	return &mockTransport{ln}
}

func (m *mockTransport) Dial(addr string, timeout time.Duration) (net.Conn, error) {
	return net.DialTimeout("tcp", addr, timeout)
}

func (m *mockTransport) Accept() (net.Conn, error) { return m.ln.Accept() }

func (m *mockTransport) Close() error { return m.ln.Close() }

func (m *mockTransport) Addr() net.Addr { return m.ln.Addr() }

func mustTempDir() string {
	var err error
	path, err := ioutil.TempDir("", "rqlilte-system-test-")
	if err != nil {
		panic("failed to create temp dir")
	}
	return path
}
<|endoftext|>


<commit_before>package example

import "os"
<commit_msg>Add example<commit_after>package main

import "os"

var testsJs = []string{
	"./static/js/a.js",
	"./static/js/b.js",
}

var testCss = []string{
	"./static/css/a.css",
	"./static/css/b.css",
}

func main() {
	// Combo test static: js
	comboJs, err := Combo(testsJs)
	// Combo test static: css
	comboCss, err2 := Combo(testCss)
	// Combo test static: js to dist file
	err3 := ComboTo("./static/js/dist.js", testsJs)
}
<|endoftext|>


<commit_before>// radix example program.

package main

import (
	"fmt"
	"github.com/fzzbt/radix/redis"
	"strconv"
	"time"
)

func main() {
	var c *redis.Client
	var err error

	c, err = redis.NewClient(redis.Configuration{
		Database: 8,
		// Timeout in seconds
		Timeout: 10,

		// Custom TCP/IP address or Unix path.
		// Path: "/tmp/redis.sock",
		// Address: "127.0.0.1:6379",
	})

	if err != nil {
		fmt.Println("NewClient failed:", err)
	}

	defer c.Close()

	//** Blocking calls
	rep := c.Flushdb()
	if rep.Error != nil {
		fmt.Println("redis:", rep.Error)
		return
	}

	//* Strings

	// It's generally good idea to check for errors like this,
	// but for the sake of keeping this example short we'll omit these from now on.
    if rep = c.Set("mykey0", "myval0"); rep.Error != nil {
		fmt.Println("redis:", rep.Error)
		return
	}

	s, err := c.Get("mykey0").Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("mykey0:", s)

	myhash := map[string]string{
		"mykey1": "myval1",
		"mykey2": "myval2",
		"mykey3": "myval3",
	}

	// Alternatively:
	// c.Mset("mykey1", "myval1", "mykey2", "myval2", "mykey3", "myval3")
	c.Mset(myhash)

	ls, err := c.Mget("mykey1", "mykey2", "mykey3").List()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("mykeys values:", ls)

	//* List handling
	mylist := []string{"foo", "bar", "qux"}

	// Alternativaly:
	// c.Rpush("mylist", "foo", "bar", "qux")
	c.Rpush("mylist", mylist)

	if mylist, err = c.Lrange("mylist", 0, -1).List(); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("mylist:", mylist)

	//* Hash handling

	// Alternatively:
	// c.Hmset("myhash", ""mykey1", "myval1", "mykey2", "myval2", "mykey3", "myval3")
	c.Hmset("myhash", myhash)

	if myhash, err = c.Hgetall("myhash").Hash(); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("myhash:", myhash)

	//* Multicalls
	rep = c.MultiCall(func(mc *redis.MultiCall) {
		mc.Set("multikey", "multival")
		mc.Get("multikey")
	})

	r1, err := rep.At(1)
	if err != nil {
		fmt.Println(err)
		return
	}

	s, err = r1.Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("multikey:", s)

	//* Transactions
	rep = c.Transaction(func(mc *redis.MultiCall) {
		mc.Set("trankey", "tranval")
		mc.Get("trankey")
	})

	r1, err = rep.At(1)
	if err != nil {
		fmt.Println(err)
		return
	}

	s, err = r1.Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("trankey:", s)

	//* Complex transactions
	//  Atomic INCR replacement with transactions
	myIncr := func(key string) *redis.Reply {
		return c.MultiCall(func(mc *redis.MultiCall) {
			var curval int

			mc.Watch(key)
			mc.Get(key)
			rep := mc.Flush()
			r1, err := rep.At(1)
			if err != nil {
				return
			}

			s, err := r1.Str()
			if err == nil {
				curval, err = strconv.Atoi(s)
			}
			nextval := curval + 1

			mc.Multi()
			mc.Set(key, nextval)
			mc.Exec()
		})
	}

	myIncr("ctrankey")
	myIncr("ctrankey")
	myIncr("ctrankey")

	fmt.Println(c.Get("ctrankey"))
//	s, err = c.Get("ctrankey").Str()
//	if err != nil {
//		fmt.Println(err)
//		return
//	}

//	fmt.Println("ctrankey:", s)

	//** Asynchronous calls
	c.Set("asynckey", "asyncval")
	fut := c.AsyncGet("asynckey")

	// do something here

	// block until reply is available
	s, err = fut.Reply().Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("asynckey:", s)

	//* Pub/sub
	msgHdlr := func(msg *redis.Message) {
		switch msg.Type {
		case redis.MessageMessage:
			fmt.Printf("Received message \"%s\" from channel \"%s\".\n", msg.Payload, msg.Channel)
		case redis.MessagePmessage:
			fmt.Printf("Received pattern message \"%s\" from channel \"%s\" with pattern "+
				"\"%s\".\n", msg.Payload, msg.Channel, msg.Pattern)
		default:
			fmt.Println("Received other message:", msg)
		}
	}

	sub, errr := c.Subscription(msgHdlr)
	if errr != nil {
		fmt.Printf("Failed to subscribe: '%s'!\n", errr)
		return
	}

	defer sub.Close()

	sub.Subscribe("chan1", "chan2")
	sub.Psubscribe("chan*")

	c.Publish("chan1", "foo")
	sub.Unsubscribe("chan1")
	c.Publish("chan2", "bar")

	// give some time for the message handler to receive the messages
	time.Sleep(time.Second)
}
<commit_msg>example: forgot to remove comments<commit_after>// radix example program.

package main

import (
	"fmt"
	"github.com/fzzbt/radix/redis"
	"strconv"
	"time"
)

func main() {
	var c *redis.Client
	var err error

	c, err = redis.NewClient(redis.Configuration{
		Database: 8,
		// Timeout in seconds
		Timeout: 10,

		// Custom TCP/IP address or Unix path.
		// Path: "/tmp/redis.sock",
		// Address: "127.0.0.1:6379",
	})

	if err != nil {
		fmt.Println("NewClient failed:", err)
	}

	defer c.Close()

	//** Blocking calls
	rep := c.Flushdb()
	if rep.Error != nil {
		fmt.Println("redis:", rep.Error)
		return
	}

	//* Strings

	// It's generally good idea to check for errors like this,
	// but for the sake of keeping this example short we'll omit these from now on.
    if rep = c.Set("mykey0", "myval0"); rep.Error != nil {
		fmt.Println("redis:", rep.Error)
		return
	}

	s, err := c.Get("mykey0").Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("mykey0:", s)

	myhash := map[string]string{
		"mykey1": "myval1",
		"mykey2": "myval2",
		"mykey3": "myval3",
	}

	// Alternatively:
	// c.Mset("mykey1", "myval1", "mykey2", "myval2", "mykey3", "myval3")
	c.Mset(myhash)

	ls, err := c.Mget("mykey1", "mykey2", "mykey3").List()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("mykeys values:", ls)

	//* List handling
	mylist := []string{"foo", "bar", "qux"}

	// Alternativaly:
	// c.Rpush("mylist", "foo", "bar", "qux")
	c.Rpush("mylist", mylist)

	if mylist, err = c.Lrange("mylist", 0, -1).List(); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("mylist:", mylist)

	//* Hash handling

	// Alternatively:
	// c.Hmset("myhash", ""mykey1", "myval1", "mykey2", "myval2", "mykey3", "myval3")
	c.Hmset("myhash", myhash)

	if myhash, err = c.Hgetall("myhash").Hash(); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("myhash:", myhash)

	//* Multicalls
	rep = c.MultiCall(func(mc *redis.MultiCall) {
		mc.Set("multikey", "multival")
		mc.Get("multikey")
	})

	r1, err := rep.At(1)
	if err != nil {
		fmt.Println(err)
		return
	}

	s, err = r1.Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("multikey:", s)

	//* Transactions
	rep = c.Transaction(func(mc *redis.MultiCall) {
		mc.Set("trankey", "tranval")
		mc.Get("trankey")
	})

	r1, err = rep.At(1)
	if err != nil {
		fmt.Println(err)
		return
	}

	s, err = r1.Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("trankey:", s)

	//* Complex transactions
	//  Atomic INCR replacement with transactions
	myIncr := func(key string) *redis.Reply {
		return c.MultiCall(func(mc *redis.MultiCall) {
			var curval int

			mc.Watch(key)
			mc.Get(key)
			rep := mc.Flush()
			r1, err := rep.At(1)
			if err != nil {
				return
			}

			s, err := r1.Str()
			if err == nil {
				curval, err = strconv.Atoi(s)
			}
			nextval := curval + 1

			mc.Multi()
			mc.Set(key, nextval)
			mc.Exec()
		})
	}

	myIncr("ctrankey")
	myIncr("ctrankey")
	myIncr("ctrankey")

	s, err = c.Get("ctrankey").Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("ctrankey:", s)

	//** Asynchronous calls
	c.Set("asynckey", "asyncval")
	fut := c.AsyncGet("asynckey")

	// do something here

	// block until reply is available
	s, err = fut.Reply().Str()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("asynckey:", s)

	//* Pub/sub
	msgHdlr := func(msg *redis.Message) {
		switch msg.Type {
		case redis.MessageMessage:
			fmt.Printf("Received message \"%s\" from channel \"%s\".\n", msg.Payload, msg.Channel)
		case redis.MessagePmessage:
			fmt.Printf("Received pattern message \"%s\" from channel \"%s\" with pattern "+
				"\"%s\".\n", msg.Payload, msg.Channel, msg.Pattern)
		default:
			fmt.Println("Received other message:", msg)
		}
	}

	sub, errr := c.Subscription(msgHdlr)
	if errr != nil {
		fmt.Printf("Failed to subscribe: '%s'!\n", errr)
		return
	}

	defer sub.Close()

	sub.Subscribe("chan1", "chan2")
	sub.Psubscribe("chan*")

	c.Publish("chan1", "foo")
	sub.Unsubscribe("chan1")
	c.Publish("chan2", "bar")

	// give some time for the message handler to receive the messages
	time.Sleep(time.Second)
}
<|endoftext|>


<commit_before><commit_msg>Update GCR container for ESP<commit_after><|endoftext|>


<commit_before><commit_msg>Issue #56: require at least one device for 'fritzctl toggle'<commit_after><|endoftext|>


<commit_before>/*
Package proj provides an interface to the Cartographic Projections Library PROJ.4.

See: http://trac.osgeo.org/proj/

Example usage:

    merc, err := proj.NewProj("+proj=merc +ellps=clrk66 +lat_ts=33")
    defer merc.Close()
    if err != nil {
        log.Fatal(err)
    }

    ll, err := proj.NewProj("+proj=latlong +ellps=clrk66")
    defer ll.Close()
    if err != nil {
        log.Fatal(err)
    }

    x, y, err := proj.Transform2(ll, merc, 1, 1, proj.DegToRad(-16), proj.DegToRad(20.25))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%.2f %.2f", x, y)  // should print: -1495284.21 1920596.79
*/
package proj

/*
#cgo LDFLAGS: -lproj
#include "proj.h"
*/
import "C"

import (
	"errors"
	"math"
	"unsafe"
)

type Proj struct {
	pj     _Ctype_projPJ
	opened bool
}

func NewProj(definition string) (*Proj, error) {
	cs := C.CString(definition)
	defer C.free(unsafe.Pointer(cs))
	proj := Proj{opened: false}
	proj.pj = C.pj_init_plus(cs)

	var err error = nil
	s := C.GoString(C.get_err())
	if s == "" {
		proj.opened = true
	} else {
		err = errors.New(s)
	}

	return &proj, err
}

func (p *Proj) Close() {
	if p.opened {
		C.pj_free(p.pj)
		p.opened = false
	}
}

func Transform2(srcpj, dstpj *Proj, point_count int64, point_offset int, x, y float64) (float64, float64, error) {
	if !(srcpj.opened && dstpj.opened) {
		return 0.0, 0.0, errors.New("projection is closed")
	}
	triple := C.transform2(srcpj.pj, dstpj.pj, C.long(point_count), C.int(point_offset), C.double(x), C.double(y))
	if e := C.GoString(C.triple_err(triple)); e != "" {
		return 0.0, 0.0, errors.New(e)
	}
	return float64(C.triple_x(triple)), float64(C.triple_y(triple)), nil
}

func Transform3(srcpj, dstpj *Proj, point_count int64, point_offset int, x, y, z float64) (float64, float64, float64, error) {
	if !(srcpj.opened && dstpj.opened) {
		return 0.0, 0.0, 0.0, errors.New("projection is closed")
	}
	triple := C.transform3(srcpj.pj, dstpj.pj, C.long(point_count), C.int(point_offset), C.double(x), C.double(y), C.double(z))
	if e := C.GoString(C.triple_err(triple)); e != "" {
		return 0.0, 0.0, 0.0, errors.New(e)
	}
	return float64(C.triple_x(triple)), float64(C.triple_y(triple)), float64(C.triple_z(triple)), nil
}

func DegToRad(deg float64) float64 {
	return deg / 180.0 * math.Pi
}

func RadToDeg(rad float64) float64 {
	return rad / math.Pi * 180.0
}
<commit_msg>simplify<commit_after>/*
Package proj provides an interface to the Cartographic Projections Library PROJ.4.

See: http://trac.osgeo.org/proj/

Example usage:

    merc, err := proj.NewProj("+proj=merc +ellps=clrk66 +lat_ts=33")
    defer merc.Close()
    if err != nil {
        log.Fatal(err)
    }

    ll, err := proj.NewProj("+proj=latlong +ellps=clrk66")
    defer ll.Close()
    if err != nil {
        log.Fatal(err)
    }

    x, y, err := proj.Transform2(ll, merc, 1, 1, proj.DegToRad(-16), proj.DegToRad(20.25))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%.2f %.2f", x, y)  // should print: -1495284.21 1920596.79
*/
package proj

/*
#cgo LDFLAGS: -lproj
#include "proj.h"
*/
import "C"

import (
	"errors"
	"math"
	"unsafe"
)

type Proj struct {
	pj     _Ctype_projPJ
	opened bool
}

func NewProj(definition string) (*Proj, error) {
	cs := C.CString(definition)
	defer C.free(unsafe.Pointer(cs))
	proj := Proj{opened: false}
	proj.pj = C.pj_init_plus(cs)

	var err error = nil
	s := C.GoString(C.get_err())
	if s == "" {
		proj.opened = true
	} else {
		err = errors.New(s)
	}

	return &proj, err
}

func (p *Proj) Close() {
	if p.opened {
		C.pj_free(p.pj)
		p.opened = false
	}
}

func transform(srcpj, dstpj *Proj, point_count int64, point_offset int, x, y, z float64, hasz bool) (float64, float64, float64, error) {
	if !(srcpj.opened && dstpj.opened) {
		return 0.0, 0.0, 0.0, errors.New("projection is closed")
	}

	var triple *C.triple
	if hasz {
		triple = C.transform3(srcpj.pj, dstpj.pj, C.long(point_count), C.int(point_offset), C.double(x), C.double(y), C.double(z))
	} else {
		triple = C.transform2(srcpj.pj, dstpj.pj, C.long(point_count), C.int(point_offset), C.double(x), C.double(y))
	}

	if e := C.GoString(C.triple_err(triple)); e != "" {
		return 0.0, 0.0, 0.0, errors.New(e)
	}

	return float64(C.triple_x(triple)), float64(C.triple_y(triple)), float64(C.triple_z(triple)), nil
}

func Transform2(srcpj, dstpj *Proj, point_count int64, point_offset int, x, y float64) (float64, float64, error) {
	xx, yy, _, err := transform(srcpj, dstpj, point_count, point_offset, x, y, 0, false)
	return xx, yy, err
}

func Transform3(srcpj, dstpj *Proj, point_count int64, point_offset int, x, y, z float64) (float64, float64, float64, error) {
	return transform(srcpj, dstpj, point_count, point_offset, x, y, z, true)
}

func DegToRad(deg float64) float64 {
	return deg / 180.0 * math.Pi
}

func RadToDeg(rad float64) float64 {
	return rad / math.Pi * 180.0
}
<|endoftext|>


<commit_before>package telemetry

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

	"github.com/ugorji/go/codec"
)

// Name contains the minimized string value of the Name field.
const Name string = "n"

// Type contains the minimized string value of the Type field.
const Type string = "t"

// Identifier contains the minimized string value of the Identifier field.
const Identifier string = "i"

// Amount contains the minimized string value of the Amount field.
const Amount string = "a"

// When contains the minimized string value of the When field.
const When string = "w"

// TODO:
// make new outputTransformer
// minimize logs
// cborize logs
// send + retry
// failsafe

// NewReporter creates a new Reporter struct and returns a pointer to it.
func NewReporter(requestsLog *RequestsLog, reportInterval int, reportURL string, telemetryEnabled bool, testing bool) *Reporter {
	return &Reporter{
		log:         requestsLog,
		interval:    reportInterval,
		url:         reportURL,
		enabled:     telemetryEnabled,
		transformer: NewOutputTransformer(testing),
		poster:      NewPoster(reportURL),
	}
}

// Reporter is the struct used to report the logged function calls, either to an endpoint or to the etcd store.
type Reporter struct {
	log         *RequestsLog
	interval    int
	url         string
	enabled     bool
	transformer *OutputTransformer
	poster      *Poster
}

// Start posts logged function calls in CBOR format to the provided url every <provided interval> seconds.
// Contains a failsafe mechanism in the case the url is unreachable.
func (r *Reporter) Start() {
	if r.enabled {
		for {
			time.Sleep(time.Duration(r.interval) * time.Second)
			extractedLog := r.log.ExtractLoggedRequests()
			r.AddTimeStamps(extractedLog)
			transformedLog, err := r.TransformToOutputFormat(extractedLog)
			if err == nil {
				r.poster.ReportLoggedCalls(transformedLog)
			} else {
				// TODO: error logging in etcd
			}

		}
	}
}

// AddTimeStamps adds the current timestamp to the logged request types.
func (r *Reporter) AddTimeStamps(extractedLog *map[string]*RequestLog) {
	timestamp := time.Now().Unix()

	for _, log := range *extractedLog {
		log.When = timestamp
	}
}

func (r *Reporter) triggerCBORFailsafe(requests *map[string]*RequestLog) {
	// TODO fill in failsafe etcd handling
}

// TransformToOutputFormat transforms the logged function calls to a minimized output format to reduce network traffic.
func (r *Reporter) TransformToOutputFormat(logs *map[string]*RequestLog) (*string, error) { // TODO: cover with test
	minimizedLogs := r.transformer.ConvertToMinimizedJSON(logs)

	cborLogs, err := r.transformer.EncodeAsCBOR(minimizedLogs)
	if err != nil {
		return nil, err
	}

	return cborLogs, nil
}

// OutputTransformer contains methods that transform the function call logs to an outputtable format.
type OutputTransformer struct {
	testing bool
}

// NewOutputTransformer creates a new OutputTransformer and returns a pointer to it.
func NewOutputTransformer(testing bool) *OutputTransformer {
	return &OutputTransformer{testing}
}

// ConvertToMinimizedJSON converts the request logs to minimized JSON
func (o *OutputTransformer) ConvertToMinimizedJSON(logs *map[string]*RequestLog) *string {
	minimizedLogs := make([]map[string]interface{}, len(*logs))

	iterations := 0
	for _, loggedRequest := range *logs {
		miniLog := make(map[string]interface{})

		miniLog[Name] = loggedRequest.Name
		miniLog[Type] = loggedRequest.Type
		miniLog[Identifier] = loggedRequest.Identifier
		miniLog[Amount] = loggedRequest.Amount
		miniLog[When] = loggedRequest.When

		minimizedLogs[iterations] = miniLog
		iterations++
	}

	rawMinimizedJSON, _ := json.Marshal(minimizedLogs)
	minimizedJSON := string(rawMinimizedJSON)
	return &minimizedJSON
}

// EncodeAsCBOR encodes logs in CBOR format and returns them as a base-16 string with two chars per byte.
// Sample output: "816B48656C6C6F20776F726C64"
func (o *OutputTransformer) EncodeAsCBOR(minimizedJSON *string) (*string, error) {
	encoded := make([]byte, 0, 64)
	cborHandle := new(codec.CborHandle)
	if o.testing {
		cborHandle.Canonical = true
	}

	encoder := codec.NewEncoderBytes(&encoded, cborHandle)
	err := encoder.Encode(minimizedJSON)

	if err != nil {
		return nil, err
	}

	byteString := fmt.Sprintf("%x", encoded)

	return &byteString, nil
}

// NewPoster creates a new
func NewPoster(url string) *Poster {
	return &Poster{url: url}
}

// Poster is a class responsible for sending the converted log to the desired location.
// Tries to send the log to a REST endpoint. If the endpoint is unreachable then the logs are stored in the etcd store.
type Poster struct {
	url string
}

// ReportLoggedCalls sends the logs to a previously determined REST endpoint.
func (p *Poster) ReportLoggedCalls(encoded *string) {
	req, err := http.NewRequest("POST", p.url, strings.NewReader(*encoded))
	req.Header.Set("Content-Type", "application/cbor")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil || resp.Status != "200" {
		p.triggerPOSTFailsafe(encoded)
	}
	defer resp.Body.Close()
}

// Should the REST endpoint be unreachable then the log is stored in the etcd key item store
func (p *Poster) triggerPOSTFailsafe(encoded *string) {

}
<commit_msg>gh-699: converted bytestring message payload to []byte<commit_after>package telemetry

import (
	"bytes"
	"encoding/json"
	"net/http"
	"time"

	"github.com/ugorji/go/codec"
)

// Name contains the minimized string value of the Name field.
const Name string = "n"

// Type contains the minimized string value of the Type field.
const Type string = "t"

// Identifier contains the minimized string value of the Identifier field.
const Identifier string = "i"

// Amount contains the minimized string value of the Amount field.
const Amount string = "a"

// When contains the minimized string value of the When field.
const When string = "w"

// TODO:
// make new outputTransformer
// minimize logs
// cborize logs
// send + retry
// failsafe

// NewReporter creates a new Reporter struct and returns a pointer to it.
func NewReporter(requestsLog *RequestsLog, reportInterval int, reportURL string, telemetryEnabled bool, testing bool) *Reporter {
	return &Reporter{
		log:         requestsLog,
		interval:    reportInterval,
		url:         reportURL,
		enabled:     telemetryEnabled,
		transformer: NewOutputTransformer(testing),
		poster:      NewPoster(reportURL),
	}
}

// Reporter is the struct used to report the logged function calls, either to an endpoint or to the etcd store.
type Reporter struct {
	log         *RequestsLog
	interval    int
	url         string
	enabled     bool
	transformer *OutputTransformer
	poster      *Poster
}

// Start posts logged function calls in CBOR format to the provided url every <provided interval> seconds.
// Contains a failsafe mechanism in the case the url is unreachable.
func (r *Reporter) Start() {
	if r.enabled {
		for {
			time.Sleep(time.Duration(r.interval) * time.Second)
			extractedLog := r.log.ExtractLoggedRequests()
			r.AddTimeStamps(extractedLog)
			transformedLog, err := r.TransformToOutputFormat(extractedLog)
			if err == nil {
				r.poster.ReportLoggedCalls(transformedLog)
			} else {
				// TODO: error logging in etcd
			}

		}
	}
}

// AddTimeStamps adds the current timestamp to the logged request types.
func (r *Reporter) AddTimeStamps(extractedLog *map[string]*RequestLog) {
	timestamp := time.Now().Unix()

	for _, log := range *extractedLog {
		log.When = timestamp
	}
}

func (r *Reporter) triggerCBORFailsafe(requests *map[string]*RequestLog) {
	// TODO fill in failsafe etcd handling
}

// TransformToOutputFormat transforms the logged function calls to a minimized output format to reduce network traffic.
func (r *Reporter) TransformToOutputFormat(logs *map[string]*RequestLog) (*[]byte, error) { // TODO: cover with test
	minimizedLogs := r.transformer.ConvertToMinimizedJSON(logs)

	cborLogs, err := r.transformer.EncodeAsCBOR(minimizedLogs)
	if err != nil {
		return nil, err
	}

	return cborLogs, nil
}

// OutputTransformer contains methods that transform the function call logs to an outputtable format.
type OutputTransformer struct {
	testing bool
}

// NewOutputTransformer creates a new OutputTransformer and returns a pointer to it.
func NewOutputTransformer(testing bool) *OutputTransformer {
	return &OutputTransformer{testing}
}

// ConvertToMinimizedJSON converts the request logs to minimized JSON
func (o *OutputTransformer) ConvertToMinimizedJSON(logs *map[string]*RequestLog) *string {
	minimizedLogs := make([]map[string]interface{}, len(*logs))

	iterations := 0
	for _, loggedRequest := range *logs {
		miniLog := make(map[string]interface{})

		miniLog[Name] = loggedRequest.Name
		miniLog[Type] = loggedRequest.Type
		miniLog[Identifier] = loggedRequest.Identifier
		miniLog[Amount] = loggedRequest.Amount
		miniLog[When] = loggedRequest.When

		minimizedLogs[iterations] = miniLog
		iterations++
	}

	rawMinimizedJSON, _ := json.Marshal(minimizedLogs)
	minimizedJSON := string(rawMinimizedJSON)
	return &minimizedJSON
}

// EncodeAsCBOR encodes logs in CBOR format and returns them as a byte array (format to base 16 to get the 'traditional' cbor format).
func (o *OutputTransformer) EncodeAsCBOR(minimizedJSON *string) (*[]byte, error) {
	encoded := make([]byte, 0, 64)
	cborHandle := new(codec.CborHandle)
	if o.testing {
		cborHandle.Canonical = true
	}

	encoder := codec.NewEncoderBytes(&encoded, cborHandle)
	err := encoder.Encode(minimizedJSON)

	if err != nil {
		return nil, err
	}

	return &encoded, nil
}

// NewPoster creates a new
func NewPoster(url string) *Poster {
	return &Poster{url: url}
}

// Poster is a class responsible for sending the converted log to the desired location.
// Tries to send the log to a REST endpoint. If the endpoint is unreachable then the logs are stored in the etcd store.
type Poster struct {
	url string
}

// ReportLoggedCalls sends the logs to a previously determined REST endpoint.
func (p *Poster) ReportLoggedCalls(encoded *[]byte) {
	req, err := http.NewRequest("POST", p.url, bytes.NewReader(*encoded))
	req.Header.Set("Content-Type", "application/cbor")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil || resp.Status != "200" {
		p.triggerPOSTFailsafe(encoded)
	}
	defer resp.Body.Close()
}

// Should the REST endpoint be unreachable then the log is stored in the etcd key item store
func (p *Poster) triggerPOSTFailsafe(encoded *[]byte) {

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io/ioutil"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// ========== Mocked CmdMock struct as test helper for Dcm ==========

type CmdMock struct {
	// CmdMock extends Cmd
	Cmd

	// Fields from CmdMock
	name, dir string
	args, env []string
}

func (c *CmdMock) Exec(name string, args ...string) Executable {
	c.name = name
	c.args = args
	return c
}

func (c *CmdMock) Setdir(dir string) Executable {
	c.dir = dir
	return c
}

func (c *CmdMock) Setenv(env []string) Executable {
	c.env = env
	return c
}

func (c *CmdMock) Getenv() []string {
	return c.env
}

func (c *CmdMock) Run() error {
	switch c.name {
	case "git":
		if len(c.args) == 3 && c.args[0] == "clone" &&
			c.args[1] == "test-dcm-setup-error" {
			return errors.New("exit status 1")
		}
		if len(c.args) == 2 && c.args[0] == "checkout" &&
			c.args[1] == "test-dcm-setup-error" {
			return errors.New("exit status 1")
		}
	case "docker-compose":
		if c.dir == "/test/dcm/run/execute/error" {
			return errors.New("exit status 1")
		}
	case "/bin/bash":
		if len(c.args) == 1 &&
			c.args[0] == "test/dcm/run/init/error" {
			return errors.New("exit status 1")
		}
	}
	return nil
}

func (c *CmdMock) Out() ([]byte, error) {
	return []byte(""), nil
}

// ========== Here starts the real tests for Dcm ==========

func TestSetup(t *testing.T) {
	fixtures := []struct {
		name   string
		config yamlConfig
		code   int
		err    error
	}{
		{
			name: "Negative case for failing reading git repository config",
			config: yamlConfig{
				"service": yamlConfig{"build": "./build/dir"},
			},
			code: 1,
			err:  errors.New("Error reading git repository config for service [service]"),
		},
		{
			name: "Negative case for failing cloning git repository",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{"dcm.repository": "test-dcm-setup-error"},
				},
			},
			code: 1,
			err:  errors.New("Error cloning git repository for service [service]: exit status 1"),
		},
		{
			name: "Negative case for failing switching to pre-configured git branch",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.repository": "test-dcm-setup-ok",
						"dcm.branch":     "test-dcm-setup-error",
					},
				},
			},
			code: 1,
			err:  errors.New("exit status 1"),
		},
		{
			name: "Positive case, success",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.repository": "test-dcm-setup-ok",
						"dcm.branch":     "test-dcm-setup-ok",
					},
				},
			},
			code: 0,
			err:  nil,
		},
	}

	td, err := ioutil.TempDir("", "dcm")
	require.Nil(t, err)
	defer os.Remove(td)

	dcm := NewDcm(NewConfig(), []string{})
	dcm.Cmd = &CmdMock{}
	dcm.Config.Srv = td

	for n, test := range fixtures {
		dcm.Config.Config = test.config
		code, err := dcm.Setup()
		assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name)
		if test.err != nil {
			assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name)
		} else {
			assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name)
		}
	}
}

func TestDoForEachService(t *testing.T) {
	var (
		doSrv doForService
		code  int
		err   error
	)

	dcm := NewDcm(NewConfig(), []string{})

	// Bad fixture data
	fixtureBad := yamlConfig{
		"srv1": "config1",
		"srv2": "config2",
	}
	// Good fixture data
	fixtureGood := yamlConfig{
		"srv1": yamlConfig{
			"config": "value",
		},
		"srv2": yamlConfig{
			"config": "value",
		},
	}

	// Negative test case for failing with panic
	dcm.Config.Config = fixtureBad
	doSrv = func(service string, configs yamlConfig) (int, error) {
		return 0, nil
	}
	assert.Panics(t, func() { dcm.doForEachService(doSrv) })

	// Negative test case for failing with error
	dcm.Config.Config = fixtureGood
	doSrv = func(service string, configs yamlConfig) (int, error) {
		return 1, errors.New("Error")
	}
	assert.NotPanics(t, func() { dcm.doForEachService(doSrv) })
	code, err = dcm.doForEachService(doSrv)
	assert.Equal(t, 1, code)
	assert.Error(t, err)

	// Positive test case, success
	dcm.Config.Config = fixtureGood
	doSrv = func(service string, configs yamlConfig) (int, error) {
		return 0, nil
	}
	assert.NotPanics(t, func() { dcm.doForEachService(doSrv) })
	code, err = dcm.doForEachService(doSrv)
	assert.Equal(t, 0, code)
	assert.NoError(t, err)
}

func TestRunExecute(t *testing.T) {
	fixtures := []struct {
		name, dir string
		code      int
	}{
		{
			name: "Negative case for failing to run docker-compose command",
			dir:  "/test/dcm/run/execute/error",
			code: 1,
		},
		{
			name: "Positive case, success",
			dir:  "/test/dcm/run/execute/ok",
			code: 0,
		},
	}

	dcm := NewDcm(NewConfig(), []string{})
	dcm.Cmd = &CmdMock{}

	for n, test := range fixtures {
		dcm.Config.Dir = test.dir
		code, err := dcm.runExecute()
		assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name)
		if test.code == 1 {
			assert.Error(t, err, "[%d: %s] Incorrect error returned", n, test.name)
		} else {
			assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name)
		}
	}
}

func TestRunInit(t *testing.T) {
	fixtures := []struct {
		name   string
		config yamlConfig
		code   int
		err    error
	}{
		{
			name: "Negative case for config has no init script",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.test": "test",
					},
				},
			},
			code: 0,
			err:  nil,
		},
		{
			name: "Negative case for failing to exuecute init script",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.initscript": "test/dcm/run/init/error",
					},
				},
			},
			code: 1,
			err:  errors.New("Error executing init script [test/dcm/run/init/error] for service [service]: exit status 1"),
		},
		{
			name: "Positive case, success",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.initscript": "test/dcm/run/init/ok",
					},
				},
			},
			code: 0,
			err:  nil,
		},
	}

	dcm := NewDcm(NewConfig(), []string{})
	dcm.Cmd = &CmdMock{}

	for n, test := range fixtures {
		dcm.Config.Config = test.config
		code, err := dcm.runInit()
		assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name)
		if test.err != nil {
			assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name)
		} else {
			assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name)
		}
	}
}

func TestDir(t *testing.T) {
}

func TestShell(t *testing.T) {
}

func TestGetContainerId(t *testing.T) {
}

func TestGetImageRepository(t *testing.T) {
}

func TestBranchForOne(t *testing.T) {
}

func TestUpdate(t *testing.T) {
}

func TestPurgeImages(t *testing.T) {
}

func TestPurgeContainers(t *testing.T) {
}
<commit_msg>Added test case for Dir()<commit_after>package main

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// ========== Mocked CmdMock struct as test helper for Dcm ==========

type CmdMock struct {
	// CmdMock extends Cmd
	Cmd

	// Fields from CmdMock
	name, dir string
	args, env []string
}

func (c *CmdMock) Exec(name string, args ...string) Executable {
	c.name = name
	c.args = args
	return c
}

func (c *CmdMock) Setdir(dir string) Executable {
	c.dir = dir
	return c
}

func (c *CmdMock) Setenv(env []string) Executable {
	c.env = env
	return c
}

func (c *CmdMock) Getenv() []string {
	return c.env
}

func (c *CmdMock) Run() error {
	switch c.name {
	case "git":
		if len(c.args) == 3 && c.args[0] == "clone" &&
			c.args[1] == "test-dcm-setup-error" {
			return errors.New("exit status 1")
		}
		if len(c.args) == 2 && c.args[0] == "checkout" &&
			c.args[1] == "test-dcm-setup-error" {
			return errors.New("exit status 1")
		}
	case "docker-compose":
		if c.dir == "/test/dcm/run/execute/error" {
			return errors.New("exit status 1")
		}
	case "/bin/bash":
		if len(c.args) == 1 &&
			c.args[0] == "test/dcm/run/init/error" {
			return errors.New("exit status 1")
		}
	}
	return nil
}

func (c *CmdMock) Out() ([]byte, error) {
	return []byte(""), nil
}

// ========== Here starts the real tests for Dcm ==========

func TestSetup(t *testing.T) {
	fixtures := []struct {
		name   string
		config yamlConfig
		code   int
		err    error
	}{
		{
			name: "Negative case for failing reading git repository config",
			config: yamlConfig{
				"service": yamlConfig{"build": "./build/dir"},
			},
			code: 1,
			err:  errors.New("Error reading git repository config for service [service]"),
		},
		{
			name: "Negative case for failing cloning git repository",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{"dcm.repository": "test-dcm-setup-error"},
				},
			},
			code: 1,
			err:  errors.New("Error cloning git repository for service [service]: exit status 1"),
		},
		{
			name: "Negative case for failing switching to pre-configured git branch",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.repository": "test-dcm-setup-ok",
						"dcm.branch":     "test-dcm-setup-error",
					},
				},
			},
			code: 1,
			err:  errors.New("exit status 1"),
		},
		{
			name: "Positive case, success",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.repository": "test-dcm-setup-ok",
						"dcm.branch":     "test-dcm-setup-ok",
					},
				},
			},
			code: 0,
			err:  nil,
		},
	}

	td, err := ioutil.TempDir("", "dcm")
	require.Nil(t, err)
	defer os.Remove(td)

	dcm := NewDcm(NewConfig(), []string{})
	dcm.Cmd = &CmdMock{}
	dcm.Config.Srv = td

	for n, test := range fixtures {
		dcm.Config.Config = test.config
		code, err := dcm.Setup()
		assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name)
		if test.err != nil {
			assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name)
		} else {
			assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name)
		}
	}
}

func TestDoForEachService(t *testing.T) {
	var (
		doSrv doForService
		code  int
		err   error
	)

	dcm := NewDcm(NewConfig(), []string{})

	// Bad fixture data
	fixtureBad := yamlConfig{
		"srv1": "config1",
		"srv2": "config2",
	}
	// Good fixture data
	fixtureGood := yamlConfig{
		"srv1": yamlConfig{
			"config": "value",
		},
		"srv2": yamlConfig{
			"config": "value",
		},
	}

	// Negative test case for failing with panic
	dcm.Config.Config = fixtureBad
	doSrv = func(service string, configs yamlConfig) (int, error) {
		return 0, nil
	}
	assert.Panics(t, func() { dcm.doForEachService(doSrv) })

	// Negative test case for failing with error
	dcm.Config.Config = fixtureGood
	doSrv = func(service string, configs yamlConfig) (int, error) {
		return 1, errors.New("Error")
	}
	assert.NotPanics(t, func() { dcm.doForEachService(doSrv) })
	code, err = dcm.doForEachService(doSrv)
	assert.Equal(t, 1, code)
	assert.Error(t, err)

	// Positive test case, success
	dcm.Config.Config = fixtureGood
	doSrv = func(service string, configs yamlConfig) (int, error) {
		return 0, nil
	}
	assert.NotPanics(t, func() { dcm.doForEachService(doSrv) })
	code, err = dcm.doForEachService(doSrv)
	assert.Equal(t, 0, code)
	assert.NoError(t, err)
}

func TestRunExecute(t *testing.T) {
	fixtures := []struct {
		name, dir string
		code      int
	}{
		{
			name: "Negative case for failing to run docker-compose command",
			dir:  "/test/dcm/run/execute/error",
			code: 1,
		},
		{
			name: "Positive case, success",
			dir:  "/test/dcm/run/execute/ok",
			code: 0,
		},
	}

	dcm := NewDcm(NewConfig(), []string{})
	dcm.Cmd = &CmdMock{}

	for n, test := range fixtures {
		dcm.Config.Dir = test.dir
		code, err := dcm.runExecute()
		assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name)
		if test.code == 1 {
			assert.Error(t, err, "[%d: %s] Incorrect error returned", n, test.name)
		} else {
			assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name)
		}
	}
}

func TestRunInit(t *testing.T) {
	fixtures := []struct {
		name   string
		config yamlConfig
		code   int
		err    error
	}{
		{
			name: "Negative case for config has no init script",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.test": "test",
					},
				},
			},
			code: 0,
			err:  nil,
		},
		{
			name: "Negative case for failing to exuecute init script",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.initscript": "test/dcm/run/init/error",
					},
				},
			},
			code: 1,
			err:  errors.New("Error executing init script [test/dcm/run/init/error] for service [service]: exit status 1"),
		},
		{
			name: "Positive case, success",
			config: yamlConfig{
				"service": yamlConfig{
					"labels": yamlConfig{
						"dcm.initscript": "test/dcm/run/init/ok",
					},
				},
			},
			code: 0,
			err:  nil,
		},
	}

	dcm := NewDcm(NewConfig(), []string{})
	dcm.Cmd = &CmdMock{}

	for n, test := range fixtures {
		dcm.Config.Config = test.config
		code, err := dcm.runInit()
		assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name)
		if test.err != nil {
			assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name)
		} else {
			assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name)
		}
	}
}

func TestDir(t *testing.T) {
	dir, err := ioutil.TempDir("", "dcm")
	require.Nil(t, err)
	srv, err := ioutil.TempDir(dir, "service")
	require.Nil(t, err)
	defer os.RemoveAll(dir)

	dcm := NewDcm(NewConfig(), []string{})
	var out string

	// Test Dir() without args
	out = helperTestOsStdout(t, func() {
		dcm.Config.Dir = dir
		dcm.Dir()
	})
	assert.Equal(t, dir, out)

	// Test Dir() with args
	out = helperTestOsStdout(t, func() {
		dcm.Config.Srv = dir
		dcm.Dir(path.Base(srv))
	})
	assert.Equal(t, srv, out)
}

func helperTestOsStdout(t *testing.T, fn func()) (out string) {
	// Capture stdout
	stdout := os.Stdout
	r, w, err := os.Pipe()
	require.Nil(t, err)
	os.Stdout = w
	outC := make(chan string)

	go func() {
		var buf bytes.Buffer
		_, err := io.Copy(&buf, r)
		r.Close()
		require.Nil(t, err)
		outC <- buf.String()
	}()

	fn()

	w.Close()
	os.Stdout = stdout
	out = <-outC

	return
}

func TestShell(t *testing.T) {
}

func TestGetContainerId(t *testing.T) {
}

func TestGetImageRepository(t *testing.T) {
}

func TestBranchForOne(t *testing.T) {
}

func TestUpdate(t *testing.T) {
}

func TestPurgeImages(t *testing.T) {
}

func TestPurgeContainers(t *testing.T) {
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/nbari/violetear"
	//	"log"
	"net/http"
)

func hello_world(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func hello_world_all(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "catch %s!", r.URL.Path)
}
func not_found(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "not found %s!", r.URL.Path)
}

func commonHeaders(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("X-app-Version", "1.0")
		fn(w, r)
	}
}

func main() {
	router := violetear.New(true)

	router.AddRegex(":uuid", `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`)
	router.AddRegex(":sopas", `sopas`)

	router.HandleFunc("/hello", hello_world)
	router.HandleFunc("/hello/world", commonHeaders(hello_world), "GET,POST")
	router.HandleFunc("/hello/world/:sopas", hello_world_all, "GET")
	router.HandleFunc(":uuid", hello_world)

	//	router.NotAllowedHandler = http.HandlerFunc(not_found)
	//	router.NotFoundHandler = http.HandlerFunc(not_found)

	router.Run(":8080")

}
<commit_msg>	modified:   main.go<commit_after>package main

import (
	"fmt"
	"github.com/nbari/violetear"
	//	"log"
	"net/http"
)

func hello_world(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func hello_world_all(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "catch %s!", r.URL.Path)
}
func not_found(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "not found %s!", r.URL.Path)
}

func commonHeaders(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("X-app-Version", "1.0")
		fn(w, r)
	}
}

func wrapper(router *violetear.Router) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		router.LogRequests = true
		fmt.Fprintf(w, "not found %s!", r.URL.Path)
	}
}

func main() {
	router := violetear.New()
	router.LogRequests = true
	router.Request_ID = "rid"

	router.AddRegex(":uuid", `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`)
	router.AddRegex(":sopas", `sopas`)

	router.HandleFunc("/hello", wrapper(router), "GET")
	router.HandleFunc("/hello/world", commonHeaders(hello_world), "GET,POST")
	router.HandleFunc("/hello/world/:sopas", hello_world_all, "GET")
	router.HandleFunc(":uuid", hello_world)
	router.HandleFunc("*", hello_world)
	router.HandleFunc("/hola/*", hello_world)
	router.HandleFunc("/hola/:sopas", hello_world)
	router.HandleFunc("/hola/epazote", hello_world)
	router.HandleFunc("/hola/epazote/*", hello_world)
	router.HandleFunc("/hola/epazote/a/papas", hello_world)

	//	router.NotAllowedHandler = http.HandlerFunc(not_found)
	//	router.NotFoundHandler = http.HandlerFunc(not_found)
	router.SetHeader("X-app-epazote", "1.1")

	router.Run(":8080")
}
<|endoftext|>