<commit_before>package postgres

import (
	"fmt"

	"github.com/aodin/sol/dialect"
)

// TODO Don't hardcode utc?
const Now = "now() at time zone 'utc'"

type timestamp struct {
	name         string
	isNotNull    bool
	isUnique     bool
	withTimezone bool
	defaultValue string // TODO Additional defaults?
}

func (t timestamp) Create(d dialect.Dialect) (string, error) {
	compiled := t.name
	if t.withTimezone {
		compiled += " with time zone"
	}
	if t.isNotNull {
		compiled += " NOT NULL"
	}
	if t.isUnique {
		compiled += " UNIQUE"
	}
	if t.defaultValue != "" {
		compiled += fmt.Sprintf(" DEFAULT (%s)", t.defaultValue)
	}
	return compiled, nil
}

func (t timestamp) Default(value string) timestamp {
	t.defaultValue = value
	return t
}

func (t timestamp) NotNull() timestamp {
	t.isNotNull = true
	return t
}

func (t timestamp) Unique() timestamp {
	t.isUnique = true
	return t
}

// TODO Date cannot have a time zone
func Date() (t timestamp) {
	t.name = "date"
	return
}

func Time() (t timestamp) {
	t.name = "time"
	return
}

func Timestamp() (t timestamp) {
	t.name = "timestamp"
	return
}
<commit_msg>With and without timezone methods for postgres datetime types<commit_after>package postgres

import (
	"fmt"

	"github.com/aodin/sol/dialect"
)

// TODO Don't hardcode utc?
const Now = "now() at time zone 'utc'"

type timestamp struct {
	name         string
	isNotNull    bool
	isUnique     bool
	withTimezone bool
	defaultValue string // TODO Additional defaults?
}

func (t timestamp) Create(d dialect.Dialect) (string, error) {
	compiled := t.name
	if t.withTimezone {
		compiled += " with time zone"
	}
	if t.isNotNull {
		compiled += " NOT NULL"
	}
	if t.isUnique {
		compiled += " UNIQUE"
	}
	if t.defaultValue != "" {
		compiled += fmt.Sprintf(" DEFAULT (%s)", t.defaultValue)
	}
	return compiled, nil
}

func (t timestamp) Default(value string) timestamp {
	t.defaultValue = value
	return t
}

func (t timestamp) NotNull() timestamp {
	t.isNotNull = true
	return t
}

func (t timestamp) Unique() timestamp {
	t.isUnique = true
	return t
}

func (t timestamp) WithoutTimezone() timestamp {
	t.withTimezone = false
	return t
}

func (t timestamp) WithTimezone() timestamp {
	// TODO specify timezone?
	t.withTimezone = true
	return t
}

// TODO Date cannot have a time zone
func Date() (t timestamp) {
	t.name = "date"
	return
}

func Time() (t timestamp) {
	t.name = "time"
	return
}

func Timestamp() (t timestamp) {
	t.name = "timestamp"
	return
}
<|endoftext|>


<commit_before>package msa

import (
	"fmt"
	"io"

	"github.com/BurntSushi/bcbgo/io/fasta"
	"github.com/BurntSushi/bcbgo/seq"
)

func translateA2M(b byte) (seq.Residue, bool) {
	switch {
	case b >= 'a' && b <= 'z':
		return seq.Residue(b), true
	case b >= 'A' && b <= 'Z':
		return seq.Residue(b), true
	case b == '*':
		return 0, true
	case b == '-':
		return '-', true
	case b == '.':
		return '.', true
	}
	return 0, false
}

// Read will read a single MSA from the input, where the input can be formatted
// in FASTA, A2M or A3M formats. Sequences are read until io.EOF.
func Read(reader io.Reader) (seq.MSA, error) {
	r := fasta.NewReader(reader)
	r.TrustSequences = false
	return read(r)
}

// ReadTrusted will read a single MSA from trusted input, where the input can
// be formatted/ in FASTA, A2M or A3M formats. Sequences are read until io.EOF.
//
// "Trust" in this context means that the input doesn't contain any illegal
// characters in the sequence. Trusting the input should be faster.
func ReadTrusted(reader io.Reader) (seq.MSA, error) {
	r := fasta.NewReader(reader)
	r.TrustSequences = true
	return read(r)
}

func read(r *fasta.Reader) (seq.MSA, error) {
	msa := seq.NewMSA()
	for {
		s, err := readSequence(r)
		if err == io.EOF {
			break
		}
		if err != nil {
			return seq.MSA{}, err
		}

		msa.Add(s)
		if len(msa.Entries) > 1 {
			// We can't use 's' directly, because a sequence added to an MSA
			// may be modified if it isn't already in A2M format.
			lastEntry := msa.Entries[len(msa.Entries)-1]
			if lastEntry.Len() != msa.Entries[0].Len() {
				return seq.MSA{},
					fmt.Errorf("Sequence '%s' has length %d, but other "+
						"sequences have length %d.",
						s.Name, lastEntry, msa.Entries[0].Len())
			}
		}
	}
	return msa, nil
}

func readSequence(r *fasta.Reader) (s seq.Sequence, err error) {
	s, err = r.ReadSequence(translateA2M) // A2M encompasses FASTA/A3M
	if !s.IsNull() {
		return s, nil
	}
	if err == io.EOF {
		return seq.Sequence{}, err
	}
	if err != nil {
		return seq.Sequence{}, err
	}
	panic("unreachable")
}

type formatSeq func(row int) seq.Sequence

// WriteFasta writes a multiple sequence alignment to the output in aligned
// FASTA format. Aligned FASTA format uses upper case characters to indicate
// matches, lower case characters to indicate insertions, and '-' characters to
// indicate deletions/insertions.
func WriteFasta(w io.Writer, msa seq.MSA) error {
	formatter := func(row int) seq.Sequence {
		return msa.GetFasta(row)
	}
	return write(w, msa, formatter)
}

// WriteA2M writes a multiple sequence alignment to the output in
// A2M format. A2M format uses upper case characters to indicate
// matches, lower case and '.' characters to indicate insertions, and '-'
// characters to indicate deletions.
func WriteA2M(w io.Writer, msa seq.MSA) error {
	formatter := func(row int) seq.Sequence {
		return msa.GetA2M(row)
	}
	return write(w, msa, formatter)
}

// WriteA3M writes a multiple sequence alignment to the output in
// A3M format. A3M format uses upper case characters to indicate
// matches, lower case characters to indicate insertions, and '-'
// characters to indicate deletions.
//
// A3M format is a more compact way to write an MSA than FASTA or A2M.
func WriteA3M(w io.Writer, msa seq.MSA) error {
	formatter := func(row int) seq.Sequence {
		return msa.GetA3M(row)
	}
	return write(w, msa, formatter)
}

func write(writer io.Writer, msa seq.MSA, formatter formatSeq) error {
	w := fasta.NewWriter(writer)
	w.Asterisk = false
	w.Columns = 0
	for row := range msa.Entries {
		if err := w.Write(formatter(row)); err != nil {
			return err
		}
	}
	return w.Flush()
}
<commit_msg>A nasty bug fix. Basically, FASTA aligned format cannot be unambiguously distinguished from A2M/A3M aligned format. So we need to handle them separately explicitly.<commit_after>package msa

import (
	"fmt"
	"io"

	"github.com/BurntSushi/bcbgo/io/fasta"
	"github.com/BurntSushi/bcbgo/seq"
)

func translateA2M(b byte) (seq.Residue, bool) {
	switch {
	case b >= 'a' && b <= 'z':
		return seq.Residue(b), true
	case b >= 'A' && b <= 'Z':
		return seq.Residue(b), true
	case b == '*':
		return 0, true
	case b == '-':
		return '-', true
	case b == '.':
		return '.', true
	}
	return 0, false
}

// Read will read a single MSA from the input, where the input can be formatted
// in A2M or A3M formats. Sequences are read until io.EOF.
//
// If you need to read FASTA aligned format, use ReadFasta.
func Read(reader io.Reader) (seq.MSA, error) {
	r := fasta.NewReader(reader)
	r.TrustSequences = false
	return read(r, false)
}

// Read will read a single MSA from the input, where the input can be formatted
// in FASTA format. Sequences are read until io.EOF.
//
// If you need to read A2M or A3M aligned formats, use Read.
func ReadFasta(reader io.Reader) (seq.MSA, error) {
	r := fasta.NewReader(reader)
	r.TrustSequences = false
	return read(r, true)
}

// ReadTrusted will read a single MSA from trusted input, where the input can
// be formatted/ in A2M or A3M formats. Sequences are read until io.EOF.
//
// "Trust" in this context means that the input doesn't contain any illegal
// characters in the sequence. Trusting the input should be faster.
//
// If you need to read FASTA aligned format, use ReadTrustedFasta.
func ReadTrusted(reader io.Reader) (seq.MSA, error) {
	r := fasta.NewReader(reader)
	r.TrustSequences = true
	return read(r, false)
}

// ReadTrustedFasta will read a single MSA from trusted input, where the input
// can be formatted/ in FASTA format. Sequences are read until io.EOF.
//
// "Trust" in this context means that the input doesn't contain any illegal
// characters in the sequence. Trusting the input should be faster.
//
// If you need to read A2M or A3M aligned formats, use ReadTrusted.
func ReadTrustedFasta(reader io.Reader) (seq.MSA, error) {
	r := fasta.NewReader(reader)
	r.TrustSequences = true
	return read(r, true)
}

func read(r *fasta.Reader, fasta bool) (seq.MSA, error) {
	msa := seq.NewMSA()
	for {
		s, err := readSequence(r)
		if err == io.EOF {
			break
		}
		if err != nil {
			return seq.MSA{}, err
		}

		if fasta {
			msa.AddFasta(s)
		} else {
			msa.Add(s)
		}
		if len(msa.Entries) > 1 {
			// We can't use 's' directly, because a sequence added to an MSA
			// may be modified if it isn't already in A2M format.
			lastEntry := msa.Entries[len(msa.Entries)-1]
			if lastEntry.Len() != msa.Entries[0].Len() {
				return seq.MSA{},
					fmt.Errorf("Sequence '%s' has length %d, but other "+
						"sequences have length %d.",
						s.Name, lastEntry, msa.Entries[0].Len())
			}
		}
	}
	return msa, nil
}

func readSequence(r *fasta.Reader) (s seq.Sequence, err error) {
	s, err = r.ReadSequence(translateA2M) // A2M encompasses FASTA/A3M
	if !s.IsNull() {
		return s, nil
	}
	if err == io.EOF {
		return seq.Sequence{}, err
	}
	if err != nil {
		return seq.Sequence{}, err
	}
	panic("unreachable")
}

type formatSeq func(row int) seq.Sequence

// WriteFasta writes a multiple sequence alignment to the output in aligned
// FASTA format. Aligned FASTA format uses upper case characters to indicate
// matches, lower case characters to indicate insertions, and '-' characters to
// indicate deletions/insertions.
func WriteFasta(w io.Writer, msa seq.MSA) error {
	formatter := func(row int) seq.Sequence {
		return msa.GetFasta(row)
	}
	return write(w, msa, formatter)
}

// WriteA2M writes a multiple sequence alignment to the output in
// A2M format. A2M format uses upper case characters to indicate
// matches, lower case and '.' characters to indicate insertions, and '-'
// characters to indicate deletions.
func WriteA2M(w io.Writer, msa seq.MSA) error {
	formatter := func(row int) seq.Sequence {
		return msa.GetA2M(row)
	}
	return write(w, msa, formatter)
}

