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

package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/apptimistco/asn/debug"
	"github.com/apptimistco/asn/debug/mutex"
	"golang.org/x/net/websocket"
)

type nopCloserWriter struct {
	io.Writer
}

func (nopCloserWriter) Close() error { return nil }

// NopCloserWriter returns a WriteCloser with a no-op Close method wrapping
// the provided writer.
func NopCloserWriter(w io.Writer) io.WriteCloser {
	return nopCloserWriter{w}
}

type SrvListener struct {
	ln    Listener
	stop  chan struct{}
	done  chan error
	ws    bool
	clean string
}

type Server struct {
	mutex.Mutex
	cmd       *Command
	repos     Repos
	listeners []*SrvListener
	sessions  []*Ses

	listening struct {
		stop chan struct{}
		done chan struct{}
	}
}

func (cmd *Command) Server(args ...string) {
	srv := &Server{
		cmd:       cmd,
		listeners: make([]*SrvListener, 0),
		sessions:  make([]*Ses, 0),
	}
	err := cmd.Cfg.Check(ServerMode)
	defer func() { cmd.Done <- err }()
	if err != nil {
		runtime.Goexit()
	}
	srv.Mutex.Set(cmd.Cfg.Name)
	if err = srv.repos.Set(cmd.Cfg.Dir); err != nil {
		runtime.Goexit()
	}
	srv.repos.Set(cmd.Cfg.Keys)
	defer func() { srv.repos.Reset() }()
	for _, k := range []*UserKeys{
		srv.cmd.Cfg.Keys.Admin,
		srv.cmd.Cfg.Keys.Server,
	} {
		user := srv.repos.users.User(k.Pub.Encr)
		if user == nil {
			user, err = srv.repos.NewUser(k.Pub.Encr)
			if err != nil {
				runtime.Goexit()
			}
			user.cache.Auth().Set(k.Pub.Auth)
			user.cache.Author().Set(k.Pub.Encr)
		}
		user = nil
	}
	if len(args) > 0 {
		// local server command line exec
		var ses Ses
		// FIXME ses.asn.Init()
		// FIXME defer ses.Reset()
		ses.Set(srv)
		ses.Set(&srv.cmd.Cfg)
		ses.Set(&srv.repos)
		ses.Set(srv.ForEachLogin)
		admin := srv.cmd.Cfg.Keys.Admin.Pub.Encr
		ses.Keys.Client.Login = *admin
		ses.asnsrv = true
		ses.user = ses.asn.repos.users.User(admin)
		v := ses.Exec(NewReqString("exec"), cmd.Stdin, args...)
		err, _ = v.(error)
		AckOut(cmd.Stdout, v)
		v = nil
		runtime.Goexit()
	}
	if err = srv.Listen(); err != nil {
		runtime.Goexit()
	}
	cmd.Stdin.Close()
	cmd.Stdout.Close()
	cmd.Stdout = NopCloserWriter(ioutil.Discard)
	cmd.Stderr.Close()
	cmd.Stderr = NopCloserWriter(ioutil.Discard)
	sigch := make(chan os.Signal, 2)
	signal.Notify(sigch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
	defer signal.Stop(sigch)
	for {
		sig := <-sigch
		srv.Diag("caught", sig)
		switch sig {
		case syscall.SIGINT:
			debug.Trace.WriteTo(debug.Log)
			srv.Close()
			srv.Hangup()
			runtime.Goexit()
		case syscall.SIGTERM:
			srv.Close()
		case syscall.SIGUSR1:
			debug.Trace.WriteTo(debug.Log)
		}
	}
}

func (srv *Server) AddListener(l *SrvListener) {
	srv.Lock()
	defer srv.Unlock()
	for _, p := range srv.listeners {
		if p == nil {
			p = l
			return
		}
	}
	srv.listeners = append(srv.listeners, l)
}

func (srv *Server) Close() {
	for i, le := range srv.listeners {
		if le.ws {
			le.ln.Close()
		} else {
			le.stop <- struct{}{}
			<-le.done
		}
		close(le.stop)
		close(le.done)
		le.ln = nil
		srv.listeners[i] = nil
	}
	srv.listeners = nil
}

func (srv *Server) ForEachLogin(f func(*Ses)) {
	srv.Lock()
	defer srv.Unlock()
	for _, ses := range srv.sessions {
		if ses != nil && ses.asn.state == established {
			f(ses)
		}
	}
}

func (srv *Server) handler(conn net.Conn) {
	var ses Ses
	svc := srv.cmd.Cfg.Keys
	ses.asn.Init()
	ses.Set(&srv.cmd.Cfg)
	ses.Set(&srv.repos)
	ses.Set(srv.ForEachLogin)
	srv.add(&ses)
	ses.asn.Set(conn)
	defer func() {
		r := recover()
		ses.Lock()
		ses.Unlock()
		if r != nil {
			err := r.(error)
			ses.asn.Diag(debug.Depth(3), err)
		}
		for i := 0; ses.asn.tx.going; i += 1 {
			if i == 0 {
				close(ses.asn.tx.ch)
			}
			time.Sleep(100 * time.Millisecond)
			if i == 3 {
				panic("can't close connection")
			}
		}
		user := srv.repos.users.User(&ses.Keys.Client.Login)
		if user != nil && user.logins > 0 {
			user.logins -= 1
		}
		srv.rm(&ses)
		srv.Log("disconnected", &ses.Keys.Client.Ephemeral)
		ses.Reset()
	}()
	for {
		n, err := conn.Read(ses.Keys.Client.Ephemeral[:])
		if err == nil {
			if n != PubEncrSz {
				panic(Error{"Oops!", "incomplete ephemeral key"})
			}
			break
		}
		if !IsNetTimeout(err) {
			panic(err)
		}
	}
	ses.asn.Set(NewBox(2, srv.cmd.Cfg.Keys.Nonce,
		&ses.Keys.Client.Ephemeral, svc.Server.Pub.Encr,
		svc.Server.Sec.Encr))
	srv.Log("connected", &ses.Keys.Client.Ephemeral)
	for {
		pdu, opened := <-ses.asn.rx.ch
		if !opened {
			runtime.Goexit()
		}
		err := pdu.Open()
		if err != nil {
			pdu.Free()
			panic(err)
		}
		var v Version
		v.ReadFrom(pdu)
		// FIXME to adjust version ... ses.asn.Set(v)
		var id Id
		id.ReadFrom(pdu)
		id.Internal(v)
		ses.asn.time.out = time.Now()
		switch id {
		case AckReqId:
			err = ses.asn.AckerRx(pdu)
		case ExecReqId:
			err = ses.RxExec(pdu)
		case LoginReqId:
			if err = ses.RxLogin(pdu); err != nil {
				// FIXME block subsequent attempts
				// and eventually terminate
			}
		case BlobId:
			if bytes.Equal(ses.Keys.Client.Login.Bytes(),
				svc.Admin.Pub.Encr.Bytes()) ||
				bytes.Equal(ses.Keys.Client.Login.Bytes(),
					svc.Server.Pub.Encr.Bytes()) {
				_, err = ses.asn.repos.Store(&ses, v, nil, pdu)
			} else {
				err = os.ErrPermission
			}
			if err != nil {
				ses.asn.Diag(err)
			}
		default:
			if id >= Nids {
				panic(ErrIncompatible)
			} else {
				panic(ErrUnsupported)
			}
		}
		pdu.Free()
		pdu = nil
		if err != nil {
			panic(err)
		}
	}
}

func (srv *Server) Hangup() {
	srv.Lock()
	for _, ses := range srv.sessions {
		if ses != nil && ses.asn.tx.going {
			close(ses.asn.tx.ch)
		}
	}
	srv.Unlock()
	for {
		active := 0
		srv.Lock()
		for _, ses := range srv.sessions {
			if ses != nil {
				active += 1
			}
		}
		srv.Unlock()
		if active == 0 {
			break
		}
		time.Sleep(100 * time.Millisecond)
	}
	srv.sessions = nil
}

func (srv *Server) Listen() error {
	for _, lurl := range srv.cmd.Cfg.Listen {
		l := &SrvListener{
			stop: make(chan struct{}, 1),
			done: make(chan error, 1),
		}
		switch lurl.Scheme {
		case "tcp":
			addr, err := net.ResolveTCPAddr(lurl.Scheme, lurl.Host)
			if err != nil {
				return err
			}
			l.ln, err = net.ListenTCP(lurl.Scheme, addr)
			if err != nil {
				return err
			}
			srv.AddListener(l)
			srv.Diag("listening on", addr)
			go l.listen(srv)
		case "unix":
			path := UrlPathSearch(lurl.Path)
			os.Remove(path)
			addr, err := net.ResolveUnixAddr(lurl.Scheme, path)
			if err != nil {
				return err
			}
			l.ln, err = net.ListenUnix(lurl.Scheme, addr)
			if err != nil {
				return err
			}
			srv.AddListener(l)
			l.clean = path
			srv.Diag("listening on", addr)
			go l.listen(srv)
		case "ws":
			l.ws = true
			if lurl.Host == "" {
				lurl.Host = ":http"
			}
			addr, err := net.ResolveTCPAddr("tcp", lurl.Host)
			if err != nil {
				return err
			}
			if l.ln, err = net.ListenTCP("tcp", addr); err != nil {
				return err
			}
			srv.AddListener(l)
			f := func(ws *websocket.Conn) {
				srv.handler(ws)
			}
			/*
				FIXME should use a custom handler
				h := func (w http.ResponseWriter, req *http.Request) {
					s := websocket.Server{Handler: websocket.Handler(webHandler)}
					s.ServeHTTP(w, req)
				});
				s := &http.Server{
					Addr:           ":8080",
					Handler:        h,
					ReadTimeout:    10 * time.Second,
					WriteTimeout:   10 * time.Second,
					MaxHeaderBytes: 1 << 20,
				}
				return s.Serve(l)
			*/
			mux := http.NewServeMux()
			mux.Handle(lurl.Path, websocket.Handler(f))
			srv.Diag("listening on", lurl.String())
			go http.Serve(l.ln, mux)
		default:
			err := &Error{lurl.Scheme, "unsupported"}
			srv.Diag(err)
			return err
		}
	}
	return nil
}

func (srv *Server) add(ses *Ses) {
	srv.Lock()
	defer srv.Unlock()
	for i := range srv.sessions {
		if srv.sessions[i] == nil {
			srv.sessions[i] = ses
			return
		}
	}
	srv.sessions = append(srv.sessions, ses)
}

func (srv *Server) rm(ses *Ses) {
	srv.Lock()
	defer srv.Unlock()
	for i := range srv.sessions {
		if srv.sessions[i] == ses {
			srv.sessions[i] = nil
			break
		}
	}
}

func (l *SrvListener) listen(srv *Server) {
	const dl = 100 * time.Millisecond
	for {
		select {
		case <-l.stop:
			err := l.ln.Close()
			if len(l.clean) > 0 {
				os.Remove(l.clean)
			}
			l.done <- err
			return
		default:
			l.ln.SetDeadline(time.Now().Add(dl))
			conn, err := l.ln.Accept()
			if err == nil {
				l.ln.SetDeadline(time.Time{})
				go srv.handler(conn)
			} else if !IsNetOpTimeout(err) {
				srv.Diag("accept", err)
				runtime.Goexit()
			}
		}
	}
}

func IsNetOpTimeout(err error) bool {
	e, ok := err.(*net.OpError)
	return ok && e.Timeout()
}
<commit_msg>logging and state checking<commit_after>// Copyright 2014-2015 Apptimist, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/apptimistco/asn/debug"
	"github.com/apptimistco/asn/debug/mutex"
	"golang.org/x/net/websocket"
)

type nopCloserWriter struct {
	io.Writer
}

func (nopCloserWriter) Close() error { return nil }

// NopCloserWriter returns a WriteCloser with a no-op Close method wrapping
// the provided writer.
func NopCloserWriter(w io.Writer) io.WriteCloser {
	return nopCloserWriter{w}
}

type SrvListener struct {
	ln    Listener
	stop  chan struct{}
	done  chan error
	ws    bool
	clean string
}

