<commit_before>package bitfield

import (
	"testing"
)

func TestNewBitField(t *testing.T) {
	var bf BitField

	bf = NewBitField(16)
	if len(bf.Data) != 2 {
		t.Errorf("NewBitField returned wrongly sized field: %v", len(bf.Data))
	}

	bf = NewBitField(17)
	if len(bf.Data) != 3 {
		t.Errorf("NewBitField returned wrongly sized field: %v", len(bf.Data))
	}
}

func TestBitFieldTest(t *testing.T) {
	bf := NewBitField(17)
	bf.Set(0)
	if !bf.Test(0) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(1) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(8) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(9) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(16) {
		t.Errorf("BitField Test returned wrong value!")
	}
}

func TestBitFieldUnset(t *testing.T) {
	bf := NewBitField(8)
	bf.Set(3)
	bf.Unset(3)
	if bf.Data[0] != 0 {
		t.Errorf("BitField Unset failed to clear bit!")
	}
}

func TestBitFieldSet(t *testing.T) {

	bf := NewBitField(16)
	for i := uint(0); i < 16; i++ {
		bf.Set(i)
	}
	for i := uint(0); i < 16; i++ {
		if !bf.Test(i) {
			t.Errorf("BitField Set or Test failed!")
		}
	}

	bf = NewBitField(17)

	bf.Set(0)
	if bf.Data[0] != 128 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(1)
	if bf.Data[0] != 192 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(8)
	if bf.Data[1] != 128 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(9)
	if bf.Data[1] != 192 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(16)
	if bf.Data[2] != 128 {
		t.Errorf("BitField Set wrong value!")
	}

}

func TestLen(t *testing.T) {
	bf := NewBitField(17)

	if bf.Len() != 17 {
		t.Errorf("BitField Len returned wrong length!")
	}
}

func TestResize(t *testing.T) {
	bf := NewBitField(2)
	bf.Set(0)
	bf.Set(1)

	bf = bf.Resize(1)
	if !bf.Test(0) {
		t.Errorf("Resize didn't preserve bits!")
	}

	bf = bf.Resize(2)
	if !bf.Test(0) {
		t.Errorf("Resize didn't preserve bits!")
	}
	if bf.Test(1) {
		t.Errorf("Resize didn't pad bits!")
	}

	bf = NewBitField(17)
	for i := uint(0); i < 17; i++ {
		bf.Set(i)
	}
	bf = bf.Resize(1)
	if bf.Data[0] != 128 {
		t.Errorf("Resize didn't clear bits!")
	}

	bf = NewBitField(9)
	bf.Set(1)
	bf = bf.Resize(8)
	if len(bf.Data) != 1 {
		t.Errorf("Resize to 8 has wrong data size!")
	}

	bf = NewBitField(1)
	bf.Set(1)
	bf = bf.Resize(0)
	if len(bf.Data) != 0 {
		t.Errorf("Resize to zero still has data!")
	}
}
<commit_msg>added a test to bitfields<commit_after>package bitfield

import (
	"testing"
)

func TestNewBitField(t *testing.T) {
	var bf BitField

	bf = NewBitField(16)
	if len(bf.Data) != 2 {
		t.Errorf("NewBitField returned wrongly sized field: %v", len(bf.Data))
	}

	bf = NewBitField(17)
	if len(bf.Data) != 3 {
		t.Errorf("NewBitField returned wrongly sized field: %v", len(bf.Data))
	}
}

func TestBitFieldTest(t *testing.T) {
	bf := NewBitField(17)
	bf.Set(0)
	if !bf.Test(0) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(1) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(8) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(9) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(16) {
		t.Errorf("BitField Test returned wrong value!")
	}
	if bf.Test(19) {
		t.Errorf("BitField Test returned wrong value!")
	}
}

func TestBitFieldUnset(t *testing.T) {
	bf := NewBitField(8)
	bf.Set(3)
	bf.Unset(3)
	if bf.Data[0] != 0 {
		t.Errorf("BitField Unset failed to clear bit!")
	}
}

func TestBitFieldSet(t *testing.T) {

	bf := NewBitField(16)
	for i := uint(0); i < 16; i++ {
		bf.Set(i)
	}
	for i := uint(0); i < 16; i++ {
		if !bf.Test(i) {
			t.Errorf("BitField Set or Test failed!")
		}
	}

	bf = NewBitField(17)

	bf.Set(0)
	if bf.Data[0] != 128 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(1)
	if bf.Data[0] != 192 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(8)
	if bf.Data[1] != 128 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(9)
	if bf.Data[1] != 192 {
		t.Errorf("BitField Set wrong value!")
	}

	bf.Set(16)
	if bf.Data[2] != 128 {
		t.Errorf("BitField Set wrong value!")
	}

}

func TestLen(t *testing.T) {
	bf := NewBitField(17)

	if bf.Len() != 17 {
		t.Errorf("BitField Len returned wrong length!")
	}
}

func TestResize(t *testing.T) {
	bf := NewBitField(2)
	bf.Set(0)
	bf.Set(1)

	bf = bf.Resize(1)
	if !bf.Test(0) {
		t.Errorf("Resize didn't preserve bits!")
	}

	bf = bf.Resize(2)
	if !bf.Test(0) {
		t.Errorf("Resize didn't preserve bits!")
	}
	if bf.Test(1) {
		t.Errorf("Resize didn't pad bits!")
	}

	bf = NewBitField(17)
	for i := uint(0); i < 17; i++ {
		bf.Set(i)
	}
	bf = bf.Resize(1)
	if bf.Data[0] != 128 {
		t.Errorf("Resize didn't clear bits!")
	}

	bf = NewBitField(9)
	bf.Set(1)
	bf = bf.Resize(8)
	if len(bf.Data) != 1 {
		t.Errorf("Resize to 8 has wrong data size!")
	}

	bf = NewBitField(1)
	bf.Set(1)
	bf = bf.Resize(0)
	if len(bf.Data) != 0 {
		t.Errorf("Resize to zero still has data!")
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reservefs.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package storage

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/syndtr/goleveldb/leveldb/util"
)

var errFileOpen = errors.New("leveldb/storage: file still open")

type fileLock interface {
	release() error
}

type fileStorageLock struct {
	fs *fileStorage
}

func (lock *fileStorageLock) Release() {
	fs := lock.fs
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.slock == lock {
		fs.slock = nil
	}
	return
}

// fileStorage is a file-system backed storage.
type fileStorage struct {
	path string

	mu    sync.Mutex
	flock fileLock
	slock *fileStorageLock
	logw  *os.File
	buf   []byte
	// Opened file counter; if open < 0 means closed.
	open int
}

// OpenFile returns a new filesytem-backed storage implementation with the given
// path. This also hold a file lock, so any subsequent attempt to open the same
// path will fail.
//
// The storage must be closed after use, by calling Close method.
func OpenFile(path string) (Storage, error) {
	if err := os.MkdirAll(path, 0755); err != nil {
		return nil, err
	}

	flock, err := newFileLock(filepath.Join(path, "LOCK"))
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			flock.release()
		}
	}()

	rename(filepath.Join(path, "LOG"), filepath.Join(path, "LOG.old"))
	logw, err := os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return nil, err
	}

	fs := &fileStorage{path: path, flock: flock, logw: logw}
	runtime.SetFinalizer(fs, (*fileStorage).Close)
	return fs, nil
}

func (fs *fileStorage) Lock() (util.Releaser, error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return nil, ErrClosed
	}
	if fs.slock != nil {
		return nil, ErrLocked
	}
	fs.slock = &fileStorageLock{fs: fs}
	return fs.slock, nil
}

func itoa(buf []byte, i int, wid int) []byte {
	var u uint = uint(i)
	if u == 0 && wid <= 1 {
		return append(buf, '0')
	}

	// Assemble decimal in reverse order.
	var b [32]byte
	bp := len(b)
	for ; u > 0 || wid > 0; u /= 10 {
		bp--
		wid--
		b[bp] = byte(u%10) + '0'
	}
	return append(buf, b[bp:]...)
}

func (fs *fileStorage) doLog(t time.Time, str string) {
	year, month, day := t.Date()
	hour, min, sec := t.Clock()
	msec := t.Nanosecond() / 1e3
	// date
	fs.buf = itoa(fs.buf[:0], year, 4)
	fs.buf = append(fs.buf, '/')
	fs.buf = itoa(fs.buf, int(month), 2)
	fs.buf = append(fs.buf, '/')
	fs.buf = itoa(fs.buf, day, 4)
	fs.buf = append(fs.buf, ' ')
	// time
	fs.buf = itoa(fs.buf, hour, 2)
	fs.buf = append(fs.buf, ':')
	fs.buf = itoa(fs.buf, min, 2)
	fs.buf = append(fs.buf, ':')
	fs.buf = itoa(fs.buf, sec, 2)
	fs.buf = append(fs.buf, '.')
	fs.buf = itoa(fs.buf, msec, 6)
	fs.buf = append(fs.buf, ' ')
	// write
	fs.buf = append(fs.buf, []byte(str)...)
	fs.buf = append(fs.buf, '\n')
	fs.logw.Write(fs.buf)
}

func (fs *fileStorage) Log(str string) {
	t := time.Now()
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return
	}
	fs.doLog(t, str)
}

func (fs *fileStorage) log(str string) {
	fs.doLog(time.Now(), str)
}

func (fs *fileStorage) GetFile(num uint64, t FileType) File {
	return &file{fs: fs, num: num, t: t}
}

func (fs *fileStorage) GetFiles(t FileType) (ff []File, err error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return nil, ErrClosed
	}
	dir, err := os.Open(fs.path)
	if err != nil {
		return
	}
	fnn, err := dir.Readdirnames(0)
	// Close the dir first before checking for Readdirnames error.
	if err := dir.Close(); err != nil {
		fs.log(fmt.Sprintf("close dir: %v", err))
	}
	if err != nil {
		return
	}
	f := &file{fs: fs}
	for _, fn := range fnn {
		if f.parse(fn) && (f.t&t) != 0 {
			ff = append(ff, f)
			f = &file{fs: fs}
		}
	}
	return
}

func (fs *fileStorage) GetManifest() (f File, err error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return nil, ErrClosed
	}
	dir, err := os.Open(fs.path)
	if err != nil {
		return
	}
	fnn, err := dir.Readdirnames(0)
	// Close the dir first before checking for Readdirnames error.
	if err := dir.Close(); err != nil {
		fs.log(fmt.Sprintf("close dir: %v", err))
	}
	if err != nil {
		return
	}
	// Find latest CURRENT file.
	var rem []string
	var pend bool
	var cerr error
	for _, fn := range fnn {
		if strings.HasPrefix(fn, "CURRENT") {
			pend1 := len(fn) > 7
			// Make sure it is valid name for a CURRENT file, otherwise skip it.
			if pend1 {
				if fn[7] != '.' || len(fn) < 9 {
					fs.log(fmt.Sprintf("skipping %s: invalid file name", fn))
					continue
				}
				if _, e1 := strconv.ParseUint(fn[7:], 10, 0); e1 != nil {
					fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", fn, e1))
					continue
				}
			}
			path := filepath.Join(fs.path, fn)
			r, e1 := os.OpenFile(path, os.O_RDONLY, 0)
			if e1 != nil {
				return nil, e1
			}
			b, e1 := ioutil.ReadAll(r)
			if e1 != nil {
				r.Close()
				return nil, e1
			}
			f1 := &file{fs: fs}
			if len(b) < 1 || b[len(b)-1] != '\n' || !f1.parse(string(b[:len(b)-1])) {
				fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", fn))
				if pend1 {
					rem = append(rem, fn)
				}
				if !pend1 || cerr == nil {
					cerr = fmt.Errorf("leveldb/storage: corrupted or incomplete %s file", fn)
				}
			} else if f != nil && f1.Num() < f.Num() {
				fs.log(fmt.Sprintf("skipping %s: obsolete", fn))
				if pend1 {
					rem = append(rem, fn)
				}
			} else {
				f = f1
				pend = pend1
			}
			if err := r.Close(); err != nil {
				fs.log(fmt.Sprintf("close %s: %v", fn, err))
			}
		}
	}
	// Don't remove any files if there is no valid CURRENT file.
	if f == nil {
		if cerr != nil {
			err = cerr
		} else {
			err = os.ErrNotExist
		}
		return
	}
	// Rename pending CURRENT file to an effective CURRENT.
	if pend {
		path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f.Num())
		if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil {
			fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %d", f.Num(), err))
		}
	}
	// Remove obsolete or incomplete pending CURRENT files.
	for _, fn := range rem {
		path := filepath.Join(fs.path, fn)
		if err := os.Remove(path); err != nil {
			fs.log(fmt.Sprintf("remove %s: %v", fn, err))
		}
	}
	return
}