// WriteA3M writes a multiple sequence alignment to the output in
// A3M format. A3M format uses upper case characters to indicate
// matches, lower case characters to indicate insertions, and '-'
// characters to indicate deletions.
//
// A3M format is a more compact way to write an MSA than FASTA or A2M.
func WriteA3M(w io.Writer, msa seq.MSA) error {
	formatter := func(row int) seq.Sequence {
		return msa.GetA3M(row)
	}
	return write(w, msa, formatter)
}

func write(writer io.Writer, msa seq.MSA, formatter formatSeq) error {
	w := fasta.NewWriter(writer)
	w.Asterisk = false
	w.Columns = 0
	for row := range msa.Entries {
		if err := w.Write(formatter(row)); err != nil {
			return err
		}
	}
	return w.Flush()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"ieveapi/apicache"
	"log"
	"net/http"
	"os"
	"runtime"
	"time"
)

var dc = NewDiskCache(conf.CacheDir)

func main() {
	log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime)
	if conf.LogFile != "" {
		logfp, err := os.OpenFile(conf.LogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			panic(fmt.Sprintf("Cannot Open Log File: %s", err))
		}
		log.SetOutput(logfp)
	}

	if conf.Threads == 0 {
		conf.Threads = runtime.NumCPU()
	}
	runtime.GOMAXPROCS(conf.Threads)
	log.Printf("EVEAPIProxy Starting Up with %d threads...", conf.Threads)

	apicache.NewClient(dc)
	startWorkers()

	var handler APIHandler

	server := http.Server{
		Addr:         conf.Listen,
		Handler:      &handler,
		ReadTimeout:  5 * time.Minute,
		WriteTimeout: 5 * time.Minute,
	}

	log.Fatal(server.ListenAndServe())
}
<commit_msg>startup messages<commit_after>package main

import (
	"fmt"
	"ieveapi/apicache"
	"log"
	"net/http"
	"os"
	"runtime"
	"time"
)

var dc *DiskCache

func main() {
	log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime)
	if conf.LogFile != "" {
		logfp, err := os.OpenFile(conf.LogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			panic(fmt.Sprintf("Cannot Open Log File: %s", err))
		}
		log.SetOutput(logfp)
	}

	if conf.Threads == 0 {
		conf.Threads = runtime.NumCPU()
	}
	runtime.GOMAXPROCS(conf.Threads)
	log.Printf("EVEAPIProxy Starting Up with %d threads...", conf.Threads)

	log.Printf("Initializing Disk Cache...")
	dc = NewDiskCache(conf.CacheDir)
	log.Printf("Done.")

	apicache.NewClient(dc)
	startWorkers()

	var handler APIHandler

	server := http.Server{
		Addr:         conf.Listen,
		Handler:      &handler,
		ReadTimeout:  5 * time.Minute,
		WriteTimeout: 5 * time.Minute,
	}

	log.Fatal(server.ListenAndServe())
}
<|endoftext|>


<commit_before>// Copyright 2009 The 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.

// # $G $F.go && $L $F.$A && ./$A.out readfile.go
// # This is some data we can recognize

package main

func main() {
	var s string;
	var ok bool;

	s, ok = sys.readfile("readfile.go");
	if !ok {
		print("couldn't readfile\n");
		sys.Exit(1)
	}
	start_of_file :=
		"// $G $F.go && $L $F.$A && ./$A.out readfile.go\n" +
		"// # This is some data we can recognize\n" +
		"\n" +
		"package main\n";
	if s[0:102] != start_of_file {
		print("wrong data\n");
		sys.Exit(1)
	}
}
<commit_msg>sys.readfile has been removed.  Remove the test case for it. It was disabled last week anyhow.<commit_after><|endoftext|>


<commit_before>package cryptdo

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha512"
	"hash"

	"golang.org/x/crypto/pbkdf2"

	"code.xoeb.us/cryptdo/cryptdopb"
)

type version interface {
	encrypt([]byte, string) (*cryptdopb.Message, error)
	decrypt(*cryptdopb.Message, string) ([]byte, error)
}

var (
	sha384 = sha512.New384

	v1 = &version1{
		iterations: 100000,
		hashAlg:    sha384,
		saltSize:   sha384().Size(),
		keySize:    32,
		nonceSize:  12,
	}
)

func lookup(vers int32) (version, bool) {
	switch vers {
	case 1:
		return v1, true
	default:
		return nil, false
	}
}

type version1 struct {
	// key derivation
	iterations int
	hashAlg    func() hash.Hash
	saltSize   int

	// encryption
	keySize   int
	nonceSize int
}

func (v *version1) encrypt(plaintext []byte, passphrase string) (*cryptdopb.Message, error) {
	salt, err := randomBytes(v.saltSize)
	if err != nil {
		return nil, err
	}

	key := v.key(passphrase, salt)
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	nonce, err := randomBytes(v.nonceSize)
	if err != nil {
		return nil, err
	}

	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)

	return &cryptdopb.Message{
		Version:    currentVersion,
		Salt:       salt,
		Nonce:      nonce,
		Ciphertext: ciphertext,
	}, nil
}

func (v *version1) decrypt(message *cryptdopb.Message, passphrase string) ([]byte, error) {
	key := v.key(passphrase, message.Salt)
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	if aesgcm.NonceSize() != len(message.Nonce) {
		return nil, &InvalidNonceError{
			expected: aesgcm.NonceSize(),
			actual:   len(message.Nonce),
		}
	}

	return aesgcm.Open(nil, message.Nonce, message.Ciphertext, nil)
}

func (v *version1) key(passphrase string, salt []byte) []byte {
	return pbkdf2.Key([]byte(passphrase), salt, v.iterations, v.keySize, v.hashAlg)
}
<commit_msg>this isn't really a default behavior<commit_after>package cryptdo

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha512"
	"hash"

	"golang.org/x/crypto/pbkdf2"

	"code.xoeb.us/cryptdo/cryptdopb"
)

type version interface {
	encrypt([]byte, string) (*cryptdopb.Message, error)
	decrypt(*cryptdopb.Message, string) ([]byte, error)
}

var (
	sha384 = sha512.New384

	v1 = &version1{
		iterations: 100000,
		hashAlg:    sha384,
		saltSize:   sha384().Size(),
		keySize:    32,
		nonceSize:  12,
	}
)

func lookup(vers int32) (version, bool) {
	switch vers {
	case 1:
		return v1, true
	}

	return nil, false
}

type version1 struct {
	// key derivation
	iterations int
	hashAlg    func() hash.Hash
	saltSize   int

	// encryption
	keySize   int
	nonceSize int
}

func (v *version1) encrypt(plaintext []byte, passphrase string) (*cryptdopb.Message, error) {
	salt, err := randomBytes(v.saltSize)
	if err != nil {
		return nil, err
	}

	key := v.key(passphrase, salt)
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	nonce, err := randomBytes(v.nonceSize)
	if err != nil {
		return nil, err
	}

	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)

	return &cryptdopb.Message{
		Version:    currentVersion,
		Salt:       salt,
		Nonce:      nonce,
		Ciphertext: ciphertext,
	}, nil
}

func (v *version1) decrypt(message *cryptdopb.Message, passphrase string) ([]byte, error) {
	key := v.key(passphrase, message.Salt)
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	if aesgcm.NonceSize() != len(message.Nonce) {
		return nil, &InvalidNonceError{
			expected: aesgcm.NonceSize(),
			actual:   len(message.Nonce),
		}
	}

	return aesgcm.Open(nil, message.Nonce, message.Ciphertext, nil)
}

func (v *version1) key(passphrase string, salt []byte) []byte {
	return pbkdf2.Key([]byte(passphrase), salt, v.iterations, v.keySize, v.hashAlg)
}
<|endoftext|>


<commit_before>// Package mmio provides data types that can be used to access memory mapped
// registers of peripherals. All methods in this package guarantee that compiler
// does not reorder method call with any memory load/store which is before it
// in source code.
package mmio

import (
	"sync/fence"
	"bits"
	"unsafe"
)

//c:volatile
type U8 struct {
	r uint8
}

func PtrU8(addr unsafe.Pointer) *U8 {
	return (*U8)(addr)
}

func AsU8(addr *uint8) *U8 {
	return (*U8)(unsafe.Pointer(addr))
}

func (r *U8) Addr() uintptr {
	return uintptr(unsafe.Pointer(r))
}

func (r *U8) SetBit(n int) {
	fence.Compiler()
	r.r |= uint8(1) << uint(n)
}

func (r *U8) ClearBit(n int) {
	fence.Compiler()
	r.r &^= uint8(1) << uint(n)
}

func (r *U8) Bit(n int) int {
	return int(r.r>>uint(n)) & 1
}

func (r *U8) StoreBit(n, v int) {
	mask := uint8(1) << uint(n)
	fence.Compiler()
	r.r = r.r&^mask | uint8(v<<uint(n))&mask
}

func (r *U8) Bits(mask uint8) uint8 {
	fence.Compiler()
	return r.r & mask
}

func (r *U8) StoreBits(mask, bits uint8) {
	fence.Compiler()
	r.r = r.r&^mask | bits&mask
}

func (r *U8) SetBits(mask uint8) {
	fence.Compiler()
	r.r |= mask
}

func (r *U8) ClearBits(mask uint8) {
	fence.Compiler()
	r.r &^= mask
}

func (r *U8) Load() uint8 {
	fence.Compiler()
	return r.r
}

func (r *U8) Store(v uint8) {
	fence.Compiler()
	r.r = v
}

func (r *U8) Field(mask uint8) int {
	fence.Compiler()
	return bits.Field32(uint32(r.r), uint32(mask))
}

func (r *U8) SetField(mask uint8, v int) {
	r.StoreBits(mask, uint8(bits.Make32(v, uint32(mask))))
}

type UM8 struct {
	U    *U8
	Mask uint8
}

func (b UM8) Set()             { b.U.SetBits(b.Mask) }
func (b UM8) Clear()           { b.U.ClearBits(b.Mask) }
func (b UM8) Load() uint8      { return b.U.Bits(b.Mask) }
func (b UM8) Store(bits uint8) { b.U.StoreBits(b.Mask, bits) }
func (b UM8) LoadVal() int     { return b.U.Field(uint8(b.Mask)) }
func (b UM8) StoreVal(v int)   { b.U.SetField(b.Mask, v) }

//c:volatile
type U16 struct {
	r uint16
}

func PtrU16(addr unsafe.Pointer) *U16 {
	return (*U16)(addr)
}

func AsU16(addr *uint16) *U16 {
	return (*U16)(unsafe.Pointer(addr))
}

func (r *U16) Addr() uintptr {
	return uintptr(unsafe.Pointer(r))
}

func (r *U16) SetBit(n int) {
	fence.Compiler()
	r.r |= uint16(1) << uint(n)
}

func (r *U16) ClearBit(n int) {
	fence.Compiler()
	r.r &^= uint16(1) << uint(n)
}

func (r *U16) Bit(n int) int {
	fence.Compiler()
	return int(r.r>>uint(n)) & 1
}

func (r *U16) StoreBit(n, v int) {
	mask := uint16(1) << uint(n)
	fence.Compiler()
	r.r = r.r&^mask | uint16(v<<uint(n))&mask
}

func (r *U16) Bits(mask uint16) uint16 {
	fence.Compiler()
	return r.r & mask
}

func (r *U16) StoreBits(mask, bits uint16) {
	fence.Compiler()
	r.r = r.r&^mask | bits&mask
}

func (r *U16) SetBits(mask uint16) {
	fence.Compiler()
	r.r |= mask
}

func (r *U16) ClearBits(mask uint16) {
	fence.Compiler()
	r.r &^= mask
}

func (r *U16) Load() uint16 {
	fence.Compiler()
	return r.r
}

func (r *U16) Store(v uint16) {
	fence.Compiler()
	r.r = v
}