type Server struct {
	mutex.Mutex
	cmd       *Command
	repos     Repos
	listeners []*SrvListener
	sessions  []*Ses

	listening struct {
		stop chan struct{}
		done chan struct{}
	}
}

func (cmd *Command) Server(args ...string) {
	srv := &Server{
		cmd:       cmd,
		listeners: make([]*SrvListener, 0),
		sessions:  make([]*Ses, 0),
	}
	err := cmd.Cfg.Check(ServerMode)
	defer func() { cmd.Done <- err }()
	if err != nil {
		runtime.Goexit()
	}
	srv.Mutex.Set(cmd.Cfg.Name)
	if err = srv.repos.Set(cmd.Cfg.Dir); err != nil {
		runtime.Goexit()
	}
	srv.repos.Set(cmd.Cfg.Keys)
	defer func() { srv.repos.Reset() }()
	for _, k := range []*UserKeys{
		srv.cmd.Cfg.Keys.Admin,
		srv.cmd.Cfg.Keys.Server,
	} {
		user := srv.repos.users.User(k.Pub.Encr)
		if user == nil {
			user, err = srv.repos.NewUser(k.Pub.Encr)
			if err != nil {
				runtime.Goexit()
			}
			user.cache.Auth().Set(k.Pub.Auth)
			user.cache.Author().Set(k.Pub.Encr)
		}
		user = nil
	}
	if len(args) > 0 {
		// local server command line exec
		var ses Ses
		// FIXME ses.asn.Init()
		// FIXME defer ses.Reset()
		ses.Set(srv)
		ses.Set(&srv.cmd.Cfg)
		ses.Set(&srv.repos)
		ses.Set(srv.ForEachLogin)
		admin := srv.cmd.Cfg.Keys.Admin.Pub.Encr
		ses.Keys.Client.Login = *admin
		ses.asnsrv = true
		ses.user = ses.asn.repos.users.User(admin)
		v := ses.Exec(NewReqString("exec"), cmd.Stdin, args...)
		err, _ = v.(error)
		AckOut(cmd.Stdout, v)
		v = nil
		runtime.Goexit()
	}
	if err = srv.Listen(); err != nil {
		runtime.Goexit()
	}
	cmd.Stdin.Close()
	cmd.Stdout.Close()
	cmd.Stdout = NopCloserWriter(ioutil.Discard)
	cmd.Stderr.Close()
	cmd.Stderr = NopCloserWriter(ioutil.Discard)
	sigch := make(chan os.Signal, 2)
	signal.Notify(sigch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
	defer signal.Stop(sigch)
	for {
		sig := <-sigch
		srv.Diag("caught", sig)
		switch sig {
		case syscall.SIGINT:
			debug.Trace.WriteTo(debug.Log)
			srv.Close()
			srv.Hangup()
			runtime.Goexit()
		case syscall.SIGTERM:
			srv.Close()
		case syscall.SIGUSR1:
			debug.Trace.WriteTo(debug.Log)
		}
	}
}

func (srv *Server) AddListener(l *SrvListener) {
	srv.Lock()
	defer srv.Unlock()
	for _, p := range srv.listeners {
		if p == nil {
			p = l
			return
		}
	}
	srv.listeners = append(srv.listeners, l)
}

func (srv *Server) Close() {
	for i, le := range srv.listeners {
		if le.ws {
			le.ln.Close()
		} else {
			le.stop <- struct{}{}
			<-le.done
		}
		close(le.stop)
		close(le.done)
		le.ln = nil
		srv.listeners[i] = nil
	}
	srv.listeners = nil
}

func (srv *Server) ForEachLogin(f func(*Ses)) {
	srv.Lock()
	defer srv.Unlock()
	for _, ses := range srv.sessions {
		if ses != nil && ses.asn.IsEstablished() {
			f(ses)
		}
	}
}

func (srv *Server) handler(conn net.Conn) {
	var ses Ses
	svc := srv.cmd.Cfg.Keys
	ses.asn.Init()
	ses.Set(&srv.cmd.Cfg)
	ses.Set(&srv.repos)
	ses.Set(srv.ForEachLogin)
	srv.add(&ses)
	ses.asn.Set(conn)
	defer func() {
		r := recover()
		ses.Lock()
		ses.Unlock()
		if r != nil {
			err := r.(error)
			srv.Log(err)
			ses.asn.Diag(debug.Depth(3), err)
		}
		for i := 0; ses.asn.tx.going; i += 1 {
			if i == 0 {
				close(ses.asn.tx.ch)
			}
			time.Sleep(100 * time.Millisecond)
			if i == 3 {
				panic("can't close connection")
			}
		}
		user := srv.repos.users.User(&ses.Keys.Client.Login)
		if user != nil && user.logins > 0 {
			user.logins -= 1
		}
		srv.rm(&ses)
		srv.Log("disconnected", &ses.Keys.Client.Ephemeral)
		ses.Reset()
	}()
	for {
		n, err := conn.Read(ses.Keys.Client.Ephemeral[:])
		if err == nil {
			if n != PubEncrSz {
				panic(Error{"Oops!", "incomplete ephemeral key"})
			}
			break
		}
		if !IsNetTimeout(err) {
			panic(err)
		}
	}
	ses.asn.Set(NewBox(2, srv.cmd.Cfg.Keys.Nonce,
		&ses.Keys.Client.Ephemeral, svc.Server.Pub.Encr,
		svc.Server.Sec.Encr))
	srv.Log("connected", &ses.Keys.Client.Ephemeral)
	for {
		pdu, opened := <-ses.asn.rx.ch
		if !opened {
			runtime.Goexit()
		}
		err := pdu.Open()
		if err != nil {
			pdu.Free()
			panic(err)
		}
		var v Version
		v.ReadFrom(pdu)
		// FIXME to adjust version ... ses.asn.Set(v)
		var id Id
		id.ReadFrom(pdu)
		id.Internal(v)
		ses.asn.time.out = time.Now()
		switch id {
		case AckReqId:
			err = ses.asn.AckerRx(pdu)
		case ExecReqId:
			err = ses.RxExec(pdu)
		case LoginReqId:
			if err = ses.RxLogin(pdu); err != nil {
				// FIXME block subsequent attempts
				// and eventually terminate
			}
		case BlobId:
			if bytes.Equal(ses.Keys.Client.Login.Bytes(),
				svc.Admin.Pub.Encr.Bytes()) ||
				bytes.Equal(ses.Keys.Client.Login.Bytes(),
					svc.Server.Pub.Encr.Bytes()) {
				_, err = ses.asn.repos.Store(&ses, v, nil, pdu)
			} else {
				err = os.ErrPermission
			}
			if err != nil {
				ses.asn.Diag(err)
			}
		default:
			if id >= Nids {
				panic(ErrIncompatible)
			} else {
				panic(ErrUnsupported)
			}
		}
		pdu.Free()
		pdu = nil
		if err != nil {
			panic(err)
		}
	}
}

func (srv *Server) Hangup() {
	srv.Lock()
	for _, ses := range srv.sessions {
		if ses != nil && ses.asn.tx.going {
			close(ses.asn.tx.ch)
		}
	}
	srv.Unlock()
	for {
		active := 0
		srv.Lock()
		for _, ses := range srv.sessions {
			if ses != nil {
				active += 1
			}
		}
		srv.Unlock()
		if active == 0 {
			break
		}
		time.Sleep(100 * time.Millisecond)
	}
	srv.sessions = nil
}

func (srv *Server) Listen() error {
	for _, lurl := range srv.cmd.Cfg.Listen {
		l := &SrvListener{
			stop: make(chan struct{}, 1),
			done: make(chan error, 1),
		}
		switch lurl.Scheme {
		case "tcp":
			addr, err := net.ResolveTCPAddr(lurl.Scheme, lurl.Host)
			if err != nil {
				return err
			}
			l.ln, err = net.ListenTCP(lurl.Scheme, addr)
			if err != nil {
				return err
			}
			srv.AddListener(l)
			srv.Diag("listening on", addr)
			go l.listen(srv)
		case "unix":
			path := UrlPathSearch(lurl.Path)
			os.Remove(path)
			addr, err := net.ResolveUnixAddr(lurl.Scheme, path)
			if err != nil {
				return err
			}
			l.ln, err = net.ListenUnix(lurl.Scheme, addr)
			if err != nil {
				return err
			}
			srv.AddListener(l)
			l.clean = path
			srv.Diag("listening on", addr)
			go l.listen(srv)
		case "ws":
			l.ws = true
			if lurl.Host == "" {
				lurl.Host = ":http"
			}
			addr, err := net.ResolveTCPAddr("tcp", lurl.Host)
			if err != nil {
				return err
			}
			if l.ln, err = net.ListenTCP("tcp", addr); err != nil {
				return err
			}
			srv.AddListener(l)
			f := func(ws *websocket.Conn) {
				srv.handler(ws)
			}
			/*
				FIXME should use a custom handler
				h := func (w http.ResponseWriter, req *http.Request) {
					s := websocket.Server{Handler: websocket.Handler(webHandler)}
					s.ServeHTTP(w, req)
				});
				s := &http.Server{
					Addr:           ":8080",
					Handler:        h,
					ReadTimeout:    10 * time.Second,
					WriteTimeout:   10 * time.Second,
					MaxHeaderBytes: 1 << 20,
				}
				return s.Serve(l)
			*/
			mux := http.NewServeMux()
			mux.Handle(lurl.Path, websocket.Handler(f))
			srv.Diag("listening on", lurl.String())
			go http.Serve(l.ln, mux)
		default:
			err := &Error{lurl.Scheme, "unsupported"}
			srv.Diag(err)
			return err
		}
	}
	return nil
}

func (srv *Server) add(ses *Ses) {
	srv.Lock()
	defer srv.Unlock()
	for i := range srv.sessions {
		if srv.sessions[i] == nil {
			srv.sessions[i] = ses
			return
		}
	}
	srv.sessions = append(srv.sessions, ses)
}

func (srv *Server) rm(ses *Ses) {
	srv.Lock()
	defer srv.Unlock()
	for i := range srv.sessions {
		if srv.sessions[i] == ses {
			srv.sessions[i] = nil
			break
		}
	}
}

func (l *SrvListener) listen(srv *Server) {
	const dl = 100 * time.Millisecond
	for {
		select {
		case <-l.stop:
			err := l.ln.Close()
			if len(l.clean) > 0 {
				os.Remove(l.clean)
			}
			l.done <- err
			return
		default:
			l.ln.SetDeadline(time.Now().Add(dl))
			conn, err := l.ln.Accept()
			if err == nil {
				l.ln.SetDeadline(time.Time{})
				go srv.handler(conn)
			} else if !IsNetOpTimeout(err) {
				srv.Diag("accept", err)
				runtime.Goexit()
			}
		}
	}
}

func IsNetOpTimeout(err error) bool {
	e, ok := err.(*net.OpError)
	return ok && e.Timeout()
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package stdscript

import (
	"bytes"
	"testing"

	"github.com/decred/dcrd/txscript/v4"
)

// complexScriptV0 is a version 0 script comprised of half as many opcodes as
// the maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
var complexScriptV0 = func() []byte {
	const (
		maxScriptSize        = txscript.MaxScriptSize
		maxScriptElementSize = txscript.MaxScriptElementSize
	)
	var scriptLen int
	builder := txscript.NewScriptBuilder()
	for i := 0; i < txscript.MaxOpsPerScript/2; i++ {
		builder.AddOp(txscript.OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, maxScriptElementSize)
	for i := 0; i < (maxScriptSize-scriptLen)/maxScriptElementSize; i++ {
		builder.AddData(maxData)
	}
	script, err := builder.Script()
	if err != nil {
		panic(err)
	}
	return script
}()

// makeBenchmarks constructs a slice of tests to use in the benchmarks as
// follows:
// - Start with a version 0 complex non standard script
// - Add all tests for which the provided filter function returns true
func makeBenchmarks(filterFn func(test scriptTest) bool) []scriptTest {
	benches := make([]scriptTest, 0, 5)
	benches = append(benches, scriptTest{
		name:    "v0 complex non standard",
		version: 0,
		script:  complexScriptV0,
	})
	for _, test := range scriptV0Tests {
		if filterFn(test) {
			benches = append(benches, test)
		}
	}
	return benches
}

// benchIsX is a convenience function that runs benchmarks for the entries that
// match the provided filter function using the given script type determination
// function and ensures the result matches the expected one.
func benchIsX(b *testing.B, filterFn func(test scriptTest) bool, isXFn func(scriptVersion uint16, script []byte) bool) {
	b.Helper()

	benches := makeBenchmarks(filterFn)
	for _, bench := range benches {
		want := filterFn(bench)
		b.Run(bench.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := isXFn(bench.version, bench.script)
				if got != want {
					b.Fatalf("%q: unexpected result -- got %v, want %v",
						bench.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsPubKeyScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pk-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyScript)
}

// BenchmarkIsPubKeyEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEd25519
	}
	benchIsX(b, filterFn, IsPubKeyEd25519Script)
}

// BenchmarkIsPubKeySchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeySchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeySchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeySchnorrSecp256k1Script)
}

// BenchmarkIsPubKeyHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashScript)
}

// BenchmarkIsPubKeyHashEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyHashEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEd25519
	}
	benchIsX(b, filterFn, IsPubKeyHashEd25519Script)
}

// BenchmarkIsPubKeyHashSchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeyHashSchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashSchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashSchnorrSecp256k1Script)
}

// BenchmarkIsScriptHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2sh scripts.
func BenchmarkIsScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STScriptHash
	}
	benchIsX(b, filterFn, IsScriptHashScript)
}

// BenchmarkIsMultiSigScript benchmarks the performance of analyzing various
// public key scripts to determine if they are multisignature scripts.
func BenchmarkIsMultiSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && !test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigScript)
}

// BenchmarkIsMultiSigSigScript benchmarks the performance of analyzing various
// signature scripts to determine if they are likely to be multisignature redeem
// scripts.
func BenchmarkIsMultiSigSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigSigScript)
}

// BenchmarkMultiSigRedeemScriptFromScriptSigV0 benchmarks the performance of
// extracting the redeem script from various version 0 signature scripts.
func BenchmarkMultiSigRedeemScriptFromScriptSigV0(b *testing.B) {
	for _, test := range scriptV0Tests {
		if test.version != 0 || test.wantType != STMultiSig || !test.isSig {
			continue
		}
		want := test.wantData.([]byte)

		b.Run(test.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := MultiSigRedeemScriptFromScriptSigV0(test.script)
				if !bytes.Equal(got, want) {
					b.Fatalf("%q: unexpected result -- got %x, want %x",
						test.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsNullDataScript benchmarks the performance of analyzing various
// public key scripts to determine if they are nulldata scripts.
func BenchmarkIsNullDataScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STNullData
	}
	benchIsX(b, filterFn, IsNullDataScript)
}

// BenchmarkIsStakeSubmissionPubKeyHashScript benchmarks the performance of
// analyzing various public key scripts to determine if they are stake
// submission p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeSubmissionPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeSubmissionPubKeyHash
	}
	benchIsX(b, filterFn, IsStakeSubmissionPubKeyHashScript)
}

// BenchmarkIsStakeSubmissionScriptHashScript benchmarks the performance of
// analyzing various public key scripts to determine if they are stake
// submission p2sh scripts.
func BenchmarkIsStakeSubmissionScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeSubmissionScriptHash
	}
	benchIsX(b, filterFn, IsStakeSubmissionScriptHashScript)
}

// BenchmarkIsStakeGenPubKeyHashScript benchmarks the performance of analyzing
// various public key scripts to determine if they are stake generation
// p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeGenPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeGenPubKeyHash
	}
	benchIsX(b, filterFn, IsStakeGenPubKeyHashScript)
}

// BenchmarkIsStakeGenScriptHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are stake generation p2sh scripts.
func BenchmarkIsStakeGenScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeGenScriptHash
	}
	benchIsX(b, filterFn, IsStakeGenScriptHashScript)
}

// BenchmarkIsStakeRevocationPubKeyHashScript benchmarks the performance of
// analyzing various public key scripts to determine if they are stake
// revocation p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeRevocationPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeRevocationPubKeyHash
	}
	benchIsX(b, filterFn, IsStakeRevocationPubKeyHashScript)
}

// BenchmarkIsStakeRevocationScriptHashScript benchmarks the performance of
// various public key scripts to determine if they are stake revocation p2sh
// scripts.
func BenchmarkIsStakeRevocationScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeRevocationScriptHash
	}
	benchIsX(b, filterFn, IsStakeRevocationScriptHashScript)
}

// BenchmarkIsStakeChangePubKeyHash benchmarks the performance of analyzing
// various public key scripts to determine if they are stake change
// p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeChangePubKeyHash(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeChangePubKeyHash
	}
	benchIsX(b, filterFn, IsStakeChangePubKeyHashScript)
}
<commit_msg>stdscript: Add v0 stake change p2sh benchmark.<commit_after>// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package stdscript

import (
	"bytes"
	"testing"

	"github.com/decred/dcrd/txscript/v4"
)

// complexScriptV0 is a version 0 script comprised of half as many opcodes as
// the maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
var complexScriptV0 = func() []byte {
	const (
		maxScriptSize        = txscript.MaxScriptSize
		maxScriptElementSize = txscript.MaxScriptElementSize
	)
	var scriptLen int
	builder := txscript.NewScriptBuilder()
	for i := 0; i < txscript.MaxOpsPerScript/2; i++ {
		builder.AddOp(txscript.OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, maxScriptElementSize)
	for i := 0; i < (maxScriptSize-scriptLen)/maxScriptElementSize; i++ {
		builder.AddData(maxData)
	}
	script, err := builder.Script()
	if err != nil {
		panic(err)
	}
	return script
}()

// makeBenchmarks constructs a slice of tests to use in the benchmarks as
// follows:
// - Start with a version 0 complex non standard script
// - Add all tests for which the provided filter function returns true
func makeBenchmarks(filterFn func(test scriptTest) bool) []scriptTest {
	benches := make([]scriptTest, 0, 5)
	benches = append(benches, scriptTest{
		name:    "v0 complex non standard",
		version: 0,
		script:  complexScriptV0,
	})
	for _, test := range scriptV0Tests {
		if filterFn(test) {
			benches = append(benches, test)
		}
	}
	return benches
}

// benchIsX is a convenience function that runs benchmarks for the entries that
// match the provided filter function using the given script type determination
// function and ensures the result matches the expected one.
func benchIsX(b *testing.B, filterFn func(test scriptTest) bool, isXFn func(scriptVersion uint16, script []byte) bool) {
	b.Helper()

	benches := makeBenchmarks(filterFn)
	for _, bench := range benches {
		want := filterFn(bench)
		b.Run(bench.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := isXFn(bench.version, bench.script)
				if got != want {
					b.Fatalf("%q: unexpected result -- got %v, want %v",
						bench.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsPubKeyScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pk-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyScript)
}

// BenchmarkIsPubKeyEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEd25519
	}
	benchIsX(b, filterFn, IsPubKeyEd25519Script)
}

// BenchmarkIsPubKeySchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeySchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeySchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeySchnorrSecp256k1Script)
}

// BenchmarkIsPubKeyHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashScript)
}

// BenchmarkIsPubKeyHashEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyHashEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEd25519
	}
	benchIsX(b, filterFn, IsPubKeyHashEd25519Script)
}

// BenchmarkIsPubKeyHashSchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeyHashSchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashSchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashSchnorrSecp256k1Script)
}

// BenchmarkIsScriptHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2sh scripts.
func BenchmarkIsScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STScriptHash
	}
	benchIsX(b, filterFn, IsScriptHashScript)
}

// BenchmarkIsMultiSigScript benchmarks the performance of analyzing various
// public key scripts to determine if they are multisignature scripts.
func BenchmarkIsMultiSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && !test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigScript)
}

// BenchmarkIsMultiSigSigScript benchmarks the performance of analyzing various
// signature scripts to determine if they are likely to be multisignature redeem
// scripts.
func BenchmarkIsMultiSigSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigSigScript)
}

// BenchmarkMultiSigRedeemScriptFromScriptSigV0 benchmarks the performance of
// extracting the redeem script from various version 0 signature scripts.
func BenchmarkMultiSigRedeemScriptFromScriptSigV0(b *testing.B) {
	for _, test := range scriptV0Tests {
		if test.version != 0 || test.wantType != STMultiSig || !test.isSig {
			continue
		}
		want := test.wantData.([]byte)

		b.Run(test.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := MultiSigRedeemScriptFromScriptSigV0(test.script)
				if !bytes.Equal(got, want) {
					b.Fatalf("%q: unexpected result -- got %x, want %x",
						test.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsNullDataScript benchmarks the performance of analyzing various
// public key scripts to determine if they are nulldata scripts.
func BenchmarkIsNullDataScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STNullData
	}
	benchIsX(b, filterFn, IsNullDataScript)
}

// BenchmarkIsStakeSubmissionPubKeyHashScript benchmarks the performance of
// analyzing various public key scripts to determine if they are stake
// submission p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeSubmissionPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeSubmissionPubKeyHash
	}
	benchIsX(b, filterFn, IsStakeSubmissionPubKeyHashScript)
}

// BenchmarkIsStakeSubmissionScriptHashScript benchmarks the performance of
// analyzing various public key scripts to determine if they are stake
// submission p2sh scripts.
func BenchmarkIsStakeSubmissionScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeSubmissionScriptHash
	}
	benchIsX(b, filterFn, IsStakeSubmissionScriptHashScript)
}

// BenchmarkIsStakeGenPubKeyHashScript benchmarks the performance of analyzing
// various public key scripts to determine if they are stake generation
// p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeGenPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeGenPubKeyHash
	}
	benchIsX(b, filterFn, IsStakeGenPubKeyHashScript)
}

// BenchmarkIsStakeGenScriptHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are stake generation p2sh scripts.
func BenchmarkIsStakeGenScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeGenScriptHash
	}
	benchIsX(b, filterFn, IsStakeGenScriptHashScript)
}

// BenchmarkIsStakeRevocationPubKeyHashScript benchmarks the performance of
// analyzing various public key scripts to determine if they are stake
// revocation p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeRevocationPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeRevocationPubKeyHash
	}
	benchIsX(b, filterFn, IsStakeRevocationPubKeyHashScript)
}

// BenchmarkIsStakeRevocationScriptHashScript benchmarks the performance of
// various public key scripts to determine if they are stake revocation p2sh
// scripts.
func BenchmarkIsStakeRevocationScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeRevocationScriptHash
	}
	benchIsX(b, filterFn, IsStakeRevocationScriptHashScript)
}

// BenchmarkIsStakeChangePubKeyHash benchmarks the performance of analyzing
// various public key scripts to determine if they are stake change
// p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsStakeChangePubKeyHash(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeChangePubKeyHash
	}
	benchIsX(b, filterFn, IsStakeChangePubKeyHashScript)
}

// BenchmarkIsStakeChangeScriptHash benchmarks the performance of analyzing
// various public key scripts to determine if they are stake change p2sh
// scripts.
func BenchmarkIsStakeChangeScriptHash(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STStakeChangeScriptHash
	}
	benchIsX(b, filterFn, IsStakeChangeScriptHashScript)
}
<|endoftext|>


