<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package gcsproxy_test

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

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

func TestOgletest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// An oglemock.Matcher that accepts a predicate function and a description,
// making it easy to make anonymous matcher types.
type predicateMatcher struct {
	Desc      string
	Predicate func(interface{}) error
}

var _ Matcher = &predicateMatcher{}

func (m *predicateMatcher) Matches(candidate interface{}) error {
	return m.Predicate(candidate)
}

func (m *predicateMatcher) Description() string {
	return m.Desc
}

func nameIs(name string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Name is: %s", name),
		Predicate: func(candidate interface{}) error {
			req := candidate.(*gcs.CreateObjectRequest)
			if req.Attrs.Name != name {
				return errors.New("")
			}

			return nil
		},
	}
}

func contentsAre(s string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Object contents are: %s", s),
		Predicate: func(candidate interface{}) error {
			// Snarf the contents.
			req := candidate.(*gcs.CreateObjectRequest)
			contents, err := ioutil.ReadAll(req.Contents)
			if err != nil {
				panic(err)
			}

			// Compare
			if string(contents) != s {
				return errors.New("")
			}

			return nil
		},
	}
}

////////////////////////////////////////////////////////////////////////
// Invariant-checking object proxy
////////////////////////////////////////////////////////////////////////

// A wrapper around ObjectProxy that calls CheckInvariants whenever invariants
// should hold. For catching logic errors early in the test.
type checkingObjectProxy struct {
	wrapped *gcsproxy.ObjectProxy
}

func (op *checkingObjectProxy) NoteLatest(o *storage.Object) error {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.NoteLatest(o)
}

func (op *checkingObjectProxy) Size() (uint64, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Size()
}

func (op *checkingObjectProxy) ReadAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.ReadAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) WriteAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.WriteAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) Truncate(n uint64) error {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Truncate(context.Background(), n)
}

func (op *checkingObjectProxy) Sync() (*storage.Object, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Sync(context.Background())
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type ObjectProxyTest struct {
	objectName string
	bucket     mock_gcs.MockBucket
	op         checkingObjectProxy
}

var _ SetUpInterface = &ObjectProxyTest{}

func (t *ObjectProxyTest) SetUp(ti *TestInfo) {
	t.objectName = "some/object"
	t.bucket = mock_gcs.NewMockBucket(ti.MockController, "bucket")

	var err error
	t.op.wrapped, err = gcsproxy.NewObjectProxy(
		t.bucket,
		t.objectName)

	if err != nil {
		panic(err)
	}
}

////////////////////////////////////////////////////////////////////////
// No source object
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are a fresh object proxy without a source
// object set.
type NoSourceObjectTest struct {
	ObjectProxyTest
}

var _ SetUpInterface = &NoSourceObjectTest{}

func init() { RegisterTestSuite(&NoSourceObjectTest{}) }

func (t *NoSourceObjectTest) NoteLatest_NegativeSize() {
	o := &storage.Object{
		Name:       t.objectName,
		Generation: 1234,
		Size:       -1,
	}

	err := t.op.NoteLatest(o)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("size")))
	ExpectThat(err, Error(HasSubstr("-1")))
}

func (t *NoSourceObjectTest) NoteLatest_WrongName() {
	o := &storage.Object{
		Name:       t.objectName + "foo",
		Generation: 1234,
		Size:       0,
	}

	err := t.op.NoteLatest(o)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("name")))
	ExpectThat(err, Error(HasSubstr("foo")))
}

func (t *NoSourceObjectTest) Size_InitialState() {
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(0, size)
}

func (t *NoSourceObjectTest) Size_AfterTruncatingToZero() {
	var err error

	// Truncate
	err = t.op.Truncate(0)
	AssertEq(nil, err)

	// Size
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(0, size)
}

func (t *NoSourceObjectTest) Size_AfterTruncatingToNonZero() {
	var err error

	// Truncate
	err = t.op.Truncate(123)
	AssertEq(nil, err)

	// Size
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(123, size)
}

func (t *NoSourceObjectTest) Size_AfterReading() {
	var err error

	// Read
	buf := make([]byte, 0)
	n, err := t.op.ReadAt(buf, 0)

	AssertEq(nil, err)
	AssertEq(0, n)

	// Size
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(0, size)
}

func (t *NoSourceObjectTest) Read_InitialState() {
	type testCase struct {
		offset      int64
		size        int
		expectedErr error
		expectedN   int
	}

	testCases := []testCase{
		// Empty ranges
		testCase{0, 0, nil, 0},
		testCase{17, 0, nil, 0},

		// Non-empty ranges
		testCase{0, 10, io.EOF, 0},
		testCase{17, 10, io.EOF, 0},
	}

	for _, tc := range testCases {
		buf := make([]byte, tc.size)
		n, err := t.op.ReadAt(buf, tc.offset)

		AssertEq(tc.expectedErr, err, "Test case: %v", tc)
		AssertEq(tc.expectedN, n, "Test case: %v", tc)
	}
}

func (t *NoSourceObjectTest) WriteToEndOfObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Extend the object by writing twice.
	n, err = t.op.WriteAt([]byte("taco"), 0)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	n, err = t.op.WriteAt([]byte("burrito"), int64(len("taco")))
	AssertEq(nil, err)
	AssertEq(len("burrito"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(len("tacoburrito"), n)
	ExpectEq("tacoburrito", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 3)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("obur", string(buf[:n]))
}

func (t *NoSourceObjectTest) WritePastEndOfObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Extend the object by writing past its end.
	n, err = t.op.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	// Check its size.
	size, err := t.op.Size()
	AssertEq(nil, err)
	ExpectEq(2+len("taco"), size)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(2+len("taco"), n)
	ExpectEq("\x00\x00taco", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 1)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("\x00tac", string(buf[:n]))
}

func (t *NoSourceObjectTest) WriteWithinObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Write several bytes to extend the object.
	n, err = t.op.WriteAt([]byte("00000"), 0)
	AssertEq(nil, err)
	AssertEq(len("00000"), n)

	// Overwrite some in the middle.
	n, err = t.op.WriteAt([]byte("11"), 1)
	AssertEq(nil, err)
	AssertEq(len("11"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(len("01100"), n)
	ExpectEq("01100", string(buf[:n]))
}

func (t *NoSourceObjectTest) GrowByTruncating() {
	var n int
	var err error
	var buf []byte

	// Truncate
	err = t.op.Truncate(4)
	AssertEq(nil, err)

	// Size
	size, err := t.op.Size()
	AssertEq(nil, err)
	ExpectEq(4, size)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(4, n)
	ExpectEq("\x00\x00\x00\x00", string(buf[:n]))
}

func (t *NoSourceObjectTest) Sync_NoInteractions() {
	// CreateObject -- should receive an empty string.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre(""))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_ReadCallsOnly() {
	// Make a Read call
	buf := make([]byte, 0)
	n, err := t.op.ReadAt(buf, 0)

	AssertEq(nil, err)
	AssertEq(0, n)

	// CreateObject -- should receive an empty string.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre(""))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_AfterWriting() {
	var n int
	var err error

	// Write some data.
	n, err = t.op.WriteAt([]byte("taco"), 0)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	n, err = t.op.WriteAt([]byte("burrito"), int64(len("taco")))
	AssertEq(nil, err)
	AssertEq(len("burrito"), n)

	// CreateObject -- should receive the contents we wrote above.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre("tacoburrito"))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_AfterTruncating() {
	// Truncate outwards.
	err := t.op.Truncate(2)
	AssertEq(nil, err)

	// CreateObject -- should receive null bytes.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre("\x00\x00"))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_CreateObjectFails() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_Successful() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) SyncTwice() {
	AssertTrue(false, "TODO")
}

////////////////////////////////////////////////////////////////////////
// Source object present
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are an object proxy branching from a source
// object in the bucket.
type SourceObjectPresentTest struct {
	ObjectProxyTest
	sourceObject storage.Object
}

var _ SetUpInterface = &SourceObjectPresentTest{}

func init() { RegisterTestSuite(&SourceObjectPresentTest{}) }

func (t *SourceObjectPresentTest) SetUp(ti *TestInfo) {
	t.ObjectProxyTest.SetUp(ti)

	// Set up the source object.
	t.sourceObject = storage.Object{
		Name:       t.objectName,
		Generation: 123,
		Size:       456,
	}

	if err := t.op.NoteLatest(&t.sourceObject); err != nil {
		panic(err)
	}
}

func (t *SourceObjectPresentTest) DoesFoo() {
	AssertTrue(false, "TODO")
}
<commit_msg>NoSourceObjectTest.Sync_CreateObjectFails<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package gcsproxy_test

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

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

func TestOgletest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// An oglemock.Matcher that accepts a predicate function and a description,
// making it easy to make anonymous matcher types.
type predicateMatcher struct {
	Desc      string
	Predicate func(interface{}) error
}

var _ Matcher = &predicateMatcher{}

func (m *predicateMatcher) Matches(candidate interface{}) error {
	return m.Predicate(candidate)
}

func (m *predicateMatcher) Description() string {
	return m.Desc
}

func nameIs(name string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Name is: %s", name),
		Predicate: func(candidate interface{}) error {
			req := candidate.(*gcs.CreateObjectRequest)
			if req.Attrs.Name != name {
				return errors.New("")
			}

			return nil
		},
	}
}

func contentsAre(s string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Object contents are: %s", s),
		Predicate: func(candidate interface{}) error {
			// Snarf the contents.
			req := candidate.(*gcs.CreateObjectRequest)
			contents, err := ioutil.ReadAll(req.Contents)
			if err != nil {
				panic(err)
			}

			// Compare
			if string(contents) != s {
				return errors.New("")
			}

			return nil
		},
	}
}

////////////////////////////////////////////////////////////////////////
// Invariant-checking object proxy
////////////////////////////////////////////////////////////////////////

// A wrapper around ObjectProxy that calls CheckInvariants whenever invariants
// should hold. For catching logic errors early in the test.
type checkingObjectProxy struct {
	wrapped *gcsproxy.ObjectProxy
}

func (op *checkingObjectProxy) NoteLatest(o *storage.Object) error {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.NoteLatest(o)
}

func (op *checkingObjectProxy) Size() (uint64, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Size()
}

func (op *checkingObjectProxy) ReadAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.ReadAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) WriteAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.WriteAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) Truncate(n uint64) error {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Truncate(context.Background(), n)
}

func (op *checkingObjectProxy) Sync() (*storage.Object, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Sync(context.Background())
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type ObjectProxyTest struct {
	objectName string
	bucket     mock_gcs.MockBucket
	op         checkingObjectProxy
}

var _ SetUpInterface = &ObjectProxyTest{}

func (t *ObjectProxyTest) SetUp(ti *TestInfo) {
	t.objectName = "some/object"
	t.bucket = mock_gcs.NewMockBucket(ti.MockController, "bucket")

	var err error
	t.op.wrapped, err = gcsproxy.NewObjectProxy(
		t.bucket,
		t.objectName)

	if err != nil {
		panic(err)
	}
}

////////////////////////////////////////////////////////////////////////
// No source object
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are a fresh object proxy without a source
// object set.
type NoSourceObjectTest struct {
	ObjectProxyTest
}

var _ SetUpInterface = &NoSourceObjectTest{}

func init() { RegisterTestSuite(&NoSourceObjectTest{}) }

func (t *NoSourceObjectTest) NoteLatest_NegativeSize() {
	o := &storage.Object{
		Name:       t.objectName,
		Generation: 1234,
		Size:       -1,
	}

	err := t.op.NoteLatest(o)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("size")))
	ExpectThat(err, Error(HasSubstr("-1")))
}

func (t *NoSourceObjectTest) NoteLatest_WrongName() {
	o := &storage.Object{
		Name:       t.objectName + "foo",
		Generation: 1234,
		Size:       0,
	}

	err := t.op.NoteLatest(o)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("name")))
	ExpectThat(err, Error(HasSubstr("foo")))
}

func (t *NoSourceObjectTest) Size_InitialState() {
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(0, size)
}