func (fs *fileStorage) SetManifest(f File) (err error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return ErrClosed
	}
	f2, ok := f.(*file)
	if !ok || f2.t != TypeManifest {
		return ErrInvalidFile
	}
	defer func() {
		if err != nil {
			fs.log(fmt.Sprintf("CURRENT: %v", err))
		}
	}()
	path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f2.Num())
	w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer func() {
		if err := w.Close(); err != nil {
			fs.log(fmt.Sprintf("close CURRENT.%d: %v", f2.num, err))
		}
	}()
	_, err = fmt.Fprintln(w, f2.name())
	if err != nil {
		return err
	}
	err = rename(path, filepath.Join(fs.path, "CURRENT"))
	return
}

func (fs *fileStorage) Close() error {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return ErrClosed
	}
	// Clear the finalizer.
	runtime.SetFinalizer(fs, nil)

	if fs.open > 0 {
		fs.log(fmt.Sprintf("refuse to close, %d files still open", fs.open))
		return fmt.Errorf("leveldb/storage: cannot close, %d files still open", fs.open)
	}
	fs.open = -1
	e1 := fs.logw.Close()
	err := fs.flock.release()
	if err == nil {
		err = e1
	}
	return err
}

type fileWrap struct {
	*os.File
	f *file
}

func (fw fileWrap) Close() error {
	f := fw.f
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if !f.open {
		return ErrClosed
	}
	f.open = false
	f.fs.open--
	err := fw.File.Close()
	if err != nil {
		f.fs.log(fmt.Sprint("close %s.%d: %v", f.Type(), f.Num(), err))
	}
	return err
}

type file struct {
	fs   *fileStorage
	num  uint64
	t    FileType
	open bool
}

func (f *file) Open() (Reader, error) {
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if f.fs.open < 0 {
		return nil, ErrClosed
	}
	if f.open {
		return nil, errFileOpen
	}
	of, err := os.OpenFile(f.path(), os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	f.open = true
	f.fs.open++
	return fileWrap{of, f}, nil
}

func (f *file) Create() (Writer, error) {
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if f.fs.open < 0 {
		return nil, ErrClosed
	}
	if f.open {
		return nil, errFileOpen
	}
	of, err := os.OpenFile(f.path(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return nil, err
	}
	f.open = true
	f.fs.open++
	return fileWrap{of, f}, nil
}

func (f *file) Type() FileType {
	return f.t
}

func (f *file) Num() uint64 {
	return f.num
}

func (f *file) Remove() error {
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if f.fs.open < 0 {
		return ErrClosed
	}
	if f.open {
		return errFileOpen
	}
	err := os.Remove(f.path())
	if err != nil {
		f.fs.log(fmt.Sprint("remove %s.%d: %v", f.Type(), f.Num(), err))
	}
	return err
}

func (f *file) name() string {
	switch f.t {
	case TypeManifest:
		return fmt.Sprintf("MANIFEST-%06d", f.num)
	case TypeJournal:
		return fmt.Sprintf("%06d.log", f.num)
	case TypeTable:
		return fmt.Sprintf("%06d.sst", f.num)
	default:
		panic("invalid file type")
	}
	return ""
}

func (f *file) path() string {
	return filepath.Join(f.fs.path, f.name())
}

func (f *file) parse(name string) bool {
	var num uint64
	var tail string
	_, err := fmt.Sscanf(name, "%d.%s", &num, &tail)
	if err == nil {
		switch tail {
		case "log":
			f.t = TypeJournal
		case "sst":
			f.t = TypeTable
		default:
			return false
		}
		f.num = num
		return true
	}
	n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &num, &tail)
	if n == 1 {
		f.t = TypeManifest
		f.num = num
		return true
	}

	return false
}
<commit_msg>storage: fileStorage.SetManifest: File should closed first before renamed<commit_after>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reservefs.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package storage

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/syndtr/goleveldb/leveldb/util"
)

var errFileOpen = errors.New("leveldb/storage: file still open")

type fileLock interface {
	release() error
}

type fileStorageLock struct {
	fs *fileStorage
}

func (lock *fileStorageLock) Release() {
	fs := lock.fs
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.slock == lock {
		fs.slock = nil
	}
	return
}

// fileStorage is a file-system backed storage.
type fileStorage struct {
	path string

	mu    sync.Mutex
	flock fileLock
	slock *fileStorageLock
	logw  *os.File
	buf   []byte
	// Opened file counter; if open < 0 means closed.
	open int
}

// OpenFile returns a new filesytem-backed storage implementation with the given
// path. This also hold a file lock, so any subsequent attempt to open the same
// path will fail.
//
// The storage must be closed after use, by calling Close method.
func OpenFile(path string) (Storage, error) {
	if err := os.MkdirAll(path, 0755); err != nil {
		return nil, err
	}

	flock, err := newFileLock(filepath.Join(path, "LOCK"))
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			flock.release()
		}
	}()

	rename(filepath.Join(path, "LOG"), filepath.Join(path, "LOG.old"))
	logw, err := os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return nil, err
	}

	fs := &fileStorage{path: path, flock: flock, logw: logw}
	runtime.SetFinalizer(fs, (*fileStorage).Close)
	return fs, nil
}

func (fs *fileStorage) Lock() (util.Releaser, error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return nil, ErrClosed
	}
	if fs.slock != nil {
		return nil, ErrLocked
	}
	fs.slock = &fileStorageLock{fs: fs}
	return fs.slock, nil
}

func itoa(buf []byte, i int, wid int) []byte {
	var u uint = uint(i)
	if u == 0 && wid <= 1 {
		return append(buf, '0')
	}

	// Assemble decimal in reverse order.
	var b [32]byte
	bp := len(b)
	for ; u > 0 || wid > 0; u /= 10 {
		bp--
		wid--
		b[bp] = byte(u%10) + '0'
	}
	return append(buf, b[bp:]...)
}

func (fs *fileStorage) doLog(t time.Time, str string) {
	year, month, day := t.Date()
	hour, min, sec := t.Clock()
	msec := t.Nanosecond() / 1e3
	// date
	fs.buf = itoa(fs.buf[:0], year, 4)
	fs.buf = append(fs.buf, '/')
	fs.buf = itoa(fs.buf, int(month), 2)
	fs.buf = append(fs.buf, '/')
	fs.buf = itoa(fs.buf, day, 4)
	fs.buf = append(fs.buf, ' ')
	// time
	fs.buf = itoa(fs.buf, hour, 2)
	fs.buf = append(fs.buf, ':')
	fs.buf = itoa(fs.buf, min, 2)
	fs.buf = append(fs.buf, ':')
	fs.buf = itoa(fs.buf, sec, 2)
	fs.buf = append(fs.buf, '.')
	fs.buf = itoa(fs.buf, msec, 6)
	fs.buf = append(fs.buf, ' ')
	// write
	fs.buf = append(fs.buf, []byte(str)...)
	fs.buf = append(fs.buf, '\n')
	fs.logw.Write(fs.buf)
}

func (fs *fileStorage) Log(str string) {
	t := time.Now()
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return
	}
	fs.doLog(t, str)
}

func (fs *fileStorage) log(str string) {
	fs.doLog(time.Now(), str)
}

func (fs *fileStorage) GetFile(num uint64, t FileType) File {
	return &file{fs: fs, num: num, t: t}
}

func (fs *fileStorage) GetFiles(t FileType) (ff []File, err error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return nil, ErrClosed
	}
	dir, err := os.Open(fs.path)
	if err != nil {
		return
	}
	fnn, err := dir.Readdirnames(0)
	// Close the dir first before checking for Readdirnames error.
	if err := dir.Close(); err != nil {
		fs.log(fmt.Sprintf("close dir: %v", err))
	}
	if err != nil {
		return
	}
	f := &file{fs: fs}
	for _, fn := range fnn {
		if f.parse(fn) && (f.t&t) != 0 {
			ff = append(ff, f)
			f = &file{fs: fs}
		}
	}
	return
}

func (fs *fileStorage) GetManifest() (f File, err error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return nil, ErrClosed
	}
	dir, err := os.Open(fs.path)
	if err != nil {
		return
	}
	fnn, err := dir.Readdirnames(0)
	// Close the dir first before checking for Readdirnames error.
	if err := dir.Close(); err != nil {
		fs.log(fmt.Sprintf("close dir: %v", err))
	}
	if err != nil {
		return
	}
	// Find latest CURRENT file.
	var rem []string
	var pend bool
	var cerr error
	for _, fn := range fnn {
		if strings.HasPrefix(fn, "CURRENT") {
			pend1 := len(fn) > 7
			// Make sure it is valid name for a CURRENT file, otherwise skip it.
			if pend1 {
				if fn[7] != '.' || len(fn) < 9 {
					fs.log(fmt.Sprintf("skipping %s: invalid file name", fn))
					continue
				}
				if _, e1 := strconv.ParseUint(fn[7:], 10, 0); e1 != nil {
					fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", fn, e1))
					continue
				}
			}
			path := filepath.Join(fs.path, fn)
			r, e1 := os.OpenFile(path, os.O_RDONLY, 0)
			if e1 != nil {
				return nil, e1
			}
			b, e1 := ioutil.ReadAll(r)
			if e1 != nil {
				r.Close()
				return nil, e1
			}
			f1 := &file{fs: fs}
			if len(b) < 1 || b[len(b)-1] != '\n' || !f1.parse(string(b[:len(b)-1])) {
				fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", fn))
				if pend1 {
					rem = append(rem, fn)
				}
				if !pend1 || cerr == nil {
					cerr = fmt.Errorf("leveldb/storage: corrupted or incomplete %s file", fn)
				}
			} else if f != nil && f1.Num() < f.Num() {
				fs.log(fmt.Sprintf("skipping %s: obsolete", fn))
				if pend1 {
					rem = append(rem, fn)
				}
			} else {
				f = f1
				pend = pend1
			}
			if err := r.Close(); err != nil {
				fs.log(fmt.Sprintf("close %s: %v", fn, err))
			}
		}
	}
	// Don't remove any files if there is no valid CURRENT file.
	if f == nil {
		if cerr != nil {
			err = cerr
		} else {
			err = os.ErrNotExist
		}
		return
	}
	// Rename pending CURRENT file to an effective CURRENT.
	if pend {
		path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f.Num())
		if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil {
			fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %d", f.Num(), err))
		}
	}
	// Remove obsolete or incomplete pending CURRENT files.
	for _, fn := range rem {
		path := filepath.Join(fs.path, fn)
		if err := os.Remove(path); err != nil {
			fs.log(fmt.Sprintf("remove %s: %v", fn, err))
		}
	}
	return
}

func (fs *fileStorage) SetManifest(f File) (err error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return ErrClosed
	}
	f2, ok := f.(*file)
	if !ok || f2.t != TypeManifest {
		return ErrInvalidFile
	}
	defer func() {
		if err != nil {
			fs.log(fmt.Sprintf("CURRENT: %v", err))
		}
	}()
	path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f2.Num())
	w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	_, err = fmt.Fprintln(w, f2.name())
	// Close the file first.
	if err := w.Close(); err != nil {
		fs.log(fmt.Sprintf("close CURRENT.%d: %v", f2.num, err))
	}
	if err != nil {
		return err
	}
	err = rename(path, filepath.Join(fs.path, "CURRENT"))
	return
}

func (fs *fileStorage) Close() error {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if fs.open < 0 {
		return ErrClosed
	}
	// Clear the finalizer.
	runtime.SetFinalizer(fs, nil)

	if fs.open > 0 {
		fs.log(fmt.Sprintf("refuse to close, %d files still open", fs.open))
		return fmt.Errorf("leveldb/storage: cannot close, %d files still open", fs.open)
	}
	fs.open = -1
	e1 := fs.logw.Close()
	err := fs.flock.release()
	if err == nil {
		err = e1
	}
	return err
}

type fileWrap struct {
	*os.File
	f *file
}

func (fw fileWrap) Close() error {
	f := fw.f
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if !f.open {
		return ErrClosed
	}
	f.open = false
	f.fs.open--
	err := fw.File.Close()
	if err != nil {
		f.fs.log(fmt.Sprint("close %s.%d: %v", f.Type(), f.Num(), err))
	}
	return err
}

type file struct {
	fs   *fileStorage
	num  uint64
	t    FileType
	open bool
}