func (r *U16) Field(mask uint16) int {
	fence.Compiler()
	return bits.Field32(uint32(r.r), uint32(mask))
}

func (r *U16) SetField(mask uint16, v int) {
	r.StoreBits(mask, uint16(bits.Make32(v, uint32(mask))))
}

type UM16 struct {
	U    *U16
	Mask uint16
}

func (b UM16) Set()              { b.U.SetBits(b.Mask) }
func (b UM16) Clear()            { b.U.ClearBits(b.Mask) }
func (b UM16) Load() uint16      { return b.U.Bits(b.Mask) }
func (b UM16) Store(bits uint16) { b.U.StoreBits(b.Mask, bits) }
func (b UM16) LoadVal() int      { return b.U.Field(uint16(b.Mask)) }
func (b UM16) StoreVal(v int)    { b.U.SetField(b.Mask, v) }

//c:volatile
type U32 struct {
	r uint32
}

func PtrU32(addr unsafe.Pointer) *U32 {
	return (*U32)(addr)
}

func AsU32(addr *uint32) *U32 {
	return (*U32)(unsafe.Pointer(addr))
}

func (r *U32) Addr() uintptr {
	return uintptr(unsafe.Pointer(r))
}

func (r *U32) SetBit(n int) {
	fence.Compiler()
	r.r |= uint32(1) << uint(n)
}

func (r *U32) ClearBit(n int) {
	fence.Compiler()
	r.r &^= uint32(1) << uint(n)
}

func (r *U32) Bit(n int) int {
	fence.Compiler()
	return int(r.r>>uint(n)) & 1
}

func (r *U32) StoreBit(n, v int) {
	mask := uint32(1) << uint(n)
	fence.Compiler()
	r.r = r.r&^mask | uint32(v<<uint(n))&mask
}
func (r *U32) Bits(mask uint32) uint32 {
	fence.Compiler()
	return r.r & mask
}

func (r *U32) StoreBits(mask, bits uint32) {
	fence.Compiler()
	r.r = r.r&^mask | bits&mask
}

func (r *U32) SetBits(mask uint32) {
	fence.Compiler()
	r.r |= mask
}

func (r *U32) ClearBits(mask uint32) {
	fence.Compiler()
	r.r &^= mask
}

func (r *U32) Load() uint32 {
	fence.Compiler()
	return r.r
}

func (r *U32) Store(v uint32) {
	fence.Compiler()
	r.r = v
}

func (r *U32) Field(mask uint32) int {
	fence.Compiler()
	return bits.Field32(r.r, mask)
}

func (r *U32) SetField(mask uint32, v int) {
	r.StoreBits(mask, bits.Make32(v, mask))
}

type UM32 struct {
	U    *U32
	Mask uint32
}

func (b UM32) Set()              { b.U.SetBits(b.Mask) }
func (b UM32) Clear()            { b.U.ClearBits(b.Mask) }
func (b UM32) Load() uint32      { return b.U.Bits(b.Mask) }
func (b UM32) Store(bits uint32) { b.U.StoreBits(b.Mask, bits) }
func (b UM32) LoadVal() int      { return b.U.Field(uint32(b.Mask)) }
func (b UM32) StoreVal(v int)    { b.U.SetField(b.Mask, v) }
<commit_msg>mmio: Avoid compiler fence (volatile must suffice).<commit_after>// Package mmio provides data types that can be used to access memory mapped
// registers of peripherals.
package mmio

import (
	"bits"
	"unsafe"
)

//c:volatile
type U8 struct {
	r uint8
}

func PtrU8(addr unsafe.Pointer) *U8 {
	return (*U8)(addr)
}

func AsU8(addr *uint8) *U8 {
	return (*U8)(unsafe.Pointer(addr))
}

func (r *U8) Addr() uintptr {
	return uintptr(unsafe.Pointer(r))
}

func (r *U8) SetBit(n int) {
	r.r |= uint8(1) << uint(n)
}

func (r *U8) ClearBit(n int) {
	r.r &^= uint8(1) << uint(n)
}

func (r *U8) Bit(n int) int {
	return int(r.r>>uint(n)) & 1
}

func (r *U8) StoreBit(n, v int) {
	mask := uint8(1) << uint(n)
	r.r = r.r&^mask | uint8(v<<uint(n))&mask
}

func (r *U8) Bits(mask uint8) uint8 {
	return r.r & mask
}

func (r *U8) StoreBits(mask, bits uint8) {
	r.r = r.r&^mask | bits&mask
}

func (r *U8) SetBits(mask uint8) {
	r.r |= mask
}

func (r *U8) ClearBits(mask uint8) {
	r.r &^= mask
}

func (r *U8) Load() uint8 {
	return r.r
}

func (r *U8) Store(v uint8) {
	r.r = v
}

func (r *U8) Field(mask uint8) int {
	return bits.Field32(uint32(r.r), uint32(mask))
}

func (r *U8) SetField(mask uint8, v int) {
	r.StoreBits(mask, uint8(bits.Make32(v, uint32(mask))))
}

type UM8 struct {
	U    *U8
	Mask uint8
}

func (b UM8) Set()             { b.U.SetBits(b.Mask) }
func (b UM8) Clear()           { b.U.ClearBits(b.Mask) }
func (b UM8) Load() uint8      { return b.U.Bits(b.Mask) }
func (b UM8) Store(bits uint8) { b.U.StoreBits(b.Mask, bits) }
func (b UM8) LoadVal() int     { return b.U.Field(uint8(b.Mask)) }
func (b UM8) StoreVal(v int)   { b.U.SetField(b.Mask, v) }

//c:volatile
type U16 struct {
	r uint16
}

func PtrU16(addr unsafe.Pointer) *U16 {
	return (*U16)(addr)
}

func AsU16(addr *uint16) *U16 {
	return (*U16)(unsafe.Pointer(addr))
}

func (r *U16) Addr() uintptr {
	return uintptr(unsafe.Pointer(r))
}

func (r *U16) SetBit(n int) {
	r.r |= uint16(1) << uint(n)
}

func (r *U16) ClearBit(n int) {
	r.r &^= uint16(1) << uint(n)
}

func (r *U16) Bit(n int) int {
	return int(r.r>>uint(n)) & 1
}

func (r *U16) StoreBit(n, v int) {
	mask := uint16(1) << uint(n)
	r.r = r.r&^mask | uint16(v<<uint(n))&mask
}

func (r *U16) Bits(mask uint16) uint16 {
	return r.r & mask
}

func (r *U16) StoreBits(mask, bits uint16) {
	r.r = r.r&^mask | bits&mask
}

func (r *U16) SetBits(mask uint16) {
	r.r |= mask
}

func (r *U16) ClearBits(mask uint16) {
	r.r &^= mask
}

func (r *U16) Load() uint16 {
	return r.r
}

func (r *U16) Store(v uint16) {
	r.r = v
}

func (r *U16) Field(mask uint16) int {
	return bits.Field32(uint32(r.r), uint32(mask))
}

func (r *U16) SetField(mask uint16, v int) {
	r.StoreBits(mask, uint16(bits.Make32(v, uint32(mask))))
}

type UM16 struct {
	U    *U16
	Mask uint16
}

func (b UM16) Set()              { b.U.SetBits(b.Mask) }
func (b UM16) Clear()            { b.U.ClearBits(b.Mask) }
func (b UM16) Load() uint16      { return b.U.Bits(b.Mask) }
func (b UM16) Store(bits uint16) { b.U.StoreBits(b.Mask, bits) }
func (b UM16) LoadVal() int      { return b.U.Field(uint16(b.Mask)) }
func (b UM16) StoreVal(v int)    { b.U.SetField(b.Mask, v) }

//c:volatile
type U32 struct {
	r uint32
}

func PtrU32(addr unsafe.Pointer) *U32 {
	return (*U32)(addr)
}

func AsU32(addr *uint32) *U32 {
	return (*U32)(unsafe.Pointer(addr))
}

func (r *U32) Addr() uintptr {
	return uintptr(unsafe.Pointer(r))
}

func (r *U32) SetBit(n int) {
	r.r |= uint32(1) << uint(n)
}

func (r *U32) ClearBit(n int) {
	r.r &^= uint32(1) << uint(n)
}

func (r *U32) Bit(n int) int {
	return int(r.r>>uint(n)) & 1
}

func (r *U32) StoreBit(n, v int) {
	mask := uint32(1) << uint(n)
	r.r = r.r&^mask | uint32(v<<uint(n))&mask
}
func (r *U32) Bits(mask uint32) uint32 {
	return r.r & mask
}

func (r *U32) StoreBits(mask, bits uint32) {
	r.r = r.r&^mask | bits&mask
}

func (r *U32) SetBits(mask uint32) {
	r.r |= mask
}

func (r *U32) ClearBits(mask uint32) {
	r.r &^= mask
}

func (r *U32) Load() uint32 {
	return r.r
}

func (r *U32) Store(v uint32) {
	r.r = v
}

func (r *U32) Field(mask uint32) int {
	return bits.Field32(r.r, mask)
}

func (r *U32) SetField(mask uint32, v int) {
	r.StoreBits(mask, bits.Make32(v, mask))
}

type UM32 struct {
	U    *U32
	Mask uint32
}

func (b UM32) Set()              { b.U.SetBits(b.Mask) }
func (b UM32) Clear()            { b.U.ClearBits(b.Mask) }
func (b UM32) Load() uint32      { return b.U.Bits(b.Mask) }
func (b UM32) Store(bits uint32) { b.U.StoreBits(b.Mask, bits) }
func (b UM32) LoadVal() int      { return b.U.Field(uint32(b.Mask)) }
func (b UM32) StoreVal(v int)    { b.U.SetField(b.Mask, v) }
<|endoftext|>


<commit_before>package downloader

import (
	//"errors"
	"github.com/nladuo/go-webcrawler/model"
	//"log"
	"net/http"
	netUrl "net/url"
	"time"
)

var (
	//default timeout
	proxyTimeOut time.Duration = 40 * time.Second
)

type Downloader interface {
	Download(tag string, task model.Task) *model.Result
	SetRetryTimes(times int)
}

func dowloadDirect(url string) (*http.Response, error) {
	return http.Get(url)
}

func dowloadWithProxy(url string, proxy *model.Proxy) (*http.Response, error) {
	request, _ := http.NewRequest("GET", url, nil)
	proxyStr := "http://" + proxy.IP + ":" + proxy.Port
	proxyUrl, err := netUrl.Parse(proxyStr)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxyUrl),
		},
	}

	client.Timeout = proxyTimeOut

	return client.Do(request)
}

func SetProxyTimeOut(timeout time.Duration) {
	proxyTimeOut = timeout
}
<commit_msg>	modified:   downloader/downloader.go<commit_after>package downloader

import (
	//"errors"
	"github.com/nladuo/go-webcrawler/model"
	//"log"
	"net/http"
	netUrl "net/url"
	"time"
)

var (
	//default timeout
	proxyTimeOut time.Duration = 0 * time.Second
)

type Downloader interface {
	Download(tag string, task model.Task) *model.Result
	SetRetryTimes(times int)
}

func dowloadDirect(url string) (*http.Response, error) {
	return http.Get(url)
}

func dowloadWithProxy(url string, proxy *model.Proxy) (*http.Response, error) {
	request, _ := http.NewRequest("GET", url, nil)
	proxyStr := "http://" + proxy.IP + ":" + proxy.Port
	proxyUrl, err := netUrl.Parse(proxyStr)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxyUrl),
		},
	}

	if proxyTimeOut != 0*time.Second {
		client.Timeout = proxyTimeOut
	}

	return client.Do(request)
}