func (t *NoSourceObjectTest) Size_AfterTruncatingToZero() {
	var err error

	// Truncate
	err = t.op.Truncate(0)
	AssertEq(nil, err)

	// Size
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(0, size)
}

func (t *NoSourceObjectTest) Size_AfterTruncatingToNonZero() {
	var err error

	// Truncate
	err = t.op.Truncate(123)
	AssertEq(nil, err)

	// Size
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(123, size)
}

func (t *NoSourceObjectTest) Size_AfterReading() {
	var err error

	// Read
	buf := make([]byte, 0)
	n, err := t.op.ReadAt(buf, 0)

	AssertEq(nil, err)
	AssertEq(0, n)

	// Size
	size, err := t.op.Size()

	AssertEq(nil, err)
	ExpectEq(0, size)
}

func (t *NoSourceObjectTest) Read_InitialState() {
	type testCase struct {
		offset      int64
		size        int
		expectedErr error
		expectedN   int
	}

	testCases := []testCase{
		// Empty ranges
		testCase{0, 0, nil, 0},
		testCase{17, 0, nil, 0},

		// Non-empty ranges
		testCase{0, 10, io.EOF, 0},
		testCase{17, 10, io.EOF, 0},
	}

	for _, tc := range testCases {
		buf := make([]byte, tc.size)
		n, err := t.op.ReadAt(buf, tc.offset)

		AssertEq(tc.expectedErr, err, "Test case: %v", tc)
		AssertEq(tc.expectedN, n, "Test case: %v", tc)
	}
}

func (t *NoSourceObjectTest) WriteToEndOfObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Extend the object by writing twice.
	n, err = t.op.WriteAt([]byte("taco"), 0)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	n, err = t.op.WriteAt([]byte("burrito"), int64(len("taco")))
	AssertEq(nil, err)
	AssertEq(len("burrito"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(len("tacoburrito"), n)
	ExpectEq("tacoburrito", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 3)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("obur", string(buf[:n]))
}

func (t *NoSourceObjectTest) WritePastEndOfObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Extend the object by writing past its end.
	n, err = t.op.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	// Check its size.
	size, err := t.op.Size()
	AssertEq(nil, err)
	ExpectEq(2+len("taco"), size)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(2+len("taco"), n)
	ExpectEq("\x00\x00taco", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 1)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("\x00tac", string(buf[:n]))
}

func (t *NoSourceObjectTest) WriteWithinObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Write several bytes to extend the object.
	n, err = t.op.WriteAt([]byte("00000"), 0)
	AssertEq(nil, err)
	AssertEq(len("00000"), n)

	// Overwrite some in the middle.
	n, err = t.op.WriteAt([]byte("11"), 1)
	AssertEq(nil, err)
	AssertEq(len("11"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(len("01100"), n)
	ExpectEq("01100", string(buf[:n]))
}

func (t *NoSourceObjectTest) GrowByTruncating() {
	var n int
	var err error
	var buf []byte

	// Truncate
	err = t.op.Truncate(4)
	AssertEq(nil, err)

	// Size
	size, err := t.op.Size()
	AssertEq(nil, err)
	ExpectEq(4, size)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(4, n)
	ExpectEq("\x00\x00\x00\x00", string(buf[:n]))
}

func (t *NoSourceObjectTest) Sync_NoInteractions() {
	// CreateObject -- should receive an empty string.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre(""))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_ReadCallsOnly() {
	// Make a Read call
	buf := make([]byte, 0)
	n, err := t.op.ReadAt(buf, 0)

	AssertEq(nil, err)
	AssertEq(0, n)

	// CreateObject -- should receive an empty string.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre(""))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_AfterWriting() {
	var n int
	var err error

	// Write some data.
	n, err = t.op.WriteAt([]byte("taco"), 0)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	n, err = t.op.WriteAt([]byte("burrito"), int64(len("taco")))
	AssertEq(nil, err)
	AssertEq(len("burrito"), n)

	// CreateObject -- should receive the contents we wrote above.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre("tacoburrito"))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_AfterTruncating() {
	// Truncate outwards.
	err := t.op.Truncate(2)
	AssertEq(nil, err)

	// CreateObject -- should receive null bytes.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre("\x00\x00"))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Sync
	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_CreateObjectFails() {
	var n int
	var err error

	// Write some data.
	n, err = t.op.WriteAt([]byte("taco"), 0)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	// First call to create object: fail.
	ExpectCall(t.bucket, "CreateObject")(Any(), Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Sync -- should fail.
	_, err = t.op.Sync()

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("CreateObject")))
	ExpectThat(err, Error(HasSubstr("taco")))

	// The data we wrote before should still be present.
	size, err := t.op.Size()
	AssertEq(nil, err)
	ExpectEq(len("taco"), size)

	buf := make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq("taco", string(buf[:n]))

	// The file should still be regarded as dirty -- a further call to Sync
	// should call CreateObject again.
	ExpectCall(t.bucket, "CreateObject")(
		Any(),
		AllOf(nameIs(t.objectName), contentsAre("taco"))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	t.op.Sync()
}

func (t *NoSourceObjectTest) Sync_Successful() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) SyncTwice() {
	AssertTrue(false, "TODO")
}

////////////////////////////////////////////////////////////////////////
// Source object present
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are an object proxy branching from a source
// object in the bucket.
type SourceObjectPresentTest struct {
	ObjectProxyTest
	sourceObject storage.Object
}

var _ SetUpInterface = &SourceObjectPresentTest{}

func init() { RegisterTestSuite(&SourceObjectPresentTest{}) }

func (t *SourceObjectPresentTest) SetUp(ti *TestInfo) {
	t.ObjectProxyTest.SetUp(ti)

	// Set up the source object.
	t.sourceObject = storage.Object{
		Name:       t.objectName,
		Generation: 123,
		Size:       456,
	}

	if err := t.op.NoteLatest(&t.sourceObject); err != nil {
		panic(err)
	}
}

func (t *SourceObjectPresentTest) DoesFoo() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package main

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"

	"github.com/xlab/treeprint"
	pb "google.golang.org/genproto/googleapis/spanner/v1"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/types/known/structpb"
)

func init() {
	// Use only ascii characters
	treeprint.EdgeTypeLink = "|"
	treeprint.EdgeTypeMid = "+-"
	treeprint.EdgeTypeEnd = "+-"
}

type Link struct {
	Dest *Node
	Type string
}

type Node struct {
	PlanNode *pb.PlanNode
	Children []*Link
}

func BuildQueryPlanTree(plan *pb.QueryPlan, idx int32) *Node {
	if len(plan.PlanNodes) == 0 {
		return &Node{}
	}

	nodeMap := map[int32]*pb.PlanNode{}
	for _, node := range plan.PlanNodes {
		nodeMap[node.Index] = node
	}

	root := &Node{
		PlanNode: plan.PlanNodes[idx],
		Children: make([]*Link, 0),
	}
	if root.PlanNode.ChildLinks != nil {
		for i, childLink := range root.PlanNode.ChildLinks {
			idx := childLink.ChildIndex
			child := BuildQueryPlanTree(plan, idx)
			childType := childLink.Type

			// Fill missing Input type into the first child of [Distributed] (Cross|Outer) Apply
			if childType == "" && strings.HasSuffix(root.PlanNode.DisplayName, "Apply") && i == 0 {
				childType = "Input"
			}
			root.Children = append(root.Children, &Link{Type: childType, Dest: child})
		}
	}

	return root
}

func (n *Node) Render() string {
	tree := treeprint.New()
	renderTree(tree, "", n)
	return "\n" + tree.String()
}

type RenderedTreeWithStats struct {
	Text         string
	RowsTotal    string
	Execution    string
	LatencyTotal string
}

func (n *Node) RenderTreeWithStats() []RenderedTreeWithStats {
	tree := treeprint.New()
	renderTreeWithStats(tree, "", n)
	var result []RenderedTreeWithStats
	for _, line := range strings.Split(tree.String(), "\n") {
		if line == "" {
			continue
		}

		split := strings.SplitN(line, "\t", 2)
		// Handle the case of the root node of treeprint
		if len(split) != 2 {
			result = append(result, RenderedTreeWithStats{Text: line})
			continue
		}
		branchText, protojsonText := split[0], split[1]

		var value structpb.Value
		if err := protojson.Unmarshal([]byte(protojsonText), &value); err != nil {
			result = append(result, RenderedTreeWithStats{Text: line})
			continue
		}

		displayName := getStringValueByPath(value.GetStructValue(), "display_name")
		linkType := getStringValueByPath(value.GetStructValue(), "link_type")

		var text string
		if linkType != "" {
			text = fmt.Sprintf("[%s] %s", linkType, displayName)
		} else {
			text = displayName
		}

		result = append(result, RenderedTreeWithStats{
			Text:      branchText + text,
			RowsTotal: getStringValueByPath(value.GetStructValue(), "execution_stats", "rows", "total"),
			Execution: getStringValueByPath(value.GetStructValue(), "execution_stats", "execution_summary", "num_executions"),
			LatencyTotal: fmt.Sprintf("%s %s",
				getStringValueByPath(value.GetStructValue(), "execution_stats", "latency", "total"),
				getStringValueByPath(value.GetStructValue(), "execution_stats", "latency", "unit")),
		})
	}
	return result
}

func (n *Node) IsVisible() bool {
	operator := n.PlanNode.DisplayName
	if operator == "Function" || operator == "Reference" || operator == "Constant" {
		return false
	}

	return true
}

func (n *Node) String() string {
	metadataFields := n.PlanNode.GetMetadata().GetFields()

	var operator string
	{
		var components []string
		for _, s := range []string{
			metadataFields["call_type"].GetStringValue(),
			metadataFields["iterator_type"].GetStringValue(),
			strings.TrimSuffix(metadataFields["scan_type"].GetStringValue(), "Scan"),
			n.PlanNode.GetDisplayName(),
		} {
			if s != "" {
				components = append(components, s)
			}
		}
		operator = strings.Join(components, " ")
	}

	var metadata string
	{
		fields := make([]string, 0)
		for k, v := range metadataFields {
			switch k {
			case "call_type", "iterator_type": // Skip because it is displayed in node title
				continue
			case "scan_target": // Skip because it is combined with scan_type
				continue
			case "subquery_cluster_node": // Skip because it is useless without displaying node id
				continue
			case "scan_type":
				fields = append(fields, fmt.Sprintf("%s: %s",
					strings.TrimSuffix(v.GetStringValue(), "Scan"),
					metadataFields["scan_target"].GetStringValue()))
			default:
				fields = append(fields, fmt.Sprintf("%s: %s", k, v.GetStringValue()))
			}
		}

		sort.Strings(fields)

		if len(fields) != 0 {
			metadata = fmt.Sprintf(`(%s)`, strings.Join(fields, ", "))
		}
	}

	if metadata == "" {
		return operator
	}
	return operator + " " + metadata
}

func renderTree(tree treeprint.Tree, linkType string, node *Node) {
	if !node.IsVisible() {
		return
	}

	str := node.String()

	if len(node.Children) > 0 {
		var branch treeprint.Tree
		if linkType != "" {
			branch = tree.AddMetaBranch(linkType, str)
		} else {
			branch = tree.AddBranch(str)
		}
		for _, child := range node.Children {
			renderTree(branch, child.Type, child.Dest)
		}
	} else {
		if linkType != "" {
			tree.AddMetaNode(linkType, str)
		} else {
			tree.AddNode(str)
		}
	}
}

func getStringValueByPath(s *structpb.Struct, first string, path ...string) string {
	current := s.GetFields()[first]
	for _, p := range path {
		current = current.GetStructValue().GetFields()[p]
	}
	return current.GetStringValue()
}