func (f *file) Open() (Reader, error) {
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if f.fs.open < 0 {
		return nil, ErrClosed
	}
	if f.open {
		return nil, errFileOpen
	}
	of, err := os.OpenFile(f.path(), os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	f.open = true
	f.fs.open++
	return fileWrap{of, f}, nil
}

func (f *file) Create() (Writer, error) {
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if f.fs.open < 0 {
		return nil, ErrClosed
	}
	if f.open {
		return nil, errFileOpen
	}
	of, err := os.OpenFile(f.path(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return nil, err
	}
	f.open = true
	f.fs.open++
	return fileWrap{of, f}, nil
}

func (f *file) Type() FileType {
	return f.t
}

func (f *file) Num() uint64 {
	return f.num
}

func (f *file) Remove() error {
	f.fs.mu.Lock()
	defer f.fs.mu.Unlock()
	if f.fs.open < 0 {
		return ErrClosed
	}
	if f.open {
		return errFileOpen
	}
	err := os.Remove(f.path())
	if err != nil {
		f.fs.log(fmt.Sprint("remove %s.%d: %v", f.Type(), f.Num(), err))
	}
	return err
}

func (f *file) name() string {
	switch f.t {
	case TypeManifest:
		return fmt.Sprintf("MANIFEST-%06d", f.num)
	case TypeJournal:
		return fmt.Sprintf("%06d.log", f.num)
	case TypeTable:
		return fmt.Sprintf("%06d.sst", f.num)
	default:
		panic("invalid file type")
	}
	return ""
}

func (f *file) path() string {
	return filepath.Join(f.fs.path, f.name())
}

func (f *file) parse(name string) bool {
	var num uint64
	var tail string
	_, err := fmt.Sscanf(name, "%d.%s", &num, &tail)
	if err == nil {
		switch tail {
		case "log":
			f.t = TypeJournal
		case "sst":
			f.t = TypeTable
		default:
			return false
		}
		f.num = num
		return true
	}
	n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &num, &tail)
	if n == 1 {
		f.t = TypeManifest
		f.num = num
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package reform

import (
	"fmt"
	"strings"
)

func filteredColumnsAndValues(str Struct, columnsIn []string, isUpdate bool) (columns []string, values []interface{}, err error) {
	columnsSet := make(map[string]struct{}, len(columnsIn))
	for _, c := range columnsIn {
		columnsSet[c] = struct{}{}
	}

	// select columns from set and collect values
	view := str.View()
	allColumns := view.Columns()
	allValues := str.Values()
	columns = make([]string, 0, len(columnsSet))
	values = make([]interface{}, 0, len(columns))

	record, _ := str.(Record)
	var pk uint
	if record != nil {
		pk = view.(Table).PKColumnIndex()
	}

	for i, c := range allColumns {
		if _, ok := columnsSet[c]; ok {
			if isUpdate && record != nil && i == int(pk) {
				err = fmt.Errorf("reform: will not update PK column: %s", c)
				return
			}
			delete(columnsSet, c)
			columns = append(columns, c)
			values = append(values, allValues[i])
		}
	}

	// make error for extra columns
	if len(columnsSet) > 0 {
		columns = make([]string, 0, len(columnsSet))
		for c := range columnsSet {
			columns = append(columns, c)
		}
		// TODO make exported type for that error
		err = fmt.Errorf("reform: unexpected columns: %v", columns)
		return
	}

	return
}

func (q *Querier) insert(str Struct, columns []string, values []interface{}) error {
	for i, c := range columns {
		columns[i] = q.QuoteIdentifier(c)
	}
	placeholders := q.Placeholders(1, len(columns))

	view := str.View()
	record, _ := str.(Record)
	lastInsertIdMethod := q.LastInsertIdMethod()
	defaultValuesMethod := q.DefaultValuesMethod()

	var pk uint
	if record != nil {
		pk = view.(Table).PKColumnIndex()
	}

	// make query
	query := q.startQuery("INSERT") + " INTO " + q.QualifiedView(view)
	if len(columns) != 0 || defaultValuesMethod == EmptyLists {
		query += " (" + strings.Join(columns, ", ") + ")"
	}
	if record != nil && lastInsertIdMethod == OutputInserted {
		query += fmt.Sprintf(" OUTPUT INSERTED.%s", q.QuoteIdentifier(view.Columns()[pk]))
	}
	if len(placeholders) != 0 || defaultValuesMethod == EmptyLists {
		query += fmt.Sprintf(" VALUES (%s)", strings.Join(placeholders, ", "))
	} else {
		query += " DEFAULT VALUES"
	}
	if record != nil && lastInsertIdMethod == Returning {
		query += fmt.Sprintf(" RETURNING %s", q.QuoteIdentifier(view.Columns()[pk]))
	}

	switch lastInsertIdMethod {
	case LastInsertId:
		res, err := q.Exec(query, values...)
		if err != nil {
			return err
		}
		if record != nil && !record.HasPK() {
			id, err := res.LastInsertId()
			if err != nil {
				return err
			}
			record.SetPK(id)
		}
		return nil

	case Returning, OutputInserted:
		var err error
		if record != nil {
			err = q.QueryRow(query, values...).Scan(record.PKPointer())
		} else {
			_, err = q.Exec(query, values...)
		}
		return err

	default:
		panic("reform: Unhandled LastInsertIdMethod. Please report this bug.")
	}
}

func (q *Querier) beforeInsert(str Struct) error {
	return q.callStructMethod(str, "BeforeInsert")
}

func (q *Querier) afterInsert(str Struct) error {
	return q.callStructMethod(str, "AfterInsert")
}

// Insert inserts a struct into SQL database table.
// If str has valid method "BeforeInsert", it calls BeforeInsert() before doing so.
// If str has valid method "AfterInsert", it calls AfterInsert() after doing so.
//
// It fills record's primary key field.
func (q *Querier) Insert(str Struct) error {
	if err := q.beforeInsert(str); err != nil {
		return err
	}

	view := str.View()
	values := str.Values()
	columns := view.Columns()
	record, _ := str.(Record)

	if record != nil {
		pk := view.(Table).PKColumnIndex()

		// cut primary key
		if !record.HasPK() {
			values = append(values[:pk], values[pk+1:]...)
			columns = append(columns[:pk], columns[pk+1:]...)
		}
	}

	err = q.insert(str, columns, values)

	if err == nil {
		return q.afterInsert(str)
	}

	return nil
}

// InsertColumns inserts a struct into SQL database table with specified columns.
// Other columns are omitted from generated INSERT statement.
// If str has valid method "BeforeInsert", it calls BeforeInsert() before doing so.
// If str has valid method "AfterInsert", it calls AfterInsert() after doing so.
//
// It fills record's primary key field.
func (q *Querier) InsertColumns(str Struct, columns ...string) error {
	if err := q.beforeInsert(str); err != nil {
		return err
	}

	columns, values, err := filteredColumnsAndValues(str, columns, false)
	if err != nil {
		return err
	}

	err = q.insert(str, columns, values)

	if err == nil {
		return q.afterInsert(str)
	}

	return nil
}

// InsertMulti inserts several structs into SQL database table with single query.
// If they has valid method "BeforeInsert", it calls BeforeInsert() before doing so.
//
// All structs should belong to the same view/table.
// All records should either have or not have primary key set.
// It doesn't fill primary key fields.
// Given all these limitations, most users should use Querier.Insert in a loop, not this method.
func (q *Querier) InsertMulti(structs ...Struct) error {
	if len(structs) == 0 {
		return nil
	}

	// check that view is the same
	view := structs[0].View()
	for _, str := range structs {
		if str.View() != view {
			return fmt.Errorf("reform: different tables in InsertMulti: %s and %s", view.Name(), str.View().Name())
		}
	}

	for _, str := range structs {
		err := q.callStructMethod(str, "BeforeInsert")
		if err != nil {
			return err
		}
	}

	// check if all PK are present or all are absent
	record, _ := structs[0].(Record)
	if record != nil {
		for _, str := range structs {
			rec, _ := str.(Record)
			if record.HasPK() != rec.HasPK() {
				return fmt.Errorf("reform: PK in present in one struct and absent in other: first: %s, second: %s",
					record, rec)
			}
		}
	}

	columns := view.Columns()
	for i, c := range columns {
		columns[i] = q.QuoteIdentifier(c)
	}

	var pk uint
	if record != nil && !record.HasPK() {
		pk = view.(Table).PKColumnIndex()
		columns = append(columns[:pk], columns[pk+1:]...)
	}

	placeholders := q.Placeholders(1, len(columns)*len(structs))
	query := fmt.Sprintf("%s INTO %s (%s) VALUES ",
		q.startQuery("INSERT"),
		q.QualifiedView(view),
		strings.Join(columns, ", "),
	)
	for i := 0; i < len(structs); i++ {
		query += fmt.Sprintf("(%s), ", strings.Join(placeholders[len(columns)*i:len(columns)*(i+1)], ", "))
	}
	query = query[:len(query)-2] // cut last ", "

	values := make([]interface{}, 0, len(placeholders))
	for _, str := range structs {
		v := str.Values()
		if record != nil && !record.HasPK() {
			v = append(v[:pk], v[pk+1:]...)
		}
		values = append(values, v...)
	}

	_, err := q.Exec(query, values...)
	return err
}

func (q *Querier) update(record Record, columns []string, values []interface{}) error {
	for i, c := range columns {
		columns[i] = q.QuoteIdentifier(c)
	}
	placeholders := q.Placeholders(1, len(columns))

	p := make([]string, len(columns))
	for i, c := range columns {
		p[i] = c + " = " + placeholders[i]
	}
	table := record.Table()
	query := fmt.Sprintf("%s %s SET %s WHERE %s = %s",
		q.startQuery("UPDATE"),
		q.QualifiedView(table),
		strings.Join(p, ", "),
		q.QuoteIdentifier(table.Columns()[table.PKColumnIndex()]),
		q.Placeholder(len(columns)+1),
	)

	args := append(values, record.PKValue())
	res, err := q.Exec(query, args...)
	if err != nil {
		return err
	}
	ra, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if ra == 0 {
		return ErrNoRows
	}
	if ra > 1 {
		panic(fmt.Sprintf("reform: %d rows by UPDATE by primary key. Please report this bug.", ra))
	}
	return nil
}

func (q *Querier) beforeUpdate(record Record) error {
	if !record.HasPK() {
		return ErrNoPK
	}

	return q.callStructMethod(record, "BeforeUpdate")
}

func (q *Querier) afterUpdate(record Record) error {
	return q.callStructMethod(record, "AfterUpdate")
}

// Update updates all columns of row specified by primary key in SQL database table with given record.
// If record has valid method "BeforeUpdate", it calls BeforeUpdate() before doing so.
// If record has valid method "AfterUpdate", it calls AfterUpdate() before doing so.
//
// Method returns ErrNoRows if no rows were updated.
// Method returns ErrNoPK if primary key is not set.
func (q *Querier) Update(record Record) error {
	if err := q.beforeUpdate(record); err != nil {
		return err
	}

	table := record.Table()
	values := record.Values()
	columns := table.Columns()

	// cut primary key
	pk := table.PKColumnIndex()
	values = append(values[:pk], values[pk+1:]...)
	columns = append(columns[:pk], columns[pk+1:]...)

	err = q.update(record, columns, values)

	if err == nil {
		return q.afterUpdate(record)
	}
	return nil
}

// UpdateColumns updates specified columns of row specified by primary key in SQL database table with given record.
// Other columns are omitted from generated UPDATE statement.
// If record has valid method "BeforeUpdate", it calls BeforeUpdate() before doing so.
// If record has valid method "AfterUpdate", it calls AfterUpdate() before doing so.
//
// Method returns ErrNoRows if no rows were updated.
// Method returns ErrNoPK if primary key is not set.
func (q *Querier) UpdateColumns(record Record, columns ...string) error {
	if err := q.beforeUpdate(record); err != nil {
		return err
	}

	columns, values, err := filteredColumnsAndValues(record, columns, true)
	if err != nil {
		return err
	}

	if len(values) == 0 {
		// TODO make exported type for that error
		return fmt.Errorf("reform: nothing to update")
	}

	err = q.update(record, columns, values)

	if err == nil {
		return q.afterUpdate(record)
	}
	return nil
}

// Save saves record in SQL database table.
// If primary key is set, it first calls Update and checks if row was updated.
// If primary key is absent or no row was updated, it calls Insert.
func (q *Querier) Save(record Record) error {
	if record.HasPK() {
		err := q.Update(record)
		if err != ErrNoRows {
			return err
		}
	}

	return q.Insert(record)
}

func (q *Querier) beforeDelete(record Record) error {
	if !record.HasPK() {
		return ErrNoPK
	}

	return q.callStructMethod(record, "BeforeDelete")
}

func (q *Querier) afterDelete(record Record) error {
	return q.callStructMethod(record, "AfterDelete")
}

// Delete deletes record from SQL database table by primary key.
// If record has valid method "BeforeDelete", it calls BeforeDelete() before doing so.
// If record has valid method "AfterDelete", it calls AfterDelete() before doing so.
//
// Method returns ErrNoRows if no rows were deleted.
// Method returns ErrNoPK if primary key is not set.
func (q *Querier) Delete(record Record) error {
	err := q.beforeDelete(record)
	if err != nil {
		return err
	}

	table := record.Table()
	pk := table.PKColumnIndex()
	query := fmt.Sprintf("%s FROM %s WHERE %s = %s",
		q.startQuery("DELETE"),
		q.QualifiedView(table),
		q.QuoteIdentifier(table.Columns()[pk]),
		q.Placeholder(1),
	)

	res, err := q.Exec(query, record.PKValue())
	if err != nil {
		return err
	}
	ra, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if ra == 0 {
		return ErrNoRows
	}
	if ra > 1 {
		panic(fmt.Sprintf("reform: %d rows by DELETE by primary key. Please report this bug.", ra))
	}
	return q.afterDelete(record)
}

// DeleteFrom deletes rows from view with tail and args and returns a number of deleted rows.
//
// Method never returns ErrNoRows.
func (q *Querier) DeleteFrom(view View, tail string, args ...interface{}) (uint, error) {
	query := fmt.Sprintf("%s FROM %s %s",
		q.startQuery("DELETE"),
		q.QualifiedView(view),
		tail,
	)

	res, err := q.Exec(query, args...)
	if err != nil {
		return 0, err
	}
	ra, err := res.RowsAffected()
	if err != nil {
		return 0, err
	}
	return uint(ra), nil
}
<commit_msg>Continued cb33a8f5d63ab7a43b9ac24fbf5b751bdc364edf<commit_after>package reform

import (
	"fmt"
	"strings"
)

func filteredColumnsAndValues(str Struct, columnsIn []string, isUpdate bool) (columns []string, values []interface{}, err error) {
	columnsSet := make(map[string]struct{}, len(columnsIn))
	for _, c := range columnsIn {
		columnsSet[c] = struct{}{}
	}

	// select columns from set and collect values
	view := str.View()
	allColumns := view.Columns()
	allValues := str.Values()
	columns = make([]string, 0, len(columnsSet))
	values = make([]interface{}, 0, len(columns))

	record, _ := str.(Record)
	var pk uint
	if record != nil {
		pk = view.(Table).PKColumnIndex()
	}

	for i, c := range allColumns {
		if _, ok := columnsSet[c]; ok {
			if isUpdate && record != nil && i == int(pk) {
				err = fmt.Errorf("reform: will not update PK column: %s", c)
				return
			}
			delete(columnsSet, c)
			columns = append(columns, c)
			values = append(values, allValues[i])
		}
	}

	// make error for extra columns
	if len(columnsSet) > 0 {
		columns = make([]string, 0, len(columnsSet))
		for c := range columnsSet {
			columns = append(columns, c)
		}
		// TODO make exported type for that error
		err = fmt.Errorf("reform: unexpected columns: %v", columns)
		return
	}

	return
}

func (q *Querier) insert(str Struct, columns []string, values []interface{}) error {
	for i, c := range columns {
		columns[i] = q.QuoteIdentifier(c)
	}
	placeholders := q.Placeholders(1, len(columns))

	view := str.View()
	record, _ := str.(Record)
	lastInsertIdMethod := q.LastInsertIdMethod()
	defaultValuesMethod := q.DefaultValuesMethod()

	var pk uint
	if record != nil {
		pk = view.(Table).PKColumnIndex()
	}

	// make query
	query := q.startQuery("INSERT") + " INTO " + q.QualifiedView(view)
	if len(columns) != 0 || defaultValuesMethod == EmptyLists {
		query += " (" + strings.Join(columns, ", ") + ")"
	}
	if record != nil && lastInsertIdMethod == OutputInserted {
		query += fmt.Sprintf(" OUTPUT INSERTED.%s", q.QuoteIdentifier(view.Columns()[pk]))
	}
	if len(placeholders) != 0 || defaultValuesMethod == EmptyLists {
		query += fmt.Sprintf(" VALUES (%s)", strings.Join(placeholders, ", "))
	} else {
		query += " DEFAULT VALUES"
	}
	if record != nil && lastInsertIdMethod == Returning {
		query += fmt.Sprintf(" RETURNING %s", q.QuoteIdentifier(view.Columns()[pk]))
	}

	switch lastInsertIdMethod {
	case LastInsertId:
		res, err := q.Exec(query, values...)
		if err != nil {
			return err
		}
		if record != nil && !record.HasPK() {
			id, err := res.LastInsertId()
			if err != nil {
				return err
			}
			record.SetPK(id)
		}
		return nil

	case Returning, OutputInserted:
		var err error
		if record != nil {
			err = q.QueryRow(query, values...).Scan(record.PKPointer())
		} else {
			_, err = q.Exec(query, values...)
		}
		return err

	default:
		panic("reform: Unhandled LastInsertIdMethod. Please report this bug.")
	}
}

func (q *Querier) beforeInsert(str Struct) error {
	return q.callStructMethod(str, "BeforeInsert")
}

func (q *Querier) afterInsert(str Struct) error {
	return q.callStructMethod(str, "AfterInsert")
}

// Insert inserts a struct into SQL database table.
// If str has valid method "BeforeInsert", it calls BeforeInsert() before doing so.
// If str has valid method "AfterInsert", it calls AfterInsert() after doing so.
//
// It fills record's primary key field.
func (q *Querier) Insert(str Struct) error {
	if err := q.beforeInsert(str); err != nil {
		return err
	}

	view := str.View()
	values := str.Values()
	columns := view.Columns()
	record, _ := str.(Record)

	if record != nil {
		pk := view.(Table).PKColumnIndex()

		// cut primary key
		if !record.HasPK() {
			values = append(values[:pk], values[pk+1:]...)
			columns = append(columns[:pk], columns[pk+1:]...)
		}
	}

	err := q.insert(str, columns, values)

	if err == nil {
		return q.afterInsert(str)
	}

	return nil
}

// InsertColumns inserts a struct into SQL database table with specified columns.
// Other columns are omitted from generated INSERT statement.
// If str has valid method "BeforeInsert", it calls BeforeInsert() before doing so.
// If str has valid method "AfterInsert", it calls AfterInsert() after doing so.
//
// It fills record's primary key field.
func (q *Querier) InsertColumns(str Struct, columns ...string) error {
	if err := q.beforeInsert(str); err != nil {
		return err
	}

	columns, values, err := filteredColumnsAndValues(str, columns, false)
	if err != nil {
		return err
	}

	err = q.insert(str, columns, values)

	if err == nil {
		return q.afterInsert(str)
	}

	return nil
}

// InsertMulti inserts several structs into SQL database table with single query.
// If they has valid method "BeforeInsert", it calls BeforeInsert() before doing so.
//
// All structs should belong to the same view/table.
// All records should either have or not have primary key set.
// It doesn't fill primary key fields.
// Given all these limitations, most users should use Querier.Insert in a loop, not this method.
func (q *Querier) InsertMulti(structs ...Struct) error {
	if len(structs) == 0 {
		return nil
	}

	// check that view is the same
	view := structs[0].View()
	for _, str := range structs {
		if str.View() != view {
			return fmt.Errorf("reform: different tables in InsertMulti: %s and %s", view.Name(), str.View().Name())
		}
	}

	for _, str := range structs {
		err := q.callStructMethod(str, "BeforeInsert")
		if err != nil {
			return err
		}
	}

	// check if all PK are present or all are absent
	record, _ := structs[0].(Record)
	if record != nil {
		for _, str := range structs {
			rec, _ := str.(Record)
			if record.HasPK() != rec.HasPK() {
				return fmt.Errorf("reform: PK in present in one struct and absent in other: first: %s, second: %s",
					record, rec)
			}
		}
	}

	columns := view.Columns()
	for i, c := range columns {
		columns[i] = q.QuoteIdentifier(c)
	}

	var pk uint
	if record != nil && !record.HasPK() {
		pk = view.(Table).PKColumnIndex()
		columns = append(columns[:pk], columns[pk+1:]...)
	}

	placeholders := q.Placeholders(1, len(columns)*len(structs))
	query := fmt.Sprintf("%s INTO %s (%s) VALUES ",
		q.startQuery("INSERT"),
		q.QualifiedView(view),
		strings.Join(columns, ", "),
	)
	for i := 0; i < len(structs); i++ {
		query += fmt.Sprintf("(%s), ", strings.Join(placeholders[len(columns)*i:len(columns)*(i+1)], ", "))
	}
	query = query[:len(query)-2] // cut last ", "

	values := make([]interface{}, 0, len(placeholders))
	for _, str := range structs {
		v := str.Values()
		if record != nil && !record.HasPK() {
			v = append(v[:pk], v[pk+1:]...)
		}
		values = append(values, v...)
	}

	_, err := q.Exec(query, values...)
	return err
}

func (q *Querier) update(record Record, columns []string, values []interface{}) error {
	for i, c := range columns {
		columns[i] = q.QuoteIdentifier(c)
	}
	placeholders := q.Placeholders(1, len(columns))

	p := make([]string, len(columns))
	for i, c := range columns {
		p[i] = c + " = " + placeholders[i]
	}
	table := record.Table()
	query := fmt.Sprintf("%s %s SET %s WHERE %s = %s",
		q.startQuery("UPDATE"),
		q.QualifiedView(table),
		strings.Join(p, ", "),
		q.QuoteIdentifier(table.Columns()[table.PKColumnIndex()]),
		q.Placeholder(len(columns)+1),
	)

	args := append(values, record.PKValue())
	res, err := q.Exec(query, args...)
	if err != nil {
		return err
	}
	ra, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if ra == 0 {
		return ErrNoRows
	}
	if ra > 1 {
		panic(fmt.Sprintf("reform: %d rows by UPDATE by primary key. Please report this bug.", ra))
	}
	return nil
}

func (q *Querier) beforeUpdate(record Record) error {
	if !record.HasPK() {
		return ErrNoPK
	}

	return q.callStructMethod(record, "BeforeUpdate")
}

func (q *Querier) afterUpdate(record Record) error {
	return q.callStructMethod(record, "AfterUpdate")
}

// Update updates all columns of row specified by primary key in SQL database table with given record.
// If record has valid method "BeforeUpdate", it calls BeforeUpdate() before doing so.
// If record has valid method "AfterUpdate", it calls AfterUpdate() before doing so.
//
// Method returns ErrNoRows if no rows were updated.
// Method returns ErrNoPK if primary key is not set.
func (q *Querier) Update(record Record) error {
	if err := q.beforeUpdate(record); err != nil {
		return err
	}

	table := record.Table()
	values := record.Values()
	columns := table.Columns()

	// cut primary key
	pk := table.PKColumnIndex()
	values = append(values[:pk], values[pk+1:]...)
	columns = append(columns[:pk], columns[pk+1:]...)

	err := q.update(record, columns, values)

	if err == nil {
		return q.afterUpdate(record)
	}
	return nil
}

// UpdateColumns updates specified columns of row specified by primary key in SQL database table with given record.
// Other columns are omitted from generated UPDATE statement.
// If record has valid method "BeforeUpdate", it calls BeforeUpdate() before doing so.
// If record has valid method "AfterUpdate", it calls AfterUpdate() before doing so.
//
// Method returns ErrNoRows if no rows were updated.
// Method returns ErrNoPK if primary key is not set.
func (q *Querier) UpdateColumns(record Record, columns ...string) error {
	if err := q.beforeUpdate(record); err != nil {
		return err
	}

	columns, values, err := filteredColumnsAndValues(record, columns, true)
	if err != nil {
		return err
	}

	if len(values) == 0 {
		// TODO make exported type for that error
		return fmt.Errorf("reform: nothing to update")
	}

	err = q.update(record, columns, values)

	if err == nil {
		return q.afterUpdate(record)
	}
	return nil
}

// Save saves record in SQL database table.
// If primary key is set, it first calls Update and checks if row was updated.
// If primary key is absent or no row was updated, it calls Insert.
func (q *Querier) Save(record Record) error {
	if record.HasPK() {
		err := q.Update(record)
		if err != ErrNoRows {
			return err
		}
	}

	return q.Insert(record)
}

func (q *Querier) beforeDelete(record Record) error {
	if !record.HasPK() {
		return ErrNoPK
	}

	return q.callStructMethod(record, "BeforeDelete")
}

func (q *Querier) afterDelete(record Record) error {
	return q.callStructMethod(record, "AfterDelete")
}

// Delete deletes record from SQL database table by primary key.
// If record has valid method "BeforeDelete", it calls BeforeDelete() before doing so.
// If record has valid method "AfterDelete", it calls AfterDelete() before doing so.
//
// Method returns ErrNoRows if no rows were deleted.
// Method returns ErrNoPK if primary key is not set.
func (q *Querier) Delete(record Record) error {
	err := q.beforeDelete(record)
	if err != nil {
		return err
	}

	table := record.Table()
	pk := table.PKColumnIndex()
	query := fmt.Sprintf("%s FROM %s WHERE %s = %s",
		q.startQuery("DELETE"),
		q.QualifiedView(table),
		q.QuoteIdentifier(table.Columns()[pk]),
		q.Placeholder(1),
	)

	res, err := q.Exec(query, record.PKValue())
	if err != nil {
		return err
	}
	ra, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if ra == 0 {
		return ErrNoRows
	}
	if ra > 1 {
		panic(fmt.Sprintf("reform: %d rows by DELETE by primary key. Please report this bug.", ra))
	}
	return q.afterDelete(record)
}

// DeleteFrom deletes rows from view with tail and args and returns a number of deleted rows.
//
// Method never returns ErrNoRows.
func (q *Querier) DeleteFrom(view View, tail string, args ...interface{}) (uint, error) {
	query := fmt.Sprintf("%s FROM %s %s",
		q.startQuery("DELETE"),
		q.QualifiedView(view),
		tail,
	)

	res, err := q.Exec(query, args...)
	if err != nil {
		return 0, err
	}
	ra, err := res.RowsAffected()
	if err != nil {
		return 0, err
	}
	return uint(ra), nil
}
<|endoftext|>


<commit_before>package app

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gilcrest/go-api-basic/domain/errs"
	"github.com/google/go-cmp/cmp"
	"github.com/pkg/errors"

	qt "github.com/frankban/quicktest"
	"github.com/gilcrest/go-api-basic/domain/auth"
)

func TestJSONContentTypeResponseHandler(t *testing.T) {

	s := Server{}

	req, err := http.NewRequest("GET", "/ping", nil)
	if err != nil {
		t.Fatalf("http.NewRequest() error = %v", err)
	}

	testJSONContentTypeResponseHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		contentType := w.Header().Get("Content-Type")
		if contentType != "application/json" {
			t.Fatalf("Content-Type %s is invalid", contentType)
		}
	})

	rr := httptest.NewRecorder()

	handlers := s.JSONContentTypeResponseHandler(testJSONContentTypeResponseHandler)
	handlers.ServeHTTP(rr, req)
}