<commit_before>package rest

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/couchbase/sync_gateway/base"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestAdminAPIAuth(t *testing.T) {
	if base.UnitTestUrlIsWalrus() {
		t.Skip("This test only works against Couchbase Server")
	}

	endPoints := []struct {
		Method          string
		DBScoped        bool
		Endpoint        string
		SkipSuccessTest bool
	}{
		{
			"POST",
			true,
			"/_session",
			false,
		},
		{
			"GET",
			true,
			"/_session/id",
			false,
		},
		{
			"DELETE",
			true,
			"/_session/id",
			false,
		},
		{
			"GET",
			true,
			"/_raw/doc",
			false,
		},
		{
			"GET",
			true,
			"/_user/",
			false,
		}, {
			"POST",
			true,
			"/_user/",
			false,
		}, {
			"GET",
			true,
			"/_user/user",
			false,
		}, {
			"PUT",
			true,
			"/_user/user",
			false,
		}, {
			"DELETE",
			true,
			"/_user/user",
			false,
		}, {
			"DELETE",
			true,
			"/_user/user/_session",
			false,
		}, {
			"DELETE",
			true,
			"/_user/user/_session/id",
			false,
		},
		{
			"GET",
			true,
			"/_role/",
			false,
		}, {
			"POST",
			true,
			"/_role/",
			false,
		},
		{
			"GET",
			true,
			"/_role/role",
			false,
		}, {
			"PUT",
			true,
			"/_role/role",
			false,
		}, {
			"DELETE",
			true,
			"/_role/role",
			false,
		}, {
			"GET",
			true,
			"/_replication/",
			false,
		}, {
			"POST",
			true,
			"/_replication/",
			false,
		}, {
			"GET",
			true,
			"/_replication/id",
			false,
		},
		{
			"PUT",
			true,
			"/_replication/id",
			false,
		},
		{
			"DELETE",
			true,
			"/_replication/id",
			false,
		},
		{
			"GET",
			true,
			"/_replicationStatus/",
			false,
		},
		{
			"GET",
			true,
			"/_replicationStatus/id",
			false,
		},
		{
			"PUT",
			true,
			"/_replicationStatus/id",
			false,
		},
		{
			"GET",
			false,
			"/_logging",
			false,
		},
		{
			"PUT",
			false,
			"/_logging",
			false,
		},
		{
			"POST",
			false,
			"/_logging",
			false,
		},
		{
			"POST",
			false,
			"/_profile/name",
			false,
		},
		{
			"POST",
			false,
			"/_profile",
			false,
		},
		{
			"POST",
			false,
			"/_heap",
			false,
		},
		{
			"GET",
			false,
			"/_stats",
			false,
		},
		{
			"GET",
			false,
			"/_expvar",
			false,
		},
		{
			"GET",
			false,
			"/_config",
			false,
		},
		{
			"GET",
			false,
			"/_status",
			false,
		},
		{
			"GET",
			false,
			"/_sgcollect_info",
			false,
		},
		{
			"DELETE",
			false,
			"/_sgcollect_info",
			false,
		},
		{
			"POST",
			false,
			"/_sgcollect_info",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/goroutine",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/cmdline",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/symbol",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/heap",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/profile",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/block",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/threadcreate",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/mutex",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/trace",
			false,
		},
		{
			"GET",
			false,
			"/_debug/fgprof",
			false,
		},
		{
			"POST",
			false,
			"/_post_upgrade",
			false,
		},
		{
			"GET",
			true,
			"/_config",
			false,
		},
		{
			"PUT",
			true,
			"/_config",
			false,
		},
		{
			"GET",
			true,
			"/_resync",
			false,
		},
		{
			"POST",
			true,
			"/_resync",
			false,
		},
		{
			"POST",
			true,
			"/_purge",
			false,
		},
		{
			"POST",
			true,
			"/_flush",
			false,
		},
		{
			"POST",
			true,
			"/_offline",
			true,
		},
		{
			"POST",
			true,
			"/_online",
			false,
		},
		{
			"GET",
			true,
			"/_dump/view",
			false,
		},
		{
			"GET",
			true,
			"/_view/view",
			false,
		},
		{
			"GET",
			true,
			"/_dumpchannel/channel",
			false,
		},
		{
			"POST",
			true,
			"/_repair",
			false,
		},
		{
			"PUT",
			true,
			"/db",
			false,
		},
		{
			"DELETE",
			true,
			"/",
			true,
		},
		{
			"GET",
			false,
			"/_all_dbs",
			false,
		},
		{
			"POST",
			true,
			"/_compact",
			false,
		},
		{
			"GET",
			true,
			"/",
			true,
		},
		{
			"POST",
			true,
			"/",
			true,
		},
		{
			"GET",
			true,
			"/_all_docs",
			false,
		},
		{
			"POST",
			true,
			"/_bulk_docs",
			false,
		},
		{
			"POST",
			true,
			"/_bulk_get",
			false,
		},
		{
			"GET",
			true,
			"/_changes",
			false,
		},
		{
			"GET",
			true,
			"/_design/ddoc",
			false,
		},
		{
			"PUT",
			true,
			"/_design/ddoc",
			false,
		},
		{
			"DELETE",
			true,
			"/_design/ddoc",
			false,
		},
		{
			"GET",
			true,
			"/_design/ddoc/_view/view",
			false,
		},
		{
			"POST",
			true,
			"/_ensure_full_commit",
			false,
		},
		{
			"POST",
			true,
			"/_revs_diff",
			false,
		},
		{
			"GET",
			true,
			"/_local/docid",
			false,
		},
		{
			"PUT",
			true,
			"/_local/docid",
			false,
		},
		{
			"DELETE",
			true,
			"/_local/docid",
			false,
		},
		{
			"GET",
			true,
			"/docid",
			false,
		},
		{
			"PUT",
			true,
			"/docid",
			false,
		},
		{
			"DELETE",
			true,
			"/docid",
			false,
		},
		{
			"GET",
			true,
			"/docid/attachid",
			false,
		},
		{
			"PUT",
			true,
			"/docid/attachid",
			false,
		},
		{
			"GET",
			true,
			"/_blipsync",
			false,
		},
	}

	rt := NewRestTester(t, &RestTesterConfig{
		adminInterfaceAuthentication:   true,
		metricsInterfaceAuthentication: true,
	})
	defer rt.Close()

	eps, _, err := rt.ServerContext().ObtainManagementEndpointsAndHTTPClient()
	require.NoError(t, err)

	MakeUser(t, eps[0], "noaccess", "password", []string{})
	defer DeleteUser(t, eps[0], "noaccess")

	MakeUser(t, eps[0], "MobileSyncGatewayUser", "password", []string{fmt.Sprintf("%s[%s]", MobileSyncGatewayRole.RoleName, rt.Bucket().GetName())})
	defer DeleteUser(t, eps[0], "MobileSyncGatewayUser")

	MakeUser(t, eps[0], "ROAdminUser", "password", []string{ReadOnlyAdminRole.RoleName})
	defer DeleteUser(t, eps[0], "ROAdminUser")

	for _, endPoint := range endPoints {
		t.Run(endPoint.Method+endPoint.Endpoint, func(t *testing.T) {
			formattedEndpoint := endPoint.Endpoint
			if endPoint.DBScoped {
				formattedEndpoint = "/db" + formattedEndpoint
			}
			resp := rt.SendAdminRequest(endPoint.Method, formattedEndpoint, `{}`)
			assertStatus(t, resp, http.StatusUnauthorized)

			resp = rt.SendAdminRequestWithAuth(endPoint.Method, formattedEndpoint, `{}`, "noaccess", "password")
			assertStatus(t, resp, http.StatusForbidden)

			if !endPoint.SkipSuccessTest {
				if endPoint.DBScoped {
					resp = rt.SendAdminRequestWithAuth(endPoint.Method, formattedEndpoint, `{}`, "MobileSyncGatewayUser", "password")
				} else {
					resp = rt.SendAdminRequestWithAuth(endPoint.Method, formattedEndpoint, `{}`, "ROAdminUser", "password")
				}

				// For some of the endpoints they have other requirements, such as setting up users and others require
				// bodies. Rather than doing a full test of the endpoint itself this will at least confirm that they pass
				// the auth stage.
				fmt.Println(resp.Code)
				assert.True(t, resp.Code != http.StatusUnauthorized && resp.Code != http.StatusForbidden)
			}
		})
	}

}
<commit_msg>Reset logging after TestAdminAPIAuth (#5106)<commit_after>package rest

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/couchbase/sync_gateway/base"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestAdminAPIAuth(t *testing.T) {

	// Don't really care about the log level but this test hits the logging endpoint so this is used to reset the logging
	defer base.SetUpTestLogging(base.LevelInfo, base.KeyNone)()

	if base.UnitTestUrlIsWalrus() {
		t.Skip("This test only works against Couchbase Server")
	}

	endPoints := []struct {
		Method          string
		DBScoped        bool
		Endpoint        string
		SkipSuccessTest bool
	}{
		{
			"POST",
			true,
			"/_session",
			false,
		},
		{
			"GET",
			true,
			"/_session/id",
			false,
		},
		{
			"DELETE",
			true,
			"/_session/id",
			false,
		},
		{
			"GET",
			true,
			"/_raw/doc",
			false,
		},
		{
			"GET",
			true,
			"/_user/",
			false,
		}, {
			"POST",
			true,
			"/_user/",
			false,
		}, {
			"GET",
			true,
			"/_user/user",
			false,
		}, {
			"PUT",
			true,
			"/_user/user",
			false,
		}, {
			"DELETE",
			true,
			"/_user/user",
			false,
		}, {
			"DELETE",
			true,
			"/_user/user/_session",
			false,
		}, {
			"DELETE",
			true,
			"/_user/user/_session/id",
			false,
		},
		{
			"GET",
			true,
			"/_role/",
			false,
		}, {
			"POST",
			true,
			"/_role/",
			false,
		},
		{
			"GET",
			true,
			"/_role/role",
			false,
		}, {
			"PUT",
			true,
			"/_role/role",
			false,
		}, {
			"DELETE",
			true,
			"/_role/role",
			false,
		}, {
			"GET",
			true,
			"/_replication/",
			false,
		}, {
			"POST",
			true,
			"/_replication/",
			false,
		}, {
			"GET",
			true,
			"/_replication/id",
			false,
		},
		{
			"PUT",
			true,
			"/_replication/id",
			false,
		},
		{
			"DELETE",
			true,
			"/_replication/id",
			false,
		},
		{
			"GET",
			true,
			"/_replicationStatus/",
			false,
		},
		{
			"GET",
			true,
			"/_replicationStatus/id",
			false,
		},
		{
			"PUT",
			true,
			"/_replicationStatus/id",
			false,
		},
		{
			"GET",
			false,
			"/_logging",
			false,
		},
		{
			"PUT",
			false,
			"/_logging",
			false,
		},
		{
			"POST",
			false,
			"/_logging",
			false,
		},
		{
			"POST",
			false,
			"/_profile/name",
			false,
		},
		{
			"POST",
			false,
			"/_profile",
			false,
		},
		{
			"POST",
			false,
			"/_heap",
			false,
		},
		{
			"GET",
			false,
			"/_stats",
			false,
		},
		{
			"GET",
			false,
			"/_expvar",
			false,
		},
		{
			"GET",
			false,
			"/_config",
			false,
		},
		{
			"GET",
			false,
			"/_status",
			false,
		},
		{
			"GET",
			false,
			"/_sgcollect_info",
			false,
		},
		{
			"DELETE",
			false,
			"/_sgcollect_info",
			false,
		},
		{
			"POST",
			false,
			"/_sgcollect_info",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/goroutine",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/cmdline",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/symbol",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/heap",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/profile",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/block",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/threadcreate",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/mutex",
			false,
		},
		{
			"GET",
			false,
			"/_debug/pprof/trace",
			false,
		},
		{
			"GET",
			false,
			"/_debug/fgprof",
			false,
		},
		{
			"POST",
			false,
			"/_post_upgrade",
			false,
		},
		{
			"GET",
			true,
			"/_config",
			false,
		},
		{
			"PUT",
			true,
			"/_config",
			false,
		},
		{
			"GET",
			true,
			"/_resync",
			false,
		},
		{
			"POST",
			true,
			"/_resync",
			false,
		},
		{
			"POST",
			true,
			"/_purge",
			false,
		},
		{
			"POST",
			true,
			"/_flush",
			false,
		},
		{
			"POST",
			true,
			"/_offline",
			true,
		},
		{
			"POST",
			true,
			"/_online",
			false,
		},
		{
			"GET",
			true,
			"/_dump/view",
			false,
		},
		{
			"GET",
			true,
			"/_view/view",
			false,
		},
		{
			"GET",
			true,
			"/_dumpchannel/channel",
			false,
		},
		{
			"POST",
			true,
			"/_repair",
			false,
		},
		{
			"PUT",
			true,
			"/db",
			false,
		},
		{
			"DELETE",
			true,
			"/",
			true,
		},
		{
			"GET",
			false,
			"/_all_dbs",
			false,
		},
		{
			"POST",
			true,
			"/_compact",
			false,
		},
		{
			"GET",
			true,
			"/",
			true,
		},
		{
			"POST",
			true,
			"/",
			true,
		},
		{
			"GET",
			true,
			"/_all_docs",
			false,
		},
		{
			"POST",
			true,
			"/_bulk_docs",
			false,
		},
		{
			"POST",
			true,
			"/_bulk_get",
			false,
		},
		{
			"GET",
			true,
			"/_changes",
			false,
		},
		{
			"GET",
			true,
			"/_design/ddoc",
			false,
		},
		{
			"PUT",
			true,
			"/_design/ddoc",
			false,
		},
		{
			"DELETE",
			true,
			"/_design/ddoc",
			false,
		},
		{
			"GET",
			true,
			"/_design/ddoc/_view/view",
			false,
		},
		{
			"POST",
			true,
			"/_ensure_full_commit",
			false,
		},
		{
			"POST",
			true,
			"/_revs_diff",
			false,
		},
		{
			"GET",
			true,
			"/_local/docid",
			false,
		},
		{
			"PUT",
			true,
			"/_local/docid",
			false,
		},
		{
			"DELETE",
			true,
			"/_local/docid",
			false,
		},
		{
			"GET",
			true,
			"/docid",
			false,
		},
		{
			"PUT",
			true,
			"/docid",
			false,
		},
		{
			"DELETE",
			true,
			"/docid",
			false,
		},
		{
			"GET",
			true,
			"/docid/attachid",
			false,
		},
		{
			"PUT",
			true,
			"/docid/attachid",
			false,
		},
		{
			"GET",
			true,
			"/_blipsync",
			false,
		},
	}

	rt := NewRestTester(t, &RestTesterConfig{
		adminInterfaceAuthentication:   true,
		metricsInterfaceAuthentication: true,
	})
	defer rt.Close()

	eps, _, err := rt.ServerContext().ObtainManagementEndpointsAndHTTPClient()
	require.NoError(t, err)

	MakeUser(t, eps[0], "noaccess", "password", []string{})
	defer DeleteUser(t, eps[0], "noaccess")

	MakeUser(t, eps[0], "MobileSyncGatewayUser", "password", []string{fmt.Sprintf("%s[%s]", MobileSyncGatewayRole.RoleName, rt.Bucket().GetName())})
	defer DeleteUser(t, eps[0], "MobileSyncGatewayUser")

	MakeUser(t, eps[0], "ROAdminUser", "password", []string{ReadOnlyAdminRole.RoleName})
	defer DeleteUser(t, eps[0], "ROAdminUser")

	for _, endPoint := range endPoints {
		t.Run(endPoint.Method+endPoint.Endpoint, func(t *testing.T) {
			formattedEndpoint := endPoint.Endpoint
			if endPoint.DBScoped {
				formattedEndpoint = "/db" + formattedEndpoint
			}
			resp := rt.SendAdminRequest(endPoint.Method, formattedEndpoint, `{}`)
			assertStatus(t, resp, http.StatusUnauthorized)

			resp = rt.SendAdminRequestWithAuth(endPoint.Method, formattedEndpoint, `{}`, "noaccess", "password")
			assertStatus(t, resp, http.StatusForbidden)

			if !endPoint.SkipSuccessTest {
				if endPoint.DBScoped {
					resp = rt.SendAdminRequestWithAuth(endPoint.Method, formattedEndpoint, `{}`, "MobileSyncGatewayUser", "password")
				} else {
					resp = rt.SendAdminRequestWithAuth(endPoint.Method, formattedEndpoint, `{}`, "ROAdminUser", "password")
				}

				// For some of the endpoints they have other requirements, such as setting up users and others require
				// bodies. Rather than doing a full test of the endpoint itself this will at least confirm that they pass
				// the auth stage.
				fmt.Println(resp.Code)
				assert.True(t, resp.Code != http.StatusUnauthorized && resp.Code != http.StatusForbidden)
			}
		})
	}

}
<|endoftext|>