func SetProxyTimeOut(timeout time.Duration) {
	proxyTimeOut = timeout
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package tchannel

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/uber/tchannel-go/typed"
)

type testCallReq int

const (
	reqHasHeaders testCallReq = (1 << iota)
	reqHasChecksum
	reqTotalCombinations
)

func (cr testCallReq) req() lazyCallReq {
	// TODO: Constructing a frame is ugly because the initial flags byte is
	// written in reqResWriter instead of callReq. We should instead handle that
	// in callReq, which will allow our tests to be sane.
	f := NewFrame(100)
	fh := fakeHeader()
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)
	payload.WriteSingleByte(0)           // flags
	payload.WriteUint32(42)              // TTL
	payload.WriteBytes(make([]byte, 25)) // tracing
	payload.WriteLen8String("bankmoji")  // service

	if cr&reqHasHeaders == 0 {
		writeHeaders(payload, 0)
	} else {
		writeHeaders(payload, 3)
	}

	if cr&reqHasChecksum == 0 {
		checksum := ChecksumTypeCrc32C
		payload.WriteSingleByte(byte(checksum)) // checksum type
		payload.WriteUint32(0)                  // checksum contents
	} else {
		checksum := ChecksumTypeNone
		payload.WriteSingleByte(byte(checksum)) // checksum type
		// no checksum contents for None
	}
	payload.WriteLen16String("moneys") // method
	return newLazyCallReq(f)
}

func withLazyCallReqCombinations(f func(cr testCallReq)) {
	for cr := testCallReq(0); cr < reqTotalCombinations; cr++ {
		f(cr)
	}
}

type testCallRes int

const (
	resIsContinued testCallRes = (1 << iota)
	resIsOK
	resHasHeaders
	resHasChecksum
	resTotalCombinations
)

func (cr testCallRes) res() lazyCallRes {
	f := NewFrame(100)
	fh := FrameHeader{
		size:        uint16(0xFF34),
		messageType: messageTypeCallRes,
		ID:          0xDEADBEEF,
	}
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)

	if cr&resIsContinued == 0 {
		payload.WriteSingleByte(hasMoreFragmentsFlag) // flags
	} else {
		payload.WriteSingleByte(0) // flags
	}

	if cr&resIsOK == 0 {
		payload.WriteSingleByte(0) // code ok
	} else {
		payload.WriteSingleByte(1) // code not ok
	}

	if cr&resHasHeaders == 0 {
		writeHeaders(payload, 0)
	} else {
		writeHeaders(payload, 3)
	}

	if cr&resHasChecksum == 0 {
		payload.WriteSingleByte(byte(ChecksumTypeCrc32C)) // checksum type
		payload.WriteUint32(0)                            // checksum contents
	} else {
		payload.WriteSingleByte(byte(ChecksumTypeNone)) // checksum type
		// No contents for ChecksumTypeNone.
	}
	payload.WriteUint16(0) // no arg1 for call res
	return newLazyCallRes(f)
}

func withLazyCallResCombinations(f func(cr testCallRes)) {
	for cr := testCallRes(0); cr < resTotalCombinations; cr++ {
		f(cr)
	}
}

func (ec SystemErrCode) fakeErrFrame() lazyError {
	f := NewFrame(100)
	fh := FrameHeader{
		size:        uint16(0xFF34),
		messageType: messageTypeError,
		ID:          invalidMessageID,
	}
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)
	payload.WriteSingleByte(byte(ec))
	payload.WriteBytes(make([]byte, 25)) // tracing

	msg := ec.String()
	payload.WriteUint16(uint16(len(msg)))
	payload.WriteBytes([]byte(msg))
	return newLazyError(f)
}

func withLazyErrorCombinations(f func(ec SystemErrCode)) {
	codes := []SystemErrCode{
		ErrCodeInvalid,
		ErrCodeTimeout,
		ErrCodeCancelled,
		ErrCodeBusy,
		ErrCodeDeclined,
		ErrCodeUnexpected,
		ErrCodeBadRequest,
		ErrCodeNetwork,
		ErrCodeProtocol,
	}
	for _, ec := range codes {
		f(ec)
	}
}

func writeHeaders(w *typed.WriteBuffer, num uint8) {
	w.WriteSingleByte(num) // number of headers
	for i := uint8(1); i <= num; i++ {
		w.WriteLen8String(fmt.Sprintf("k%d", i)) // key
		w.WriteLen8String(fmt.Sprintf("v%d", i)) // value
	}
}

func assertWrappingPanics(t testing.TB, f *Frame, wrap func(f *Frame)) {
	assert.Panics(t, func() {
		wrap(f)
	}, "Should panic when wrapping an unexpected frame type.")
}

func TestLazyCallReqRejectsOtherFrames(t *testing.T) {
	assertWrappingPanics(
		t,
		resIsContinued.res().Frame,
		func(f *Frame) { newLazyCallReq(f) },
	)
}

func TestLazyCallReqService(t *testing.T) {
	withLazyCallReqCombinations(func(crt testCallReq) {
		cr := crt.req()
		assert.Equal(t, "bankmoji", cr.Service(), "Service name mismatch")
	})
}

func TestLazyCallReqMethod(t *testing.T) {
	withLazyCallReqCombinations(func(crt testCallReq) {
		cr := crt.req()
		assert.Equal(t, "moneys", cr.Method(), "Method name mismatch")
	})
}

func TestLazyCallReqTTL(t *testing.T) {
	withLazyCallReqCombinations(func(crt testCallReq) {
		cr := crt.req()
		assert.Equal(t, 42*time.Millisecond, cr.TTL(), "Failed to parse TTL from frame.")
	})
}

func TestLazyCallResRejectsOtherFrames(t *testing.T) {
	assertWrappingPanics(
		t,
		reqHasHeaders.req().Frame,
		func(f *Frame) { newLazyCallRes(f) },
	)
}

func TestLazyCallResOK(t *testing.T) {
	withLazyCallResCombinations(func(crt testCallRes) {
		cr := crt.res()
		if crt&resIsOK == 0 {
			assert.True(t, cr.OK(), "Expected call res to have code ok.")
		} else {
			assert.False(t, cr.OK(), "Expected call res to have a non-ok code.")
		}
	})
}

func TestLazyErrorRejectsOtherFrames(t *testing.T) {
	assertWrappingPanics(
		t,
		reqHasHeaders.req().Frame,
		func(f *Frame) { newLazyError(f) },
	)
}

func TestLazyErrorCodes(t *testing.T) {
	withLazyErrorCombinations(func(ec SystemErrCode) {
		f := ec.fakeErrFrame()
		assert.Equal(t, ec, f.Code(), "Mismatch between error code and lazy frame's Code() method.")
	})
}
<commit_msg>Fix bit-flag logic in relay message tests<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package tchannel

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/uber/tchannel-go/typed"
)

type testCallReq int

const (
	reqHasHeaders testCallReq = (1 << iota)
	reqHasChecksum
	reqTotalCombinations
)

func (cr testCallReq) req() lazyCallReq {
	// TODO: Constructing a frame is ugly because the initial flags byte is
	// written in reqResWriter instead of callReq. We should instead handle that
	// in callReq, which will allow our tests to be sane.
	f := NewFrame(100)
	fh := fakeHeader()
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)
	payload.WriteSingleByte(0)           // flags
	payload.WriteUint32(42)              // TTL
	payload.WriteBytes(make([]byte, 25)) // tracing
	payload.WriteLen8String("bankmoji")  // service

	if cr&reqHasHeaders == 0 {
		writeHeaders(payload, 0)
	} else {
		writeHeaders(payload, 3)
	}

	if cr&reqHasChecksum == 0 {
		payload.WriteSingleByte(byte(ChecksumTypeNone)) // checksum type
		// no checksum contents for None
	} else {
		payload.WriteSingleByte(byte(ChecksumTypeCrc32C)) // checksum type
		payload.WriteUint32(0)                            // checksum contents
	}
	payload.WriteLen16String("moneys") // method
	return newLazyCallReq(f)
}

func withLazyCallReqCombinations(f func(cr testCallReq)) {
	for cr := testCallReq(0); cr < reqTotalCombinations; cr++ {
		f(cr)
	}
}

type testCallRes int

const (
	resIsContinued testCallRes = (1 << iota)
	resIsOK
	resHasHeaders
	resHasChecksum
	resTotalCombinations
)

func (cr testCallRes) res() lazyCallRes {
	f := NewFrame(100)
	fh := FrameHeader{
		size:        uint16(0xFF34),
		messageType: messageTypeCallRes,
		ID:          0xDEADBEEF,
	}
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)

	if cr&resIsContinued == 0 {
		payload.WriteSingleByte(0) // flags
	} else {
		payload.WriteSingleByte(hasMoreFragmentsFlag) // flags
	}

	if cr&resIsOK == 0 {
		payload.WriteSingleByte(1) // code not ok
	} else {
		payload.WriteSingleByte(0) // code ok
	}

	if cr&resHasHeaders == 0 {
		writeHeaders(payload, 0)
	} else {
		writeHeaders(payload, 3)
	}

	if cr&resHasChecksum == 0 {
		payload.WriteSingleByte(byte(ChecksumTypeNone)) // checksum type
		// No contents for ChecksumTypeNone.
	} else {
		payload.WriteSingleByte(byte(ChecksumTypeCrc32C)) // checksum type
		payload.WriteUint32(0)                            // checksum contents
	}
	payload.WriteUint16(0) // no arg1 for call res
	return newLazyCallRes(f)
}

func withLazyCallResCombinations(f func(cr testCallRes)) {
	for cr := testCallRes(0); cr < resTotalCombinations; cr++ {
		f(cr)
	}
}

func (ec SystemErrCode) fakeErrFrame() lazyError {
	f := NewFrame(100)
	fh := FrameHeader{
		size:        uint16(0xFF34),
		messageType: messageTypeError,
		ID:          invalidMessageID,
	}
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)
	payload.WriteSingleByte(byte(ec))
	payload.WriteBytes(make([]byte, 25)) // tracing

	msg := ec.String()
	payload.WriteUint16(uint16(len(msg)))
	payload.WriteBytes([]byte(msg))
	return newLazyError(f)
}

func withLazyErrorCombinations(f func(ec SystemErrCode)) {
	codes := []SystemErrCode{
		ErrCodeInvalid,
		ErrCodeTimeout,
		ErrCodeCancelled,
		ErrCodeBusy,
		ErrCodeDeclined,
		ErrCodeUnexpected,
		ErrCodeBadRequest,
		ErrCodeNetwork,
		ErrCodeProtocol,
	}
	for _, ec := range codes {
		f(ec)
	}
}

func writeHeaders(w *typed.WriteBuffer, num uint8) {
	w.WriteSingleByte(num) // number of headers
	for i := uint8(1); i <= num; i++ {
		w.WriteLen8String(fmt.Sprintf("k%d", i)) // key
		w.WriteLen8String(fmt.Sprintf("v%d", i)) // value
	}
}

func assertWrappingPanics(t testing.TB, f *Frame, wrap func(f *Frame)) {
	assert.Panics(t, func() {
		wrap(f)
	}, "Should panic when wrapping an unexpected frame type.")
}

func TestLazyCallReqRejectsOtherFrames(t *testing.T) {
	assertWrappingPanics(
		t,
		resIsContinued.res().Frame,
		func(f *Frame) { newLazyCallReq(f) },
	)
}

func TestLazyCallReqService(t *testing.T) {
	withLazyCallReqCombinations(func(crt testCallReq) {
		cr := crt.req()
		assert.Equal(t, "bankmoji", cr.Service(), "Service name mismatch")
	})
}