func TestAccessTokenHandler(t *testing.T) {
	t.Run("typical", func(t *testing.T) {
		c := qt.New(t)

		req, err := http.NewRequest("GET", "/ping", nil)
		if err != nil {
			t.Fatalf("http.NewRequest() error = %v", err)
		}
		req.Header.Add("Authorization", auth.BearerTokenType+" abcdef123")

		testAccessTokenHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			token, ok := auth.AccessTokenFromRequest(r)
			if !ok {
				t.Fatal("auth.AccessTokenFromRequest() !ok")
			}
			wantToken := auth.AccessToken{
				Token:     "abcdef123",
				TokenType: auth.BearerTokenType,
			}
			c.Assert(token, qt.Equals, wantToken)
		})

		rr := httptest.NewRecorder()

		s := Server{}

		handlers := s.DefaultRealmHandler(s.AccessTokenHandler(testAccessTokenHandler))
		handlers.ServeHTTP(rr, req)

		// If there is any issues with the Access Token, the body
		// should be empty and the status code should be 401
		c.Assert(rr.Code, qt.Equals, http.StatusOK)
	})

	// Authorization header is not added at all
	t.Run("no auth header", func(t *testing.T) {
		c := qt.New(t)

		req, err := http.NewRequest("GET", "/ping", nil)
		if err != nil {
			t.Fatalf("http.NewRequest() error = %v", err)
		}

		testAccessTokenHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			c.Fatal("handler should not make it here")
		})

		rr := httptest.NewRecorder()

		s := Server{}

		handlers := s.DefaultRealmHandler(s.AccessTokenHandler(testAccessTokenHandler))
		handlers.ServeHTTP(rr, req)

		body, err := ioutil.ReadAll(rr.Body)
		if err != nil {
			t.Fatalf("ioutil.ReadAll() error = %v", err)
		}

		// If there is any issues with the Access Token, the status
		// code should be 401, and the body should be empty
		c.Assert(rr.Code, qt.Equals, http.StatusUnauthorized)
		c.Assert(string(body), qt.Equals, "")
	})
}