<commit_before>package repository

import (
	"context"
	"io"
	"math/rand"
	"os"
	"testing"

	"github.com/restic/restic/internal/backend/mem"
	"github.com/restic/restic/internal/crypto"
	"github.com/restic/restic/internal/fs"
	"github.com/restic/restic/internal/mock"
	"github.com/restic/restic/internal/restic"
)

type randReader struct {
	src  rand.Source
	rand *rand.Rand
}

func newRandReader(src rand.Source) *randReader {
	return &randReader{
		src:  src,
		rand: rand.New(src),
	}
}

// Read generates len(p) random bytes and writes them into p. It
// always returns len(p) and a nil error.
func (r *randReader) Read(p []byte) (n int, err error) {
	for i := 0; i < len(p); i += 7 {
		val := r.src.Int63()
		for j := 0; i+j < len(p) && j < 7; j++ {
			p[i+j] = byte(val)
			val >>= 8
		}
	}
	return len(p), nil
}

func randomID(rd io.Reader) restic.ID {
	id := restic.ID{}
	_, err := io.ReadFull(rd, id[:])
	if err != nil {
		panic(err)
	}
	return id
}

const maxBlobSize = 1 << 20

func saveFile(t testing.TB, be Saver, length int, f *os.File, id restic.ID) {
	h := restic.Handle{Type: restic.DataFile, Name: id.String()}
	t.Logf("save file %v", h)

	rd, err := restic.NewFileReader(f)
	if err != nil {
		t.Fatal(err)
	}

	err = be.Save(context.TODO(), h, rd)
	if err != nil {
		t.Fatal(err)
	}

	if err := f.Close(); err != nil {
		t.Fatal(err)
	}

	if err := fs.RemoveIfExists(f.Name()); err != nil {
		t.Fatal(err)
	}
}

func fillPacks(t testing.TB, rnd *randReader, be Saver, pm *packerManager, buf []byte) (bytes int) {
	for i := 0; i < 100; i++ {
		l := rnd.rand.Intn(1 << 20)
		seed := rnd.rand.Int63()

		packer, err := pm.findPacker()
		if err != nil {
			t.Fatal(err)
		}

		rd := newRandReader(rand.NewSource(seed))
		id := randomID(rd)
		buf = buf[:l]
		_, err = io.ReadFull(rd, buf)
		if err != nil {
			t.Fatal(err)
		}

		n, err := packer.Add(restic.DataBlob, id, buf)
		if err != nil {
			t.Fatal(err)
		}
		if n != l {
			t.Errorf("Add() returned invalid number of bytes: want %v, got %v", n, l)
		}
		bytes += l

		if packer.Size() < minPackSize {
			pm.insertPacker(packer)
			continue
		}

		_, err = packer.Finalize()
		if err != nil {
			t.Fatal(err)
		}

		packID := restic.IDFromHash(packer.hw.Sum(nil))
		saveFile(t, be, int(packer.Size()), packer.tmpfile, packID)
	}

	return bytes
}

func flushRemainingPacks(t testing.TB, rnd *randReader, be Saver, pm *packerManager) (bytes int) {
	if pm.countPacker() > 0 {
		for _, packer := range pm.packers {
			n, err := packer.Finalize()
			if err != nil {
				t.Fatal(err)
			}
			bytes += int(n)

			packID := restic.IDFromHash(packer.hw.Sum(nil))
			saveFile(t, be, int(packer.Size()), packer.tmpfile, packID)
		}
	}

	return bytes
}

func TestPackerManager(t *testing.T) {
	rnd := newRandReader(rand.NewSource(23))

	be := mem.New()
	pm := newPackerManager(be, crypto.NewRandomKey())

	blobBuf := make([]byte, maxBlobSize)

	bytes := fillPacks(t, rnd, be, pm, blobBuf)
	bytes += flushRemainingPacks(t, rnd, be, pm)

	t.Logf("saved %d bytes", bytes)
}

func BenchmarkPackerManager(t *testing.B) {
	rnd := newRandReader(rand.NewSource(23))

	be := &mock.Backend{
		SaveFn: func(context.Context, restic.Handle, restic.RewindReader) error { return nil },
	}
	blobBuf := make([]byte, maxBlobSize)

	t.ResetTimer()

	for i := 0; i < t.N; i++ {
		bytes := 0
		pm := newPackerManager(be, crypto.NewRandomKey())
		bytes += fillPacks(t, rnd, be, pm, blobBuf)
		bytes += flushRemainingPacks(t, rnd, be, pm)
		t.Logf("saved %d bytes", bytes)
	}
}
<commit_msg>Remove Go 1.5 compatibility code from PackerManager benchmark<commit_after>package repository

import (
	"context"
	"io"
	"math/rand"
	"os"
	"testing"

	"github.com/restic/restic/internal/backend/mem"
	"github.com/restic/restic/internal/crypto"
	"github.com/restic/restic/internal/fs"
	"github.com/restic/restic/internal/mock"
	"github.com/restic/restic/internal/restic"
)

func randomID(rd io.Reader) restic.ID {
	id := restic.ID{}
	_, err := io.ReadFull(rd, id[:])
	if err != nil {
		panic(err)
	}
	return id
}

const maxBlobSize = 1 << 20

func saveFile(t testing.TB, be Saver, length int, f *os.File, id restic.ID) {
	h := restic.Handle{Type: restic.DataFile, Name: id.String()}
	t.Logf("save file %v", h)

	rd, err := restic.NewFileReader(f)
	if err != nil {
		t.Fatal(err)
	}

	err = be.Save(context.TODO(), h, rd)
	if err != nil {
		t.Fatal(err)
	}

	if err := f.Close(); err != nil {
		t.Fatal(err)
	}

	if err := fs.RemoveIfExists(f.Name()); err != nil {
		t.Fatal(err)
	}
}

func fillPacks(t testing.TB, rnd *rand.Rand, be Saver, pm *packerManager, buf []byte) (bytes int) {
	for i := 0; i < 100; i++ {
		l := rnd.Intn(1 << 20)
		seed := rnd.Int63()

		packer, err := pm.findPacker()
		if err != nil {
			t.Fatal(err)
		}

		rd := rand.New(rand.NewSource(seed))
		id := randomID(rd)
		buf = buf[:l]
		_, err = io.ReadFull(rd, buf)
		if err != nil {
			t.Fatal(err)
		}

		n, err := packer.Add(restic.DataBlob, id, buf)
		if err != nil {
			t.Fatal(err)
		}
		if n != l {
			t.Errorf("Add() returned invalid number of bytes: want %v, got %v", n, l)
		}
		bytes += l

		if packer.Size() < minPackSize {
			pm.insertPacker(packer)
			continue
		}

		_, err = packer.Finalize()
		if err != nil {
			t.Fatal(err)
		}

		packID := restic.IDFromHash(packer.hw.Sum(nil))
		saveFile(t, be, int(packer.Size()), packer.tmpfile, packID)
	}

	return bytes
}

func flushRemainingPacks(t testing.TB, be Saver, pm *packerManager) (bytes int) {
	if pm.countPacker() > 0 {
		for _, packer := range pm.packers {
			n, err := packer.Finalize()
			if err != nil {
				t.Fatal(err)
			}
			bytes += int(n)

			packID := restic.IDFromHash(packer.hw.Sum(nil))
			saveFile(t, be, int(packer.Size()), packer.tmpfile, packID)
		}
	}

	return bytes
}

func TestPackerManager(t *testing.T) {
	rnd := rand.New(rand.NewSource(23))

	be := mem.New()
	pm := newPackerManager(be, crypto.NewRandomKey())

	blobBuf := make([]byte, maxBlobSize)

	bytes := fillPacks(t, rnd, be, pm, blobBuf)
	bytes += flushRemainingPacks(t, be, pm)

	t.Logf("saved %d bytes", bytes)
}