func renderTreeWithStats(tree treeprint.Tree, linkType string, node *Node) {
	if !node.IsVisible() {
		return
	}

	statsJson, _ := protojson.Marshal(node.PlanNode.GetExecutionStats())
	b, _ := json.Marshal(
		map[string]interface{}{
			"execution_stats": json.RawMessage(statsJson),
			"display_name":    node.String(),
			"link_type":       linkType,
		},
	)
	// Prefixed by tab to ease to split
	str := "\t" + string(b)

	if len(node.Children) > 0 {
		branch := tree.AddBranch(str)
		for _, child := range node.Children {
			renderTreeWithStats(branch, child.Type, child.Dest)
		}
	} else {
		tree.AddNode(str)
	}
}
<commit_msg>Fix extra new lines for result of EXPLAIN statement (#68)<commit_after>//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package main

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"

	"github.com/xlab/treeprint"
	pb "google.golang.org/genproto/googleapis/spanner/v1"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/types/known/structpb"
)

func init() {
	// Use only ascii characters
	treeprint.EdgeTypeLink = "|"
	treeprint.EdgeTypeMid = "+-"
	treeprint.EdgeTypeEnd = "+-"
}

type Link struct {
	Dest *Node
	Type string
}

type Node struct {
	PlanNode *pb.PlanNode
	Children []*Link
}

func BuildQueryPlanTree(plan *pb.QueryPlan, idx int32) *Node {
	if len(plan.PlanNodes) == 0 {
		return &Node{}
	}

	nodeMap := map[int32]*pb.PlanNode{}
	for _, node := range plan.PlanNodes {
		nodeMap[node.Index] = node
	}

	root := &Node{
		PlanNode: plan.PlanNodes[idx],
		Children: make([]*Link, 0),
	}
	if root.PlanNode.ChildLinks != nil {
		for i, childLink := range root.PlanNode.ChildLinks {
			idx := childLink.ChildIndex
			child := BuildQueryPlanTree(plan, idx)
			childType := childLink.Type

			// Fill missing Input type into the first child of [Distributed] (Cross|Outer) Apply
			if childType == "" && strings.HasSuffix(root.PlanNode.DisplayName, "Apply") && i == 0 {
				childType = "Input"
			}
			root.Children = append(root.Children, &Link{Type: childType, Dest: child})
		}
	}

	return root
}

func (n *Node) Render() string {
	tree := treeprint.New()
	renderTree(tree, "", n)
	return strings.TrimSuffix(tree.String(), "\n") // remove an extra new line appended to rendered tree
}

type RenderedTreeWithStats struct {
	Text         string
	RowsTotal    string
	Execution    string
	LatencyTotal string
}

func (n *Node) RenderTreeWithStats() []RenderedTreeWithStats {
	tree := treeprint.New()
	renderTreeWithStats(tree, "", n)
	var result []RenderedTreeWithStats
	for _, line := range strings.Split(tree.String(), "\n") {
		if line == "" {
			continue
		}

		split := strings.SplitN(line, "\t", 2)
		// Handle the case of the root node of treeprint
		if len(split) != 2 {
			result = append(result, RenderedTreeWithStats{Text: line})
			continue
		}
		branchText, protojsonText := split[0], split[1]

		var value structpb.Value
		if err := protojson.Unmarshal([]byte(protojsonText), &value); err != nil {
			result = append(result, RenderedTreeWithStats{Text: line})
			continue
		}

		displayName := getStringValueByPath(value.GetStructValue(), "display_name")
		linkType := getStringValueByPath(value.GetStructValue(), "link_type")

		var text string
		if linkType != "" {
			text = fmt.Sprintf("[%s] %s", linkType, displayName)
		} else {
			text = displayName
		}

		result = append(result, RenderedTreeWithStats{
			Text:      branchText + text,
			RowsTotal: getStringValueByPath(value.GetStructValue(), "execution_stats", "rows", "total"),
			Execution: getStringValueByPath(value.GetStructValue(), "execution_stats", "execution_summary", "num_executions"),
			LatencyTotal: fmt.Sprintf("%s %s",
				getStringValueByPath(value.GetStructValue(), "execution_stats", "latency", "total"),
				getStringValueByPath(value.GetStructValue(), "execution_stats", "latency", "unit")),
		})
	}
	return result
}

func (n *Node) IsVisible() bool {
	operator := n.PlanNode.DisplayName
	if operator == "Function" || operator == "Reference" || operator == "Constant" {
		return false
	}

	return true
}

func (n *Node) String() string {
	metadataFields := n.PlanNode.GetMetadata().GetFields()

	var operator string
	{
		var components []string
		for _, s := range []string{
			metadataFields["call_type"].GetStringValue(),
			metadataFields["iterator_type"].GetStringValue(),
			strings.TrimSuffix(metadataFields["scan_type"].GetStringValue(), "Scan"),
			n.PlanNode.GetDisplayName(),
		} {
			if s != "" {
				components = append(components, s)
			}
		}
		operator = strings.Join(components, " ")
	}

	var metadata string
	{
		fields := make([]string, 0)
		for k, v := range metadataFields {
			switch k {
			case "call_type", "iterator_type": // Skip because it is displayed in node title
				continue
			case "scan_target": // Skip because it is combined with scan_type
				continue
			case "subquery_cluster_node": // Skip because it is useless without displaying node id
				continue
			case "scan_type":
				fields = append(fields, fmt.Sprintf("%s: %s",
					strings.TrimSuffix(v.GetStringValue(), "Scan"),
					metadataFields["scan_target"].GetStringValue()))
			default:
				fields = append(fields, fmt.Sprintf("%s: %s", k, v.GetStringValue()))
			}
		}

		sort.Strings(fields)

		if len(fields) != 0 {
			metadata = fmt.Sprintf(`(%s)`, strings.Join(fields, ", "))
		}
	}

	if metadata == "" {
		return operator
	}
	return operator + " " + metadata
}

func renderTree(tree treeprint.Tree, linkType string, node *Node) {
	if !node.IsVisible() {
		return
	}

	str := node.String()

	if len(node.Children) > 0 {
		var branch treeprint.Tree
		if linkType != "" {
			branch = tree.AddMetaBranch(linkType, str)
		} else {
			branch = tree.AddBranch(str)
		}
		for _, child := range node.Children {
			renderTree(branch, child.Type, child.Dest)
		}
	} else {
		if linkType != "" {
			tree.AddMetaNode(linkType, str)
		} else {
			tree.AddNode(str)
		}
	}
}

func getStringValueByPath(s *structpb.Struct, first string, path ...string) string {
	current := s.GetFields()[first]
	for _, p := range path {
		current = current.GetStructValue().GetFields()[p]
	}
	return current.GetStringValue()
}

func renderTreeWithStats(tree treeprint.Tree, linkType string, node *Node) {
	if !node.IsVisible() {
		return
	}

	statsJson, _ := protojson.Marshal(node.PlanNode.GetExecutionStats())
	b, _ := json.Marshal(
		map[string]interface{}{
			"execution_stats": json.RawMessage(statsJson),
			"display_name":    node.String(),
			"link_type":       linkType,
		},
	)
	// Prefixed by tab to ease to split
	str := "\t" + string(b)

	if len(node.Children) > 0 {
		branch := tree.AddBranch(str)
		for _, child := range node.Children {
			renderTreeWithStats(branch, child.Type, child.Dest)
		}
	} else {
		tree.AddNode(str)
	}
}
<|endoftext|>


<commit_before>package app

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net"
	"strings"
)

func logRequest(req *http.Request, status int, reason string) {
	host, _, err := net.SplitHostPort(req.RemoteAddr)
	if err != nil {
		host = req.RemoteAddr
	}

	log.Printf("%s %s %s %d \"%s\"\n", host, req.Method, req.RequestURI, http.StatusForbidden, reason)
}

func Forward(w http.ResponseWriter, req *http.Request) {
	token := ""
	if cookie, err := req.Cookie("access_token"); err == nil {
		token = cookie.Value
	}
	if !LookupAccess(token, req.URL.Path) {
		logRequest(req, http.StatusForbidden, "Invalid access token")
		http.Error(w, "Access denied", http.StatusForbidden)
		return
	}
	info := LookupPath(req.URL.Path)
	if info == nil {
		logRequest(req, http.StatusNotFound, "Path mapping not found")
		http.Error(w, "Path not mapped", http.StatusNotFound)
		return
	}

	if serveStatic(info.StaticOverrides, w, req) {
		return
	}

	conn := getBackendConnection(info)
	if conn == nil {
		logRequest(req, http.StatusInternalServerError, "Couldn't connect to backend server")
		return
	}

	director := func(req *http.Request) {
		req.URL.Path = info.Backend.BasePath + strings.TrimPrefix(req.URL.Path, info.Prefix)
		req.URL.Scheme = "http"
		req.URL.Host = info.Backend.Address
	}

	var revProxy http.Handler
	if (isWebsocket(req)) {
		revProxy = &WebsocketReverseProxy{
			Director: director,
			Dial: func(network, addr string) (net.Conn, error) {
				log.Println(`SSH->WebSocket @ ` + info.Backend.Address)
				return conn, nil
			},
		}

	} else {
		revProxy = &httputil.ReverseProxy{
			Director: director,
			Transport: &http.Transport{
				Dial: func(network, addr string) (net.Conn, error) {
					log.Println(`SSH->HTTP @ ` + info.Backend.Address)
					return conn, nil
				},
			},
		}
	}
	revProxy.ServeHTTP(w, req)
}
<commit_msg>Preparing interface for "progress dialogs"<commit_after>package app

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net"
	"strings"
)

func logRequest(req *http.Request, status int, reason string) {
	host, _, err := net.SplitHostPort(req.RemoteAddr)
	if err != nil {
		host = req.RemoteAddr
	}

	log.Printf("%s %s %s %d \"%s\"\n", host, req.Method, req.RequestURI, http.StatusForbidden, reason)
}

func showConnectionProgress(info *PathInfo, w http.ResponseWriter, req *http.Request) bool {
	return false
}

func Forward(w http.ResponseWriter, req *http.Request) {
	token := ""
	if cookie, err := req.Cookie("access_token"); err == nil {
		token = cookie.Value
	}
	if !LookupAccess(token, req.URL.Path) {
		logRequest(req, http.StatusForbidden, "Invalid access token")
		http.Error(w, "Access denied", http.StatusForbidden)
		return
	}
	info := LookupPath(req.URL.Path)
	if info == nil {
		logRequest(req, http.StatusNotFound, "Path mapping not found")
		http.Error(w, "Path not mapped", http.StatusNotFound)
		return
	}

	if serveStatic(info.StaticOverrides, w, req) {
		return
	}

	if showConnectionProgress(info, w, req) {
		return
	}

	conn := getBackendConnection(info)
	if conn == nil {
		logRequest(req, http.StatusInternalServerError, "Couldn't connect to backend server")
		return
	}

	director := func(req *http.Request) {
		req.URL.Path = info.Backend.BasePath + strings.TrimPrefix(req.URL.Path, info.Prefix)
		req.URL.Scheme = "http"
		req.URL.Host = info.Backend.Address
	}

	var revProxy http.Handler
	if (isWebsocket(req)) {
		revProxy = &WebsocketReverseProxy{
			Director: director,
			Dial: func(network, addr string) (net.Conn, error) {
				log.Println(`SSH->WebSocket @ ` + info.Backend.Address)
				return conn, nil
			},
		}

	} else {
		revProxy = &httputil.ReverseProxy{
			Director: director,
			Transport: &http.Transport{
				Dial: func(network, addr string) (net.Conn, error) {
					log.Println(`SSH->HTTP @ ` + info.Backend.Address)
					return conn, nil
				},
			},
		}
	}
	revProxy.ServeHTTP(w, req)
}
<|endoftext|>


<commit_before>package fastreplace

import (
	"bytes"
	"sort"
)

/*
	Usage:

	see README.md
*/

type FReplace struct {
	original  []byte
	positions map[int]string // maps a replacement string/sequence of bytes to an array of the indices of the original before which it appears
	sortedPos []int
}

func New(delimiter []byte, input []byte) (ø *FReplace) {
	ø = &FReplace{}
	ø.Parse(delimiter, input)
	return
}

func NewString(delimiter string, input string) (ø *FReplace) {
	return New([]byte(delimiter), []byte(input))
}