func Test_authHeader(t *testing.T) {
	c := qt.New(t)

	const realm auth.WWWAuthenticateRealm = "DeepInTheRealm"
	const reqHeader string = "Authorization"

	type args struct {
		realm  auth.WWWAuthenticateRealm
		header http.Header
	}

	hdr := http.Header{}
	hdr.Add(reqHeader, "Bearer foobarbbq")

	emptyHdr := http.Header{}
	emptyHdrErr := errs.NewUnauthenticatedError(string(realm), errors.New("unauthenticated: no Authorization header sent"))

	noBearer := http.Header{}
	noBearer.Add(reqHeader, "xyz")
	noBearerErr := errs.NewUnauthenticatedError(string(realm), errors.New("unauthenticated: Bearer authentication scheme not found"))

	hdrSpacesBearer := http.Header{}
	hdrSpacesBearer.Add("Authorization", "Bearer  ")
	spacesHdrErr := errs.NewUnauthenticatedError(string(realm), errors.New("unauthenticated: Authorization header sent with Bearer scheme, but no token found"))

	tests := []struct {
		name      string
		args      args
		wantToken string
		wantErr   error
	}{
		{"typical", args{realm: realm, header: hdr}, "foobarbbq", nil},
		{"no authorization header", args{realm: realm, header: emptyHdr}, "", emptyHdrErr},
		{"no bearer scheme", args{realm: realm, header: noBearer}, "", noBearerErr},
		{"spaces as token", args{realm: realm, header: hdrSpacesBearer}, "", spacesHdrErr},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotToken, err := authHeader(tt.args.realm, tt.args.header)
			if (err != nil) && (tt.wantErr == nil) {
				t.Errorf("authHeader() error = %v, nil expected", err)
				return
			}
			c.Assert(err, qt.CmpEquals(cmp.Comparer(errs.MatchUnauthenticated)), tt.wantErr)
			c.Assert(gotToken, qt.Equals, tt.wantToken)
		})
	}
}
<commit_msg>make middleware methods private<commit_after>package app

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gilcrest/go-api-basic/domain/errs"
	"github.com/google/go-cmp/cmp"
	"github.com/pkg/errors"

	qt "github.com/frankban/quicktest"
	"github.com/gilcrest/go-api-basic/domain/auth"
)

func TestJSONContentTypeResponseHandler(t *testing.T) {

	s := Server{}

	req, err := http.NewRequest("GET", "/ping", nil)
	if err != nil {
		t.Fatalf("http.NewRequest() error = %v", err)
	}

	testJSONContentTypeResponseHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		contentType := w.Header().Get("Content-Type")
		if contentType != "application/json" {
			t.Fatalf("Content-Type %s is invalid", contentType)
		}
	})

	rr := httptest.NewRecorder()

	handlers := s.jsonContentTypeResponseHandler(testJSONContentTypeResponseHandler)
	handlers.ServeHTTP(rr, req)
}

func TestAccessTokenHandler(t *testing.T) {
	t.Run("typical", func(t *testing.T) {
		c := qt.New(t)

		req, err := http.NewRequest("GET", "/ping", nil)
		if err != nil {
			t.Fatalf("http.NewRequest() error = %v", err)
		}
		req.Header.Add("Authorization", auth.BearerTokenType+" abcdef123")

		testAccessTokenHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			token, ok := auth.AccessTokenFromRequest(r)
			if !ok {
				t.Fatal("auth.AccessTokenFromRequest() !ok")
			}
			wantToken := auth.AccessToken{
				Token:     "abcdef123",
				TokenType: auth.BearerTokenType,
			}
			c.Assert(token, qt.Equals, wantToken)
		})

		rr := httptest.NewRecorder()

		s := Server{}

		handlers := s.defaultRealmHandler(s.accessTokenHandler(testAccessTokenHandler))
		handlers.ServeHTTP(rr, req)

		// If there is any issues with the Access Token, the body
		// should be empty and the status code should be 401
		c.Assert(rr.Code, qt.Equals, http.StatusOK)
	})

	// Authorization header is not added at all
	t.Run("no auth header", func(t *testing.T) {
		c := qt.New(t)

		req, err := http.NewRequest("GET", "/ping", nil)
		if err != nil {
			t.Fatalf("http.NewRequest() error = %v", err)
		}

		testAccessTokenHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			c.Fatal("handler should not make it here")
		})

		rr := httptest.NewRecorder()

		s := Server{}

		handlers := s.defaultRealmHandler(s.accessTokenHandler(testAccessTokenHandler))
		handlers.ServeHTTP(rr, req)

		body, err := ioutil.ReadAll(rr.Body)
		if err != nil {
			t.Fatalf("ioutil.ReadAll() error = %v", err)
		}

		// If there is any issues with the Access Token, the status
		// code should be 401, and the body should be empty
		c.Assert(rr.Code, qt.Equals, http.StatusUnauthorized)
		c.Assert(string(body), qt.Equals, "")
	})
}

func Test_authHeader(t *testing.T) {
	c := qt.New(t)

	const realm auth.WWWAuthenticateRealm = "DeepInTheRealm"
	const reqHeader string = "Authorization"

	type args struct {
		realm  auth.WWWAuthenticateRealm
		header http.Header
	}

	hdr := http.Header{}
	hdr.Add(reqHeader, "Bearer foobarbbq")

	emptyHdr := http.Header{}
	emptyHdrErr := errs.NewUnauthenticatedError(string(realm), errors.New("unauthenticated: no Authorization header sent"))

	noBearer := http.Header{}
	noBearer.Add(reqHeader, "xyz")
	noBearerErr := errs.NewUnauthenticatedError(string(realm), errors.New("unauthenticated: Bearer authentication scheme not found"))

	hdrSpacesBearer := http.Header{}
	hdrSpacesBearer.Add("Authorization", "Bearer  ")
	spacesHdrErr := errs.NewUnauthenticatedError(string(realm), errors.New("unauthenticated: Authorization header sent with Bearer scheme, but no token found"))

	tests := []struct {
		name      string
		args      args
		wantToken string
		wantErr   error
	}{
		{"typical", args{realm: realm, header: hdr}, "foobarbbq", nil},
		{"no authorization header", args{realm: realm, header: emptyHdr}, "", emptyHdrErr},
		{"no bearer scheme", args{realm: realm, header: noBearer}, "", noBearerErr},
		{"spaces as token", args{realm: realm, header: hdrSpacesBearer}, "", spacesHdrErr},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotToken, err := authHeader(tt.args.realm, tt.args.header)
			if (err != nil) && (tt.wantErr == nil) {
				t.Errorf("authHeader() error = %v, nil expected", err)
				return
			}
			c.Assert(err, qt.CmpEquals(cmp.Comparer(errs.MatchUnauthenticated)), tt.wantErr)
			c.Assert(gotToken, qt.Equals, tt.wantToken)
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"testing"

	"fmt"
	"github.com/tg123/sshpiper/sshpiperd/auditor"
	"github.com/tg123/sshpiper/sshpiperd/challenger"
	"github.com/tg123/sshpiper/sshpiperd/registry"
	"github.com/tg123/sshpiper/sshpiperd/upstream"
	"golang.org/x/crypto/ssh"
	"net"
	"time"
)

type testplugin struct {
	name string
	init func(logger *log.Logger) error
}

func (p *testplugin) GetName() string {
	return p.name
}

func (p *testplugin) GetOpts() interface{} {
	return nil
}

func (p *testplugin) Init(logger *log.Logger) error {
	if p.init == nil {
		return nil
	}
	return p.init(logger)
}

func Test_getAndInstall(t *testing.T) {

	// ignore empty
	getAndInstall("", func(n string) registry.Plugin {
		t.Errorf("should not call get")
		return nil
	}, func(plugin registry.Plugin) error {
		t.Errorf("should not call install")
		return nil
	}, nil)

	// fail when not found
	err := getAndInstall("test", func(n string) registry.Plugin {
		if n != "test" {
			t.Errorf("plugin name changed")
		}
		return nil
	}, func(plugin registry.Plugin) error {
		t.Errorf("should not call install")
		return nil
	}, nil)

	if err == nil {
		t.Errorf("should err when not found")
	}

	// init err
	err = getAndInstall("test", func(n string) registry.Plugin {
		return &testplugin{
			init: func(logger *log.Logger) error {
				return fmt.Errorf("init failed")
			},
		}
	}, func(plugin registry.Plugin) error {
		return fmt.Errorf("test")
	}, nil)

	if err == nil {
		t.Errorf("should err when not found")
	}

	// call init
	inited := false
	installed := false
	err = getAndInstall("test", func(n string) registry.Plugin {
		if n != "test" {
			t.Errorf("plugin name changed")
		}
		return &testplugin{
			init: func(logger *log.Logger) error {
				inited = true
				return nil
			},
		}
	}, func(plugin registry.Plugin) error {
		if !inited {
			t.Errorf("not inited")
		}

		installed = true
		return nil
	}, nil)

	if !installed {
		t.Errorf("not installed")
	}

	if err != nil {
		t.Errorf("should err when not found")
	}
}

type testupstream struct {
	testplugin

	h upstream.Handler
}

func (t *testupstream) GetHandler() upstream.Handler {
	return t.h
}

type testchallenger struct {
	testplugin

	h challenger.Handler
}

func (t *testchallenger) GetHandler() challenger.Handler {
	return t.h
}

type testauditorprovider struct {
	testplugin

	a auditor.Auditor
}

func (t *testauditorprovider) Create(ssh.ConnMetadata) (auditor.Auditor, error) {
	return t.a, nil
}

type testauditor struct {
	up   auditor.Hook
	down auditor.Hook
}

func (t *testauditor) GetUpstreamHook() auditor.Hook {
	return t.up
}

func (t *testauditor) GetDownstreamHook() auditor.Hook {
	return t.down
}

func (t *testauditor) Close() error {
	return nil
}

func Test_installDriver(t *testing.T) {
	var (
		upstreamName    = fmt.Sprintf("u_%v", time.Now().UTC().UnixNano())
		challengerName  = fmt.Sprintf("c_%v", time.Now().UTC().UnixNano())
		auditorName     = fmt.Sprintf("a_%v", time.Now().UTC().UnixNano())
		upstreamErrName = fmt.Sprintf("ue_%v", time.Now().UTC().UnixNano())
		upstreamNilName = fmt.Sprintf("un_%v", time.Now().UTC().UnixNano())
	)

	findUpstream := func(conn ssh.ConnMetadata) (net.Conn, *ssh.AuthPipe, error) {
		return nil, nil, nil
	}

	upstream.Register(upstreamName, &testupstream{
		testplugin: testplugin{
			name: upstreamName,
		},
		h: findUpstream,
	})

	upstream.Register(upstreamErrName, &testupstream{
		testplugin: testplugin{
			name: upstreamErrName,
			init: func(logger *log.Logger) error {
				return fmt.Errorf("test err")
			},
		},
		h: findUpstream,
	})

	upstream.Register(upstreamNilName, &testupstream{
		testplugin: testplugin{
			name: upstreamNilName,
		},
		h: nil,
	})

	challenger.Register(challengerName, &testchallenger{
		testplugin: testplugin{
			name: upstreamName,
		},
		h: func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) {
			return true, nil
		},
	})

	auditor.Register(auditorName, &testauditorprovider{})

	// empty driver name
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: "",
		}, nil)

		if err == nil {
			t.Errorf("should fail when empty driver")
		}
	}

	// install upstream
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamName,
		}, nil)

		if err != nil {
			t.Errorf("install failed %v", err)
		}

		if _, _, err := piper.FindUpstream(nil); err != nil {
			t.Errorf("install wrong func")
		}

		if piper.AdditionalChallenge != nil {
			t.Errorf("should not install challenger")
		}
	}

	// install upstream with failed init
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamErrName,
		}, nil)

		if err == nil {
			t.Errorf("install should fail")
		}

		if piper.FindUpstream != nil {
			t.Errorf("should not install upstream provider")
		}

		if piper.AdditionalChallenge != nil {
			t.Errorf("should not install challenger")
		}
	}

	// install upstream with nil handler
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamNilName,
		}, nil)

		if err == nil {
			t.Errorf("install should fail")
		}

		if piper.FindUpstream != nil {
			t.Errorf("should not install upstream provider")
		}

		if piper.AdditionalChallenge != nil {
			t.Errorf("should not install challenger")
		}
	}

	// install challenger
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver:   upstreamName,
			ChallengerDriver: challengerName,
		}, nil)

		if err != nil {
			t.Errorf("install failed %v", err)
		}

		if ok, err := piper.AdditionalChallenge(nil, nil); err != nil || !ok {
			t.Errorf("should install challenger")
		}
	}

	// install auditor
	{
		piper := &ssh.PiperConfig{}
		ap, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamName,
			AuditorDriver:  auditorName,
		}, nil)

		if err != nil {
			t.Errorf("install failed %v", err)
		}

		if ap == nil {
			t.Errorf("nil auditor provider")
		}

		ap0 := ap.(*testauditorprovider)

		ap0.a = &testauditor{
			up: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) {
				msg[0] = 42
				return msg, nil
			},
			down: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) {
				msg[0] = 100
				return msg, nil
			},
		}

		a, err := ap.Create(nil)
		if err != nil {
			t.Errorf("install failed %v", err)
		}

		m := []byte{0}

		a.GetUpstreamHook()(nil, m)
		if m[0] != 42 {
			t.Errorf("upstream not handled")
		}

		a.GetDownstreamHook()(nil, m)
		if m[0] != 100 {
			t.Errorf("downstream not handled")
		}
	}
}
<commit_msg>add missing test file<commit_after>package main