func TestLazyCallReqMethod(t *testing.T) {
	withLazyCallReqCombinations(func(crt testCallReq) {
		cr := crt.req()
		assert.Equal(t, "moneys", cr.Method(), "Method name mismatch")
	})
}

func TestLazyCallReqTTL(t *testing.T) {
	withLazyCallReqCombinations(func(crt testCallReq) {
		cr := crt.req()
		assert.Equal(t, 42*time.Millisecond, cr.TTL(), "Failed to parse TTL from frame.")
	})
}

func TestLazyCallResRejectsOtherFrames(t *testing.T) {
	assertWrappingPanics(
		t,
		reqHasHeaders.req().Frame,
		func(f *Frame) { newLazyCallRes(f) },
	)
}

func TestLazyCallResOK(t *testing.T) {
	withLazyCallResCombinations(func(crt testCallRes) {
		cr := crt.res()
		if crt&resIsOK == 0 {
			assert.False(t, cr.OK(), "Expected call res to have a non-ok code.")
		} else {
			assert.True(t, cr.OK(), "Expected call res to have code ok.")
		}
	})
}

func TestLazyErrorRejectsOtherFrames(t *testing.T) {
	assertWrappingPanics(
		t,
		reqHasHeaders.req().Frame,
		func(f *Frame) { newLazyError(f) },
	)
}

func TestLazyErrorCodes(t *testing.T) {
	withLazyErrorCombinations(func(ec SystemErrCode) {
		f := ec.fakeErrFrame()
		assert.Equal(t, ec, f.Code(), "Mismatch between error code and lazy frame's Code() method.")
	})
}
<|endoftext|>


<commit_before>package repo

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/kopia/kopia/blob"
	"github.com/kopia/kopia/internal/config"
	"github.com/kopia/kopia/internal/jsonstream"
)

// ObjectReader allows reading, seeking, getting the length of and closing of a repository object.
type ObjectReader interface {
	io.Reader
	io.Seeker
	io.Closer
	Length() int64
}

// ObjectManager implements a content-addressable storage on top of blob storage.
type ObjectManager struct {
	stats   Stats
	storage blob.Storage

	verbose   bool
	format    config.RepositoryObjectFormat
	formatter objectFormatter

	packMgr *packManager

	async              bool
	writeBackWG        sync.WaitGroup
	writeBackSemaphore semaphore

	trace func(message string, args ...interface{})

	newSplitter func() objectSplitter
}

// Close closes the connection to the underlying blob storage and releases any resources.
func (r *ObjectManager) Close() error {
	r.writeBackWG.Wait()
	return r.Flush()
}

// Optimize performs object optimizations to improve performance of future operations.
// The opeartion will not affect objects written after cutoffTime to prevent race conditions.
func (r *ObjectManager) Optimize(cutoffTime time.Time) error {
	if err := r.packMgr.Compact(cutoffTime); err != nil {
		return err
	}

	return nil
}

// NewWriter creates an ObjectWriter for writing to the repository.
func (r *ObjectManager) NewWriter(opt WriterOptions) ObjectWriter {
	w := &objectWriter{
		repo:        r,
		splitter:    r.newSplitter(),
		description: opt.Description,
		prefix:      opt.BlockNamePrefix,
		packGroup:   opt.PackGroup,
	}

	if opt.splitter != nil {
		w.splitter = opt.splitter
	}

	return w
}

// Open creates new ObjectReader for reading given object from a repository.
func (r *ObjectManager) Open(objectID ObjectID) (ObjectReader, error) {
	// log.Printf("Repository::Open %v", objectID.String())
	// defer log.Printf("finished Repository::Open() %v", objectID.String())

	// Flush any pending writes.
	r.writeBackWG.Wait()

	if objectID.Section != nil {
		baseReader, err := r.Open(objectID.Section.Base)
		if err != nil {
			return nil, fmt.Errorf("cannot create base reader: %+v %v", objectID.Section.Base, err)
		}

		return newObjectSectionReader(objectID.Section.Start, objectID.Section.Length, baseReader)
	}

	if objectID.Indirect != nil {
		rd, err := r.Open(*objectID.Indirect)
		if err != nil {
			return nil, err
		}
		defer rd.Close()

		seekTable, err := r.flattenListChunk(rd)
		if err != nil {
			return nil, err
		}

		totalLength := seekTable[len(seekTable)-1].endOffset()

		return &objectReader{
			repo:        r,
			seekTable:   seekTable,
			totalLength: totalLength,
		}, nil
	}

	return r.newRawReader(objectID)
}

// VerifyObject ensures that all objects backing ObjectID are present in the repository
// and returns the total length of the object and storage blocks of which it is composed.
func (r *ObjectManager) VerifyObject(oid ObjectID) (int64, []string, error) {
	// Flush any pending writes.
	r.writeBackWG.Wait()

	blocks := &blockTracker{}
	l, err := r.verifyObjectInternal(oid, blocks)
	if err != nil {
		return 0, nil, err
	}

	return l, blocks.blockIDs(), nil
}

func (r *ObjectManager) verifyObjectInternal(oid ObjectID, blocks *blockTracker) (int64, error) {
	log.Printf("verifyObjectInternal %v", oid)
	if oid.Section != nil {
		l, err := r.verifyObjectInternal(oid.Section.Base, blocks)
		if err != nil {
			return 0, err
		}

		if oid.Section.Length >= 0 && oid.Section.Start+oid.Section.Length <= l {
			return oid.Section.Length, nil
		}

		return 0, fmt.Errorf("section object %q not within parent object size of %v", oid, l)
	}

	if oid.Indirect != nil {
		if _, err := r.verifyObjectInternal(*oid.Indirect, blocks); err != nil {
			return 0, fmt.Errorf("unable to read index: %v", err)
		}
		rd, err := r.Open(*oid.Indirect)
		if err != nil {
			return 0, err
		}
		defer rd.Close()

		seekTable, err := r.flattenListChunk(rd)
		if err != nil {
			return 0, err
		}

		for i, m := range seekTable {
			l, err := r.verifyObjectInternal(m.Object, blocks)
			if err != nil {
				return 0, err
			}

			if l != m.Length {
				return 0, fmt.Errorf("unexpected length of part %#v of indirect object %q: %v %v, expected %v", i, oid, m.Object, l, m.Length)
			}
		}

		totalLength := seekTable[len(seekTable)-1].endOffset()
		return totalLength, nil
	}

	p, isPacked, err := r.packMgr.blockIDToPackSection(oid.StorageBlock)
	if err != nil {
		return 0, err
	}

	if isPacked {
		l, err := r.verifyObjectInternal(p.Base, blocks)
		if err != nil {
			return 0, err
		}

		if p.Length >= 0 && p.Start+p.Length <= l {
			return p.Length, nil
		}

		return 0, fmt.Errorf("packed object %v does not fit within its parent pack %v (pack length %v)", oid, p, l)
	}

	l, err := r.packMgr.blockSize(oid.StorageBlock)
	if err != nil {
		return 0, fmt.Errorf("unable to read %q: %v", oid.StorageBlock, err)
	}

	blocks.addBlock(oid.StorageBlock)
	return l, nil
}

// Flush closes any pending pack files. Once this method returns, ObjectIDs returned by ObjectManager are
// ok to be used.
func (r *ObjectManager) Flush() error {
	r.writeBackWG.Wait()
	return r.packMgr.Flush()
}

func nullTrace(message string, args ...interface{}) {
}

// newObjectManager creates an ObjectManager with the specified storage, format and options.
func newObjectManager(s blob.Storage, f config.RepositoryObjectFormat, opts *Options) (*ObjectManager, error) {
	if err := validateFormat(&f); err != nil {
		return nil, err
	}

	sf := objectFormatterFactories[f.ObjectFormat]
	r := &ObjectManager{
		storage: s,
		format:  f,
		trace:   nullTrace,
	}

	os := objectSplitterFactories[applyDefaultString(f.Splitter, "FIXED")]
	if os == nil {
		return nil, fmt.Errorf("unsupported splitter %q", f.Splitter)
	}

	r.newSplitter = func() objectSplitter {
		return os(&r.format)
	}

	var err error
	r.formatter, err = sf(&r.format)
	if err != nil {
		return nil, err
	}

	if opts != nil {
		if opts.TraceObjectManager != nil {
			r.trace = opts.TraceObjectManager
		} else {
			r.trace = nullTrace
		}
		if opts.WriteBack > 0 {
			r.async = true
			r.writeBackSemaphore = make(semaphore, opts.WriteBack)
		}
	}

	r.packMgr = newPackManager(r)

	return r, nil
}

// hashEncryptAndWrite computes hash of a given buffer, optionally encrypts and writes it to storage.
// The write is not guaranteed to complete synchronously in case write-back is used, but by the time
// Repository.Close() returns all writes are guaranteed be over.
func (r *ObjectManager) hashEncryptAndWrite(packGroup string, buffer *bytes.Buffer, prefix string, isPackInternalObject bool) (ObjectID, error) {
	var data []byte
	if buffer != nil {
		data = buffer.Bytes()
	}

	// Hash the block and compute encryption key.
	objectID := r.formatter.ComputeObjectID(data)
	objectID.StorageBlock = prefix + objectID.StorageBlock
	atomic.AddInt32(&r.stats.HashedBlocks, 1)
	atomic.AddInt64(&r.stats.HashedBytes, int64(len(data)))

	if !isPackInternalObject {
		if r.format.MaxPackedContentLength > 0 && len(data) <= r.format.MaxPackedContentLength {
			packOID, err := r.packMgr.AddToPack(packGroup, objectID.StorageBlock, data)
			return packOID, err
		}

		// Before performing encryption, check if the block is already there.
		blockSize, err := r.packMgr.blockSize(objectID.StorageBlock)
		atomic.AddInt32(&r.stats.CheckedBlocks, int32(1))
		if err == nil && blockSize == int64(len(data)) {
			atomic.AddInt32(&r.stats.PresentBlocks, int32(1))
			// Block already exists in storage, correct size, return without uploading.
			return objectID, nil
		}

		if err != nil && err != blob.ErrBlockNotFound {
			// Don't know whether block exists in storage.
			return NullObjectID, err
		}
	}

	// Encrypt the block in-place.
	atomic.AddInt64(&r.stats.EncryptedBytes, int64(len(data)))
	data, err := r.formatter.Encrypt(data, objectID, 0)
	if err != nil {
		return NullObjectID, err
	}

	atomic.AddInt32(&r.stats.WrittenBlocks, int32(1))
	atomic.AddInt64(&r.stats.WrittenBytes, int64(len(data)))

	if err := r.storage.PutBlock(objectID.StorageBlock, data); err != nil {
		return NullObjectID, err
	}

	if !isPackInternalObject {
		r.packMgr.RegisterUnpackedBlock(objectID.StorageBlock, int64(len(data)))
	}
	return objectID, nil
}

func (r *ObjectManager) flattenListChunk(rawReader io.Reader) ([]indirectObjectEntry, error) {
	pr, err := jsonstream.NewReader(bufio.NewReader(rawReader), indirectStreamType)
	if err != nil {
		return nil, err
	}
	var seekTable []indirectObjectEntry

	for {
		var oe indirectObjectEntry

		err := pr.Read(&oe)
		if err == io.EOF {
			break
		}

		if err != nil {
			log.Printf("Failed to read indirect object: %v", err)
			return nil, err
		}

		seekTable = append(seekTable, oe)
	}

	return seekTable, nil
}