// returns a map with all positions and their replacements for the placeholders given in the input map
func (ø *FReplace) AllPos(in map[string][]byte) (out map[int][]byte) {
	out = map[int][]byte{}
	for k, v := range in {
		pos := ø.Pos(k)
		for _, p := range pos {
			out[p] = v
		}
	}
	return
}

// returns all positions for the placeholder string
func (ø *FReplace) Pos(placeholder string) (p []int) {
	for pos, s := range ø.positions {
		if placeholder == s {
			p = append(p, pos)
		}
	}
	return
}

// replace based on positions
func (ø *FReplace) ReplacePos(m map[int][]byte) (res []byte) {
	last := 0
	for _, pos := range ø.sortedPos {
		res = append(res, ø.original[last:pos]...)
		if repl := m[pos]; repl != nil {
			// we have a replacement for the anchor
			res = append(res, repl...)
		}
		last = pos
	}
	res = append(res, ø.original[last:len(ø.original)]...)
	return
}

// like Replace but returns a string
func (ø *FReplace) ReplaceString(m map[string][]byte) (res string) {
	return string(ø.Replace(m))
}

// replace based on placeholders
func (ø *FReplace) Replace(m map[string][]byte) (res []byte) {
	last := 0
	for _, pos := range ø.sortedPos {
		res = append(res, ø.original[last:pos]...)
		posBt := ø.positions[pos]
		if repl := m[posBt]; repl != nil {
			// we have a replacement for the anchor
			res = append(res, repl...)
		}
		last = pos
	}
	res = append(res, ø.original[last:len(ø.original)]...)
	return
}

func (ø *FReplace) ParseString(delimiter string, s string) {
	ø.Parse([]byte(delimiter), []byte(s))
}

// parse the input for placeholders and caches the result
func (ø *FReplace) Parse(delimiter []byte, in []byte) {
	ø.positions = map[int]string{}
	ø.original = []byte{}
	ø.sortedPos = []int{}
	lenDel := len(delimiter)
	lenIn := len(in)
	for i := 0; i < lenIn; i++ {
		found := bytes.Index(in[i:], delimiter)
		if found != -1 {
			start := found + i
			ø.original = append(ø.original, in[i:start]...)
			startPlaceH := start + lenDel
			found = bytes.Index(in[startPlaceH:], delimiter)
			if found == -1 {
				// is not a delimiter
				ø.original = append(ø.original, in[startPlaceH:]...)
				break
			} else {
				end := found + start + lenDel
				pos := len(ø.original)
				ø.sortedPos = append(ø.sortedPos, pos)
				ø.positions[pos] = string(in[startPlaceH:end])
				i = end + 1
			}
		} else {
			ø.original = append(ø.original, in[i:]...)
			break
		}
	}
	sort.Ints(ø.sortedPos)
}

// returns an Instance that offers more comfort and caching of replacements
func (ø *FReplace) Instance() *Instance {
	return &Instance{replace: ø, replacePos: map[int][]byte{}}
}

type Instance struct {
	replace    *FReplace
	replacePos map[int][]byte
}

func (ø *Instance) String() string {
	return string(ø.Replace())
}

func (ø *Instance) Replace() []byte {
	return ø.replace.ReplacePos(ø.replacePos)
}

func (ø *Instance) Assign(key string, val []byte) {
	poses := ø.replace.Pos(key)
	for _, pos := range poses {
		ø.replacePos[pos] = val
	}
}

func (ø *Instance) AssignString(key string, val string) {
	ø.Assign(key, []byte(val))
}
<commit_msg>add Compiler interface<commit_after>package fastreplace

import (
	"bytes"
	"sort"
)

/*
	Usage:

	see README.md
*/

type Compiler interface {
	Compile() *FReplace
}

type FReplace struct {
	original  []byte
	positions map[int]string // maps a replacement string/sequence of bytes to an array of the indices of the original before which it appears
	sortedPos []int
}

func New(delimiter []byte, input []byte) (ø *FReplace) {
	ø = &FReplace{}
	ø.Parse(delimiter, input)
	return
}

func NewString(delimiter string, input string) (ø *FReplace) {
	return New([]byte(delimiter), []byte(input))
}

// returns a map with all positions and their replacements for the placeholders given in the input map
func (ø *FReplace) AllPos(in map[string][]byte) (out map[int][]byte) {
	out = map[int][]byte{}
	for k, v := range in {
		pos := ø.Pos(k)
		for _, p := range pos {
			out[p] = v
		}
	}
	return
}

// returns all positions for the placeholder string
func (ø *FReplace) Pos(placeholder string) (p []int) {
	for pos, s := range ø.positions {
		if placeholder == s {
			p = append(p, pos)
		}
	}
	return
}

// replace based on positions
func (ø *FReplace) ReplacePos(m map[int][]byte) (res []byte) {
	last := 0
	for _, pos := range ø.sortedPos {
		res = append(res, ø.original[last:pos]...)
		if repl := m[pos]; repl != nil {
			// we have a replacement for the anchor
			res = append(res, repl...)
		}
		last = pos
	}
	res = append(res, ø.original[last:len(ø.original)]...)
	return
}

// like Replace but returns a string
func (ø *FReplace) ReplaceString(m map[string][]byte) (res string) {
	return string(ø.Replace(m))
}

// replace based on placeholders
func (ø *FReplace) Replace(m map[string][]byte) (res []byte) {
	last := 0
	for _, pos := range ø.sortedPos {
		res = append(res, ø.original[last:pos]...)
		posBt := ø.positions[pos]
		if repl := m[posBt]; repl != nil {
			// we have a replacement for the anchor
			res = append(res, repl...)
		}
		last = pos
	}
	res = append(res, ø.original[last:len(ø.original)]...)
	return
}

func (ø *FReplace) ParseString(delimiter string, s string) {
	ø.Parse([]byte(delimiter), []byte(s))
}

// parse the input for placeholders and caches the result
func (ø *FReplace) Parse(delimiter []byte, in []byte) {
	ø.positions = map[int]string{}
	ø.original = []byte{}
	ø.sortedPos = []int{}
	lenDel := len(delimiter)
	lenIn := len(in)
	for i := 0; i < lenIn; i++ {
		found := bytes.Index(in[i:], delimiter)
		if found != -1 {
			start := found + i
			ø.original = append(ø.original, in[i:start]...)
			startPlaceH := start + lenDel
			found = bytes.Index(in[startPlaceH:], delimiter)
			if found == -1 {
				// is not a delimiter
				ø.original = append(ø.original, in[startPlaceH:]...)
				break
			} else {
				end := found + start + lenDel
				pos := len(ø.original)
				ø.sortedPos = append(ø.sortedPos, pos)
				ø.positions[pos] = string(in[startPlaceH:end])
				i = end + 1
			}
		} else {
			ø.original = append(ø.original, in[i:]...)
			break
		}
	}
	sort.Ints(ø.sortedPos)
}

// returns an Instance that offers more comfort and caching of replacements
func (ø *FReplace) Instance() *Instance {
	return &Instance{replace: ø, replacePos: map[int][]byte{}}
}

type Instance struct {
	replace    *FReplace
	replacePos map[int][]byte
}

func (ø *Instance) String() string {
	return string(ø.Replace())
}

func (ø *Instance) Replace() []byte {
	return ø.replace.ReplacePos(ø.replacePos)
}

func (ø *Instance) Assign(key string, val []byte) {
	poses := ø.replace.Pos(key)
	for _, pos := range poses {
		ø.replacePos[pos] = val
	}
}

func (ø *Instance) AssignString(key string, val string) {
	ø.Assign(key, []byte(val))
}
<|endoftext|>