import (
	"log"
	"testing"

	"fmt"
	"github.com/tg123/sshpiper/sshpiperd/auditor"
	"github.com/tg123/sshpiper/sshpiperd/challenger"
	"github.com/tg123/sshpiper/sshpiperd/registry"
	"github.com/tg123/sshpiper/sshpiperd/upstream"
	"golang.org/x/crypto/ssh"
	"net"
	"time"
)

type testplugin struct {
	name string
	init func(logger *log.Logger) error
}

func (p *testplugin) GetName() string {
	return p.name
}

func (p *testplugin) GetOpts() interface{} {
	return nil
}

func (p *testplugin) Init(logger *log.Logger) error {
	if p.init == nil {
		return nil
	}
	return p.init(logger)
}

func Test_getAndInstall(t *testing.T) {

	// ignore empty
	getAndInstall("", "", func(n string) registry.Plugin {
		t.Errorf("should not call get")
		return nil
	}, func(plugin registry.Plugin) error {
		t.Errorf("should not call install")
		return nil
	}, nil)

	// fail when not found
	err := getAndInstall("", "test", func(n string) registry.Plugin {
		if n != "test" {
			t.Errorf("plugin name changed")
		}
		return nil
	}, func(plugin registry.Plugin) error {
		t.Errorf("should not call install")
		return nil
	}, nil)

	if err == nil {
		t.Errorf("should err when not found")
	}

	// init err
	err = getAndInstall("", "test", func(n string) registry.Plugin {
		return &testplugin{
			init: func(logger *log.Logger) error {
				return fmt.Errorf("init failed")
			},
		}
	}, func(plugin registry.Plugin) error {
		return fmt.Errorf("test")
	}, nil)

	if err == nil {
		t.Errorf("should err when not found")
	}

	// call init
	inited := false
	installed := false
	err = getAndInstall("", "test", func(n string) registry.Plugin {
		if n != "test" {
			t.Errorf("plugin name changed")
		}
		return &testplugin{
			init: func(logger *log.Logger) error {
				inited = true
				return nil
			},
		}
	}, func(plugin registry.Plugin) error {
		if !inited {
			t.Errorf("not inited")
		}

		installed = true
		return nil
	}, nil)

	if !installed {
		t.Errorf("not installed")
	}

	if err != nil {
		t.Errorf("should err when not found")
	}
}

type testupstream struct {
	testplugin

	h upstream.Handler
}

func (t *testupstream) GetHandler() upstream.Handler {
	return t.h
}

type testchallenger struct {
	testplugin

	h challenger.Handler
}

func (t *testchallenger) GetHandler() challenger.Handler {
	return t.h
}

type testauditorprovider struct {
	testplugin

	a auditor.Auditor
}

func (t *testauditorprovider) Create(ssh.ConnMetadata) (auditor.Auditor, error) {
	return t.a, nil
}

type testauditor struct {
	up   auditor.Hook
	down auditor.Hook
}

func (t *testauditor) GetUpstreamHook() auditor.Hook {
	return t.up
}

func (t *testauditor) GetDownstreamHook() auditor.Hook {
	return t.down
}

func (t *testauditor) Close() error {
	return nil
}

func Test_installDriver(t *testing.T) {
	var (
		upstreamName    = fmt.Sprintf("u_%v", time.Now().UTC().UnixNano())
		challengerName  = fmt.Sprintf("c_%v", time.Now().UTC().UnixNano())
		auditorName     = fmt.Sprintf("a_%v", time.Now().UTC().UnixNano())
		upstreamErrName = fmt.Sprintf("ue_%v", time.Now().UTC().UnixNano())
		upstreamNilName = fmt.Sprintf("un_%v", time.Now().UTC().UnixNano())
	)

	findUpstream := func(conn ssh.ConnMetadata) (net.Conn, *ssh.AuthPipe, error) {
		return nil, nil, nil
	}

	upstream.Register(upstreamName, &testupstream{
		testplugin: testplugin{
			name: upstreamName,
		},
		h: findUpstream,
	})

	upstream.Register(upstreamErrName, &testupstream{
		testplugin: testplugin{
			name: upstreamErrName,
			init: func(logger *log.Logger) error {
				return fmt.Errorf("test err")
			},
		},
		h: findUpstream,
	})

	upstream.Register(upstreamNilName, &testupstream{
		testplugin: testplugin{
			name: upstreamNilName,
		},
		h: nil,
	})

	challenger.Register(challengerName, &testchallenger{
		testplugin: testplugin{
			name: upstreamName,
		},
		h: func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) {
			return true, nil
		},
	})

	auditor.Register(auditorName, &testauditorprovider{})

	// empty driver name
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: "",
		}, nil)

		if err == nil {
			t.Errorf("should fail when empty driver")
		}
	}

	// install upstream
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamName,
		}, nil)

		if err != nil {
			t.Errorf("install failed %v", err)
		}

		if _, _, err := piper.FindUpstream(nil); err != nil {
			t.Errorf("install wrong func")
		}

		if piper.AdditionalChallenge != nil {
			t.Errorf("should not install challenger")
		}
	}

	// install upstream with failed init
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamErrName,
		}, nil)

		if err == nil {
			t.Errorf("install should fail")
		}

		if piper.FindUpstream != nil {
			t.Errorf("should not install upstream provider")
		}

		if piper.AdditionalChallenge != nil {
			t.Errorf("should not install challenger")
		}
	}

	// install upstream with nil handler
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamNilName,
		}, nil)

		if err == nil {
			t.Errorf("install should fail")
		}

		if piper.FindUpstream != nil {
			t.Errorf("should not install upstream provider")
		}

		if piper.AdditionalChallenge != nil {
			t.Errorf("should not install challenger")
		}
	}

	// install challenger
	{
		piper := &ssh.PiperConfig{}
		_, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver:   upstreamName,
			ChallengerDriver: challengerName,
		}, nil)

		if err != nil {
			t.Errorf("install failed %v", err)
		}

		if ok, err := piper.AdditionalChallenge(nil, nil); err != nil || !ok {
			t.Errorf("should install challenger")
		}
	}

	// install auditor
	{
		piper := &ssh.PiperConfig{}
		ap, err := installDrivers(piper, &piperdConfig{
			UpstreamDriver: upstreamName,
			AuditorDriver:  auditorName,
		}, nil)

		if err != nil {
			t.Errorf("install failed %v", err)
		}

		if ap == nil {
			t.Errorf("nil auditor provider")
		}

		ap0 := ap.(*testauditorprovider)

		ap0.a = &testauditor{
			up: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) {
				msg[0] = 42
				return msg, nil
			},
			down: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) {
				msg[0] = 100
				return msg, nil
			},
		}

		a, err := ap.Create(nil)
		if err != nil {
			t.Errorf("install failed %v", err)
		}

		m := []byte{0}

		a.GetUpstreamHook()(nil, m)
		if m[0] != 42 {
			t.Errorf("upstream not handled")
		}

		a.GetDownstreamHook()(nil, m)
		if m[0] != 100 {
			t.Errorf("downstream not handled")
		}
	}
}
<|endoftext|>


<commit_before>package model

// Analytics save unique values for web analytics service
type Analytics struct {
	Google string `toml:"google" ini:"google"`
	Baidu  string `toml:"baidu" ini:"baidu"`
}
<commit_msg>添加站长统计<commit_after>package model

// Analytics save unique values for web analytics service
type Analytics struct {
	Google string `toml:"google" ini:"google"`
	Baidu  string `toml:"baidu" ini:"baidu"`
        Cnzz string `toml:"cnzz" ini:"cnzz"`
}
<|endoftext|>


<commit_before>// +build windows

package state

import (
	"math"
	"os"
	"sync"
	"syscall"
	"unsafe"
)

type stateLock struct {
	handle syscall.Handle
}

var (
	modkernel32      = syscall.NewLazyDLL("kernel32.dll")
	procLockFileEx   = modkernel32.NewProc("LockFileEx")
	procCreateEventW = modkernel32.NewProc("CreateEventW")

	lockedFilesMu sync.Mutex
	lockedFiles   = map[*os.File]syscall.Handle{}
)

const (
	_LOCKFILE_FAIL_IMMEDIATELY = 1
	_LOCKFILE_EXCLUSIVE_LOCK   = 2
)

func (s *LocalState) lock() error {
	lockedFilesMu.Lock()
	defer lockedFilesMu.Unlock()

	name, err := syscall.UTF16PtrFromString(s.PathOut)
	if err != nil {
		return err
	}

	handle, err := syscall.CreateFile(
		name,
		syscall.GENERIC_READ|syscall.GENERIC_WRITE,
		// since this file is already open in out process, we need shared
		// access here for this call.
		syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
		nil,
		syscall.OPEN_EXISTING,
		syscall.FILE_ATTRIBUTE_NORMAL,
		0,
	)
	if err != nil {
		return err
	}

	lockedFiles[s.stateFileOut] = handle

	// even though we're failing immediately, an overlapped event structure is
	// required
	ol, err := newOverlapped()
	if err != nil {
		return err
	}
	defer syscall.CloseHandle(ol.HEvent)

	return lockFileEx(
		handle,
		_LOCKFILE_EXCLUSIVE_LOCK|_LOCKFILE_FAIL_IMMEDIATELY,
		0,              // reserved
		0,              // bytes low
		math.MaxUint32, // bytes high
		ol,
	)
}

func (s *LocalState) unlock() error {
	lockedFilesMu.Lock()
	defer lockedFilesMu.Unlock()

	handle, ok := lockedFiles[s.stateFileOut]
	if !ok {
		// we allow multiple Unlock calls
		return nil
	}
	delete(lockedFiles, s.stateFileOut)
	return syscall.Close(handle)
}