func (r *ObjectManager) newRawReader(objectID ObjectID) (ObjectReader, error) {
	var payload []byte
	var err error
	underlyingObjectID := objectID
	var decryptSkip int

	p, ok, err := r.packMgr.blockIDToPackSection(objectID.StorageBlock)
	if err != nil {
		return nil, err
	}
	if ok {
		payload, err = r.storage.GetBlock(p.Base.StorageBlock, p.Start, p.Length)
		underlyingObjectID = p.Base
		decryptSkip = int(p.Start)
	} else {
		payload, err = r.storage.GetBlock(objectID.StorageBlock, 0, -1)
	}

	if err != nil {
		return nil, err
	}

	atomic.AddInt32(&r.stats.ReadBlocks, 1)
	atomic.AddInt64(&r.stats.ReadBytes, int64(len(payload)))

	payload, err = r.formatter.Decrypt(payload, underlyingObjectID, decryptSkip)
	atomic.AddInt64(&r.stats.DecryptedBytes, int64(len(payload)))
	if err != nil {
		return nil, err
	}

	// Since the encryption key is a function of data, we must be able to generate exactly the same key
	// after decrypting the content. This serves as a checksum.
	if err := r.verifyChecksum(payload, objectID.StorageBlock); err != nil {
		return nil, err
	}

	return newObjectReaderWithData(payload), nil
}

func (r *ObjectManager) verifyChecksum(data []byte, blockID string) error {
	expected := r.formatter.ComputeObjectID(data)
	if !strings.HasSuffix(blockID, expected.StorageBlock) {
		atomic.AddInt32(&r.stats.InvalidBlocks, 1)
		return fmt.Errorf("invalid checksum for blob: '%v', expected %v", blockID, expected.StorageBlock)
	}

	atomic.AddInt32(&r.stats.ValidBlocks, 1)
	return nil
}

type readerWithData struct {
	io.ReadSeeker
	length int64
}

func (rwd *readerWithData) Close() error {
	return nil
}

func (rwd *readerWithData) Length() int64 {
	return rwd.length
}

func newObjectReaderWithData(data []byte) ObjectReader {
	return &readerWithData{
		ReadSeeker: bytes.NewReader(data),
		length:     int64(len(data)),
	}
}
<commit_msg>cleanup<commit_after>package repo

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/kopia/kopia/blob"
	"github.com/kopia/kopia/internal/config"
	"github.com/kopia/kopia/internal/jsonstream"
)

// ObjectReader allows reading, seeking, getting the length of and closing of a repository object.
type ObjectReader interface {
	io.Reader
	io.Seeker
	io.Closer
	Length() int64
}

// ObjectManager implements a content-addressable storage on top of blob storage.
type ObjectManager struct {
	stats   Stats
	storage blob.Storage

	verbose   bool
	format    config.RepositoryObjectFormat
	formatter objectFormatter

	packMgr *packManager

	async              bool
	writeBackWG        sync.WaitGroup
	writeBackSemaphore semaphore

	trace func(message string, args ...interface{})

	newSplitter func() objectSplitter
}

// Close closes the connection to the underlying blob storage and releases any resources.
func (r *ObjectManager) Close() error {
	r.writeBackWG.Wait()
	return r.Flush()
}

// Optimize performs object optimizations to improve performance of future operations.
// The opeartion will not affect objects written after cutoffTime to prevent race conditions.
func (r *ObjectManager) Optimize(cutoffTime time.Time) error {
	if err := r.packMgr.Compact(cutoffTime); err != nil {
		return err
	}

	return nil
}

// NewWriter creates an ObjectWriter for writing to the repository.
func (r *ObjectManager) NewWriter(opt WriterOptions) ObjectWriter {
	w := &objectWriter{
		repo:        r,
		splitter:    r.newSplitter(),
		description: opt.Description,
		prefix:      opt.BlockNamePrefix,
		packGroup:   opt.PackGroup,
	}

	if opt.splitter != nil {
		w.splitter = opt.splitter
	}

	return w
}

// Open creates new ObjectReader for reading given object from a repository.
func (r *ObjectManager) Open(objectID ObjectID) (ObjectReader, error) {
	// log.Printf("Repository::Open %v", objectID.String())
	// defer log.Printf("finished Repository::Open() %v", objectID.String())

	// Flush any pending writes.
	r.writeBackWG.Wait()

	if objectID.Section != nil {
		baseReader, err := r.Open(objectID.Section.Base)
		if err != nil {
			return nil, fmt.Errorf("cannot create base reader: %+v %v", objectID.Section.Base, err)
		}

		return newObjectSectionReader(objectID.Section.Start, objectID.Section.Length, baseReader)
	}

	if objectID.Indirect != nil {
		rd, err := r.Open(*objectID.Indirect)
		if err != nil {
			return nil, err
		}
		defer rd.Close()

		seekTable, err := r.flattenListChunk(rd)
		if err != nil {
			return nil, err
		}

		totalLength := seekTable[len(seekTable)-1].endOffset()

		return &objectReader{
			repo:        r,
			seekTable:   seekTable,
			totalLength: totalLength,
		}, nil
	}

	return r.newRawReader(objectID)
}

// VerifyObject ensures that all objects backing ObjectID are present in the repository
// and returns the total length of the object and storage blocks of which it is composed.
func (r *ObjectManager) VerifyObject(oid ObjectID) (int64, []string, error) {
	// Flush any pending writes.
	r.writeBackWG.Wait()

	blocks := &blockTracker{}
	l, err := r.verifyObjectInternal(oid, blocks)
	if err != nil {
		return 0, nil, err
	}

	return l, blocks.blockIDs(), nil
}

func (r *ObjectManager) verifyObjectInternal(oid ObjectID, blocks *blockTracker) (int64, error) {
	//log.Printf("verifyObjectInternal %v", oid)
	if oid.Section != nil {
		l, err := r.verifyObjectInternal(oid.Section.Base, blocks)
		if err != nil {
			return 0, err
		}

		if oid.Section.Length >= 0 && oid.Section.Start+oid.Section.Length <= l {
			return oid.Section.Length, nil
		}

		return 0, fmt.Errorf("section object %q not within parent object size of %v", oid, l)
	}

	if oid.Indirect != nil {
		if _, err := r.verifyObjectInternal(*oid.Indirect, blocks); err != nil {
			return 0, fmt.Errorf("unable to read index: %v", err)
		}
		rd, err := r.Open(*oid.Indirect)
		if err != nil {
			return 0, err
		}
		defer rd.Close()

		seekTable, err := r.flattenListChunk(rd)
		if err != nil {
			return 0, err
		}

		for i, m := range seekTable {
			l, err := r.verifyObjectInternal(m.Object, blocks)
			if err != nil {
				return 0, err
			}

			if l != m.Length {
				return 0, fmt.Errorf("unexpected length of part %#v of indirect object %q: %v %v, expected %v", i, oid, m.Object, l, m.Length)
			}
		}

		totalLength := seekTable[len(seekTable)-1].endOffset()
		return totalLength, nil
	}

	p, isPacked, err := r.packMgr.blockIDToPackSection(oid.StorageBlock)
	if err != nil {
		return 0, err
	}

	if isPacked {
		l, err := r.verifyObjectInternal(p.Base, blocks)
		if err != nil {
			return 0, err
		}

		if p.Length >= 0 && p.Start+p.Length <= l {
			return p.Length, nil
		}

		return 0, fmt.Errorf("packed object %v does not fit within its parent pack %v (pack length %v)", oid, p, l)
	}

	l, err := r.packMgr.blockSize(oid.StorageBlock)
	if err != nil {
		return 0, fmt.Errorf("unable to read %q: %v", oid.StorageBlock, err)
	}

	blocks.addBlock(oid.StorageBlock)
	return l, nil
}

// Flush closes any pending pack files. Once this method returns, ObjectIDs returned by ObjectManager are
// ok to be used.
func (r *ObjectManager) Flush() error {
	r.writeBackWG.Wait()
	return r.packMgr.Flush()
}

func nullTrace(message string, args ...interface{}) {
}

// newObjectManager creates an ObjectManager with the specified storage, format and options.
func newObjectManager(s blob.Storage, f config.RepositoryObjectFormat, opts *Options) (*ObjectManager, error) {
	if err := validateFormat(&f); err != nil {
		return nil, err
	}

	sf := objectFormatterFactories[f.ObjectFormat]
	r := &ObjectManager{
		storage: s,
		format:  f,
		trace:   nullTrace,
	}

	os := objectSplitterFactories[applyDefaultString(f.Splitter, "FIXED")]
	if os == nil {
		return nil, fmt.Errorf("unsupported splitter %q", f.Splitter)
	}

	r.newSplitter = func() objectSplitter {
		return os(&r.format)
	}

	var err error
	r.formatter, err = sf(&r.format)
	if err != nil {
		return nil, err
	}

	if opts != nil {
		if opts.TraceObjectManager != nil {
			r.trace = opts.TraceObjectManager
		} else {
			r.trace = nullTrace
		}
		if opts.WriteBack > 0 {
			r.async = true
			r.writeBackSemaphore = make(semaphore, opts.WriteBack)
		}
	}

	r.packMgr = newPackManager(r)

	return r, nil
}

// hashEncryptAndWrite computes hash of a given buffer, optionally encrypts and writes it to storage.
// The write is not guaranteed to complete synchronously in case write-back is used, but by the time
// Repository.Close() returns all writes are guaranteed be over.
func (r *ObjectManager) hashEncryptAndWrite(packGroup string, buffer *bytes.Buffer, prefix string, isPackInternalObject bool) (ObjectID, error) {
	var data []byte
	if buffer != nil {
		data = buffer.Bytes()
	}

	// Hash the block and compute encryption key.
	objectID := r.formatter.ComputeObjectID(data)
	objectID.StorageBlock = prefix + objectID.StorageBlock
	atomic.AddInt32(&r.stats.HashedBlocks, 1)
	atomic.AddInt64(&r.stats.HashedBytes, int64(len(data)))

	if !isPackInternalObject {
		if r.format.MaxPackedContentLength > 0 && len(data) <= r.format.MaxPackedContentLength {
			packOID, err := r.packMgr.AddToPack(packGroup, objectID.StorageBlock, data)
			return packOID, err
		}

		// Before performing encryption, check if the block is already there.
		blockSize, err := r.packMgr.blockSize(objectID.StorageBlock)
		atomic.AddInt32(&r.stats.CheckedBlocks, int32(1))
		if err == nil && blockSize == int64(len(data)) {
			atomic.AddInt32(&r.stats.PresentBlocks, int32(1))
			// Block already exists in storage, correct size, return without uploading.
			return objectID, nil
		}

		if err != nil && err != blob.ErrBlockNotFound {
			// Don't know whether block exists in storage.
			return NullObjectID, err
		}
	}

	// Encrypt the block in-place.
	atomic.AddInt64(&r.stats.EncryptedBytes, int64(len(data)))
	data, err := r.formatter.Encrypt(data, objectID, 0)
	if err != nil {
		return NullObjectID, err
	}

	atomic.AddInt32(&r.stats.WrittenBlocks, int32(1))
	atomic.AddInt64(&r.stats.WrittenBytes, int64(len(data)))

	if err := r.storage.PutBlock(objectID.StorageBlock, data); err != nil {
		return NullObjectID, err
	}

	if !isPackInternalObject {
		r.packMgr.RegisterUnpackedBlock(objectID.StorageBlock, int64(len(data)))
	}
	return objectID, nil
}

func (r *ObjectManager) flattenListChunk(rawReader io.Reader) ([]indirectObjectEntry, error) {
	pr, err := jsonstream.NewReader(bufio.NewReader(rawReader), indirectStreamType)
	if err != nil {
		return nil, err
	}
	var seekTable []indirectObjectEntry

	for {
		var oe indirectObjectEntry

		err := pr.Read(&oe)
		if err == io.EOF {
			break
		}

		if err != nil {
			log.Printf("Failed to read indirect object: %v", err)
			return nil, err
		}

		seekTable = append(seekTable, oe)
	}

	return seekTable, nil
}