<commit_before>/* Copyright (C) 2015-2020 김운하(UnHa Kim)  < unha.kim.ghts at gmail dot com >

이 파일은 GHTS의 일부입니다.

이 프로그램은 자유 소프트웨어입니다.
소프트웨어의 피양도자는 자유 소프트웨어 재단이 공표한 GNU LGPL 2.1판
규정에 따라 프로그램을 개작하거나 재배포할 수 있습니다.

이 프로그램은 유용하게 사용될 수 있으리라는 희망에서 배포되고 있지만,
특정한 목적에 적합하다거나, 이익을 안겨줄 수 있다는 묵시적인 보증을 포함한
어떠한 형태의 보증도 제공하지 않습니다.
보다 자세한 사항에 대해서는 GNU LGPL 2.1판을 참고하시기 바랍니다.
GNU LGPL 2.1판은 이 프로그램과 함께 제공됩니다.
만약, 이 문서가 누락되어 있다면 자유 소프트웨어 재단으로 문의하시기 바랍니다.
(자유 소프트웨어 재단 : Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA)

Copyright (C) 2015-2020년 UnHa Kim (< unha.kim.ghts at gmail dot com >)

This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 2.1 of the License.

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

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

package xing

import (
	"github.com/ghts/ghts/lib"
	xt "github.com/ghts/ghts/xing/base"
	"math"
	"testing"
	"time"
)

func TestCSPAQ12300_현물계좌_잔고내역_질의값(t *testing.T) {
	t.Parallel()

	_, ok := interface{}(new(xt.CSPAQ12300_현물계좌_잔고내역_질의값)).(lib.I질의값)
	lib.F테스트_참임(t, ok)
}

func TestCSPAQ12300_현물계좌_잔고내역_조회(t *testing.T) {
	t.Parallel()

	const 수량 = 5
	const 가격_정상주문 = int64(0) // 현재가 주문은 가격이 0
	const 호가_유형 = lib.P호가_시장가

	계좌번호, 에러 := F계좌_번호(0)
	lib.F테스트_에러없음(t, 에러)

	응답값, 에러 := TrCSPAQ12300_현물계좌_잔고내역_조회(계좌번호, xt.CSPAQ12300_BEP_단가, true)
	lib.F테스트_에러없음(t, 에러)

	값1 := 응답값.M헤더1
	lib.F테스트_같음(t, 값1.M레코드_수량, 1)

	lib.F테스트_같음(t, 값1.M계좌번호, 계좌번호)
	lib.F테스트_같음(t, 값1.M잔고생성_구분, "0")    // 0:전체, 1:현물
	lib.F테스트_같음(t, 값1.M수수료적용_구분, "1")   // 0:수수료 미적용, 1:수수료 적용
	lib.F테스트_같음(t, 값1.D2잔고기준조회_구분, "1") // 0:전부조회, 1:D2잔고 0이상만 조회
	lib.F테스트_같음(t, 값1.M단가_구분, "1")      // 0:평균단가, 1:BEP단가

	// OutBlock2 데이터 제공 안함 (DevCenter)

	for _, 값 := range 응답값.M반복값_모음 {
		lib.F테스트_참임(t, F종목코드_존재함(값.M종목코드), 값.M종목코드)
		lib.F테스트_다름(t, 값.M종목명, "")
		lib.F테스트_다름(t, 값.M유가증권잔고유형코드, "")
		lib.F테스트_다름(t, 값.M유가증권잔고유형명, "")
		lib.F테스트_참임(t, 값.M잔고수량 >= 0)
		lib.F테스트_참임(t, 값.M매매기준잔고수량 >= 0)
		lib.F테스트_참임(t, 값.M금일매수체결수량 >= 0)
		lib.F테스트_참임(t, 값.M금일매도체결수량 >= 0)
		lib.F테스트_참임(t, 값.M매도가 >= 0)
		lib.F테스트_참임(t, 값.M매수가 >= 0)

		// 모의투자 세금은 0.25%, 수수료는 0.35% 입니다.
		// 0.6% 로 계산시 해당 값이 나옵니다.
		매도손익금액 := (값.M매도가 - 값.M매수가) * float64(값.M매매기준잔고수량)

		lib.F테스트_참임(t, math.Abs(float64(값.M매도손익금액)-매도손익금액) <= 1,
			값.M매도손익금액, 매도손익금액)
		lib.F테스트_참임(t, 값.M손익율*float64(값.M평가손익) >= 0)
		lib.F테스트_참임(t, 값.M현재가 > 0)
		lib.F테스트_참임(t, 값.M신용금액 >= 0)
		lib.F테스트_참임(t, 값.M만기일.Equal(time.Time{}) || 값.M만기일.After(F당일()))
		lib.F테스트_참임(t, 값.M전일매도체결가 >= 0)
		lib.F테스트_참임(t, 값.M전일매도수량 >= 0)
		lib.F테스트_참임(t, 값.M전일매수체결가 >= 0)
		lib.F테스트_참임(t, 값.M전일매수수량 >= 0)
		lib.F테스트_참임(t, 값.M대출일.Equal(time.Time{}) || 값.M대출일.Equal(F당일()))
		lib.F테스트_참임(t, 값.M평균단가 >= 0)
		lib.F테스트_참임(t, 값.M매도가능수량 >= 0)
		lib.F테스트_참임(t, 값.M매도주문수량 >= 0)
		lib.F테스트_참임(t, 값.M금일매수체결금액 >= 0)
		lib.F테스트_참임(t, 값.M금일매도체결금액 >= 0)
		lib.F테스트_참임(t, 값.M전일매수체결금액 >= 0)
		lib.F테스트_참임(t, 값.M전일매도체결금액 >= 0)
		lib.F테스트_참임(t, 값.M잔고평가금액 > 0)

		// 평가손익 = 매입금액 - 평가금액
		lib.F메모("ETF종목 게시판 질문 후 대기중")

		if ETF_ETN_종목_여부(값.M종목코드) { // 세율 0%, 모의서버 수수료 0.35%, 합계 0.35%
			//오차 := 값.M잔고평가금액 - int64(float64(값.M매입금액)*1.0035) - 값.M평가손익
			//lib.F테스트_참임(t, lib.F절대값_정수64(오차) <= 1, 오차, 값.M매입금액, 값.M잔고평가금액, 값.M평가손익, int64(float64(값.M매입금액)*1.0035))
		} else { // 세율 0.25%, 모의서버 수수료 0.35%, 합계 0.6%
			오차 := 값.M잔고평가금액 - int64(float64(값.M매입금액)*1.006) - 값.M평가손익
			lib.F테스트_참임(t, lib.F절대값_정수64(오차) <= 1, 오차, 값.M평가손익, 값.M매입금액, int(float64(값.M매입금액)*1.006), 값.M잔고평가금액) // 평가손익 = 매입금액 - 평가금액
		}

		lib.F테스트_참임(t, 값.M현금주문가능금액 >= 0)
		lib.F테스트_참임(t, 값.M주문가능금액 >= 0)
		lib.F테스트_참임(t, 값.M매도미체결수량 >= 0)
		lib.F테스트_참임(t, 값.M매도미결제수량 >= 0)
		lib.F테스트_참임(t, 값.M매수미체결수량 >= 0)
		lib.F테스트_참임(t, 값.M매수미결제수량 >= 0)
		lib.F테스트_참임(t, 값.M미결제수량 >= 0)
		lib.F테스트_참임(t, 값.M미체결수량 >= 0)
		lib.F테스트_참임(t, 값.M전일종가 > 0)
		lib.F테스트_참임(t, 값.M매입금액 > 0)
		lib.F테스트_같음(t, 값.M등록시장코드,
			xt.CSPAQ12300_코스피, xt.CSPAQ12300_코스닥, xt.CSPAQ12300_코넥스,
			xt.CSPAQ12300_K_OTC, xt.CSPAQ12300_채권, xt.CSPAQ12300_비상장)
		lib.F테스트_같음(t, 값.M대출상세분류코드,
			xt.CSPAQ12300_대출없음, xt.CSPAQ12300_유통융자,
			xt.CSPAQ12300_자기융자, xt.CSPAQ12300_예탁주식담보융자)
		lib.F테스트_참임(t, 값.M예탁담보대출수량 >= 0)
	}
}
<commit_msg>테스트 에러 수정.<commit_after>/* Copyright (C) 2015-2020 김운하(UnHa Kim)  < unha.kim.ghts at gmail dot com >

이 파일은 GHTS의 일부입니다.

이 프로그램은 자유 소프트웨어입니다.
소프트웨어의 피양도자는 자유 소프트웨어 재단이 공표한 GNU LGPL 2.1판
규정에 따라 프로그램을 개작하거나 재배포할 수 있습니다.

이 프로그램은 유용하게 사용될 수 있으리라는 희망에서 배포되고 있지만,
특정한 목적에 적합하다거나, 이익을 안겨줄 수 있다는 묵시적인 보증을 포함한
어떠한 형태의 보증도 제공하지 않습니다.
보다 자세한 사항에 대해서는 GNU LGPL 2.1판을 참고하시기 바랍니다.
GNU LGPL 2.1판은 이 프로그램과 함께 제공됩니다.
만약, 이 문서가 누락되어 있다면 자유 소프트웨어 재단으로 문의하시기 바랍니다.
(자유 소프트웨어 재단 : Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA)

Copyright (C) 2015-2020년 UnHa Kim (< unha.kim.ghts at gmail dot com >)

This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 2.1 of the License.

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

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

package xing

import (
	"github.com/ghts/ghts/lib"
	xt "github.com/ghts/ghts/xing/base"
	"math"
	"testing"
	"time"
)

func TestCSPAQ12300_현물계좌_잔고내역_질의값(t *testing.T) {
	t.Parallel()

	_, ok := interface{}(new(xt.CSPAQ12300_현물계좌_잔고내역_질의값)).(lib.I질의값)
	lib.F테스트_참임(t, ok)
}

func TestCSPAQ12300_현물계좌_잔고내역_조회(t *testing.T) {
	t.Parallel()

	const 수량 = 5
	const 가격_정상주문 = int64(0) // 현재가 주문은 가격이 0
	const 호가_유형 = lib.P호가_시장가

	계좌번호, 에러 := F계좌_번호(0)
	lib.F테스트_에러없음(t, 에러)

	응답값, 에러 := TrCSPAQ12300_현물계좌_잔고내역_조회(계좌번호, xt.CSPAQ12300_평균_단가, false)
	lib.F테스트_에러없음(t, 에러)

	값1 := 응답값.M헤더1
	lib.F테스트_같음(t, 값1.M레코드_수량, 1)

	lib.F테스트_같음(t, 값1.M계좌번호, 계좌번호)
	lib.F테스트_같음(t, 값1.M잔고생성_구분, "0")    // 0:전체, 1:현물
	lib.F테스트_같음(t, 값1.M수수료적용_구분, "0")   // 0:수수료 미적용, 1:수수료 적용
	lib.F테스트_같음(t, 값1.D2잔고기준조회_구분, "1") // 0:전부조회, 1:D2잔고 0이상만 조회
	lib.F테스트_같음(t, 값1.M단가_구분, "0")      // 0:평균단가, 1:BEP단가

	// OutBlock2 데이터 제공 안함 (DevCenter)

	for _, 값 := range 응답값.M반복값_모음 {
		lib.F테스트_참임(t, F종목코드_존재함(값.M종목코드), 값.M종목코드)
		lib.F테스트_다름(t, 값.M종목명, "")
		lib.F테스트_다름(t, 값.M유가증권잔고유형코드, "")
		lib.F테스트_다름(t, 값.M유가증권잔고유형명, "")
		lib.F테스트_참임(t, 값.M잔고수량 >= 0)
		lib.F테스트_참임(t, 값.M매매기준잔고수량 >= 0)
		lib.F테스트_참임(t, 값.M금일매수체결수량 >= 0)
		lib.F테스트_참임(t, 값.M금일매도체결수량 >= 0)
		lib.F테스트_참임(t, 값.M매도가 >= 0)
		lib.F테스트_참임(t, 값.M매수가 >= 0)

		// 모의투자 세금은 0.25%, 수수료는 0.35% 입니다.
		// 0.6% 로 계산시 해당 값이 나옵니다.
		매도손익금액 := (값.M매도가 - 값.M매수가) * float64(값.M매매기준잔고수량)

		lib.F테스트_참임(t, math.Abs(float64(값.M매도손익금액)-매도손익금액) <= 1,
			값.M매도손익금액, 매도손익금액)
		lib.F테스트_참임(t, 값.M손익율*float64(값.M평가손익) >= 0)
		lib.F테스트_참임(t, 값.M현재가 > 0)
		lib.F테스트_참임(t, 값.M신용금액 >= 0)
		lib.F테스트_참임(t, 값.M만기일.Equal(time.Time{}) || 값.M만기일.After(F당일()))
		lib.F테스트_참임(t, 값.M전일매도체결가 >= 0)
		lib.F테스트_참임(t, 값.M전일매도수량 >= 0)
		lib.F테스트_참임(t, 값.M전일매수체결가 >= 0)
		lib.F테스트_참임(t, 값.M전일매수수량 >= 0)
		lib.F테스트_참임(t, 값.M대출일.Equal(time.Time{}) || 값.M대출일.Equal(F당일()))
		lib.F테스트_참임(t, 값.M평균단가 >= 0)
		lib.F테스트_참임(t, 값.M매도가능수량 >= 0)
		lib.F테스트_참임(t, 값.M매도주문수량 >= 0)
		lib.F테스트_참임(t, 값.M금일매수체결금액 >= 0)
		lib.F테스트_참임(t, 값.M금일매도체결금액 >= 0)
		lib.F테스트_참임(t, 값.M전일매수체결금액 >= 0)
		lib.F테스트_참임(t, 값.M전일매도체결금액 >= 0)
		lib.F테스트_참임(t, 값.M잔고평가금액 > 0)

		// 평가손익 = 매입금액 - 평가금액 : 어렵다...
		//if ETF_ETN_종목_여부(값.M종목코드) { // 세율 0%, 모의서버 수수료 0.35%, 합계 0.35%
		//	//오차 := 값.M잔고평가금액 - int64(float64(값.M매입금액)*1.0035) - 값.M평가손익
		//	//lib.F테스트_참임(t, lib.F절대값_정수64(오차) <= 1, 오차, 값.M매입금액, 값.M잔고평가금액, 값.M평가손익, int64(float64(값.M매입금액)*1.0035))
		//} else { // 세율 0.25%, 모의서버 수수료 0.35%, 합계 0.6%
		//	오차 := 값.M잔고평가금액 - int64(float64(값.M매입금액)*1.006) - 값.M평가손익
		//	lib.F테스트_참임(t, lib.F절대값_정수64(오차) <= 1, 오차, 값.M평가손익, 값.M매입금액, int(float64(값.M매입금액)*1.006), 값.M잔고평가금액) // 평가손익 = 매입금액 - 평가금액
		//}

		lib.F테스트_참임(t, 값.M현금주문가능금액 >= 0)
		lib.F테스트_참임(t, 값.M주문가능금액 >= 0)
		lib.F테스트_참임(t, 값.M매도미체결수량 >= 0)
		lib.F테스트_참임(t, 값.M매도미결제수량 >= 0)
		lib.F테스트_참임(t, 값.M매수미체결수량 >= 0)
		lib.F테스트_참임(t, 값.M매수미결제수량 >= 0)
		lib.F테스트_참임(t, 값.M미결제수량 >= 0)
		lib.F테스트_참임(t, 값.M미체결수량 >= 0)
		lib.F테스트_참임(t, 값.M전일종가 > 0)
		lib.F테스트_참임(t, 값.M매입금액 > 0)
		lib.F테스트_같음(t, 값.M등록시장코드,
			xt.CSPAQ12300_코스피, xt.CSPAQ12300_코스닥, xt.CSPAQ12300_코넥스,
			xt.CSPAQ12300_K_OTC, xt.CSPAQ12300_채권, xt.CSPAQ12300_비상장)
		lib.F테스트_같음(t, 값.M대출상세분류코드,
			xt.CSPAQ12300_대출없음, xt.CSPAQ12300_유통융자,
			xt.CSPAQ12300_자기융자, xt.CSPAQ12300_예탁주식담보융자)
		lib.F테스트_참임(t, 값.M예탁담보대출수량 >= 0)
	}
}
<|endoftext|>


<commit_before>package generators

import (
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/yext/edward/common"
	"github.com/yext/edward/services"
)

var goTests = []struct {
	name        string
	path        string
	outServices []*services.ServiceConfig
	outErr      error
}{

	{
		name: "Go Simple",
		path: "testdata/go_simple/",
		outServices: []*services.ServiceConfig{
			&services.ServiceConfig{
				Name: "simple",
				Path: common.StringToStringPointer("testdata/go_simple/gocode/src/yext/simple"),
				Env:  []string{},
				Commands: services.ServiceConfigCommands{
					Build:  "go install",
					Launch: "simple",
				},
				Properties: services.ServiceConfigProperties{
					Started: "Listening",
				},
			},
		},
		outErr: nil,
	},
}

func TestGoGenerator(t *testing.T) {
	for _, test := range goTests {
		services, _, err := GenerateServices(test.path)
		if !reflect.DeepEqual(test.outServices, services) {
			t.Errorf("%v: Services did not match.\nExpected:\n%v\nGot:%v", test.name, spew.Sdump(test.outServices), spew.Sdump(services))
		}
		if err != nil && test.outErr != nil {
			if err.Error() != test.outErr.Error() {
				t.Errorf("%v: Error did not match. Expected %v, got %v", test.name, test.outErr, err)
			}
		} else if err != test.outErr {
			t.Errorf("%v: Errors did not match. Expected: %v, got: %v", test.name, test.outErr, err)
		}
	}
}
<commit_msg>Fix test data, since paths are now handled correctly.<commit_after>package generators

import (
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/yext/edward/common"
	"github.com/yext/edward/services"
)

var goTests = []struct {
	name        string
	path        string
	outServices []*services.ServiceConfig
	outErr      error
}{

	{
		name: "Go Simple",
		path: "testdata/go_simple/",
		outServices: []*services.ServiceConfig{
			&services.ServiceConfig{
				Name: "simple",
				Path: common.StringToStringPointer("gocode/src/yext/simple"),
				Env:  []string{},
				Commands: services.ServiceConfigCommands{
					Build:  "go install",
					Launch: "simple",
				},
				Properties: services.ServiceConfigProperties{
					Started: "Listening",
				},
			},
		},
		outErr: nil,
	},
}

func TestGoGenerator(t *testing.T) {
	for _, test := range goTests {
		services, _, err := GenerateServices(test.path)
		if !reflect.DeepEqual(test.outServices, services) {
			t.Errorf("%v: Services did not match.\nExpected:\n%v\nGot:%v", test.name, spew.Sdump(test.outServices), spew.Sdump(services))
		}
		if err != nil && test.outErr != nil {
			if err.Error() != test.outErr.Error() {
				t.Errorf("%v: Error did not match. Expected %v, got %v", test.name, test.outErr, err)
			}
		} else if err != test.outErr {
			t.Errorf("%v: Errors did not match. Expected: %v, got: %v", test.name, test.outErr, err)
		}
	}
}
<|endoftext|>


<commit_before>package dnsdb

import (
	"github.com/stretchr/testify/assert"

	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
)

func Test_RDataService_LookupName(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupName("hq.fsi.io", nil)
	assert.NotNil(t, err)

	// Verify that an invalid response fails
	invalidServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{`)
	}))
	defer invalidServer.Close()
	u, err = url.Parse(invalidServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupName("hq.fsi.io", nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":45644,"time_first":1372706073,"time_last":1468330740,"rrname":"fsi.io.","rrtype":"MX","rdata":"10 hq.fsi.io."}
{"count":19304,"time_first":1374098929,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"MX","rdata":"10 hq.fsi.io."}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupName("hq.fsi.io", &RDataLookupNameOptions{
		RRType: "MX",
	})
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(45644),
			TimeFirst: NewTimestamp(1372706073),
			TimeLast:  NewTimestamp(1468330740),
			RRName:    String("fsi.io."),
			RRType:    String("MX"),
			RData:     String("10 hq.fsi.io."),
		},
		RData{
			Count:     Uint64(19304),
			TimeFirst: NewTimestamp(1374098929),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("MX"),
			RData:     String("10 hq.fsi.io."),
		},
	}, actual)
}

func Test_RDataService_LookupIP(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}

func Test_RDataService_LookupIPNet(t *testing.T) {
	// Setup a client
	c := NewClient(nil)
	_, ipnet, _ := net.ParseCIDR("104.244.13.104/29")

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIPNet(*ipnet, nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIPNet(*ipnet, nil)
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}
<commit_msg>Improve rdata.go test coverage<commit_after>package dnsdb

import (
	"github.com/stretchr/testify/assert"

	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
)

func Test_RDataService_LookupName(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupName("hq.fsi.io", nil)
	assert.NotNil(t, err)

	// Verify that an invalid response fails
	invalidServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{`)
	}))
	defer invalidServer.Close()
	u, err = url.Parse(invalidServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupName("hq.fsi.io", nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":45644,"time_first":1372706073,"time_last":1468330740,"rrname":"fsi.io.","rrtype":"MX","rdata":"10 hq.fsi.io."}
{"count":19304,"time_first":1374098929,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"MX","rdata":"10 hq.fsi.io."}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupName("hq.fsi.io", &RDataLookupNameOptions{
		RRType: "MX",
	})
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(45644),
			TimeFirst: NewTimestamp(1372706073),
			TimeLast:  NewTimestamp(1468330740),
			RRName:    String("fsi.io."),
			RRType:    String("MX"),
			RData:     String("10 hq.fsi.io."),
		},
		RData{
			Count:     Uint64(19304),
			TimeFirst: NewTimestamp(1374098929),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("MX"),
			RData:     String("10 hq.fsi.io."),
		},
	}, actual)
}

func Test_RDataService_LookupIP(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.NotNil(t, err)

	// Verify that an invalid response fails
	invalidServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{`)
	}))
	defer invalidServer.Close()
	u, err = url.Parse(invalidServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIP(net.ParseIP("104.244.13.104"), &RDataLookupIPOptions{
		RRType: "A",
	})
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}

func Test_RDataService_LookupIPNet(t *testing.T) {
	// Setup a client
	c := NewClient(nil)
	_, ipnet, _ := net.ParseCIDR("104.244.13.104/29")

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIPNet(*ipnet, nil)
	assert.NotNil(t, err)

	// Verify that an invalid response fails
	invalidServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{`)
	}))
	defer invalidServer.Close()
	u, err = url.Parse(invalidServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIPNet(*ipnet, nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIPNet(*ipnet, &RDataLookupIPNetOptions{
		RRType: "A",
	})
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}

func Test_RDataService_LookupRaw(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupRaw([]byte{}, nil)
	assert.NotNil(t, err)

	// Verify that an invalid response fails
	invalidServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{`)
	}))
	defer invalidServer.Close()
	u, err = url.Parse(invalidServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupRaw([]byte{}, nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupRaw([]byte("\x68\xF4\x0D\x68"), &RDataLookupRawOptions{
		RRType: "A",
	})
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"github.com/gorilla/mux"
	"io"
	"log"
	"net/http"
)

var (
	operatorPort = flag.String("operatorPort", "3424", "port the operator pings at")
	lastGame     bytes.Buffer
)

func handleClientPost(clientPost chan<- []byte) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		log.Println("responding to /frontend")
		var buf bytes.Buffer
		io.Copy(&buf, r.Body)
		clientPost <- buf.Bytes()
	}
}

func handleClientGet(clientGet <-chan []byte) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("handleClientGet: waiting for value from channel")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		io.Copy(w, bytes.NewBuffer(<-clientGet))
		log.Println("handleClientGet: got resp from channel, resolving")
	}
}

func handleOperatorPost(operatorPost chan<- []byte, gameToOperator <-chan []byte) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("responding to /move")
		var buf bytes.Buffer
		io.Copy(&buf, r.Body)
		operatorPost <- buf.Bytes()
		cp := <-gameToOperator
		log.Println("resolving /move")
		io.Copy(w, bytes.NewBuffer(cp))
	}
}

func main() {
	flag.Parse()
	r := mux.NewRouter()
	operatorPost := make(chan []byte)
	clientPost := make(chan []byte)
	clientGet := make(chan []byte)
	gameToOperator := make(chan []byte)
	r.Path("/frontend").Methods("GET").HandlerFunc(handleClientGet(clientGet))
	r.Path("/frontend").Methods("POST").HandlerFunc(handleClientPost(clientPost))
	r.Path("/move").Methods("POST").HandlerFunc(handleOperatorPost(operatorPost, gameToOperator))
	go func() {
		var previousGame []byte
		for {
			sendGameToClient := clientGet
			if previousGame == nil {
				sendGameToClient = nil
			}
			select {
			case x := <-clientPost:
				gameToOperator <- x
				previousGame = nil

			case x := <-operatorPost:
				previousGame = x

			case sendGameToClient <- previousGame:
			}
		}
	}()

	go func() {
		http.ListenAndServe(":"+*operatorPort, r)
	}()
	http.ListenAndServe(":1337", r)
}
<commit_msg>Simpler flags.<commit_after>package main

import (
	"bytes"
	"flag"
	"github.com/gorilla/mux"
	"io"
	"log"
	"net/http"
)

var (
	port = flag.String("port", "3424", "port the operator pings at")
)

func handleClientPost(clientPost chan<- []byte) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		log.Println("responding to /frontend")
		var buf bytes.Buffer
		io.Copy(&buf, r.Body)
		clientPost <- buf.Bytes()
	}
}

func handleClientGet(clientGet <-chan []byte) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("handleClientGet: waiting for value from channel")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		io.Copy(w, bytes.NewBuffer(<-clientGet))
		log.Println("handleClientGet: got resp from channel, resolving")
	}
}

func handleOperatorPost(operatorPost chan<- []byte, gameToOperator <-chan []byte) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("responding to /move")
		var buf bytes.Buffer
		io.Copy(&buf, r.Body)
		operatorPost <- buf.Bytes()
		cp := <-gameToOperator
		log.Println("resolving /move")
		io.Copy(w, bytes.NewBuffer(cp))
	}
}

func main() {
	flag.Parse()
	r := mux.NewRouter()
	operatorPost := make(chan []byte)
	clientPost := make(chan []byte)
	clientGet := make(chan []byte)
	gameToOperator := make(chan []byte)
	r.Path("/frontend").Methods("GET").HandlerFunc(handleClientGet(clientGet))
	r.Path("/frontend").Methods("POST").HandlerFunc(handleClientPost(clientPost))
	r.Path("/move").Methods("POST").HandlerFunc(handleOperatorPost(operatorPost, gameToOperator))
	go func() {
		var previousGame []byte
		for {
			sendGameToClient := clientGet
			if previousGame == nil {
				sendGameToClient = nil
			}
			select {
			case x := <-clientPost:
				gameToOperator <- x
				previousGame = nil

			case x := <-operatorPost:
				previousGame = x

			case sendGameToClient <- previousGame:
			}
		}
	}()

	go func() {
		http.ListenAndServe(":"+*port, r)
	}()
	http.ListenAndServe(":1337", r)
}
<|endoftext|>


<commit_before>package goassets

const TPL = `package {{ .Package }}

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"
	"strings"
)

var builtAt time.Time

type assetFileSystemI interface {
	Open(name string) (http.File, error)
	AssetNames() []string
}

var assets assetFileSystemI

func assetNames() (names []string) {
	return assets.AssetNames()
}

func readAsset(key string) ([]byte, error) {
	r, e := assets.Open(key)
	if e != nil {
		return nil, e
	}
	defer func() {
		_ = r.Close()
	}()

	p, e := ioutil.ReadAll(r)
	if e != nil {
		return nil, e
	}
	return p, nil
}

func mustReadAsset(key string) []byte {
	p, e := readAsset(key)
	if e != nil {
		panic("could not read asset with key " + key + ": " + e.Error())
	}
	return p
}

type assetOsFS struct{ root string }

func (aFS assetOsFS) Open(name string) (http.File, error) {
	return os.Open(filepath.Join(aFS.root, name))
}

func (aFS *assetOsFS) AssetNames() ([]string) {
	names, e := filepath.Glob(aFS.root + "/*")
	if e != nil {
		log.Print(e)
	}
	return names
}

type assetIntFS map[string][]byte

type assetFile struct {
	name string
	*bytes.Reader
}

type assetFileInfo struct {
	*assetFile
}

func (info assetFileInfo) Name() string {
	return info.assetFile.name
}

func (info assetFileInfo) ModTime() time.Time {
	return builtAt
}

func (info assetFileInfo) Mode() os.FileMode {
	return 0644
}

func (info assetFileInfo) Sys() interface{} {
	return nil
}

func (info assetFileInfo) Size() int64 {
	return int64(info.assetFile.Reader.Len())
}

func (info assetFileInfo) IsDir() bool {
	return false
}

func (info assetFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func (f *assetFile) Stat() (os.FileInfo, error) {
	info := assetFileInfo{assetFile: f}
	return info, nil
}

func (afs assetIntFS) AssetNames() (names []string) {
	names = make([]string, 0, len(afs))
	for k, _ := range afs {
		names = append(names, k)
	}
	return names
}

func (afs assetIntFS) Open(name string) (af http.File, e error) {
	name = strings.TrimPrefix(name, "/")
	if name == "" {
		name = "index.html"
	}
	log.Printf("opening %q", name)
	if asset, found := afs[name]; found {
		decomp, e := gzip.NewReader(bytes.NewBuffer(asset))
		if e != nil {
			return nil, e
		}
		defer func() {
			_ = decomp.Close()
		}()
		b, e := ioutil.ReadAll(decomp)
		if e != nil {
			return nil, e
		}
		af = &assetFile{Reader: bytes.NewReader(b)}
		return af, nil
	}
	return nil, os.ErrNotExist
}

func (a *assetFile) Close() error {
	return nil
}

func (a *assetFile) Read(p []byte) (n int, e error) {
	if a.Reader == nil {
		return 0, os.ErrInvalid
	}
	return a.Reader.Read(p)
}

func init() {
	builtAt, _ = time.Parse(time.RFC3339Nano, "{{ .BuiltAt }}")
	env_name := fmt.Sprintf("GOASSETS_PATH")
	path := os.Getenv(env_name)
	if path != "" {
		stat, e := os.Stat(path)
		if e == nil && stat.IsDir() {
			assets = &assetOsFS{root: path}
			return
		}
	}

	assetsTmp := assetIntFS{}
	{{ range .Assets }}assetsTmp["{{ .Key }}"] = []byte{
		{{ .Bytes }}
	}
	{{ end }}
	assets = assetsTmp
}
`
<commit_msg>remove log statement<commit_after>package goassets

const TPL = `package {{ .Package }}

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"
	"strings"
)

var builtAt time.Time

type assetFileSystemI interface {
	Open(name string) (http.File, error)
	AssetNames() []string
}

var assets assetFileSystemI

func assetNames() (names []string) {
	return assets.AssetNames()
}

func readAsset(key string) ([]byte, error) {
	r, e := assets.Open(key)
	if e != nil {
		return nil, e
	}
	defer func() {
		_ = r.Close()
	}()

	p, e := ioutil.ReadAll(r)
	if e != nil {
		return nil, e
	}
	return p, nil
}

func mustReadAsset(key string) []byte {
	p, e := readAsset(key)
	if e != nil {
		panic("could not read asset with key " + key + ": " + e.Error())
	}
	return p
}

type assetOsFS struct{ root string }

func (aFS assetOsFS) Open(name string) (http.File, error) {
	return os.Open(filepath.Join(aFS.root, name))
}

func (aFS *assetOsFS) AssetNames() ([]string) {
	names, e := filepath.Glob(aFS.root + "/*")
	if e != nil {
		log.Print(e)
	}
	return names
}

type assetIntFS map[string][]byte

type assetFile struct {
	name string
	*bytes.Reader
}

type assetFileInfo struct {
	*assetFile
}

func (info assetFileInfo) Name() string {
	return info.assetFile.name
}

func (info assetFileInfo) ModTime() time.Time {
	return builtAt
}

func (info assetFileInfo) Mode() os.FileMode {
	return 0644
}

func (info assetFileInfo) Sys() interface{} {
	return nil
}

func (info assetFileInfo) Size() int64 {
	return int64(info.assetFile.Reader.Len())
}

func (info assetFileInfo) IsDir() bool {
	return false
}

func (info assetFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func (f *assetFile) Stat() (os.FileInfo, error) {
	info := assetFileInfo{assetFile: f}
	return info, nil
}

func (afs assetIntFS) AssetNames() (names []string) {
	names = make([]string, 0, len(afs))
	for k, _ := range afs {
		names = append(names, k)
	}
	return names
}

func (afs assetIntFS) Open(name string) (af http.File, e error) {
	name = strings.TrimPrefix(name, "/")
	if name == "" {
		name = "index.html"
	}
	if asset, found := afs[name]; found {
		decomp, e := gzip.NewReader(bytes.NewBuffer(asset))
		if e != nil {
			return nil, e
		}
		defer func() {
			_ = decomp.Close()
		}()
		b, e := ioutil.ReadAll(decomp)
		if e != nil {
			return nil, e
		}
		af = &assetFile{Reader: bytes.NewReader(b)}
		return af, nil
	}
	return nil, os.ErrNotExist
}

func (a *assetFile) Close() error {
	return nil
}

func (a *assetFile) Read(p []byte) (n int, e error) {
	if a.Reader == nil {
		return 0, os.ErrInvalid
	}
	return a.Reader.Read(p)
}

func init() {
	builtAt, _ = time.Parse(time.RFC3339Nano, "{{ .BuiltAt }}")
	env_name := fmt.Sprintf("GOASSETS_PATH")
	path := os.Getenv(env_name)
	if path != "" {
		stat, e := os.Stat(path)
		if e == nil && stat.IsDir() {
			assets = &assetOsFS{root: path}
			return
		}
	}

	assetsTmp := assetIntFS{}
	{{ range .Assets }}assetsTmp["{{ .Key }}"] = []byte{
		{{ .Bytes }}
	}
	{{ end }}
	assets = assetsTmp
}
`
<|endoftext|>


<commit_before><commit_msg>doc: add examples<commit_after><|endoftext|>


<commit_before>package livedb

import (
	"testing"
	"bytes"
	"io"
	"fmt"
)

var testData map[string]interface{} = map[string]interface{}{
	"foo":	"bar",
	"h":	map[string]string {
		"ga": "bu",
	},
}

func TestNewFrom(t *testing.T) {
	if !NewFrom(testData).FieldEquals("foo", "bar") {
		t.Fatalf("NewFrom")
	}
}

func TestSET(t *testing.T) {
	db := New()
	db.SET("foo", "bar")
	if !db.FieldEquals("foo", "bar") {
		t.Fatalf("%s != %s", db.data["foo"], "bar")
	}
}

func TestApplySET(t *testing.T) {
	db := New()
	_, err := db.Apply("SET", "foo", "bar")
	if err != nil {
		t.Fatal(err)
	}
	if !db.FieldEquals("foo", "bar") {
		t.Fatal("GET/SET")
	}
}

func testGETExists(t *testing.T) {
	db := NewFrom(map[string]interface{}{"foo":"bar"})
	if value, err := db.GET("foo"); err != nil {
		t.Fatal(err)
	} else if !stringEqual(value, "bar") {
		t.Fatalf("GET returned %s instead of bar", value)
	}
}

func TestGETNonExist(t *testing.T) {
	db := New()
	if value, err := db.GET("foo"); err != nil {
		t.Fatal("GET on non-existing key should return nil, not an error")
	} else if value != nil {
		t.Fatal("GET on non-existing key should return nil")
	}
}

func TestGETonHash(t *testing.T) {
	db := New()
	db.HSET("foo", "k", "hello")
	if _, err := db.GET("foo"); err == nil {
		t.Fatal("GET on hash should return an error")
	}
}

func TestHSET(t *testing.T) {
	db := New()
	db.HSET("foo", "k", "hello")
	if !db.Equals(NewFromJSON([]byte("{\"foo\": {\"k\": \"hello\"}}"))) {
		t.Fatalf("Wrong db state after HSET: %#v\n", db.data)
	}
}

func TestHGET(t *testing.T) {
	db := NewFrom(testData)
	if value, err := db.HGET("h", "ga"); err != nil {
		t.Fatal(err)
	} else if !stringEqual(value, "bu") {
		t.Fatalf("HGET returned %s intead of %s", value, "bu")
	}
}

func TestHGETNonExistingHash(t *testing.T) {
	db := New()
	if value, err := db.HGET("foo", "k"); err != nil {
		t.Fatal("HGET on non-existing hash should return null")
	} else if value != nil {
		t.Fatal("HGET on non-existing hash should return null")
	}
}

func TestHGETNonExistingKey(t *testing.T) {
	db := New()
	if value, err := db.HGET("foo", "k"); err != nil {
		t.Fatal(err)
	} else if value != nil {
		t.Fatal("HGET on non-existing key should return null")
	}
}

func TestLoadJSON1(t *testing.T) {
	db := New()
	if n, err := db.LoadJSON([]byte("{\"foo\": \"bar\"}")); err != nil {
		t.Fatal(err)
	} else if n != 1 {
		t.Fatalf("LoadJSON returned %d instead of 1", n)
	}
	if value, err := db.GET("foo"); err != nil {
		t.Fatal(err)
	} else if value == nil {
		t.Fatalf("LoadJSON didn't store a value")
	} else if *value != "bar" {
		t.Fatalf("LoadJSON stored the wrong value (%s)", *value)
	}
}

func TestLoadJSON2(t *testing.T) {
	db := New()
	if n, err := db.LoadJSON([]byte("{\"foo\": {\"ga\": \"bu\"}}")); err != nil {
		t.Fatal(err)
	} else if n != 1 {
		t.Fatalf("LoadJSON returned %d instead of 1", n)
	}
	if !db.FieldEquals("foo", map[string]string{"ga": "bu"}) {
		t.Fatalf("Wrong DB state after LoadJSON: %#v\n", db.data)
	}
}

func TestReplicateOneSET(t *testing.T) {
	ReplicationTest(t,
		Command{"SET", "hello", "world"},
	)
}

func TestReplicateTwoSET(t *testing.T) {
	ReplicationTest(t,
		Command{"SET", "foo", "bar"},
		Command{"SET", "hello", "world"},
	)
}

func TestBigReplication(t *testing.T) {
	ReplicationTest(t,
		Command{"SET", "foo", "bar"},
		Command{"SET", "hello", "world"},
		Command{"HSET", "animal_colors", "macaque", "brown"},
		Command{"HSET", "animal_colors", "lion", "yello"},
		Command{"HSET", "animal_colors", "flamingo", "pink"},
		Command{"HSET", "animal_colors", "gordon", "fancy green"},
		Command{"HSET", "animal_colors", "fox", "brown"},
		Command{"HSET", "animal_colors", "elephant", "gray"},
		Command{"SET", "foo", "baz"},
	)
}

func ReplicationTest(t *testing.T, commands ...Command) {
	if err := func() error {
		master := New()
		slave := New()
		r, w := io.Pipe()
		syncFeed := master.Subscribe()
		errs := make(chan error)
		go func() {
			if n, err := master.ReplicateToN(w, len(commands)); err != nil {
				errs <-err
			} else if n != len(commands) {
				errs <-fmt.Errorf("ReplicateToN() should return %d, not %d", len(commands), n)
			} else {
				errs <-nil
			}
			w.Close()
		}()
		if cmd := <-syncFeed; cmd[0] != "_new_slave" {
			return fmt.Errorf("Expected command '%s', not '%s'\n", "_new_slave", cmd)
		}
		master.Unsubscribe(syncFeed)
		go func() {
			if n, err := slave.ReplicateFromN(r, len(commands)); err != nil {
				errs <-err
			} else if n != len(commands) {
				errs <-fmt.Errorf("ReplicateFromN() should return %d, not %d", len(commands), n)
			} else {
				errs <-nil
			}
		}()
		for _, command := range commands {
			if _, err := master.Apply(command[0], command[1:]...); err != nil {
				return err
			}
		}
		if err := <-errs; err != nil {
			return err
		}
		if err := <-errs; err != nil {
			return err
		}
		if !master.Equals(slave) {
			return fmt.Errorf("Slave and master differ after replication:\n\t   %v\t\t!= %v\n", master, slave)
		}
		return nil
	}(); err != nil {
		t.Fatal(err)
	}
}

func TestReplicateWrongArgSize(t *testing.T) {
	db := New()
	input := new(bytes.Buffer)
	// Dump initial state to wire
	if err := NewDump(New().data).Encode(input); err != nil {
		t.Fatal(err)
	}
	// Send a manually encoded replication command (with a voluntary error)
	input.WriteString("*3\r\n$3\r\nSET\r\n$4\r\nfoo\r\n$3\r\nbar\r\n")
	if _, err := db.ReplicateFromN(input, 1); err == nil {
		t.Fatalf("Wrong command in replication stream should trigger an error")
	}
}

func TestNewDump(t *testing.T) {
	in := NewFrom(testData)
	dump := NewDump(in.data)
	if !stringEqual(dump.Strings["foo"], "bar") {
		t.Fatalf("Dump didn't preserve string")
	}
	if !hashEqual(dump.Hashes["h"], map[string]string{"ga":"bu"}) {
		t.Fatal("Dump didn't preserve hash")
	}
}

func TestDumpData(t *testing.T) {
	in := NewFrom(testData)
	dump := NewDump(in.data)
	data := dump.Data()
	if !stringEqual(data["foo"], "bar") {
		t.Fatalf("Dump didn't preserve string")
	}
	if !hashEqual(data["h"].(map[string]string), map[string]string{"ga":"bu"}) {
		t.Fatal("Dump didn't preserve hash")
	}
}

func TestDump(t *testing.T) {
	in := NewFrom(testData)
	dump := NewDump(in.data)
	out := NewFrom(dump.Data())
	t.Logf("--> %#v\n", *(dump.Data()["foo"].(*string)))
	if !out.FieldEquals("foo", "bar") {
		t.Errorf("Dump didn't preserve string: %s", out.data["foo"])
	}
	if !out.FieldEquals("h", map[string]string{"ga":"bu"}) {
		t.Errorf("Dump didn't preserve hash")
	}
}

func TestLoadData(t *testing.T) {
	out := NewFrom(testData)
	if !out.FieldEquals("foo", "bar") {
		t.Errorf("NewFrom didn't preserve string: %s", out.data["foo"])
	}
	if !out.FieldEquals("h", map[string]string{"ga":"bu"}) {
		t.Errorf("NewFrom didn't preserve hash")
	}
}
<commit_msg>Added a test to reproduce bug in APPLY("DEL", ...)<commit_after>package livedb

import (
	"testing"
	"bytes"
	"io"
	"fmt"
)

var testData map[string]interface{} = map[string]interface{}{
	"foo":	"bar",
	"h":	map[string]string {
		"ga": "bu",
	},
}

func TestNewFrom(t *testing.T) {
	if !NewFrom(testData).FieldEquals("foo", "bar") {
		t.Fatalf("NewFrom")
	}
}

func TestSET(t *testing.T) {
	db := New()
	db.SET("foo", "bar")
	if !db.FieldEquals("foo", "bar") {
		t.Fatalf("%s != %s", db.data["foo"], "bar")
	}
}

func TestApplySET(t *testing.T) {
	db := New()
	_, err := db.Apply("SET", "foo", "bar")
	if err != nil {
		t.Fatal(err)
	}
	if !db.FieldEquals("foo", "bar") {
		t.Fatal("GET/SET")
	}
}

func testGETExists(t *testing.T) {
	db := NewFrom(map[string]interface{}{"foo":"bar"})
	if value, err := db.GET("foo"); err != nil {
		t.Fatal(err)
	} else if !stringEqual(value, "bar") {
		t.Fatalf("GET returned %s instead of bar", value)
	}
}

func TestGETNonExist(t *testing.T) {
	db := New()
	if value, err := db.GET("foo"); err != nil {
		t.Fatal("GET on non-existing key should return nil, not an error")
	} else if value != nil {
		t.Fatal("GET on non-existing key should return nil")
	}
}

func TestGETonHash(t *testing.T) {
	db := New()
	db.HSET("foo", "k", "hello")
	if _, err := db.GET("foo"); err == nil {
		t.Fatal("GET on hash should return an error")
	}
}

func TestHSET(t *testing.T) {
	db := New()
	db.HSET("foo", "k", "hello")
	if !db.Equals(NewFromJSON([]byte("{\"foo\": {\"k\": \"hello\"}}"))) {
		t.Fatalf("Wrong db state after HSET: %#v\n", db.data)
	}
}

func TestHGET(t *testing.T) {
	db := NewFrom(testData)
	if value, err := db.HGET("h", "ga"); err != nil {
		t.Fatal(err)
	} else if !stringEqual(value, "bu") {
		t.Fatalf("HGET returned %s intead of %s", value, "bu")
	}
}

func TestHGETNonExistingHash(t *testing.T) {
	db := New()
	if value, err := db.HGET("foo", "k"); err != nil {
		t.Fatal("HGET on non-existing hash should return null")
	} else if value != nil {
		t.Fatal("HGET on non-existing hash should return null")
	}
}

func TestHGETNonExistingKey(t *testing.T) {
	db := New()
	if value, err := db.HGET("foo", "k"); err != nil {
		t.Fatal(err)
	} else if value != nil {
		t.Fatal("HGET on non-existing key should return null")
	}
}

func TestDelExists(t *testing.T) {
	db := New()
	if err := db.SET("foo", "bar"); err != nil {
		t.Fatal(err)
	}
	if n := db.DEL("foo"); n != 1 {
		t.Fatalf("Should have deleted %d keys, not %d", 1, n)
	}
	if val, _ := db.GET("foo"); val != nil {
		t.Fatal("Unsuccessful DEL")
	}
}

func TestApplyDel(t *testing.T) {
	db := New()
	if err := db.SET("foo", "bar"); err != nil {
		t.Fatal(err)
	}
	if n, err := db.Apply("DEL", "foo"); err != nil {
		t.Fatal(err)
	} else if n != 1 {
		t.Fatalf("Should have deleted %d keys, not %d", 1, n)
	}
	if val, _ := db.GET("foo"); val != nil {
		t.Fatal("Unsuccessful DEL")
	}
}

func TestLoadJSON1(t *testing.T) {
	db := New()
	if n, err := db.LoadJSON([]byte("{\"foo\": \"bar\"}")); err != nil {
		t.Fatal(err)
	} else if n != 1 {
		t.Fatalf("LoadJSON returned %d instead of 1", n)
	}
	if value, err := db.GET("foo"); err != nil {
		t.Fatal(err)
	} else if value == nil {
		t.Fatalf("LoadJSON didn't store a value")
	} else if *value != "bar" {
		t.Fatalf("LoadJSON stored the wrong value (%s)", *value)
	}
}

func TestLoadJSON2(t *testing.T) {
	db := New()
	if n, err := db.LoadJSON([]byte("{\"foo\": {\"ga\": \"bu\"}}")); err != nil {
		t.Fatal(err)
	} else if n != 1 {
		t.Fatalf("LoadJSON returned %d instead of 1", n)
	}
	if !db.FieldEquals("foo", map[string]string{"ga": "bu"}) {
		t.Fatalf("Wrong DB state after LoadJSON: %#v\n", db.data)
	}
}

func TestReplicateOneSET(t *testing.T) {
	ReplicationTest(t,
		Command{"SET", "hello", "world"},
	)
}

func TestReplicateTwoSET(t *testing.T) {
	ReplicationTest(t,
		Command{"SET", "foo", "bar"},
		Command{"SET", "hello", "world"},
	)
}

func TestBigReplication(t *testing.T) {
	ReplicationTest(t,
		Command{"SET", "foo", "bar"},
		Command{"SET", "hello", "world"},
		Command{"HSET", "animal_colors", "macaque", "brown"},
		Command{"HSET", "animal_colors", "lion", "yello"},
		Command{"HSET", "animal_colors", "flamingo", "pink"},
		Command{"HSET", "animal_colors", "gordon", "fancy green"},
		Command{"HSET", "animal_colors", "fox", "brown"},
		Command{"HSET", "animal_colors", "elephant", "gray"},
		Command{"SET", "foo", "baz"},
	)
}

func ReplicationTest(t *testing.T, commands ...Command) {
	if err := func() error {
		master := New()
		slave := New()
		r, w := io.Pipe()
		syncFeed := master.Subscribe()
		errs := make(chan error)
		go func() {
			if n, err := master.ReplicateToN(w, len(commands)); err != nil {
				errs <-err
			} else if n != len(commands) {
				errs <-fmt.Errorf("ReplicateToN() should return %d, not %d", len(commands), n)
			} else {
				errs <-nil
			}
			w.Close()
		}()
		if cmd := <-syncFeed; cmd[0] != "_new_slave" {
			return fmt.Errorf("Expected command '%s', not '%s'\n", "_new_slave", cmd)
		}
		master.Unsubscribe(syncFeed)
		go func() {
			if n, err := slave.ReplicateFromN(r, len(commands)); err != nil {
				errs <-err
			} else if n != len(commands) {
				errs <-fmt.Errorf("ReplicateFromN() should return %d, not %d", len(commands), n)
			} else {
				errs <-nil
			}
		}()
		for _, command := range commands {
			if _, err := master.Apply(command[0], command[1:]...); err != nil {
				return err
			}
		}
		if err := <-errs; err != nil {
			return err
		}
		if err := <-errs; err != nil {
			return err
		}
		if !master.Equals(slave) {
			return fmt.Errorf("Slave and master differ after replication:\n\t   %v\t\t!= %v\n", master, slave)
		}
		return nil
	}(); err != nil {
		t.Fatal(err)
	}
}

func TestReplicateWrongArgSize(t *testing.T) {
	db := New()
	input := new(bytes.Buffer)
	// Dump initial state to wire
	if err := NewDump(New().data).Encode(input); err != nil {
		t.Fatal(err)
	}
	// Send a manually encoded replication command (with a voluntary error)
	input.WriteString("*3\r\n$3\r\nSET\r\n$4\r\nfoo\r\n$3\r\nbar\r\n")
	if _, err := db.ReplicateFromN(input, 1); err == nil {
		t.Fatalf("Wrong command in replication stream should trigger an error")
	}
}

func TestNewDump(t *testing.T) {
	in := NewFrom(testData)
	dump := NewDump(in.data)
	if !stringEqual(dump.Strings["foo"], "bar") {
		t.Fatalf("Dump didn't preserve string")
	}
	if !hashEqual(dump.Hashes["h"], map[string]string{"ga":"bu"}) {
		t.Fatal("Dump didn't preserve hash")
	}
}

func TestDumpData(t *testing.T) {
	in := NewFrom(testData)
	dump := NewDump(in.data)
	data := dump.Data()
	if !stringEqual(data["foo"], "bar") {
		t.Fatalf("Dump didn't preserve string")
	}
	if !hashEqual(data["h"].(map[string]string), map[string]string{"ga":"bu"}) {
		t.Fatal("Dump didn't preserve hash")
	}
}

func TestDump(t *testing.T) {
	in := NewFrom(testData)
	dump := NewDump(in.data)
	out := NewFrom(dump.Data())
	t.Logf("--> %#v\n", *(dump.Data()["foo"].(*string)))
	if !out.FieldEquals("foo", "bar") {
		t.Errorf("Dump didn't preserve string: %s", out.data["foo"])
	}
	if !out.FieldEquals("h", map[string]string{"ga":"bu"}) {
		t.Errorf("Dump didn't preserve hash")
	}
}

func TestLoadData(t *testing.T) {
	out := NewFrom(testData)
	if !out.FieldEquals("foo", "bar") {
		t.Errorf("NewFrom didn't preserve string: %s", out.data["foo"])
	}
	if !out.FieldEquals("h", map[string]string{"ga":"bu"}) {
		t.Errorf("NewFrom didn't preserve hash")
	}
}
<|endoftext|>