func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
	r1, _, e1 := syscall.Syscall6(
		procLockFileEx.Addr(),
		6,
		uintptr(h),
		uintptr(flags),
		uintptr(reserved),
		uintptr(locklow),
		uintptr(lockhigh),
		uintptr(unsafe.Pointer(ol)),
	)
	if r1 == 0 {
		if e1 != 0 {
			err = error(e1)
		} else {
			err = syscall.EINVAL
		}
	}
	return
}

// newOverlapped creates a structure used to track asynchronous
// I/O requests that have been issued.
func newOverlapped() (*syscall.Overlapped, error) {
	event, err := createEvent(nil, true, false, nil)
	if err != nil {
		return nil, err
	}
	return &syscall.Overlapped{HEvent: event}, nil
}

func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
	var _p0 uint32
	if manualReset {
		_p0 = 1
	}
	var _p1 uint32
	if initialState {
		_p1 = 1
	}

	r0, _, e1 := syscall.Syscall6(
		procCreateEventW.Addr(),
		4,
		uintptr(unsafe.Pointer(sa)),
		uintptr(_p0),
		uintptr(_p1),
		uintptr(unsafe.Pointer(name)),
		0,
		0,
	)
	handle = syscall.Handle(r0)
	if handle == syscall.InvalidHandle {
		if e1 != 0 {
			err = error(e1)
		} else {
			err = syscall.EINVAL
		}
	}
	return
}
<commit_msg>add msdn link for LockFileEx<commit_after>// +build windows

package state

import (
	"math"
	"os"
	"sync"
	"syscall"
	"unsafe"
)

type stateLock struct {
	handle syscall.Handle
}

var (
	modkernel32      = syscall.NewLazyDLL("kernel32.dll")
	procLockFileEx   = modkernel32.NewProc("LockFileEx")
	procCreateEventW = modkernel32.NewProc("CreateEventW")

	lockedFilesMu sync.Mutex
	lockedFiles   = map[*os.File]syscall.Handle{}
)

const (
	// dwFlags defined for LockFileEx
	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
	_LOCKFILE_FAIL_IMMEDIATELY = 1
	_LOCKFILE_EXCLUSIVE_LOCK   = 2
)

func (s *LocalState) lock() error {
	lockedFilesMu.Lock()
	defer lockedFilesMu.Unlock()

	name, err := syscall.UTF16PtrFromString(s.PathOut)
	if err != nil {
		return err
	}

	handle, err := syscall.CreateFile(
		name,
		syscall.GENERIC_READ|syscall.GENERIC_WRITE,
		// since this file is already open in out process, we need shared
		// access here for this call.
		syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
		nil,
		syscall.OPEN_EXISTING,
		syscall.FILE_ATTRIBUTE_NORMAL,
		0,
	)
	if err != nil {
		return err
	}

	lockedFiles[s.stateFileOut] = handle

	// even though we're failing immediately, an overlapped event structure is
	// required
	ol, err := newOverlapped()
	if err != nil {
		return err
	}
	defer syscall.CloseHandle(ol.HEvent)

	return lockFileEx(
		handle,
		_LOCKFILE_EXCLUSIVE_LOCK|_LOCKFILE_FAIL_IMMEDIATELY,
		0,              // reserved
		0,              // bytes low
		math.MaxUint32, // bytes high
		ol,
	)
}

func (s *LocalState) unlock() error {
	lockedFilesMu.Lock()
	defer lockedFilesMu.Unlock()

	handle, ok := lockedFiles[s.stateFileOut]
	if !ok {
		// we allow multiple Unlock calls
		return nil
	}
	delete(lockedFiles, s.stateFileOut)
	return syscall.Close(handle)
}

func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
	r1, _, e1 := syscall.Syscall6(
		procLockFileEx.Addr(),
		6,
		uintptr(h),
		uintptr(flags),
		uintptr(reserved),
		uintptr(locklow),
		uintptr(lockhigh),
		uintptr(unsafe.Pointer(ol)),
	)
	if r1 == 0 {
		if e1 != 0 {
			err = error(e1)
		} else {
			err = syscall.EINVAL
		}
	}
	return
}

// newOverlapped creates a structure used to track asynchronous
// I/O requests that have been issued.
func newOverlapped() (*syscall.Overlapped, error) {
	event, err := createEvent(nil, true, false, nil)
	if err != nil {
		return nil, err
	}
	return &syscall.Overlapped{HEvent: event}, nil
}

func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
	var _p0 uint32
	if manualReset {
		_p0 = 1
	}
	var _p1 uint32
	if initialState {
		_p1 = 1
	}

	r0, _, e1 := syscall.Syscall6(
		procCreateEventW.Addr(),
		4,
		uintptr(unsafe.Pointer(sa)),
		uintptr(_p0),
		uintptr(_p1),
		uintptr(unsafe.Pointer(name)),
		0,
		0,
	)
	handle = syscall.Handle(r0)
	if handle == syscall.InvalidHandle {
		if e1 != 0 {
			err = error(e1)
		} else {
			err = syscall.EINVAL
		}
	}
	return
}
<|endoftext|>


<commit_before>//The server package privdes the basic gofire server
package server

import (
	"encoding/json"
	"net/http"
)

//Rounting of the restful api
const(
	API = "/api"
	CHAT = "/api/c"
)

type FireServer struct {
	Name                string
	Addr                string `json:"-"`
	RegisteredChatRooms []string
}

//a fireserver instance
var fireServer = new(FireServer)
var restCommands = make(map[string]string)

func init() {
	AddRestCommand(API, ApiHandler, "Get all commands")
	AddRestCommand(CHAT, ChatRoomHandler, "Get all chatrooms")

	//initServer()
}

//adds a rest command
func AddRestCommand(pattern string, handler func(http.ResponseWriter, *http.Request), desc string) {
	restCommands[pattern] = desc
	http.HandleFunc(pattern, handler)
}

//A wrapper for the ListenAndServe of net/http
func ListenAndServe(addr string) error {
	fireServer.Addr = addr
	err := http.ListenAndServe(addr, nil)
	return err
}

func ApiHandler(w http.ResponseWriter, r *http.Request){
	json, err := json.Marshal(restCommands)
	if err != nil {
		w.Write([]byte("404"))
	} else {
		w.Write(json)
	}
}

//ChatRoomHandler
func ChatRoomHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		chatName := r.URL.Path[len(CHAT):]
		if len(chatName) == 0 {
			getAllChatrooms(w, r)
		} else {
			w.Write([]byte(chatName))
		}
	}

	if r.Method == "POST" {
		err := r.ParseForm()
		if err != nil{
			//TODO Write error better
			w.Write([]byte("404"))
		}else{
			name := r.FormValue("name")
			fireServer.RegisteredChatRooms = append(fireServer.RegisteredChatRooms, name)
			w.Write([]byte(name))
		}
	}
}

// get /c/
func getAllChatrooms(w http.ResponseWriter, r *http.Request) {
	json, err := json.Marshal(fireServer.RegisteredChatRooms)
	if err == nil {
		w.Write(json)
	} else {
		w.Write([]byte("Fail"))
	}
}
<commit_msg>better error handling, not everywhere implemented now<commit_after>//The server package privdes the basic gofire server
package server

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

//Rounting of the restful api
const(
	API = "/api"
	CHAT = "/api/c"
)

type FireServer struct {
	Name                string
	Addr                string `json:"-"`
	RegisteredChatRooms []string
}

//a fireserver instance
var fireServer = new(FireServer)
var restCommands = make(map[string]string)

func init() {
	AddRestCommand(API, ApiHandler, "Get all commands")
	AddRestCommand(CHAT, ChatRoomHandler, "Get all chatrooms")

	//initServer()
}

//adds a rest command
func AddRestCommand(pattern string, handler func(http.ResponseWriter, *http.Request), desc string) {
	restCommands[pattern] = desc
	http.HandleFunc(pattern, handler)
}

//A wrapper for the ListenAndServe of net/http
func ListenAndServe(addr string) error {
	fireServer.Addr = addr
	err := http.ListenAndServe(addr, nil)
	return err
}

func ApiHandler(w http.ResponseWriter, r *http.Request){
	json, err := json.Marshal(restCommands)
	if err != nil {
		w.Write([]byte("404"))
	} else {
		w.Write(json)
	}
}

//ChatRoomHandler
func ChatRoomHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		chatName := r.URL.Path[len(CHAT):]
		if len(chatName) == 0 {
			getAllChatrooms(w, r)
		} else {
			w.Write([]byte(string(chatName)))
		}
	}

	if r.Method == "POST" {
		err := r.ParseForm()
		if err != nil{
			//TODO Write error better
			w.Write([]byte([]byte(string(http.StatusBadRequest))))
		}else{
			name := r.FormValue("name")
			fireServer.RegisteredChatRooms = append(fireServer.RegisteredChatRooms, name)
			w.Write([]byte(name))
		}
	}
}

func postChatRoom(form url.Values, w http.ResponseWriter){
	name := form.Get("name")
	fireServer.RegisteredChatRooms = append(fireServer.RegisteredChatRooms, name)
	w.Write([]byte(string(http.StatusOK)))
}

// get /c/
func getAllChatrooms(w http.ResponseWriter, r *http.Request) {
	json, err := json.Marshal(fireServer.RegisteredChatRooms)
	if err == nil {
		w.Write(json)
	} else {
		w.Write([]byte("Fail"))
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The nvim-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"path/filepath"
	"reflect"
	"testing"

	"nvim-go/context"

	"github.com/neovim/go-client/nvim"
)

var testLintDir = filepath.Join(testGoPath, "src", "lint")

func TestCommands_Lint(t *testing.T) {
	type fields struct {
		v    *nvim.Nvim
		p    *nvim.Pipeline
		ctxt *context.Context
	}
	type args struct {
		args []string
		file string
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    []*nvim.QuickfixError
		wantErr bool
	}{
		{
			name: "no suggest(go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "blank-import-main.go")),
			},
			args: args{
				file: filepath.Join(testLintDir, "blank-import-main.go"),
			},
			want:    nil,
			wantErr: false,
		},
		{
			name: "2 suggest(go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				args: []string{"%"},
				file: filepath.Join(testLintDir, "make.go"),
			},
			want: []*nvim.QuickfixError{&nvim.QuickfixError{
				FileName: "make.go",
				LNum:     14,
				Col:      2,
				Text:     "can probably use \"var x []T\" instead",
			}, &nvim.QuickfixError{
				FileName: "make.go",
				LNum:     15,
				Col:      2,
				Text:     "can probably use \"var y []http.Request\" instead",
			}},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		ctxt := context.NewContext()
		c := NewCommands(tt.fields.v, ctxt)
		c.v.SetCurrentDirectory(filepath.Dir(tt.args.file))

		got, err := c.Lint(tt.args.args, tt.args.file)
		if (err != nil) != tt.wantErr {
			t.Errorf("%q. Commands.Lint(%v, %v) error = %v, wantErr %v", tt.name, tt.args.args, tt.args.file, err, tt.wantErr)
			continue
		}
		if !reflect.DeepEqual(got, tt.want) {
			t.Logf("%+v\n%+v", got[0], got[1])
			t.Errorf("%q. Commands.Lint(%v, %v) = %v, want %v", tt.name, tt.args.args, tt.args.file, got, tt.want)
		}
	}
}

func TestCommands_cmdLintComplete(t *testing.T) {
	type fields struct {
		v    *nvim.Nvim
		p    *nvim.Pipeline
		ctxt *context.Context
	}
	type args struct {
		a   *nvim.CommandCompletionArgs
		cwd string
	}
	tests := []struct {
		name         string
		fields       fields
		args         args
		wantFilelist []string
		wantErr      bool
	}{
		{
			name: "lint dir - no args (go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: testLintDir,
			},
			wantFilelist: []string{"blank-import-main.go", "make.go", "time.go"},
		},
		{
			name: "lint dir - 'ma' (go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a: &nvim.CommandCompletionArgs{
					ArgLead: "ma",
				},
				cwd: testLintDir,
			},
			wantFilelist: []string{"make.go"},
		},
		{
			name: "astdump (go)",
			fields: fields{
				v: testVim(t, astdumpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: astdump,
			},
			wantFilelist: []string{"astdump.go"},
		},
		{
			name: "gsftp (gb)",
			fields: fields{
				v: testVim(t, gsftpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: gsftp,
			},
			wantFilelist: []string{"main.go"},
		},
	}
	for _, tt := range tests {
		tt.fields.ctxt = context.NewContext()
		c := NewCommands(tt.fields.v, tt.fields.ctxt)

		gotFilelist, err := c.cmdLintComplete(tt.args.a, tt.args.cwd)
		if (err != nil) != tt.wantErr {
			t.Errorf("%q. Commands.cmdLintComplete(%v, %v) error = %v, wantErr %v", tt.name, tt.args.a, tt.args.cwd, err, tt.wantErr)
			continue
		}
		if !reflect.DeepEqual(gotFilelist, tt.wantFilelist) {
			t.Errorf("%q. Commands.cmdLintComplete(%v, %v) = %v, want %v", tt.name, tt.args.a, tt.args.cwd, gotFilelist, tt.wantFilelist)
		}
	}
}
<commit_msg>test/lint: change test file to time.go<commit_after>// Copyright 2016 The nvim-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"path/filepath"
	"reflect"
	"testing"

	"nvim-go/context"

	"github.com/neovim/go-client/nvim"
)