func (r *ObjectManager) newRawReader(objectID ObjectID) (ObjectReader, error) {
	var payload []byte
	var err error
	underlyingObjectID := objectID
	var decryptSkip int

	p, ok, err := r.packMgr.blockIDToPackSection(objectID.StorageBlock)
	if err != nil {
		return nil, err
	}
	if ok {
		payload, err = r.storage.GetBlock(p.Base.StorageBlock, p.Start, p.Length)
		underlyingObjectID = p.Base
		decryptSkip = int(p.Start)
	} else {
		payload, err = r.storage.GetBlock(objectID.StorageBlock, 0, -1)
	}

	if err != nil {
		return nil, err
	}

	atomic.AddInt32(&r.stats.ReadBlocks, 1)
	atomic.AddInt64(&r.stats.ReadBytes, int64(len(payload)))

	payload, err = r.formatter.Decrypt(payload, underlyingObjectID, decryptSkip)
	atomic.AddInt64(&r.stats.DecryptedBytes, int64(len(payload)))
	if err != nil {
		return nil, err
	}

	// Since the encryption key is a function of data, we must be able to generate exactly the same key
	// after decrypting the content. This serves as a checksum.
	if err := r.verifyChecksum(payload, objectID.StorageBlock); err != nil {
		return nil, err
	}

	return newObjectReaderWithData(payload), nil
}

func (r *ObjectManager) verifyChecksum(data []byte, blockID string) error {
	expected := r.formatter.ComputeObjectID(data)
	if !strings.HasSuffix(blockID, expected.StorageBlock) {
		atomic.AddInt32(&r.stats.InvalidBlocks, 1)
		return fmt.Errorf("invalid checksum for blob: '%v', expected %v", blockID, expected.StorageBlock)
	}

	atomic.AddInt32(&r.stats.ValidBlocks, 1)
	return nil
}

type readerWithData struct {
	io.ReadSeeker
	length int64
}

func (rwd *readerWithData) Close() error {
	return nil
}

func (rwd *readerWithData) Length() int64 {
	return rwd.length
}

func newObjectReaderWithData(data []byte) ObjectReader {
	return &readerWithData{
		ReadSeeker: bytes.NewReader(data),
		length:     int64(len(data)),
	}
}
<|endoftext|>


<commit_before>package ovpm

import (
	"strings"
	"testing"

	"github.com/Sirupsen/logrus"
	"github.com/bouk/monkey"
	"github.com/cad/ovpm/supervisor"
)

var fs map[string]string

func setupTestCase() {
	// Initialize.
	fs = make(map[string]string)
	vpnProc.Stop()
}

func TestVPNInit(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	// Prepare:
	// Test:

	// Check database if the database has no server.
	var server dbServerModel
	db.First(&server)

	// Isn't server empty struct?
	if !db.NewRecord(&server) {
		t.Fatalf("server is expected to be empty struct(new record) but it isn't %+v", server)
	}

	// Wrongfully initialize server.
	err := Init("localhost", "asdf", UDPProto, "", "")
	if err == nil {
		t.Fatalf("error is expected to be not nil but it's nil instead")
	}

	// Initialize the server.
	Init("localhost", "", UDPProto, "", "")

	// Check database if the database has no server.
	var server2 dbServerModel
	db.First(&server2)

	// Is server empty struct?
	if db.NewRecord(&server2) {
		t.Fatalf("server is expected to be not empty struct(new record) but it is %+v", server2)
	}
}

func TestVPNDeinit(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:
	// Initialize the server.
	Init("localhost", "", UDPProto, "", "")
	u, err := CreateNewUser("user", "p", false, 0, true)
	if err != nil {
		t.Fatal(err)
	}
	u.Delete()

	// Test:
	var server dbServerModel
	db.First(&server)

	// Isn't server empty struct?
	if db.NewRecord(&server) {
		t.Fatalf("server is expected to be not empty struct(new record) but it is %+v", server)
	}

	// Test if Revoked table contains the removed user's entries.
	var revoked dbRevokedModel
	db.First(&revoked)

	if db.NewRecord(&revoked) {
		t.Errorf("revoked shouldn't be empty")
	}

	// Deinitialize.
	Deinit()

	// Get server from db.
	var server2 dbServerModel
	db.First(&server2)

	// Isn't server empty struct?
	if !db.NewRecord(&server2) {
		t.Fatalf("server is expected to be empty struct(new record) but it is not %+v", server2)
	}

	// Test if Revoked table contains the removed user's entries.
	var revoked2 dbRevokedModel
	db.First(&revoked2)

	// Is revoked empty?
	if !db.NewRecord(&revoked2) {
		t.Errorf("revoked should be empty")
	}
}
func TestVPNUpdate(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	// Prepare:
	Init("localhost", "", UDPProto, "", "")
	// Test:

	var updatetests = []struct {
		vpnnet     string
		dns        string
		vpnChanged bool
		dnsChanged bool
	}{
		{"", "", false, false},
		{"192.168.9.0/24", "", true, false},
		{"", "2.2.2.2", false, true},
		{"9.9.9.0/24", "1.1.1.1", true, true},
	}
	for _, tt := range updatetests {
		server, err := GetServerInstance()
		if err != nil {
			t.Fatal(err)
		}

		oldIP := server.Net
		oldDNS := server.DNS
		Update(tt.vpnnet, tt.dns)
		server = nil
		server, err = GetServerInstance()
		if (server.Net != oldIP) != tt.vpnChanged {
			t.Fatalf("expected vpn change: %t but opposite happened", tt.vpnChanged)
		}
		if (server.DNS != oldDNS) != tt.dnsChanged {
			t.Fatalf("expected vpn change: %t but opposite happened", tt.dnsChanged)
		}
	}

}

func TestVPNIsInitialized(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	// Is initialized?
	if IsInitialized() {
		t.Fatalf("IsInitialized() is expected to return false but it returned true")
	}

	// Initialize the server.
	Init("localhost", "", UDPProto, "", "")

	// Isn't initialized?
	if !IsInitialized() {
		t.Fatalf("IsInitialized() is expected to return true but it returned false")
	}
}

func TestVPNGetServerInstance(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	server, err := GetServerInstance()

	// Is it nil?
	if err == nil {
		t.Fatalf("GetServerInstance() is expected to give error since server is not initialized yet, but it gave no error instead")
	}

	// Isn't server nil?
	if server != nil {
		t.Fatal("server is expected to be nil but it's not")
	}

	// Initialize server.
	Init("localhost", "", UDPProto, "", "")

	server, err = GetServerInstance()

	// Isn't it nil?
	if err != nil {
		t.Fatalf("GetServerInstance() is expected to give no error since server is initialized yet, but it gave error instead")
	}

	// Is server nil?
	if server == nil {
		t.Fatal("server is expected to be not nil but it is")
	}
}

func TestVPNDumpsClientConfig(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:
	user, _ := CreateNewUser("user", "password", false, 0, true)

	// Test:
	clientConfigBlob, err := DumpsClientConfig(user.GetUsername())
	if err != nil {
		t.Fatalf("expected to dump client config but we got error instead: %v", err)
	}

	// Is empty?
	if len(clientConfigBlob) == 0 {
		t.Fatal("expected the dump not empty but it's empty instead")
	}
}

func TestVPNDumpClientConfig(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:
	noGW := false
	user, err := CreateNewUser("user", "password", noGW, 0, true)
	if err != nil {
		t.Fatalf("can not create user: %v", err)
	}

	// Test:
	err = DumpClientConfig(user.GetUsername(), "/tmp/user.ovpn")
	if err != nil {
		t.Fatalf("expected to dump client config but we got error instead: %v", err)
	}

	// Read file.
	clientConfigBlob := fs["/tmp/user.ovpn"]

	// Is empty?
	if len(clientConfigBlob) == 0 {
		t.Fatal("expected the dump not empty but it's empty instead")
	}

	// Is noGW honored?
	if strings.Contains(clientConfigBlob, "route-nopull") != noGW {
		logrus.Info(clientConfigBlob)
		t.Fatalf("client config generator doesn't honor NoGW")
	}

	user.Delete()

	noGW = true
	user, err = CreateNewUser("user", "password", noGW, 0, true)
	if err != nil {
		t.Fatalf("can not create user: %v", err)
	}

	err = DumpClientConfig(user.GetUsername(), "/tmp/user.ovpn")
	if err != nil {
		t.Fatalf("expected to dump client config but we got error instead: %v", err)
	}

	// Read file.
	clientConfigBlob = fs["/tmp/user.ovpn"]

	// Is noGW honored?
	if strings.Contains(clientConfigBlob, "route-nopull") != noGW {
		logrus.Info(clientConfigBlob)
		t.Fatalf("client config generator doesn't honor NoGW")
	}

}

func TestVPNGetSystemCA(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	ca, err := GetSystemCA()
	if err == nil {
		t.Fatalf("GetSystemCA() is expected to give error but it didn't instead")
	}

	// Initialize system.
	Init("localhost", "", UDPProto, "", "")

	ca, err = GetSystemCA()
	if err != nil {
		t.Fatalf("GetSystemCA() is expected to get system ca, but it gave us an error instead: %v", err)
	}

	// Is it empty?
	if len(ca.Cert) == 0 {
		t.Fatalf("ca.Cert is expected to be not empty, but it's empty instead")
	}
	if len(ca.Key) == 0 {
		t.Fatalf("ca.Key is expected to be not empty, but it's empty instead")

	}
}

func TestVPNStartVPNProc(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	// Isn't it stopped?
	if vpnProc.Status() != supervisor.STOPPED {
		t.Fatalf("expected state is STOPPED, got %s instead", vpnProc.Status())
	}

	// Call start without server initialization.
	StartVPNProc()

	// Isn't it still stopped?
	if vpnProc.Status() != supervisor.STOPPED {
		t.Fatalf("expected state is STOPPED, got %s instead", vpnProc.Status())
	}

	// Initialize OVPM server.
	Init("localhost", "", UDPProto, "", "")

	// Call start again..
	StartVPNProc()

	// Isn't it RUNNING?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}
}

func TestVPNStopVPNProc(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:
	vpnProc.Start()

	// Test:
	// Isn't it running?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}

	// Call stop.
	StopVPNProc()

	// Isn't it stopped?
	if vpnProc.Status() != supervisor.STOPPED {
		t.Fatalf("expected state is STOPPED, got %s instead", vpnProc.Status())
	}
}

func TestVPNRestartVPNProc(t *testing.T) {
	// Init:
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:

	// Test:

	// Call restart.

	RestartVPNProc()

	// Isn't it running?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}

	// Call restart again.
	RestartVPNProc()

	// Isn't it running?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}
}

func TestVPNEmit(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:

	// Test:
	Emit()

	var emittests = []string{
		_DefaultVPNConfPath,
		_DefaultKeyPath,
		_DefaultCertPath,
		_DefaultCRLPath,
		_DefaultCACertPath,
		_DefaultCAKeyPath,
		_DefaultDHParamsPath,
	}

	for _, tt := range emittests {
		if len(fs[tt]) == 0 {
			t.Errorf("%s is expected to be not empty but it is", tt)
		}
	}

	// TODO(cad): Write test cases for ccd/ files as well.
}