func BenchmarkPackerManager(t *testing.B) {
	rnd := rand.New(rand.NewSource(23))

	be := &mock.Backend{
		SaveFn: func(context.Context, restic.Handle, restic.RewindReader) error { return nil },
	}
	blobBuf := make([]byte, maxBlobSize)

	t.ResetTimer()

	for i := 0; i < t.N; i++ {
		bytes := 0
		pm := newPackerManager(be, crypto.NewRandomKey())
		bytes += fillPacks(t, rnd, be, pm, blobBuf)
		bytes += flushRemainingPacks(t, be, pm)
		t.Logf("saved %d bytes", bytes)
	}
}
<|endoftext|>


<commit_before>package mxml

import (
	"encoding/xml"
)

// Marshal returns string of obj xml format.
func Marshal(obj interface{}) string {
	//b, err := xml.Marshal(obj)
	b, err := xml.MarshalIndent(obj, "", "  ")
	// Marshal error
	if logger.CheckError(err) {

	}
	return string(b)
}
<commit_msg>add xml func<commit_after>package mxml

import (
	"encoding/xml"
	"fmt"
	"io"

	"github.com/mabetle/mgo/mcore"
)

// Marshal returns string of obj xml format.
func Marshal(obj interface{}) string {
	//b, err := xml.Marshal(obj)
	b, err := xml.MarshalIndent(obj, "", "  ")
	// Marshal error
	if logger.CheckError(err) {

	}
	return string(b)
}

// Write to io.Writer
func Write(obj interface{}, w io.Writer) error {
	s := Marshal(obj)
	if s == "" {
		return fmt.Errorf("Parse object to xml error")
	}
	_, err := w.Write([]byte(s))
	return err
}