var testLintDir = filepath.Join(testGoPath, "src", "lint")

func TestCommands_Lint(t *testing.T) {
	type fields struct {
		v    *nvim.Nvim
		p    *nvim.Pipeline
		ctxt *context.Context
	}
	type args struct {
		args []string
		file string
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    []*nvim.QuickfixError
		wantErr bool
	}{
		{
			name: "no suggest(go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "blank-import-main.go")),
			},
			args: args{
				file: filepath.Join(testLintDir, "blank-import-main.go"),
			},
			want:    nil,
			wantErr: false,
		},
		{
			name: "2 suggest(go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "time.go")),
			},
			args: args{
				args: []string{"%"},
				file: filepath.Join(testLintDir, "time.go"),
			},
			want: []*nvim.QuickfixError{&nvim.QuickfixError{
				FileName: "time.go",
				LNum:     11,
				Col:      5,
				Text:     "var rpcTimeoutMsec is of type *time.Duration; don't use unit-specific suffix \"Msec\"",
			}, &nvim.QuickfixError{
				FileName: "time.go",
				LNum:     13,
				Col:      5,
				Text:     "var timeoutSecs is of type time.Duration; don't use unit-specific suffix \"Secs\"",
			}},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		ctxt := context.NewContext()
		c := NewCommands(tt.fields.v, ctxt)
		c.v.SetCurrentDirectory(filepath.Dir(tt.args.file))

		got, err := c.Lint(tt.args.args, tt.args.file)
		if (err != nil) != tt.wantErr {
			t.Errorf("%q. Commands.Lint(%v, %v) error = %v, wantErr %v", tt.name, tt.args.args, tt.args.file, err, tt.wantErr)
			continue
		}
		if !reflect.DeepEqual(got, tt.want) {
			t.Logf("%+v\n%+v", got[0], got[1])
			t.Errorf("%q. Commands.Lint(%v, %v) = %v, want %v", tt.name, tt.args.args, tt.args.file, got, tt.want)
		}
	}
}

func TestCommands_cmdLintComplete(t *testing.T) {
	type fields struct {
		v    *nvim.Nvim
		p    *nvim.Pipeline
		ctxt *context.Context
	}
	type args struct {
		a   *nvim.CommandCompletionArgs
		cwd string
	}
	tests := []struct {
		name         string
		fields       fields
		args         args
		wantFilelist []string
		wantErr      bool
	}{
		{
			name: "lint dir - no args (go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: testLintDir,
			},
			wantFilelist: []string{"blank-import-main.go", "make.go", "time.go"},
		},
		{
			name: "lint dir - 'ma' (go)",
			fields: fields{
				v: testVim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a: &nvim.CommandCompletionArgs{
					ArgLead: "ma",
				},
				cwd: testLintDir,
			},
			wantFilelist: []string{"make.go"},
		},
		{
			name: "astdump (go)",
			fields: fields{
				v: testVim(t, astdumpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: astdump,
			},
			wantFilelist: []string{"astdump.go"},
		},
		{
			name: "gsftp (gb)",
			fields: fields{
				v: testVim(t, gsftpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: gsftp,
			},
			wantFilelist: []string{"main.go"},
		},
	}
	for _, tt := range tests {
		tt.fields.ctxt = context.NewContext()
		c := NewCommands(tt.fields.v, tt.fields.ctxt)

		gotFilelist, err := c.cmdLintComplete(tt.args.a, tt.args.cwd)
		if (err != nil) != tt.wantErr {
			t.Errorf("%q. Commands.cmdLintComplete(%v, %v) error = %v, wantErr %v", tt.name, tt.args.a, tt.args.cwd, err, tt.wantErr)
			continue
		}
		if !reflect.DeepEqual(gotFilelist, tt.wantFilelist) {
			t.Errorf("%q. Commands.cmdLintComplete(%v, %v) = %v, want %v", tt.name, tt.args.a, tt.args.cwd, gotFilelist, tt.wantFilelist)
		}
	}
}
<|endoftext|>


<commit_before>package apps

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/generator"
	archive_helpers "github.com/pivotal-golang/archiver/extractor/test_helper"
)

var _ = Describe("An application using an admin buildpack", func() {
	var (
		appName       string
		BuildpackName string

		appPath string

		buildpackPath        string
		buildpackArchivePath string
	)

	matchingFilename := func(appName string) string {
		return fmt.Sprintf("simple-buildpack-please-match-%s", appName)
	}

	BeforeEach(func() {
		AsUser(context.AdminUserContext(), func() {
			BuildpackName = RandomName()
			appName = RandomName()

			tmpdir, err := ioutil.TempDir(os.TempDir(), "matching-app")
			Expect(err).ToNot(HaveOccurred())

			appPath = tmpdir

			tmpdir, err = ioutil.TempDir(os.TempDir(), "matching-buildpack")
			Expect(err).ToNot(HaveOccurred())

			buildpackPath = tmpdir
			buildpackArchivePath = path.Join(buildpackPath, "buildpack.zip")

			archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
				{
					Name: "bin/compile",
					Body: `#!/usr/bin/env bash

echo "Staging with Simple Buildpack"

sleep 10
`,
				},
				{
					Name: "bin/detect",
					Body: fmt.Sprintf(`#!/bin/bash

if [ -f "${1}/%s" ]; then
  echo Simple
else
  echo no
  exit 1
fi
`, matchingFilename(appName)),
				},
				{
					Name: "bin/release",
					Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
  PATH: bin:/usr/local/bin:/usr/bin:/bin
  FROM_BUILD_PACK: "yes"
default_process_types:
  web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "hi from a simple admin buildpack"; } | nc -l \$PORT; done
EOF
`,
				},
			})

			_, err = os.Create(path.Join(appPath, matchingFilename(appName)))
			Expect(err).ToNot(HaveOccurred())

			_, err = os.Create(path.Join(appPath, "some-file"))
			Expect(err).ToNot(HaveOccurred())

			createBuildpack := Cf("create-buildpack", BuildpackName, buildpackArchivePath, "0")
			Eventually(createBuildpack, DefaultTimeout).Should(Say("Creating"))
			Eventually(createBuildpack, DefaultTimeout).Should(Say("OK"))
			Eventually(createBuildpack, DefaultTimeout).Should(Say("Uploading"))
			Eventually(createBuildpack, DefaultTimeout).Should(Say("OK"))
			Eventually(createBuildpack, DefaultTimeout).Should(Exit(0))
		})
	})

	AfterEach(func() {
		AsUser(context.AdminUserContext(), func() {
			Eventually(Cf("delete-buildpack", BuildpackName, "-f"), DefaultTimeout).Should(Exit(0))
		})
	})

	Context("when the buildpack is detected", func() {
		It("is used for the app", func() {
			push := Cf("push", appName, "-p", appPath)
			Eventually(push, CFPushTimeout).Should(Say("Staging with Simple Buildpack"))
			Eventually(push, CFPushTimeout).Should(Exit(0))
		})
	})

	Context("when the buildpack fails to detect", func() {
		BeforeEach(func() {
			err := os.Remove(path.Join(appPath, matchingFilename(appName)))
			Expect(err).ToNot(HaveOccurred())
		})

		It("fails to stage", func() {
			Eventually(Cf("push", appName, "-p", appPath), CFPushTimeout).Should(Say("Staging error"))
		})
	})

	Context("when the buildpack is deleted", func() {
		BeforeEach(func() {
			AsUser(context.AdminUserContext(), func() {
				Eventually(Cf("delete-buildpack", BuildpackName, "-f"), DefaultTimeout).Should(Exit(0))
			})
		})

		It("fails to stage", func() {
			Eventually(Cf("push", appName, "-p", appPath), CFPushTimeout).Should(Say("Staging error"))
		})
	})

	Context("when the buildpack is disabled", func() {
		BeforeEach(func() {
			AsUser(context.AdminUserContext(), func() {
				var response QueryResponse

				ApiRequest("GET", "/v2/buildpacks?q=name:"+BuildpackName, &response)

				Expect(response.Resources).To(HaveLen(1))

				buildpackGuid := response.Resources[0].Metadata.Guid

				ApiRequest(
					"PUT",
					"/v2/buildpacks/"+buildpackGuid,
					nil,
					`{"enabled":false}`,
				)
			})
		})

		It("fails to stage", func() {
			Eventually(Cf("push", appName, "-p", appPath), CFPushTimeout).Should(Say("Staging error"))
		})
	})
})
<commit_msg>Change buildpack tests to wait for CF exit before testing status and output.<commit_after>package apps

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/generator"
	archive_helpers "github.com/pivotal-golang/archiver/extractor/test_helper"
)

var _ = Describe("An application using an admin buildpack", func() {
	var (
		appName       string
		BuildpackName string

		appPath string

		buildpackPath        string
		buildpackArchivePath string
	)

	matchingFilename := func(appName string) string {
		return fmt.Sprintf("simple-buildpack-please-match-%s", appName)
	}

	BeforeEach(func() {
		AsUser(context.AdminUserContext(), func() {
			BuildpackName = RandomName()
			appName = RandomName()

			tmpdir, err := ioutil.TempDir(os.TempDir(), "matching-app")
			Expect(err).ToNot(HaveOccurred())

			appPath = tmpdir

			tmpdir, err = ioutil.TempDir(os.TempDir(), "matching-buildpack")
			Expect(err).ToNot(HaveOccurred())

			buildpackPath = tmpdir
			buildpackArchivePath = path.Join(buildpackPath, "buildpack.zip")

			archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
				{
					Name: "bin/compile",
					Body: `#!/usr/bin/env bash

echo "Staging with Simple Buildpack"

sleep 10
`,
				},
				{
					Name: "bin/detect",
					Body: fmt.Sprintf(`#!/bin/bash

if [ -f "${1}/%s" ]; then
  echo Simple
else
  echo no
  exit 1
fi
`, matchingFilename(appName)),
				},
				{
					Name: "bin/release",
					Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
  PATH: bin:/usr/local/bin:/usr/bin:/bin
  FROM_BUILD_PACK: "yes"
default_process_types:
  web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "hi from a simple admin buildpack"; } | nc -l \$PORT; done
EOF
`,
				},
			})

			_, err = os.Create(path.Join(appPath, matchingFilename(appName)))
			Expect(err).ToNot(HaveOccurred())

			_, err = os.Create(path.Join(appPath, "some-file"))
			Expect(err).ToNot(HaveOccurred())

			createBuildpack := Cf("create-buildpack", BuildpackName, buildpackArchivePath, "0").Wait(DefaultTimeout)
			Expect(createBuildpack).Should(Exit(0))
			Expect(createBuildpack).Should(Say("Creating"))
			Expect(createBuildpack).Should(Say("OK"))
			Expect(createBuildpack).Should(Say("Uploading"))
			Expect(createBuildpack).Should(Say("OK"))
		})
	})

	AfterEach(func() {
		AsUser(context.AdminUserContext(), func() {
			Expect(Cf("delete-buildpack", BuildpackName, "-f").Wait(DefaultTimeout)).To(Exit(0))
		})
	})

	Context("when the buildpack is detected", func() {
		It("is used for the app", func() {
			push := Cf("push", appName, "-p", appPath).Wait(CFPushTimeout)
			Expect(push).To(Exit(0))
			Expect(push).To(Say("Staging with Simple Buildpack"))
		})
	})

	Context("when the buildpack fails to detect", func() {
		BeforeEach(func() {
			err := os.Remove(path.Join(appPath, matchingFilename(appName)))
			Expect(err).ToNot(HaveOccurred())
		})

		It("fails to stage", func() {
			push := Cf("push", appName, "-p", appPath).Wait(CFPushTimeout)
			Expect(push).To(Exit(1))
			Expect(push).To(Say("Staging error"))
		})
	})

	Context("when the buildpack is deleted", func() {
		BeforeEach(func() {
			AsUser(context.AdminUserContext(), func() {
				Expect(Cf("delete-buildpack", BuildpackName, "-f").Wait(DefaultTimeout)).To(Exit(0))
			})
		})

		It("fails to stage", func() {
			push := Cf("push", appName, "-p", appPath).Wait(CFPushTimeout)
			Expect(push).To(Exit(1))
			Expect(push).To(Say("Staging error"))
		})
	})

	Context("when the buildpack is disabled", func() {
		BeforeEach(func() {
			AsUser(context.AdminUserContext(), func() {
				var response QueryResponse

				ApiRequest("GET", "/v2/buildpacks?q=name:"+BuildpackName, &response)

				Expect(response.Resources).To(HaveLen(1))

				buildpackGuid := response.Resources[0].Metadata.Guid

				ApiRequest(
					"PUT",
					"/v2/buildpacks/"+buildpackGuid,
					nil,
					`{"enabled":false}`,
				)
			})
		})

		It("fails to stage", func() {
			push := Cf("push", appName, "-p", appPath).Wait(CFPushTimeout)
			Expect(push).To(Exit(1))
			Expect(push).To(Say("Staging error"))
		})
	})
})
<|endoftext|>