func TestVPNemitToFile(t *testing.T) {
	// Initialize:
	// Prepare:
	path := "/test/file"
	content := "blah blah blah"

	// Test:
	// Is path exist?
	if _, ok := fs[path]; ok {
		t.Fatalf("key '%s' expected to be non-existent on fs, but it is instead", path)
	}

	// Emit the contents.
	err := emitToFile(path, content, 0)
	if err != nil {
		t.Fatalf("expected  to be able to emit to the filesystem but we got this error instead: %v", err)
	}

	// Is the content on the filesystem correct?
	if fs[path] != content {
		t.Fatalf("content on the filesytem is expected to be same with '%s' but it's '%s' instead", content, fs[path])
	}
}

type fakeProcess struct {
	state supervisor.State
}

func (f *fakeProcess) Start() {
	f.state = supervisor.RUNNING
}

func (f *fakeProcess) Stop() {
	f.state = supervisor.STOPPED
}

func (f *fakeProcess) Restart() {
	f.state = supervisor.RUNNING
}

func (f *fakeProcess) Status() supervisor.State {
	return f.state
}

func init() {
	// Init
	Testing = true
	fs = make(map[string]string)
	// Monkeypatch emitToFile()
	monkey.Patch(emitToFile, func(path, content string, mode uint) error {
		fs[path] = content
		return nil
	})

	vpnProc = &fakeProcess{state: supervisor.STOPPED}
}
<commit_msg>test(vpn): remove client ovpn config nopull check<commit_after>package ovpm

import (
	"strings"
	"testing"

	"github.com/Sirupsen/logrus"
	"github.com/bouk/monkey"
	"github.com/cad/ovpm/supervisor"
)

var fs map[string]string

func setupTestCase() {
	// Initialize.
	fs = make(map[string]string)
	vpnProc.Stop()
}

func TestVPNInit(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	// Prepare:
	// Test:

	// Check database if the database has no server.
	var server dbServerModel
	db.First(&server)

	// Isn't server empty struct?
	if !db.NewRecord(&server) {
		t.Fatalf("server is expected to be empty struct(new record) but it isn't %+v", server)
	}

	// Wrongfully initialize server.
	err := Init("localhost", "asdf", UDPProto, "", "")
	if err == nil {
		t.Fatalf("error is expected to be not nil but it's nil instead")
	}

	// Initialize the server.
	Init("localhost", "", UDPProto, "", "")

	// Check database if the database has no server.
	var server2 dbServerModel
	db.First(&server2)

	// Is server empty struct?
	if db.NewRecord(&server2) {
		t.Fatalf("server is expected to be not empty struct(new record) but it is %+v", server2)
	}
}

func TestVPNDeinit(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:
	// Initialize the server.
	Init("localhost", "", UDPProto, "", "")
	u, err := CreateNewUser("user", "p", false, 0, true)
	if err != nil {
		t.Fatal(err)
	}
	u.Delete()

	// Test:
	var server dbServerModel
	db.First(&server)

	// Isn't server empty struct?
	if db.NewRecord(&server) {
		t.Fatalf("server is expected to be not empty struct(new record) but it is %+v", server)
	}

	// Test if Revoked table contains the removed user's entries.
	var revoked dbRevokedModel
	db.First(&revoked)

	if db.NewRecord(&revoked) {
		t.Errorf("revoked shouldn't be empty")
	}

	// Deinitialize.
	Deinit()

	// Get server from db.
	var server2 dbServerModel
	db.First(&server2)

	// Isn't server empty struct?
	if !db.NewRecord(&server2) {
		t.Fatalf("server is expected to be empty struct(new record) but it is not %+v", server2)
	}

	// Test if Revoked table contains the removed user's entries.
	var revoked2 dbRevokedModel
	db.First(&revoked2)

	// Is revoked empty?
	if !db.NewRecord(&revoked2) {
		t.Errorf("revoked should be empty")
	}
}
func TestVPNUpdate(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	// Prepare:
	Init("localhost", "", UDPProto, "", "")
	// Test:

	var updatetests = []struct {
		vpnnet     string
		dns        string
		vpnChanged bool
		dnsChanged bool
	}{
		{"", "", false, false},
		{"192.168.9.0/24", "", true, false},
		{"", "2.2.2.2", false, true},
		{"9.9.9.0/24", "1.1.1.1", true, true},
	}
	for _, tt := range updatetests {
		server, err := GetServerInstance()
		if err != nil {
			t.Fatal(err)
		}

		oldIP := server.Net
		oldDNS := server.DNS
		Update(tt.vpnnet, tt.dns)
		server = nil
		server, err = GetServerInstance()
		if (server.Net != oldIP) != tt.vpnChanged {
			t.Fatalf("expected vpn change: %t but opposite happened", tt.vpnChanged)
		}
		if (server.DNS != oldDNS) != tt.dnsChanged {
			t.Fatalf("expected vpn change: %t but opposite happened", tt.dnsChanged)
		}
	}

}

func TestVPNIsInitialized(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	// Is initialized?
	if IsInitialized() {
		t.Fatalf("IsInitialized() is expected to return false but it returned true")
	}

	// Initialize the server.
	Init("localhost", "", UDPProto, "", "")

	// Isn't initialized?
	if !IsInitialized() {
		t.Fatalf("IsInitialized() is expected to return true but it returned false")
	}
}

func TestVPNGetServerInstance(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	server, err := GetServerInstance()

	// Is it nil?
	if err == nil {
		t.Fatalf("GetServerInstance() is expected to give error since server is not initialized yet, but it gave no error instead")
	}

	// Isn't server nil?
	if server != nil {
		t.Fatal("server is expected to be nil but it's not")
	}

	// Initialize server.
	Init("localhost", "", UDPProto, "", "")

	server, err = GetServerInstance()

	// Isn't it nil?
	if err != nil {
		t.Fatalf("GetServerInstance() is expected to give no error since server is initialized yet, but it gave error instead")
	}

	// Is server nil?
	if server == nil {
		t.Fatal("server is expected to be not nil but it is")
	}
}

func TestVPNDumpsClientConfig(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:
	user, _ := CreateNewUser("user", "password", false, 0, true)

	// Test:
	clientConfigBlob, err := DumpsClientConfig(user.GetUsername())
	if err != nil {
		t.Fatalf("expected to dump client config but we got error instead: %v", err)
	}

	// Is empty?
	if len(clientConfigBlob) == 0 {
		t.Fatal("expected the dump not empty but it's empty instead")
	}
}

func TestVPNDumpClientConfig(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:
	noGW := false
	user, err := CreateNewUser("user", "password", noGW, 0, true)
	if err != nil {
		t.Fatalf("can not create user: %v", err)
	}

	// Test:
	err = DumpClientConfig(user.GetUsername(), "/tmp/user.ovpn")
	if err != nil {
		t.Fatalf("expected to dump client config but we got error instead: %v", err)
	}

	// Read file.
	clientConfigBlob := fs["/tmp/user.ovpn"]

	// Is empty?
	if len(clientConfigBlob) == 0 {
		t.Fatal("expected the dump not empty but it's empty instead")
	}

	// Is noGW honored?
	if strings.Contains(clientConfigBlob, "route-nopull") != noGW {
		logrus.Info(clientConfigBlob)
		t.Fatalf("client config generator doesn't honor NoGW")
	}

	user.Delete()

	noGW = true
	user, err = CreateNewUser("user", "password", noGW, 0, true)
	if err != nil {
		t.Fatalf("can not create user: %v", err)
	}

	err = DumpClientConfig(user.GetUsername(), "/tmp/user.ovpn")
	if err != nil {
		t.Fatalf("expected to dump client config but we got error instead: %v", err)
	}

	// Read file.
	clientConfigBlob = fs["/tmp/user.ovpn"]

}

func TestVPNGetSystemCA(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	ca, err := GetSystemCA()
	if err == nil {
		t.Fatalf("GetSystemCA() is expected to give error but it didn't instead")
	}

	// Initialize system.
	Init("localhost", "", UDPProto, "", "")

	ca, err = GetSystemCA()
	if err != nil {
		t.Fatalf("GetSystemCA() is expected to get system ca, but it gave us an error instead: %v", err)
	}

	// Is it empty?
	if len(ca.Cert) == 0 {
		t.Fatalf("ca.Cert is expected to be not empty, but it's empty instead")
	}
	if len(ca.Key) == 0 {
		t.Fatalf("ca.Key is expected to be not empty, but it's empty instead")

	}
}

func TestVPNStartVPNProc(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()

	// Prepare:

	// Test:
	// Isn't it stopped?
	if vpnProc.Status() != supervisor.STOPPED {
		t.Fatalf("expected state is STOPPED, got %s instead", vpnProc.Status())
	}

	// Call start without server initialization.
	StartVPNProc()

	// Isn't it still stopped?
	if vpnProc.Status() != supervisor.STOPPED {
		t.Fatalf("expected state is STOPPED, got %s instead", vpnProc.Status())
	}

	// Initialize OVPM server.
	Init("localhost", "", UDPProto, "", "")

	// Call start again..
	StartVPNProc()

	// Isn't it RUNNING?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}
}

func TestVPNStopVPNProc(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:
	vpnProc.Start()

	// Test:
	// Isn't it running?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}

	// Call stop.
	StopVPNProc()

	// Isn't it stopped?
	if vpnProc.Status() != supervisor.STOPPED {
		t.Fatalf("expected state is STOPPED, got %s instead", vpnProc.Status())
	}
}

func TestVPNRestartVPNProc(t *testing.T) {
	// Init:
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:

	// Test:

	// Call restart.

	RestartVPNProc()

	// Isn't it running?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}

	// Call restart again.
	RestartVPNProc()

	// Isn't it running?
	if vpnProc.Status() != supervisor.RUNNING {
		t.Fatalf("expected state is RUNNING, got %s instead", vpnProc.Status())
	}
}

func TestVPNEmit(t *testing.T) {
	// Init:
	setupTestCase()
	CreateDB("sqlite3", ":memory:")
	defer db.Cease()
	Init("localhost", "", UDPProto, "", "")

	// Prepare:

	// Test:
	Emit()

	var emittests = []string{
		_DefaultVPNConfPath,
		_DefaultKeyPath,
		_DefaultCertPath,
		_DefaultCRLPath,
		_DefaultCACertPath,
		_DefaultCAKeyPath,
		_DefaultDHParamsPath,
	}

	for _, tt := range emittests {
		if len(fs[tt]) == 0 {
			t.Errorf("%s is expected to be not empty but it is", tt)
		}
	}

	// TODO(cad): Write test cases for ccd/ files as well.
}

func TestVPNemitToFile(t *testing.T) {
	// Initialize:
	// Prepare:
	path := "/test/file"
	content := "blah blah blah"

	// Test:
	// Is path exist?
	if _, ok := fs[path]; ok {
		t.Fatalf("key '%s' expected to be non-existent on fs, but it is instead", path)
	}

	// Emit the contents.
	err := emitToFile(path, content, 0)
	if err != nil {
		t.Fatalf("expected  to be able to emit to the filesystem but we got this error instead: %v", err)
	}

	// Is the content on the filesystem correct?
	if fs[path] != content {
		t.Fatalf("content on the filesytem is expected to be same with '%s' but it's '%s' instead", content, fs[path])
	}
}

type fakeProcess struct {
	state supervisor.State
}

func (f *fakeProcess) Start() {
	f.state = supervisor.RUNNING
}

func (f *fakeProcess) Stop() {
	f.state = supervisor.STOPPED
}

func (f *fakeProcess) Restart() {
	f.state = supervisor.RUNNING
}

func (f *fakeProcess) Status() supervisor.State {
	return f.state
}

func init() {
	// Init
	Testing = true
	fs = make(map[string]string)
	// Monkeypatch emitToFile()
	monkey.Patch(emitToFile, func(path, content string, mode uint) error {
		fs[path] = content
		return nil
	})

	vpnProc = &fakeProcess{state: supervisor.STOPPED}
}
<|endoftext|>