// WriteFile write marshal xml to file
func WriteFile(obj interface{}, file string) error {
	s := Marshal(obj)
	if s == "" {
		return fmt.Errorf("Parse object to xml error")
	}
	_, err := mcore.WriteFile(file, s)
	return err
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2014, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package mysql

import (
	"errors"
	"fmt"
	"os/exec"
	"path"
	"strings"
)

type DSN struct {
	Username     string
	Password     string
	Hostname     string
	Port         string
	Socket       string
	OldPasswords bool
	Protocol     string
}

const (
	dsnSuffix         = "/?parseTime=true"
	allowOldPasswords = "&allowOldPasswords=true"
)

var ErrNoSocket error = errors.New("Cannot find MySQL socket (localhost implies socket).  Specify socket or use 127.0.0.1 instead of localhost.")

func (dsn DSN) DSN() (string, error) {
	// Make Sprintf format easier; password doesn't really start with ":".
	if dsn.Password != "" {
		dsn.Password = ":" + dsn.Password
	}

	// http://dev.mysql.com/doc/refman/5.0/en/connecting.html#option_general_protocol:
	// "connections on Unix to localhost are made using a Unix socket file by default"
	if dsn.Hostname == "localhost" && (dsn.Protocol == "" || dsn.Protocol == "socket") {
		if dsn.Socket == "" {
			// Try to auto-detect MySQL socket from netstat output.
			out, err := exec.Command("netstat", "-anp").Output()
			if err != nil {
				return "", ErrNoSocket
			}
			socket := ParseSocketFromNetstat(string(out))
			if socket == "" {
				return "", ErrNoSocket
			}
			dsn.Socket = socket
		}
	}

	dsnString := ""
	if dsn.Socket != "" {
		dsnString = fmt.Sprintf("%s%s@unix(%s)",
			dsn.Username,
			dsn.Password,
			dsn.Socket,
		)
	} else if dsn.Hostname != "" {
		if dsn.Port == "" {
			dsn.Port = "3306"
		}
		dsnString = fmt.Sprintf("%s%s@tcp(%s:%s)",
			dsn.Username,
			dsn.Password,
			dsn.Hostname,
			dsn.Port,
		)
	}
	dsnString = dsnString + dsnSuffix
	if dsn.OldPasswords {
		dsnString = dsnString + allowOldPasswords
	}
	return dsnString, nil
}

func (dsn DSN) To() string {
	if dsn.Socket != "" {
		return dsn.Socket
	} else if dsn.Hostname != "" {
		if dsn.Port == "" {
			dsn.Port = "3306"
		}
		return fmt.Sprintf(dsn.Hostname + ":" + dsn.Port)
	}
	return "localhost"
}

func (dsn DSN) String() string {
	dsn.Password = "<password-hidden>"
	dsnString, _ := dsn.DSN()
	dsnString = strings.TrimSuffix(dsnString, allowOldPasswords)
	dsnString = strings.TrimSuffix(dsnString, dsnSuffix)
	return dsnString
}

func (dsn DSN) StringWithSuffixes() string {
	dsn.Password = "<password-hidden>"
	dsnString, _ := dsn.DSN()
	return dsnString
}

func ParseSocketFromNetstat(out string) string {
	lines := strings.Split(out, "\n")
	for _, line := range lines {
		if strings.HasPrefix(line, "unix") && strings.Contains(line, "mysql") {
			fields := strings.Fields(line)
			socket := fields[len(fields)-1]
			if path.IsAbs(socket) {
				return socket
			}
		}
	}
	return ""
}
<commit_msg>Make it more explicit in DSN when anonymous user is used (no user)<commit_after>/*
   Copyright (c) 2014, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package mysql

import (
	"errors"
	"fmt"
	"os/exec"
	"path"
	"strings"
)

type DSN struct {
	Username     string
	Password     string
	Hostname     string
	Port         string
	Socket       string
	OldPasswords bool
	Protocol     string
}

const (
	dsnSuffix         = "/?parseTime=true"
	allowOldPasswords = "&allowOldPasswords=true"
)

var ErrNoSocket error = errors.New("Cannot find MySQL socket (localhost implies socket).  Specify socket or use 127.0.0.1 instead of localhost.")

func (dsn DSN) DSN() (string, error) {
	// Make Sprintf format easier; password doesn't really start with ":".
	if dsn.Password != "" {
		dsn.Password = ":" + dsn.Password
	}

	// http://dev.mysql.com/doc/refman/5.0/en/connecting.html#option_general_protocol:
	// "connections on Unix to localhost are made using a Unix socket file by default"
	if dsn.Hostname == "localhost" && (dsn.Protocol == "" || dsn.Protocol == "socket") {
		if dsn.Socket == "" {
			// Try to auto-detect MySQL socket from netstat output.
			out, err := exec.Command("netstat", "-anp").Output()
			if err != nil {
				return "", ErrNoSocket
			}
			socket := ParseSocketFromNetstat(string(out))
			if socket == "" {
				return "", ErrNoSocket
			}
			dsn.Socket = socket
		}
	}

	dsnString := ""
	if dsn.Socket != "" {
		dsnString = fmt.Sprintf("%s%s@unix(%s)",
			dsn.Username,
			dsn.Password,
			dsn.Socket,
		)
	} else if dsn.Hostname != "" {
		if dsn.Port == "" {
			dsn.Port = "3306"
		}
		dsnString = fmt.Sprintf("%s%s@tcp(%s:%s)",
			dsn.Username,
			dsn.Password,
			dsn.Hostname,
			dsn.Port,
		)
	}
	dsnString = dsnString + dsnSuffix
	if dsn.OldPasswords {
		dsnString = dsnString + allowOldPasswords
	}
	return dsnString, nil
}

func (dsn DSN) To() string {
	if dsn.Socket != "" {
		return dsn.Socket
	} else if dsn.Hostname != "" {
		if dsn.Port == "" {
			dsn.Port = "3306"
		}
		return fmt.Sprintf(dsn.Hostname + ":" + dsn.Port)
	}
	return "localhost"
}

func (dsn DSN) String() string {
	if dsn.Username == "" {
		dsn.Username = "<anonymous-user>"
	}
	dsn.Password = "<password-hidden>"
	dsnString, _ := dsn.DSN()
	dsnString = strings.TrimSuffix(dsnString, allowOldPasswords)
	dsnString = strings.TrimSuffix(dsnString, dsnSuffix)
	return dsnString
}

func (dsn DSN) StringWithSuffixes() string {
	if dsn.Username == "" {
		dsn.Username = "<anonymous-user>"
	}
	dsn.Password = "<password-hidden>"
	dsnString, _ := dsn.DSN()
	return dsnString
}

func ParseSocketFromNetstat(out string) string {
	lines := strings.Split(out, "\n")
	for _, line := range lines {
		if strings.HasPrefix(line, "unix") && strings.Contains(line, "mysql") {
			fields := strings.Fields(line)
			socket := fields[len(fields)-1]
			if path.IsAbs(socket) {
				return socket
			}
		}
	}
	return ""
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package platformvm

import (
	"github.com/ava-labs/avalanchego/utils/wrappers"
	"github.com/prometheus/client_golang/prometheus"
)

type metrics struct {
	percentConnected prometheus.Gauge
	totalStake       prometheus.Gauge
}

// Initialize platformvm metrics
func (m *metrics) Initialize(
	namespace string,
	registerer prometheus.Registerer,
) error {
	m.percentConnected = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: namespace,
		Name:      "percent_connected",
		Help:      "Percent of connected stake",
	})
	m.totalStake = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: namespace,
		Name:      "total_staked",
		Help:      "Total amount of AVAX staked",
	})

	errs := wrappers.Errs{}
	errs.Add(
		registerer.Register(m.percentConnected),
		registerer.Register(m.totalStake),
	)
	return errs.Err
}
<commit_msg>nit imports<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package platformvm

import (
	"github.com/prometheus/client_golang/prometheus"

	"github.com/ava-labs/avalanchego/utils/wrappers"
)

type metrics struct {
	percentConnected prometheus.Gauge
	totalStake       prometheus.Gauge
}

// Initialize platformvm metrics
func (m *metrics) Initialize(
	namespace string,
	registerer prometheus.Registerer,
) error {
	m.percentConnected = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: namespace,
		Name:      "percent_connected",
		Help:      "Percent of connected stake",
	})
	m.totalStake = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: namespace,
		Name:      "total_staked",
		Help:      "Total amount of AVAX staked",
	})

	errs := wrappers.Errs{}
	errs.Add(
		registerer.Register(m.percentConnected),
		registerer.Register(m.totalStake),
	)
	return errs.Err
}
<|endoftext|>


<commit_before>package main

import (
    "golang.org/x/crypto/pbkdf2"
	"golang.org/x/crypto/scrypt"
	"bytes"
	"crypto/sha256"
	"fmt"
	"time"
	"os"
	"math/rand"
	"github.com/vsergeev/btckeygenie/btckey"
)

// source: http://stackoverflow.com/a/31832326/1025599
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
    letterIdxBits = 6                    // 6 bits to represent a letter index
    letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

func RandStringBytesMaskImpr(n int) string {
    b := make([]byte, n)
    // A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
    for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; {
        if remain == 0 {
            cache, remain = rand.Int63(), letterIdxMax
        }
        if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
            b[i] = letterBytes[idx]
            i--
        }
        cache >>= letterIdxBits
        remain--
    }

    return string(b)
}
// end source

func main () {
	var address string
	saltValue := ""

	if len(os.Args) >= 2 {
		address = os.Args[1]
		if len(os.Args) == 3 {
			saltValue = os.Args[2]
		} else {
			saltValue = "";
		}
	} else {
		fmt.Printf("Usage: %s [Address] [Salt - optional]\n\n", os.Args[0])
		os.Exit(0)
	}

	fmt.Printf("Using address \"%s\" and salt \"%s\"\n", address, saltValue)

	tries := 0
	start := time.Now()
	for {
		passphraseValue := RandStringBytesMaskImpr(8)
		bruteforce(passphraseValue, saltValue, address);
		tries += 1

		if tries % 1000 == 1 { // only update every 1000 attempts
			fmt.Printf("\rTried %d passphrases in %s [last passphrase: %s]", tries, time.Since(start), passphraseValue)
		}
	}
}

func bruteforce(passphraseValue string, saltValue string, address string) {
	var priv btckey.PrivateKey
	var err error

    pass := fmt.Sprint(passphraseValue, "\x01")
    salt := fmt.Sprint(saltValue, "\x01")
    key, _ := scrypt.Key([]byte(pass), []byte(salt), 262144, 8, 1, 32)
    pass = fmt.Sprint(passphraseValue, "\x02")
    salt = fmt.Sprint(saltValue, "\x02")
    key2 := pbkdf2.Key([]byte(pass), []byte(salt), 65536, 32, sha256.New)

    var result bytes.Buffer
    for i := 0; i < len(key); i++ {
        result.WriteByte(key[i] ^ key2[i])
    }

	err = priv.FromBytes(result.Bytes())
	if err != nil {
		fmt.Printf("Error importing private key: %s [%s]\n", err, passphraseValue)
		os.Exit(0)
	}

	address_uncompressed := priv.ToAddressUncompressed()

	if (address_uncompressed == address) {
		wif := priv.ToWIF()
		fmt.Printf("Found! Passphrase      %s\n", passphraseValue)
		fmt.Printf("Bitcoin Address (Uncompressed)      %s\n", address_uncompressed)
		fmt.Printf("Private Key WIF (Uncompressed)      %s\n", wif)
		os.Exit(0)
	}
}
<commit_msg>seed rand correctly<commit_after>package main

import (
    "golang.org/x/crypto/pbkdf2"
	"golang.org/x/crypto/scrypt"
	"bytes"
	"crypto/sha256"
	"fmt"
	"time"
	"os"
	"math/rand"
	"github.com/vsergeev/btckeygenie/btckey"
)

// source: http://stackoverflow.com/a/31832326/1025599
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
    letterIdxBits = 6                    // 6 bits to represent a letter index
    letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

func RandStringBytesMaskImpr(n int) string {
    b := make([]byte, n)
    // A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
    for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; {
        if remain == 0 {
            cache, remain = rand.Int63(), letterIdxMax
        }
        if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
            b[i] = letterBytes[idx]
            i--
        }
        cache >>= letterIdxBits
        remain--
    }

    return string(b)
}
// end source

func main () {
	rand.Seed(time.Now().UTC().UnixNano()) // seed rand

	var address string
	saltValue := ""

	if len(os.Args) >= 2 {
		address = os.Args[1]
		if len(os.Args) == 3 {
			saltValue = os.Args[2]
		} else {
			saltValue = "";
		}
	} else {
		fmt.Printf("Usage: %s [Address] [Salt - optional]\n\n", os.Args[0])
		os.Exit(0)
	}

	fmt.Printf("Using address \"%s\" and salt \"%s\"\n", address, saltValue)

	tries := 0
	start := time.Now()
	for {
		passphraseValue := RandStringBytesMaskImpr(8)
		bruteforce(passphraseValue, saltValue, address);
		tries += 1

		if tries % 1000 == 1 { // only update every 1000 attempts
			fmt.Printf("\rTried %d passphrases in %s [last passphrase: %s]", tries, time.Since(start), passphraseValue)
		}
	}
}

func bruteforce(passphraseValue string, saltValue string, address string) {
	var priv btckey.PrivateKey
	var err error

    pass := fmt.Sprint(passphraseValue, "\x01")
    salt := fmt.Sprint(saltValue, "\x01")
    key, _ := scrypt.Key([]byte(pass), []byte(salt), 262144, 8, 1, 32)
    pass = fmt.Sprint(passphraseValue, "\x02")
    salt = fmt.Sprint(saltValue, "\x02")
    key2 := pbkdf2.Key([]byte(pass), []byte(salt), 65536, 32, sha256.New)

    var result bytes.Buffer
    for i := 0; i < len(key); i++ {
        result.WriteByte(key[i] ^ key2[i])
    }

	err = priv.FromBytes(result.Bytes())
	if err != nil {
		fmt.Printf("Error importing private key: %s [%s]\n", err, passphraseValue)
		os.Exit(0)
	}

	address_uncompressed := priv.ToAddressUncompressed()

	if (address_uncompressed == address) {
		wif := priv.ToWIF()
		fmt.Printf("Found! Passphrase      %s\n", passphraseValue)
		fmt.Printf("Bitcoin Address (Uncompressed)      %s\n", address_uncompressed)
		fmt.Printf("Private Key WIF (Uncompressed)      %s\n", wif)
		os.Exit(0)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	concurrent = flag.Int("j", runtime.NumCPU(), "number of concurrent")
	timeout    = flag.Int64("timeout", 10, "timeout second for HTTP request")
)

var (
	errRedirectNotFollowed = errors.New("redirection not followed")
)

var customTransport http.RoundTripper = &http.Transport{
	Proxy: http.ProxyFromEnvironment,
	Dial: (&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}).Dial,
	TLSHandshakeTimeout: 10 * time.Second,
	MaxIdleConnsPerHost: 3 * http.DefaultMaxIdleConnsPerHost,
}

var httpClient = &http.Client{
	Transport: customTransport,
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		return errRedirectNotFollowed
	},
	Timeout: time.Duration(*timeout * int64(time.Second)),
}

type responseSet struct {
	res    *http.Response
	urlStr string
}

func main() {
	flag.Parse()

	var stock []*responseSet
	var m sync.Mutex
	enq := make(chan string, *concurrent)
	printq := make(chan string, *concurrent)
	stockq := make(chan bool, *concurrent)
	waitingq := make(chan bool, *concurrent)
	quitq := make(chan bool)
	eof := false

	go func() {
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			urlStr := strings.TrimRight(scanner.Text(), "\n")
			printq <- urlStr

			enq <- urlStr
			go func() {
				urlStr := <-enq
				waitingq <- true
				res, _ := fetch(urlStr)
				m.Lock()
				stock = append(stock, &responseSet{res: res, urlStr: urlStr})
				m.Unlock()
				<-waitingq
				stockq <- true
			}()
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
		}
		eof = true
	}()

	go func() {
		for {
			urlStr := <-printq
		L:
			for {
				for i, set := range stock {
					if set.urlStr == urlStr {
						fmt.Fprintf(os.Stdout, "%s\t%s\n", edit(set.res), set.urlStr)
						m.Lock()
						stock = append(stock[:i], stock[i+1:]...)
						m.Unlock()
						if eof && len(waitingq) == 0 && len(stock) == 0 {
							quitq <- true
						}
						break L
					}
				}
				<-stockq
			}
		}
	}()

	<-quitq
}

func fetch(urlStr string) (*http.Response, error) {
	res, err := httpClient.Head(urlStr)
	if err != nil {
		ue, ok := err.(*url.Error)
		if ok {
			if ue.Err == errRedirectNotFollowed {
				// ignore
			} else {
				return nil, err
			}
		} else {
			return nil, err
		}
	}
	return res, nil
}

func edit(res *http.Response) string {
	if res == nil {
		return "???"
	}
	// TODO Implement other style
	return strconv.Itoa(res.StatusCode)
}
<commit_msg>Remove enq limit<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	concurrent = flag.Int("j", runtime.NumCPU(), "number of concurrent")
	timeout    = flag.Int64("timeout", 10, "timeout second for HTTP request")
)

var (
	errRedirectNotFollowed = errors.New("redirection not followed")
)

var customTransport http.RoundTripper = &http.Transport{
	Proxy: http.ProxyFromEnvironment,
	Dial: (&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}).Dial,
	TLSHandshakeTimeout: 10 * time.Second,
	MaxIdleConnsPerHost: 3 * http.DefaultMaxIdleConnsPerHost,
}

var httpClient = &http.Client{
	Transport: customTransport,
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		return errRedirectNotFollowed
	},
	Timeout: time.Duration(*timeout * int64(time.Second)),
}

type responseSet struct {
	res    *http.Response
	urlStr string
}

func main() {
	flag.Parse()

	var stock []*responseSet
	var m sync.Mutex
	printq := make(chan string, *concurrent)
	stockq := make(chan bool, *concurrent)
	waitingq := make(chan bool, *concurrent)
	quitq := make(chan bool)
	eof := false

	go func() {
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			urlStr := strings.TrimRight(scanner.Text(), "\n")
			printq <- urlStr

			go func() {
				waitingq <- true
				res, _ := fetch(urlStr)
				m.Lock()
				stock = append(stock, &responseSet{res: res, urlStr: urlStr})
				m.Unlock()
				<-waitingq
				stockq <- true
			}()
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
		}
		eof = true
	}()

	go func() {
		for {
			urlStr := <-printq
		L:
			for {
				for i, set := range stock {
					if set.urlStr == urlStr {
						fmt.Fprintf(os.Stdout, "%s\t%s\n", edit(set.res), set.urlStr)
						m.Lock()
						stock = append(stock[:i], stock[i+1:]...)
						m.Unlock()
						if eof && len(waitingq) == 0 && len(stock) == 0 {
							quitq <- true
						}
						break L
					}
				}
				<-stockq
			}
		}
	}()

	<-quitq
}

func fetch(urlStr string) (*http.Response, error) {
	res, err := httpClient.Head(urlStr)
	if err != nil {
		ue, ok := err.(*url.Error)
		if ok {
			if ue.Err == errRedirectNotFollowed {
				// ignore
			} else {
				return nil, err
			}
		} else {
			return nil, err
		}
	}
	return res, nil
}

func edit(res *http.Response) string {
	if res == nil {
		return "???"
	}
	// TODO Implement other style
	return strconv.Itoa(res.StatusCode)
}
<|endoftext|>


<commit_before>package modelmapper

import "database/sql"
import "github.com/herb-go/herb/model/sql/querybuilder"

type Task interface {
	SetDB(querybuilder.DB)
	DB() querybuilder.DB
	OnSuccess(func() error)
	EmitSuccess() error
	OnPrepare(func() error)
	EmitPrepare() error
}

type CommonTask struct {
	db              querybuilder.DB
	successHandlers []func() error
	prepareHandlers []func() error
}

func (t *CommonTask) SetDB(db querybuilder.DB) {
	t.db = db
}

func (t *CommonTask) DB() querybuilder.DB {
	return t.db
}

func (t *CommonTask) OnSuccess(f func() error) {
	t.successHandlers = append(t.successHandlers, f)
}

func (t *CommonTask) EmitSuccess() error {
	var err error
	for k := range t.successHandlers {
		err = t.successHandlers[k]()
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *CommonTask) OnPrepare(f func() error) {
	t.prepareHandlers = append(t.prepareHandlers, f)
}

func (t *CommonTask) EmitPrepare() error {
	var err error
	for k := range t.prepareHandlers {
		err = t.prepareHandlers[k]()
		if err != nil {
			return err
		}
	}
	return nil
}

type InsertTask struct {
	*querybuilder.InsertQuery
	CommonTask
}

func (t *InsertTask) Exec() (sql.Result, error) {
	err := t.EmitPrepare()
	if err != nil {
		return nil, err
	}
	r, err := t.InsertQuery.Query().Exec(t.db)
	if err != nil {
		return r, err
	}
	return r, t.EmitSuccess()
}

func NewInsertTask(q *querybuilder.InsertQuery, db querybuilder.DB) *InsertTask {
	t := &InsertTask{
		InsertQuery: q,
	}
	t.SetDB(db)
	return t
}

type UpdateTask struct {
	*querybuilder.UpdateQuery
	CommonTask
}

func (t *UpdateTask) Exec() (sql.Result, error) {
	err := t.EmitPrepare()
	if err != nil {
		return nil, err
	}
	r, err := t.UpdateQuery.Query().Exec(t.db)
	if err != nil {
		return r, err
	}
	return r, t.EmitSuccess()
}

func NewUpdateTask(q *querybuilder.UpdateQuery, db querybuilder.DB) *UpdateTask {
	t := &UpdateTask{
		UpdateQuery: q,
	}
	t.SetDB(db)
	return t
}

type DeleteTask struct {
	*querybuilder.DeleteQuery
	CommonTask
}

func (t *DeleteTask) Exec() (sql.Result, error) {
	err := t.EmitPrepare()
	if err != nil {
		return nil, err
	}
	r, err := t.DeleteQuery.Query().Exec(t.db)
	if err != nil {
		return r, err
	}
	return r, t.EmitSuccess()
}

func NewDeleteTask(q *querybuilder.DeleteQuery, db querybuilder.DB) *DeleteTask {
	t := &DeleteTask{
		DeleteQuery: q,
	}
	t.SetDB(db)
	return t
}

type SelectTask struct {
	*querybuilder.SelectQuery
	CommonTask
}

func (t *SelectTask) QueryRow() *sql.Row {
	return t.SelectQuery.Query().QueryRow(t.db)
}
func (t *SelectTask) QueryRows() (*sql.Rows, error) {
	return t.SelectQuery.Query().QueryRows(t.db)
}

func NewSelectTask(q *querybuilder.SelectQuery, db querybuilder.DB) *SelectTask {
	t := &SelectTask{
		SelectQuery: q,
	}
	t.SetDB(db)
	return t
}

func (t *SelectTask) ByField(fieldName string, fieldValue interface{}) *SelectTask {
	t.Where.Condition = t.Builder.Equal(fieldName, fieldValue)
	return t
}

func (t *SelectTask) ByFields(fieldsmap map[string]interface{}) *SelectTask {
	for k, v := range fieldsmap {
		t.Where.Condition.And(t.Builder.Equal(k, v))
	}
	return t
}

func (t *SelectTask) QueryRowToFields(fields *querybuilder.Fields) error {
	row := t.QueryRow()
	err := t.Select.Result().
		BindFields(fields).
		ScanFrom(row)

	return err
}
func (t *SelectTask) QueryRowsToResult(rs ...Result) error {
	r := Results(rs)
	rows, err := t.QueryRows()
	if err != nil {
		return r.OnFinish(err)
	}
	defer rows.Close()
	err = t.Select.Result().
		BindFields(r.Fields()).
		ScanFrom(rows)
	if err != nil {
		return r.OnFinish(err)
	}
	return r.OnFinish(nil)
}

func (t *SelectTask) QueryRowToResult(rs ...Result) error {
	r := Results(rs)
	row := t.QueryRow()
	var sr = t.Select.Result()
	sr.BindFields(r.Fields())
	err := sr.ScanFrom(row)
	return r.OnFinish(err)
}

type Results []Result

func (rs *Results) Append(r ...Result) {
	*rs = append(*rs, r...)
}
func (rs *Results) Fields() *querybuilder.Fields {
	fields := querybuilder.NewFields()
	for _, v := range *rs {
		*fields = append(*fields, *v.Fields()...)
	}
	return fields
}
func (rs *Results) OnFinish(err error) error {
	for _, v := range *rs {
		err = v.OnFinish(err)
	}
	return err
}

type Result interface {
	Fields() *querybuilder.Fields
	OnFinish(error) error
}
<commit_msg>update<commit_after>package modelmapper

import "database/sql"
import "github.com/herb-go/herb/model/sql/querybuilder"

type Task interface {
	SetDB(querybuilder.DB)
	DB() querybuilder.DB
	OnSuccess(func() error)
	EmitSuccess() error
	OnPrepare(func() error)
	EmitPrepare() error
}

type CommonTask struct {
	db              querybuilder.DB
	successHandlers []func() error
	prepareHandlers []func() error
}

func (t *CommonTask) SetDB(db querybuilder.DB) {
	t.db = db
}

func (t *CommonTask) DB() querybuilder.DB {
	return t.db
}

func (t *CommonTask) OnSuccess(f func() error) {
	t.successHandlers = append(t.successHandlers, f)
}

func (t *CommonTask) EmitSuccess() error {
	var err error
	for k := range t.successHandlers {
		err = t.successHandlers[k]()
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *CommonTask) OnPrepare(f func() error) {
	t.prepareHandlers = append(t.prepareHandlers, f)
}

func (t *CommonTask) EmitPrepare() error {
	var err error
	for k := range t.prepareHandlers {
		err = t.prepareHandlers[k]()
		if err != nil {
			return err
		}
	}
	return nil
}

type InsertTask struct {
	*querybuilder.InsertQuery
	CommonTask
}

func (t *InsertTask) Exec() (sql.Result, error) {
	err := t.EmitPrepare()
	if err != nil {
		return nil, err
	}
	r, err := t.InsertQuery.Query().Exec(t.db)
	if err != nil {
		return r, err
	}
	return r, t.EmitSuccess()
}

func NewInsertTask(q *querybuilder.InsertQuery, db querybuilder.DB) *InsertTask {
	t := &InsertTask{
		InsertQuery: q,
	}
	t.SetDB(db)
	return t
}

type UpdateTask struct {
	*querybuilder.UpdateQuery
	CommonTask
}

func (t *UpdateTask) Exec() (sql.Result, error) {
	err := t.EmitPrepare()
	if err != nil {
		return nil, err
	}
	r, err := t.UpdateQuery.Query().Exec(t.db)
	if err != nil {
		return r, err
	}
	return r, t.EmitSuccess()
}

func NewUpdateTask(q *querybuilder.UpdateQuery, db querybuilder.DB) *UpdateTask {
	t := &UpdateTask{
		UpdateQuery: q,
	}
	t.SetDB(db)
	return t
}

type DeleteTask struct {
	*querybuilder.DeleteQuery
	CommonTask
}

func (t *DeleteTask) Exec() (sql.Result, error) {
	err := t.EmitPrepare()
	if err != nil {
		return nil, err
	}
	r, err := t.DeleteQuery.Query().Exec(t.db)
	if err != nil {
		return r, err
	}
	return r, t.EmitSuccess()
}

func NewDeleteTask(q *querybuilder.DeleteQuery, db querybuilder.DB) *DeleteTask {
	t := &DeleteTask{
		DeleteQuery: q,
	}
	t.SetDB(db)
	return t
}

type SelectTask struct {
	*querybuilder.SelectQuery
	CommonTask
}

func (t *SelectTask) QueryRow() *sql.Row {
	return t.SelectQuery.Query().QueryRow(t.db)
}
func (t *SelectTask) QueryRows() (*sql.Rows, error) {
	return t.SelectQuery.Query().QueryRows(t.db)
}

func NewSelectTask(q *querybuilder.SelectQuery, db querybuilder.DB) *SelectTask {
	t := &SelectTask{
		SelectQuery: q,
	}
	t.SetDB(db)
	return t
}

func (t *SelectTask) ByField(fieldName string, fieldValue interface{}) *SelectTask {
	t.Where.Condition = t.Builder.Equal(fieldName, fieldValue)
	return t
}

func (t *SelectTask) ByFields(fieldsmap map[string]interface{}) *SelectTask {
	for k, v := range fieldsmap {
		t.Where.Condition.And(t.Builder.Equal(k, v))
	}
	return t
}

func (t *SelectTask) QueryRowToFields(fields *querybuilder.Fields) error {
	row := t.QueryRow()
	err := t.Select.Result().
		BindFields(fields).
		ScanFrom(row)

	return err
}
func (t *SelectTask) FindAllTo(rs ...Result) error {
	r := Results(rs)
	rows, err := t.QueryRows()
	if err != nil {
		return r.OnFinish(err)
	}
	defer rows.Close()
	for rows.Next() {
		err = t.Select.Result().
			BindFields(r.Fields()).
			ScanFrom(rows)
		if err != nil {
			return r.OnFinish(err)
		}
		err = r.OnFinish(err)
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *SelectTask) FindTo(rs ...Result) error {
	r := Results(rs)
	row := t.QueryRow()
	var sr = t.Select.Result()
	sr.BindFields(r.Fields())
	err := sr.ScanFrom(row)
	return r.OnFinish(err)
}

type Results []Result

func (rs *Results) Append(r ...Result) {
	*rs = append(*rs, r...)
}
func (rs *Results) Fields() *querybuilder.Fields {
	fields := querybuilder.NewFields()
	for _, v := range *rs {
		*fields = append(*fields, *v.Fields()...)
	}
	return fields
}
func (rs *Results) OnFinish(err error) error {
	for _, v := range *rs {
		err = v.OnFinish(err)
	}
	return err
}

type Result interface {
	Fields() *querybuilder.Fields
	OnFinish(error) error
}
<|endoftext|>


<commit_before>package route

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

var endpoints = []string{"/test/handler/1", "/test/handler/2"}

func TestRouter(t *testing.T) {
	r := new(Router)
	r.HandleFunc(endpoints[0], testHandler1)
	r.HandleFunc(endpoints[1], testHandler2)

	server := httptest.NewServer(r)
	defer server.Close()

	for _, endpoint := range endpoints {
		res, err := http.Get(server.URL + endpoint)
		if err != nil {
			t.Fatal(err)
		}

		if res.StatusCode != http.StatusOK {
			t.Fatal(res)
		}
	}
}

func TestNotFoundRoute(t *testing.T) {
	r := new(Router)
	r.HandleFunc(endpoints[0], testHandler1)
	r.HandleFunc(endpoints[1], testHandler2)

	server := httptest.NewServer(r)
	defer server.Close()

	res, err := http.Get(server.URL + "/test/handler/3")
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != http.StatusNotFound {
		t.Fatal(res)
	}
}

func TestFoundRegexpRoute(t *testing.T) {
	r := new(Router)
	r.HandleFunc("/test/handler/[0-9]/hello", testHandlerHello)

	server := httptest.NewServer(r)
	defer server.Close()

	res, err := http.Get(server.URL + "/test/handler/1/hello")
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != http.StatusOK {
		t.Fatal(res)
	}
}

func TestNotFoundRegexpRoute(t *testing.T) {
	r := new(Router)
	r.HandleFunc("/test/handler/[0-9]/hello", testHandlerHello)

	server := httptest.NewServer(r)
	defer server.Close()

	res, err := http.Get(server.URL + "/test/handler/a/hello")
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != http.StatusNotFound {
		t.Fatal(res)
	}
}

func testHandler1(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "testHandler1 has been reached!")
}

func testHandler2(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "testHandler2 has been reached!")
}

func testHandlerHello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "testHandlerHello has been reached!")
}
<commit_msg>better test<commit_after>package route

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

var endpoints = []string{
	"/test/handler/1/?",
	"/test/handler/2/?",
}

func TestRouter(t *testing.T) {
	r := new(Router)
	r.HandleFunc(endpoints[0], handler1)
	r.HandleFunc(endpoints[1], handler2)

	server := httptest.NewServer(r)
	defer server.Close()

	var urls = []string{
		"/test/handler/1",
		"/test/handler/2",
		"/test/handler/1/",
		"/test/handler/2/",
	}

	for _, u := range urls {
		res, err := http.Get(server.URL + u)
		if err != nil {
			t.Fatal(err)
		}

		if res.StatusCode != http.StatusOK {
			t.Fatal(res)
		}
	}
}

func TestNotFoundRoute(t *testing.T) {
	r := new(Router)
	r.HandleFunc(endpoints[0], handler1)
	r.HandleFunc(endpoints[1], handler2)

	server := httptest.NewServer(r)
	defer server.Close()

	res, err := http.Get(server.URL + "/test/handler/3")
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != http.StatusNotFound {
		t.Fatal(res)
	}
}

func TestFoundRegexpRoute(t *testing.T) {
	r := new(Router)
	r.HandleFunc("/test/handler/[0-9]+/hello/?", handlerHello)

	urls := []string{
		"/test/handler/1/hello",
		"/test/handler/2/hello/",
		"/test/handler/2123/hello/",
		"/test/handler/2123/hello",
	}

	server := httptest.NewServer(r)
	defer server.Close()

	for _, u := range urls {
		res, err := http.Get(server.URL + u)
		if err != nil {
			t.Fatal(err)
		}
		if res.StatusCode != http.StatusOK {
			t.Fatal(res)
		}
	}

}

func TestNotFoundRegexpRoute(t *testing.T) {
	r := new(Router)
	r.HandleFunc("/test/handler/[0-9]/hello", handlerHello)

	server := httptest.NewServer(r)
	defer server.Close()

	res, err := http.Get(server.URL + "/test/handler/a/hello")
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != http.StatusNotFound {
		t.Fatal(res)
	}
}

func handler1(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "testHandler1 has been reached!")
}

func handler2(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "testHandler2 has been reached!")
}

func handlerHello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "testHandlerHello has been reached!")
}
<|endoftext|>