<commit_before>/*
Copyright 2020 The Vitess Authors.

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 endtoend

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/stretchr/testify/require"
	"vitess.io/vitess/go/vt/vttablet/endtoend/framework"
)

//TODO: Add Counter checks in all the tests.

func TestDifferentConnIDOnMultipleReserve(t *testing.T) {
	client1 := framework.NewClient()
	client2 := framework.NewClient()

	//vstart := framework.DebugVars()

	query := "select connection_id()"

	qrc1_1, err := client1.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client1.Release()
	qrc2_1, err := client2.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client2.Release()
	require.NotEqual(t, qrc1_1.Rows, qrc2_1.Rows)

	qrc1_2, err := client1.Execute(query, nil)
	require.NoError(t, err)
	qrc2_2, err := client2.Execute(query, nil)
	require.NoError(t, err)
	require.Equal(t, qrc1_1.Rows, qrc1_2.Rows)
	require.Equal(t, qrc2_1.Rows, qrc2_2.Rows)

	//expectedDiffs := []struct {
	//	tag  string
	//	diff int
	//}{{
	//	tag:  "Release/TotalCount",
	//	diff: 2,
	//}, {
	//	tag:  "Transactions/Histograms/commit/Count",
	//	diff: 2,
	//}, {
	//	tag:  "Queries/TotalCount",
	//	diff: 4,
	//}, {
	//	tag:  "Queries/Histograms/BEGIN/Count",
	//	diff: 0,
	//}, {
	//	tag:  "Queries/Histograms/COMMIT/Count",
	//	diff: 0,
	//}, {
	//	tag:  "Queries/Histograms/Insert/Count",
	//	diff: 1,
	//}, {
	//	tag:  "Queries/Histograms/DeleteLimit/Count",
	//	diff: 1,
	//}, {
	//	tag:  "Queries/Histograms/Select/Count",
	//	diff: 2,
	//}}
	//vend := framework.DebugVars()
	//for _, expected := range expectedDiffs {
	//	got := framework.FetchInt(vend, expected.tag)
	//	want := framework.FetchInt(vstart, expected.tag) + expected.diff
	//	// It's possible that other house-keeping transactions (like messaging)
	//	// can happen during this test. So, don't perform equality comparisons.
	//	if got < want {
	//		t.Errorf("%s: %d, must be at least %d", expected.tag, got, want)
	//	}
	//}
}

func TestReserveBeginRelease(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	qr2, err := client.BeginExecute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
	assert.Equal(t, client.ReservedID(), client.TransactionID())

	require.NoError(t, client.Release())
}

func TestBeginReserveRelease(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.BeginExecute(query, nil)
	require.NoError(t, err)
	defer client.Release()

	qr2, err := client.BeginExecute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
	assert.Equal(t, client.ReservedID(), client.TransactionID())

	require.NoError(t, client.Release())
}

func TestReserveBeginExecute(t *testing.T) {
	client1 := framework.NewClient()
	client2 := framework.NewClient()

	query := "select connection_id()"

	qrc1_1, err := client1.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer func() {
		if client1.ReservedID() != 0 {
			t.Error("should not be reserved after release")
			_ = client1.Release()
		}
	}()
	qrc2_1, err := client2.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer func() {
		if client2.ReservedID() != 0 {
			t.Error("should not be reserved after release")
			_ = client2.Release()
		}
	}()
	require.NotEqual(t, qrc1_1.Rows, qrc2_1.Rows)
	assert.Equal(t, client1.ReservedID(), client1.TransactionID())
	assert.Equal(t, client2.ReservedID(), client2.TransactionID())

	// rows with values 1, 2 and 3 already exist
	query1 := "insert into vitess_test (intval, floatval, charval, binval) values (4, null, null, null)"
	qrc1_2, err := client1.Execute(query1, nil)
	require.NoError(t, err)
	assert.Equal(t, uint64(1), qrc1_2.RowsAffected, "insert should create 1 row")

	query2 := "insert into vitess_test (intval, floatval, charval, binval) values (5, null, null, null)"
	qrc2_2, err := client2.Execute(query2, nil)
	require.NoError(t, err)
	assert.Equal(t, uint64(1), qrc2_2.RowsAffected, "insert should create 1 row")

	query = "select intval from vitess_test"
	qrc1_2, err = client1.Execute(query, nil)
	require.NoError(t, err)
	// client1 does not see row inserted by client2
	expectedRows1 := "[[INT32(1)] [INT32(2)] [INT32(3)] [INT32(4)]]"
	assert.Equal(t, expectedRows1, fmt.Sprintf("%v", qrc1_2.Rows), "wrong result from select1")

	qrc2_2, err = client2.Execute(query, nil)
	require.NoError(t, err)
	expectedRows2 := "[[INT32(1)] [INT32(2)] [INT32(3)] [INT32(5)]]"
	assert.Equal(t, expectedRows2, fmt.Sprintf("%v", qrc2_2.Rows), "wrong result from select2")

	// Release connections without committing
	err = client1.Release()
	require.NoError(t, err)
	err = client1.Release()
	require.Error(t, err)
	err = client2.Release()
	require.NoError(t, err)
	err = client2.Release()
	require.Error(t, err)

	// test that inserts were rolled back
	client3 := framework.NewClient()
	qrc3, err := client3.Execute(query, nil)
	require.NoError(t, err)
	expectedRows := "[[INT32(1)] [INT32(2)] [INT32(3)]]"
	assert.Equal(t, expectedRows, fmt.Sprintf("%v", qrc3.Rows), "wrong result from select after release")
}

func TestCommitOnReserveConn(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldRID := client.ReservedID()
	err = client.Commit()
	require.NoError(t, err)
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after commit")
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after commit")

	qr2, err := client.Execute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
}

func TestRollbackOnReserveConn(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldRID := client.ReservedID()
	err = client.Rollback()
	require.NoError(t, err)
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after rollback")
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after commit")

	qr2, err := client.Execute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
}

func TestReserveBeginRollbackAndBeginCommitAgain(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldRID := client.ReservedID()
	err = client.Rollback()
	require.NoError(t, err)
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after rollback")
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after rollback")

	oldRID = client.ReservedID()

	qr2, err := client.BeginExecute(query, nil)
	require.NoError(t, err)

	err = client.Commit()
	require.NoError(t, err)
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after commit")
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after rollback")

	qr3, err := client.Execute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
	assert.Equal(t, qr2.Rows, qr3.Rows)

	require.NoError(t,
		client.Release())
}

func TestReserveBeginCommitTryToReuseTxID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	_, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldTxID := client.TransactionID()

	err = client.Commit()
	require.NoError(t, err)

	client.SetTransactionID(oldTxID)

	_, err = client.Execute(query, nil)
	require.Error(t, err)
	require.NoError(t,
		client.Release())
}

func TestReserveBeginRollbackTryToReuseTxID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	_, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldTxID := client.TransactionID()

	err = client.Rollback()
	require.NoError(t, err)

	client.SetTransactionID(oldTxID)

	_, err = client.Execute(query, nil)
	require.Error(t, err)
	require.NoError(t,
		client.Release())
}

func TestReserveReleaseAndTryToUseReservedIDAgain(t *testing.T) {
	client := framework.NewClient()

	query := "select 42"

	_, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)

	rID := client.ReservedID()
	require.NoError(t,
		client.Release())

	client.SetReservedID(rID)

	_, err = client.Execute(query, nil)
	require.Error(t, err)
}

func TestReserveAndTryToRunTwiceConcurrently(t *testing.T) {
	client := framework.NewClient()

	query := "select 42"

	_, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	go func() {
		_, err = client.Execute("select sleep(1)", nil)
	}()

	_, err2 := client.Execute("select sleep(1)", nil)

	if err == nil && err2 == nil {
		assert.Fail(t, "at least one execution should fail")
	}
}
<commit_msg>reserve-conn: added unhappy test related to using old reservedID<commit_after>/*
Copyright 2020 The Vitess Authors.

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 endtoend

import (
	"fmt"
	"sync"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/stretchr/testify/require"
	"vitess.io/vitess/go/vt/vttablet/endtoend/framework"
)

//TODO: Add Counter checks in all the tests.

func TestMultipleReserveHaveDifferentConnection(t *testing.T) {
	client1 := framework.NewClient()
	client2 := framework.NewClient()

	//vstart := framework.DebugVars()

	query := "select connection_id()"

	qrc1_1, err := client1.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client1.Release()
	qrc2_1, err := client2.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client2.Release()
	require.NotEqual(t, qrc1_1.Rows, qrc2_1.Rows)

	qrc1_2, err := client1.Execute(query, nil)
	require.NoError(t, err)
	qrc2_2, err := client2.Execute(query, nil)
	require.NoError(t, err)
	require.Equal(t, qrc1_1.Rows, qrc1_2.Rows)
	require.Equal(t, qrc2_1.Rows, qrc2_2.Rows)

}

func TestReserveBeginRelease(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	qr2, err := client.BeginExecute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
	assert.Equal(t, client.ReservedID(), client.TransactionID())

	require.NoError(t, client.Release())
}

func TestBeginReserveRelease(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.BeginExecute(query, nil)
	require.NoError(t, err)
	defer client.Release()

	qr2, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
	assert.Equal(t, client.ReservedID(), client.TransactionID())

	require.NoError(t, client.Release())
}

func TestReserveBeginExecute(t *testing.T) {
	client1 := framework.NewClient()
	client2 := framework.NewClient()

	query := "select connection_id()"

	qrc1_1, err := client1.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer func() {
		if client1.ReservedID() != 0 {
			t.Error("should not be reserved after release")
			_ = client1.Release()
		}
	}()
	qrc2_1, err := client2.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer func() {
		if client2.ReservedID() != 0 {
			t.Error("should not be reserved after release")
			_ = client2.Release()
		}
	}()
	require.NotEqual(t, qrc1_1.Rows, qrc2_1.Rows)
	assert.Equal(t, client1.ReservedID(), client1.TransactionID())
	assert.Equal(t, client2.ReservedID(), client2.TransactionID())

	// rows with values 1, 2 and 3 already exist
	query1 := "insert into vitess_test (intval, floatval, charval, binval) values (4, null, null, null)"
	qrc1_2, err := client1.Execute(query1, nil)
	require.NoError(t, err)
	assert.Equal(t, uint64(1), qrc1_2.RowsAffected, "insert should create 1 row")

	query2 := "insert into vitess_test (intval, floatval, charval, binval) values (5, null, null, null)"
	qrc2_2, err := client2.Execute(query2, nil)
	require.NoError(t, err)
	assert.Equal(t, uint64(1), qrc2_2.RowsAffected, "insert should create 1 row")

	query = "select intval from vitess_test"
	qrc1_2, err = client1.Execute(query, nil)
	require.NoError(t, err)
	// client1 does not see row inserted by client2
	expectedRows1 := "[[INT32(1)] [INT32(2)] [INT32(3)] [INT32(4)]]"
	assert.Equal(t, expectedRows1, fmt.Sprintf("%v", qrc1_2.Rows), "wrong result from select1")

	qrc2_2, err = client2.Execute(query, nil)
	require.NoError(t, err)
	expectedRows2 := "[[INT32(1)] [INT32(2)] [INT32(3)] [INT32(5)]]"
	assert.Equal(t, expectedRows2, fmt.Sprintf("%v", qrc2_2.Rows), "wrong result from select2")

	// Release connections without committing
	err = client1.Release()
	require.NoError(t, err)
	err = client1.Release()
	require.Error(t, err)
	err = client2.Release()
	require.NoError(t, err)
	err = client2.Release()
	require.Error(t, err)

	// test that inserts were rolled back
	client3 := framework.NewClient()
	qrc3, err := client3.Execute(query, nil)
	require.NoError(t, err)
	expectedRows := "[[INT32(1)] [INT32(2)] [INT32(3)]]"
	assert.Equal(t, expectedRows, fmt.Sprintf("%v", qrc3.Rows), "wrong result from select after release")
}

func TestCommitOnReserveConn(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldRID := client.ReservedID()
	err = client.Commit()
	require.NoError(t, err)
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after commit")
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after commit")

	qr2, err := client.Execute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
}

func TestRollbackOnReserveConn(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldRID := client.ReservedID()
	err = client.Rollback()
	require.NoError(t, err)
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after rollback")
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after commit")

	qr2, err := client.Execute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
}

func TestReserveBeginRollbackAndBeginCommitAgain(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qr1, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldRID := client.ReservedID()
	err = client.Rollback()
	require.NoError(t, err)
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after rollback")
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after rollback")

	oldRID = client.ReservedID()

	qr2, err := client.BeginExecute(query, nil)
	require.NoError(t, err)

	err = client.Commit()
	require.NoError(t, err)
	assert.EqualValues(t, 0, client.TransactionID(), "transactionID should be 0 after commit")
	assert.NotEqual(t, client.ReservedID(), oldRID, "reservedID must change after rollback")

	qr3, err := client.Execute(query, nil)
	require.NoError(t, err)
	assert.Equal(t, qr1.Rows, qr2.Rows)
	assert.Equal(t, qr2.Rows, qr3.Rows)

	require.NoError(t,
		client.Release())
}

func TestReserveBeginCommitFailToReuseTxID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	_, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldTxID := client.TransactionID()

	err = client.Commit()
	require.NoError(t, err)

	client.SetTransactionID(oldTxID)

	_, err = client.Execute(query, nil)
	require.Error(t, err)
	require.NoError(t,
		client.Release())
}

func TestReserveBeginRollbackFailToReuseTxID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	_, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	oldTxID := client.TransactionID()

	err = client.Rollback()
	require.NoError(t, err)

	client.SetTransactionID(oldTxID)

	_, err = client.Execute(query, nil)
	require.Error(t, err)
	require.NoError(t,
		client.Release())
}

func TestReserveBeginCommitFailToReuseOldReservedID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	_, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)

	oldRID := client.ReservedID()

	err = client.Commit()
	require.NoError(t, err)
	newRID := client.ReservedID()

	client.SetReservedID(oldRID)

	_, err = client.Execute(query, nil)
	require.Error(t, err)

	client.SetReservedID(newRID)
	require.NoError(t,
		client.Release())
}

func TestReserveBeginRollbackFailToReuseOldReservedID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	_, err := client.ReserveBeginExecute(query, nil, nil)
	require.NoError(t, err)

	oldRID := client.ReservedID()

	err = client.Rollback()
	require.NoError(t, err)
	newRID := client.ReservedID()

	client.SetReservedID(oldRID)
	_, err = client.Execute(query, nil)
	require.Error(t, err)

	client.SetReservedID(newRID)
	require.NoError(t,
		client.Release())
}

func TestReserveReleaseAndFailToUseReservedIDAgain(t *testing.T) {
	client := framework.NewClient()

	query := "select 42"

	_, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)

	rID := client.ReservedID()
	require.NoError(t,
		client.Release())

	client.SetReservedID(rID)

	_, err = client.Execute(query, nil)
	require.Error(t, err)
}

func TestReserveAndFailToRunTwiceConcurrently(t *testing.T) {
	client := framework.NewClient()

	query := "select 42"

	_, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	defer client.Release()

	// WaitGroup will make defer call to wait for go func to complete.
	wg := &sync.WaitGroup{}
	wg.Add(1)
	go func() {
		_, err = client.Execute("select sleep(1)", nil)
		wg.Done()
	}()
	_, err2 := client.Execute("select sleep(1)", nil)
	wg.Wait()

	if err == nil && err2 == nil {
		assert.Fail(t, "at least one execution should fail")
	}
}

func TestBeginReserveCommitAndNewTransactionsOnSameReservedID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qrTx, err := client.BeginExecute(query, nil)
	require.NoError(t, err)

	qrRID, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	require.Equal(t, qrTx.Rows, qrRID.Rows)

	err = client.Commit()
	require.NoError(t, err)

	qrTx, err = client.BeginExecute(query, nil)
	require.NoError(t, err)
	require.Equal(t, qrTx.Rows, qrRID.Rows)

	err = client.Commit()
	require.NoError(t, err)

	qrTx, err = client.BeginExecute(query, nil)
	require.NoError(t, err)
	require.Equal(t, qrTx.Rows, qrRID.Rows)

	err = client.Rollback()
	require.NoError(t, err)

	require.NoError(t,
		client.Release())
}

func TestBeginReserveRollbackAndNewTransactionsOnSameReservedID(t *testing.T) {
	client := framework.NewClient()

	query := "select connection_id()"

	qrTx, err := client.BeginExecute(query, nil)
	require.NoError(t, err)

	qrRID, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)
	require.Equal(t, qrTx.Rows, qrRID.Rows)

	err = client.Rollback()
	require.NoError(t, err)

	qrTx, err = client.BeginExecute(query, nil)
	require.NoError(t, err)
	require.Equal(t, qrTx.Rows, qrRID.Rows)

	err = client.Commit()
	require.NoError(t, err)

	qrTx, err = client.BeginExecute(query, nil)
	require.NoError(t, err)
	require.Equal(t, qrTx.Rows, qrRID.Rows)

	err = client.Rollback()
	require.NoError(t, err)

	require.NoError(t,
		client.Release())
}

func TestBeginReserveReleaseAndFailToUseReservedIDAndTxIDAgain(t *testing.T) {
	client := framework.NewClient()

	query := "select 42"

	_, err := client.BeginExecute(query, nil)
	require.NoError(t, err)

	_, err = client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)

	rID := client.ReservedID()
	txID := client.TransactionID()

	require.NoError(t,
		client.Release())

	client.SetReservedID(rID)
	_, err = client.Execute(query, nil)
	require.Error(t, err)

	client.SetReservedID(0)
	client.SetTransactionID(txID)
	_, err = client.Execute(query, nil)
	require.Error(t, err)
}

func TestReserveBeginReleaseAndFailToUseReservedIDAndTxIDAgain(t *testing.T) {
	client := framework.NewClient()

	query := "select 42"

	_, err := client.ReserveExecute(query, nil, nil)
	require.NoError(t, err)

	_, err = client.BeginExecute(query, nil)
	require.NoError(t, err)

	rID := client.ReservedID()
	txID := client.TransactionID()

	require.NoError(t,
		client.Release())

	client.SetReservedID(rID)
	_, err = client.Execute(query, nil)
	require.Error(t, err)

	client.SetReservedID(0)
	client.SetTransactionID(txID)
	_, err = client.Execute(query, nil)
	require.Error(t, err)
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
)

const nonUniqueWriterAccount = "serviceAccount:cloud-logs@system.gserviceaccount.com"

func resourceLoggingProjectSink() *schema.Resource {
	schm := &schema.Resource{
		Create: resourceLoggingProjectSinkCreate,
		Read:   resourceLoggingProjectSinkRead,
		Delete: resourceLoggingProjectSinkDelete,
		Update: resourceLoggingProjectSinkUpdate,
		Schema: resourceLoggingSinkSchema(),
		Importer: &schema.ResourceImporter{
			State: resourceLoggingProjectSinkImportState,
		},
	}
	schm.Schema["project"] = &schema.Schema{
		Type:     schema.TypeString,
		Optional: true,
		Computed: true,
		ForceNew: true,
	}
	schm.Schema["unique_writer_identity"] = &schema.Schema{
		Type:     schema.TypeBool,
		Optional: true,
		Default:  false,
		ForceNew: true,
	}
	return schm
}

func resourceLoggingProjectSinkCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	id, sink := expandResourceLoggingSink(d, "projects", project)
	uniqueWriterIdentity := d.Get("unique_writer_identity").(bool)

	_, err = config.clientLogging.Projects.Sinks.Create(id.parent(), sink).UniqueWriterIdentity(uniqueWriterIdentity).Do()
	if err != nil {
		return err
	}

	d.SetId(id.canonicalId())

	return resourceLoggingProjectSinkRead(d, meta)
}

func resourceLoggingProjectSinkRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	sink, err := config.clientLogging.Projects.Sinks.Get(d.Id()).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("Project Logging Sink %s", d.Get("name").(string)))
	}

	d.Set("project", project)
	flattenResourceLoggingSink(d, sink)
	if sink.WriterIdentity != nonUniqueWriterAccount {
		d.Set("unique_writer_identity", true)
	} else {
		d.Set("unique_writer_identity", false)
	}
	return nil
}

func resourceLoggingProjectSinkUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	sink := expandResourceLoggingSinkForUpdate(d)
	uniqueWriterIdentity := d.Get("unique_writer_identity").(bool)

	_, err := config.clientLogging.Projects.Sinks.Patch(d.Id(), sink).UniqueWriterIdentity(uniqueWriterIdentity).Do()
	if err != nil {
		return err
	}

	return resourceLoggingProjectSinkRead(d, meta)
}

func resourceLoggingProjectSinkDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	_, err := config.clientLogging.Projects.Sinks.Delete(d.Id()).Do()
	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}

func resourceLoggingProjectSinkImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	parts := strings.Split(d.Id(), "/")
	if len(parts) != 4 {
		return nil, fmt.Errorf("Invalid logging sink specifier. Expecting projects/{project_id}/sinks/{sink_id}")
	}

	project := parts[1]
	d.Set("project", project)

	return []*schema.ResourceData{d}, nil
}
<commit_msg>Call 'parseLoggingSinkId' to parse logging project sink ID.<commit_after>package google

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
)

const nonUniqueWriterAccount = "serviceAccount:cloud-logs@system.gserviceaccount.com"

func resourceLoggingProjectSink() *schema.Resource {
	schm := &schema.Resource{
		Create: resourceLoggingProjectSinkCreate,
		Read:   resourceLoggingProjectSinkRead,
		Delete: resourceLoggingProjectSinkDelete,
		Update: resourceLoggingProjectSinkUpdate,
		Schema: resourceLoggingSinkSchema(),
		Importer: &schema.ResourceImporter{
			State: resourceLoggingProjectSinkImportState,
		},
	}
	schm.Schema["project"] = &schema.Schema{
		Type:     schema.TypeString,
		Optional: true,
		Computed: true,
		ForceNew: true,
	}
	schm.Schema["unique_writer_identity"] = &schema.Schema{
		Type:     schema.TypeBool,
		Optional: true,
		Default:  false,
		ForceNew: true,
	}
	return schm
}

func resourceLoggingProjectSinkCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	id, sink := expandResourceLoggingSink(d, "projects", project)
	uniqueWriterIdentity := d.Get("unique_writer_identity").(bool)

	_, err = config.clientLogging.Projects.Sinks.Create(id.parent(), sink).UniqueWriterIdentity(uniqueWriterIdentity).Do()
	if err != nil {
		return err
	}

	d.SetId(id.canonicalId())

	return resourceLoggingProjectSinkRead(d, meta)
}

func resourceLoggingProjectSinkRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	sink, err := config.clientLogging.Projects.Sinks.Get(d.Id()).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("Project Logging Sink %s", d.Get("name").(string)))
	}

	d.Set("project", project)
	flattenResourceLoggingSink(d, sink)
	if sink.WriterIdentity != nonUniqueWriterAccount {
		d.Set("unique_writer_identity", true)
	} else {
		d.Set("unique_writer_identity", false)
	}
	return nil
}

func resourceLoggingProjectSinkUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	sink := expandResourceLoggingSinkForUpdate(d)
	uniqueWriterIdentity := d.Get("unique_writer_identity").(bool)

	_, err := config.clientLogging.Projects.Sinks.Patch(d.Id(), sink).UniqueWriterIdentity(uniqueWriterIdentity).Do()
	if err != nil {
		return err
	}

	return resourceLoggingProjectSinkRead(d, meta)
}

func resourceLoggingProjectSinkDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	_, err := config.clientLogging.Projects.Sinks.Delete(d.Id()).Do()
	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}

func resourceLoggingProjectSinkImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	config := meta.(*Config)

	loggingSinkId, err := parseLoggingSinkId(d.Id())
	if err != nil {
		return nil, err
	}

	if config.Project != loggingSinkId.resourceId {
		d.Set("project", loggingSinkId.resourceId)
	}

	return []*schema.ResourceData{d}, nil
}
<|endoftext|>


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

package wizard

import (
	"fmt"
	"time"

	"github.com/tsuru/tsuru-autoscale/alarm"
	"github.com/tsuru/tsuru-autoscale/db"
	"gopkg.in/mgo.v2/bson"
)

type AutoScale struct {
	Name      string      `json:"name"`
	ScaleUp   scaleAction `json:"scaleUp"`
	ScaleDown scaleAction `json:"scaleDown"`
	MinUnits  int         `json:"minUnits"`
}

type scaleAction struct {
	Metric   string        `json:"metric"`
	Operator string        `json:"operator"`
	Value    string        `json:"value"`
	Step     string        `json:"step"`
	Wait     time.Duration `json:"wait"`
}

func New(a *AutoScale) error {
	err := newScaleAction(a.ScaleUp, "scale_up", a.Name)
	if err != nil {
		return err
	}
	err = newScaleAction(a.ScaleDown, "scale_down", a.Name)
	if err != nil {
		return err
	}
	err = enableScaleDown(a.Name, a.MinUnits)
	if err != nil {
		return err
	}
	err = disableScaleDown(a.Name, a.MinUnits)
	if err != nil {
		return err
	}
	conn, err := db.Conn()
	if err != nil {
		return nil
	}
	defer conn.Close()
	return conn.Wizard().Insert(&a)
}

func enableScaleDown(instanceName string, minUnits int) error {
	a := alarm.Alarm{
		Name:       fmt.Sprintf("enable_scale_down_%s", instanceName),
		Expression: fmt.Sprintf("units > %d", minUnits),
		Enabled:    true,
		Wait:       15 * 1000 * 1000 * 1000,
		Actions:    []string{"enable_alarm"},
		Instance:   instanceName,
		Envs:       map[string]string{"alarm": fmt.Sprintf("scale_down_%s", instanceName)},
	}
	return alarm.NewAlarm(&a)
}

func disableScaleDown(instanceName string, minUnits int) error {
	a := alarm.Alarm{
		Name:       fmt.Sprintf("disable_scale_down_%s", instanceName),
		Expression: fmt.Sprintf("units <= %d", minUnits),
		Enabled:    true,
		Wait:       15 * 1000 * 1000 * 1000,
		Actions:    []string{"disable_alarm"},
		Instance:   instanceName,
		Envs:       map[string]string{"alarm": fmt.Sprintf("scale_down_%s", instanceName)},
	}
	return alarm.NewAlarm(&a)
}

func newScaleAction(action scaleAction, kind, instanceName string) error {
	a := alarm.Alarm{
		Name:       fmt.Sprintf("%s_%s", kind, instanceName),
		Expression: fmt.Sprintf("%s %s %s", action.Metric, action.Operator, action.Value),
		Enabled:    true,
		Wait:       action.Wait,
		Actions:    []string{kind},
		Instance:   instanceName,
		Envs:       map[string]string{"step": action.Step},
	}
	return alarm.NewAlarm(&a)
}

// FindByName finds auto scale by name
func FindByName(name string) (*AutoScale, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	var autoScale AutoScale
	err = conn.Wizard().Find(bson.M{"name": name}).One(&autoScale)
	if err != nil {
		return nil, err
	}
	return &autoScale, nil
}

// Remove removes an auto scale.
func Remove(a *AutoScale) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.Wizard().Remove(a)
}
<commit_msg>wizard: add process field in auto scale conf<commit_after>// Copyright 2015 tsuru-autoscale authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package wizard

import (
	"fmt"
	"time"

	"github.com/tsuru/tsuru-autoscale/alarm"
	"github.com/tsuru/tsuru-autoscale/db"
	"gopkg.in/mgo.v2/bson"
)

type AutoScale struct {
	Name      string      `json:"name"`
	ScaleUp   scaleAction `json:"scaleUp"`
	ScaleDown scaleAction `json:"scaleDown"`
	MinUnits  int         `json:"minUnits"`
	Process   string      `json:"process"`
}

type scaleAction struct {
	Metric   string        `json:"metric"`
	Operator string        `json:"operator"`
	Value    string        `json:"value"`
	Step     string        `json:"step"`
	Wait     time.Duration `json:"wait"`
}

func New(a *AutoScale) error {
	err := newScaleAction(a.ScaleUp, "scale_up", a.Name)
	if err != nil {
		return err
	}
	err = newScaleAction(a.ScaleDown, "scale_down", a.Name)
	if err != nil {
		return err
	}
	err = enableScaleDown(a.Name, a.MinUnits)
	if err != nil {
		return err
	}
	err = disableScaleDown(a.Name, a.MinUnits)
	if err != nil {
		return err
	}
	conn, err := db.Conn()
	if err != nil {
		return nil
	}
	defer conn.Close()
	return conn.Wizard().Insert(&a)
}

func enableScaleDown(instanceName string, minUnits int) error {
	a := alarm.Alarm{
		Name:       fmt.Sprintf("enable_scale_down_%s", instanceName),
		Expression: fmt.Sprintf("units > %d", minUnits),
		Enabled:    true,
		Wait:       15 * 1000 * 1000 * 1000,
		Actions:    []string{"enable_alarm"},
		Instance:   instanceName,
		Envs:       map[string]string{"alarm": fmt.Sprintf("scale_down_%s", instanceName)},
	}
	return alarm.NewAlarm(&a)
}

func disableScaleDown(instanceName string, minUnits int) error {
	a := alarm.Alarm{
		Name:       fmt.Sprintf("disable_scale_down_%s", instanceName),
		Expression: fmt.Sprintf("units <= %d", minUnits),
		Enabled:    true,
		Wait:       15 * 1000 * 1000 * 1000,
		Actions:    []string{"disable_alarm"},
		Instance:   instanceName,
		Envs:       map[string]string{"alarm": fmt.Sprintf("scale_down_%s", instanceName)},
	}
	return alarm.NewAlarm(&a)
}

func newScaleAction(action scaleAction, kind, instanceName string) error {
	a := alarm.Alarm{
		Name:       fmt.Sprintf("%s_%s", kind, instanceName),
		Expression: fmt.Sprintf("%s %s %s", action.Metric, action.Operator, action.Value),
		Enabled:    true,
		Wait:       action.Wait,
		Actions:    []string{kind},
		Instance:   instanceName,
		Envs:       map[string]string{"step": action.Step},
	}
	return alarm.NewAlarm(&a)
}

// FindByName finds auto scale by name
func FindByName(name string) (*AutoScale, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	var autoScale AutoScale
	err = conn.Wizard().Find(bson.M{"name": name}).One(&autoScale)
	if err != nil {
		return nil, err
	}
	return &autoScale, nil
}

// Remove removes an auto scale.
func Remove(a *AutoScale) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.Wizard().Remove(a)
}
<|endoftext|>


<commit_before>package worker

import "sync"

// There is my implementation of the "pipeling". The original idea is described in
// the "Go Blog": https://blog.golang.org/pipelines

// TaskFunction is a function type for tasks to be performed.
// All incoming tasks have to conform to this function type.
type TaskFunction func() interface{}

// PerformTasks is a function which will be called by the client to perform
// multiple task concurrently.
// Input:
// tasks: the slice with functions (type TaskFunction)
// done:  the channel to trigger the end of task processing and return
// Output: the channel with results
func PerformTasks(tasks []TaskFunction, done chan struct{}) chan interface{} {

	// Create a worker for each incoming task
	workers := make([]chan interface{}, 0, len(tasks))

	for _, task := range tasks {
		resultChannel := newWorker(task, done)
		workers = append(workers, resultChannel)
	}

	// Merge results from all workers
	out := merge(workers, done)
	return out
}

func newWorker(task TaskFunction, done chan struct{}) chan interface{} {
	out := make(chan interface{})
	go func() {
		defer close(out)

		select {
		case <-done:
			// Received a signal to abandon further processing
			return
		case out <- task():
			// Got some result
		}
	}()

	return out
}

func merge(workers []chan interface{}, done chan struct{}) chan interface{} {
	// Merged channel with results
	out := make(chan interface{})

	// Synchronization over channels: do not close "out" before all tasks are completed
	var wg sync.WaitGroup

	// Start output goroutine for each outbound channel from the workers
	// get all values from channel (c) before channel is closed
	// if interruption signal has received decrease the counter of running tasks via wg.Done()
	output := func(c <-chan interface{}) {
		defer wg.Done()
		for result := range c {
			select {
			case <-done:
				// Received a signal to abandon furher processing
				return
			case out <- result:
				// some message or nothing
			}
		}
	}

	wg.Add(len(workers))
	for _, workerChannel := range workers {
		go output(workerChannel)
	}

	go func() {
		wg.Wait()
		close(out)
	}()

	return out
}
<commit_msg>Update worker.go<commit_after>package worker

import "sync"

// There is my implementation of the "pipeling". The original idea is described in
// the "Go Blog": https://blog.golang.org/pipelines

// TaskFunction is a function type for tasks to be performed.
// All incoming tasks have to conform to this function type.
type TaskFunction func() interface{}

// PerformTasks is a function which will be called by the client to perform
// multiple task concurrently.
// Input:
// tasks: the slice with functions (type TaskFunction)
// done:  the channel to trigger the end of task processing and return
// Output: the channel with results
func PerformTasks(tasks []TaskFunction, done chan struct{}) chan interface{} {

	// Create a worker for each incoming task
	workers := make([]chan interface{}, 0, len(tasks))

	for _, task := range tasks {
		resultChannel := newWorker(task, done)
		workers = append(workers, resultChannel)
	}

	// Merge results from all workers
	out := merge(workers, done)
	return out
}

func newWorker(task TaskFunction, done chan struct{}) chan interface{} {
	out := make(chan interface{})
	go func() {
		defer close(out)

		select {
		case <-done:
			// Received a signal to abandon further processing
			return
		case out <- task():
			// Got some result
		}
	}()

	return out
}

func merge(workers []chan interface{}, done chan struct{}) chan interface{} {
	// Merged channel with results
	out := make(chan interface{})

	// Synchronization over channels: do not close "out" before all tasks are completed
	var wg sync.WaitGroup

	// Define function which waits the result from worker channel
	// and sends this result to the merged channel.
	// Then it decreases the counter of running tasks via wg.Done().
	output := func(c <-chan interface{}) {
		defer wg.Done()
		for result := range c {
			select {
			case <-done:
				// Received a signal to abandon furher processing
				return
			case out <- result:
				// some message or nothing
			}
		}
	}

	wg.Add(len(workers))
	for _, workerChannel := range workers {
		go output(workerChannel)
	}

	go func() {
		wg.Wait()
		close(out)
	}()

	return out
}
<|endoftext|>


<commit_before>package system

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"kego.io/uerr"
)

func TestRuleTypes(t *testing.T) {

	type ruleStruct struct {
		*Object
	}
	parentType := &Type{
		Object: &Object{Id: "a", Type: NewReference("kego.io/system", "type")},
	}
	ruleType := &Type{
		Object: &Object{Id: "@a", Type: NewReference("kego.io/system", "type")},
	}
	RegisterType("a.b/c:a", parentType)
	RegisterType("a.b/c:@a", ruleType)
	defer UnregisterType("a.b/c:a")
	defer UnregisterType("a.b/c:@a")

	r := &ruleStruct{
		&Object{Type: NewReference("a.b/c", "@a")},
	}
	rt, pt, err := ruleTypes(r, "", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "a", pt.Id)
	assert.Equal(t, "@a", rt.Id)

	r1 := ruleStruct{}
	rt, pt, err = ruleTypes(r1, "", map[string]string{})
	// A non pointer rule will cause ruleTypeReference to return an error
	uerr.Assert(t, err, "BNEKIFYDDL")

	r = &ruleStruct{
		&Object{Type: NewReference("a.b/c", "unregistered")},
	}
	rt, pt, err = ruleTypes(r, "", map[string]string{})
	// An unregistered type will cause ruleReference.GetType to return an error
	uerr.Assert(t, err, "PFGWISOHRR")

	r = &ruleStruct{
		&Object{Type: NewReference("a.b/c", "a")},
	}
	rt, pt, err = ruleTypes(r, "", map[string]string{})
	// A rule with a non rule type will cause ruleReference.RuleToParentType to error
	uerr.Assert(t, err, "NXRCPQMUIE")

	RegisterType("a.b/c:@b", ruleType)
	r = &ruleStruct{
		&Object{Type: NewReference("a.b/c", "@b")},
	}
	rt, pt, err = ruleTypes(r, "", map[string]string{})
	// An rule type with an unregistered parent type typeReference.GetType to return an error
	uerr.Assert(t, err, "KYCTDXKFYR")

}
<commit_msg>Tests<commit_after>package system

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"kego.io/uerr"
)

func TestRuleTypes(t *testing.T) {

	type ruleStruct struct {
		*Object
	}
	parentType := &Type{
		Object: &Object{Id: "a", Type: NewReference("kego.io/system", "type")},
	}
	ruleType := &Type{
		Object: &Object{Id: "@a", Type: NewReference("kego.io/system", "type")},
	}
	RegisterType("a.b/c:a", parentType)
	RegisterType("a.b/c:@a", ruleType)
	defer UnregisterType("a.b/c:a")
	defer UnregisterType("a.b/c:@a")

	r := &ruleStruct{
		&Object{Type: NewReference("a.b/c", "@a")},
	}
	rt, pt, err := ruleTypes(r, "", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "a", pt.Id)
	assert.Equal(t, "@a", rt.Id)

	r1 := ruleStruct{}
	rt, pt, err = ruleTypes(r1, "", map[string]string{})
	// A non pointer rule will cause ruleTypeReference to return an error
	uerr.Assert(t, err, "BNEKIFYDDL")

	r = &ruleStruct{
		&Object{Type: NewReference("a.b/c", "unregistered")},
	}
	rt, pt, err = ruleTypes(r, "", map[string]string{})
	// An unregistered type will cause ruleReference.GetType to return an error
	uerr.Assert(t, err, "PFGWISOHRR")

	r = &ruleStruct{
		&Object{Type: NewReference("a.b/c", "a")},
	}
	rt, pt, err = ruleTypes(r, "", map[string]string{})
	// A rule with a non rule type will cause ruleReference.RuleToParentType to error
	uerr.Assert(t, err, "NXRCPQMUIE")

	RegisterType("a.b/c:@b", ruleType)
	r = &ruleStruct{
		&Object{Type: NewReference("a.b/c", "@b")},
	}
	rt, pt, err = ruleTypes(r, "", map[string]string{})
	// An rule type with an unregistered parent type typeReference.GetType to return an error
	uerr.Assert(t, err, "KYCTDXKFYR")

}

func TestRuleTypeReference(t *testing.T) {

	type ruleStruct struct {
		*Object
	}
	rs := &ruleStruct{
		&Object{Type: NewReference("a.b/c", "@a")},
	}
	r, err := ruleTypeReference(rs, "", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "a.b/c:@a", r.Value)

	ri := map[string]interface{}{}
	r, err = ruleTypeReference(ri, "", map[string]string{})
	uerr.Assert(t, err, "OLHOVKXEXN")

	ri = map[string]interface{}{
		"type": 1, //not a string
	}
	r, err = ruleTypeReference(ri, "", map[string]string{})
	uerr.Assert(t, err, "IILEXGQDXL")

	ri = map[string]interface{}{
		"type": "a:b", // package will not be registered so UnmarshalJSON will error
	}
	r, err = ruleTypeReference(ri, "", map[string]string{})
	uerr.Assert(t, err, "QBTHPRVBWN")

	ri = map[string]interface{}{
		"type": "a.b/c:@a",
	}
	r, err = ruleTypeReference(rs, "", map[string]string{})
	assert.NoError(t, err)
	assert.Equal(t, "a.b/c:@a", r.Value)

	rsp := ruleStruct{}
	r, err = ruleTypeReference(rsp, "", map[string]string{})
	// rsp is not a pointer so ruleFieldByReflection will error
	uerr.Assert(t, err, "QJQAIGPYXC")

	type structWithoutType struct{}
	rwt := &structWithoutType{}
	r, err = ruleTypeReference(rwt, "", map[string]string{})
	uerr.Assert(t, err, "NXYRAJITEV")

	type structWithIntType struct {
		Type int
	}
	rwi := &structWithIntType{
		Type: 1,
	}
	r, err = ruleTypeReference(rwi, "", map[string]string{})
	uerr.Assert(t, err, "FHUPSRTRFE")
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// 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 logger_demo

import (
	"bytes"
	"io"
	"net/http"
	"strconv"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
	"github.com/venicegeo/pz-gocommon/gocommon"
	"github.com/venicegeo/pz-logger/logger"
)

func sleep() {
	time.Sleep(1 * time.Second)
}

type LoggerTester struct {
	suite.Suite
	client *logger.Client
	url    string
	apiKey string
}

func (suite *LoggerTester) setupFixture() {
	t := suite.T()
	assert := assert.New(t)

	var err error

	suite.url = "https://pz-logger.int.geointservices.io"

	suite.apiKey, err = piazza.GetApiKey("int")
	assert.NoError(err)

	client, err := logger.NewClient2(suite.url, suite.apiKey)
	assert.NoError(err)
	suite.client = client
}

func (suite *LoggerTester) teardownFixture() {
}

func TestRunSuite(t *testing.T) {
	s := &LoggerTester{}
	suite.Run(t, s)
}

func (suite *LoggerTester) verifyMessageExists(expected *logger.Message) bool {
	t := suite.T()
	assert := assert.New(t)

	client := suite.client

	format := &piazza.JsonPagination{
		PerPage: 100,
		Page:    0,
		Order:   piazza.SortOrderDescending,
		SortBy:  "createdOn",
	}
	ms, _, err := client.GetMessages(format, nil)
	assert.NoError(err)
	assert.Len(ms, format.PerPage)

	for _, m := range ms {
		if m.String() == expected.String() {
			return true
		}
	}
	return false
}

func (suite *LoggerTester) Test00Version() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	version, err := client.GetVersion()
	assert.NoError(err)
	assert.EqualValues("1.0.0", version.Version)
}

func (suite *LoggerTester) Test01RawGet() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	resp, err := http.Get(suite.url + "/message?perPage=13&page=&0")
	assert.NoError(err)
	assert.True(resp.ContentLength >= 0)
	if resp.ContentLength == -1 {
		assert.FailNow("bonk")
	}
	assert.True(resp.ContentLength > 0)

	raw := make([]byte, resp.ContentLength)
	_, err = io.ReadFull(resp.Body, raw)
	defer resp.Body.Close()
	if err != nil && err != io.EOF {
		assert.NoError(err)
	}

	assert.Equal(200, resp.StatusCode)
}

func (suite *LoggerTester) Test02RawPost() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	jsn := `
	{
		"address":"XXX",
		"createdOn":"2016-07-22T16:44:58.065583138-04:00",
		"message":"XXX",
		"service":"XXX",
		"severity":"XXX"
	}`
	reader := bytes.NewReader([]byte(jsn))

	resp, err := http.Post(suite.url+"/message",
		piazza.ContentTypeJSON, reader)
	assert.NoError(err)

	raw := make([]byte, resp.ContentLength)
	_, err = io.ReadFull(resp.Body, raw)
	defer resp.Body.Close()
	if err != nil && err != io.EOF {
		assert.NoError(err)
	}

	//err = json.Unmarshal(raw, output)
	//assett.NoError(err)

	assert.Equal(200, resp.StatusCode)
}

func (suite *LoggerTester) Test03Get() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	format := &piazza.JsonPagination{
		PerPage: 12,
		Page:    0,
		Order:   piazza.SortOrderAscending,
		SortBy:  "createdOn",
	}
	ms, _, err := client.GetMessages(format, nil)
	assert.NoError(err)
	assert.Len(ms, format.PerPage)
}

func (suite *LoggerTester) Test04Post() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	var err error

	key := time.Now().String()

	data := &logger.Message{
		Service:   "log-tester",
		Address:   "128.1.2.3",
		CreatedOn: time.Now(),
		Severity:  "Info",
		Message:   key,
	}

	err = client.PostMessage(data)
	assert.NoError(err, "PostToMessages")

	sleep()

	assert.True(suite.verifyMessageExists(data))
}

func (suite *LoggerTester) Test05PostHelpers() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	uniq := time.Now().String()
	client.Info(uniq)

	sleep()

	{
		format := &piazza.JsonPagination{
			PerPage: 100,
			Page:    0,
			Order:   piazza.SortOrderDescending,
			SortBy:  "createdOn",
		}
		ms, _, err := client.GetMessages(format, nil)
		assert.NoError(err)
		assert.True(len(ms) <= format.PerPage)

		ok := false
		for _, m := range ms {
			if m.Message == uniq {
				ok = true
				break
			}
		}
		assert.True(ok)
	}
}

func (suite *LoggerTester) Test06Admin() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	stats, err := client.GetStats()
	assert.NoError(err)
	assert.NotZero(stats.NumMessages)
}

func (suite *LoggerTester) Test07Pagination() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	format := &piazza.JsonPagination{
		PerPage: 10,
		Page:    0,
		SortBy:  "createdOn",
		Order:   piazza.SortOrderAscending,
	}
	params := &piazza.HttpQueryParams{}

	// check per-page
	{
		format.PerPage = 17
		ms, _, err := client.GetMessages(format, params)
		assert.NoError(err)
		assert.Len(ms, 17)
	}

	// check sort order
	{
		format.PerPage = 10
		format.Order = piazza.SortOrderAscending
		ms, _, err := client.GetMessages(format, params)
		assert.NoError(err)
		last := len(ms) - 1
		assert.True(last <= 9)

		// we can't check "before", because two createdOn's might be the same
		isBefore := ms[0].CreatedOn.Before(ms[last].CreatedOn)
		isEqual := ms[0].CreatedOn.Equal(ms[last].CreatedOn)
		assert.True(isBefore || isEqual)

		format.Order = piazza.SortOrderDescending
		ms, _, err = client.GetMessages(format, params)
		assert.NoError(err)
		last = len(ms) - 1
		assert.True(last <= 9)

		isAfter := ms[0].CreatedOn.After(ms[last].CreatedOn)
		isEqual = ms[0].CreatedOn.Equal(ms[last].CreatedOn)
		assert.True(isAfter || isEqual)
	}

	// check sort-by
	{
		format.Order = piazza.SortOrderAscending
		format.SortBy = "severity"
		format.PerPage = 100
		format.Page = 0
		ms, _, err := client.GetMessages(format, params)
		if err != nil {
			panic(88)
		}
		assert.NoError(err)

		last := len(ms) - 1
		for i := 0; i < last; i++ {
			a, b := string(ms[i].Severity), string(ms[i+1].Severity)
			isBefore := (a <= b)
			assert.True(isBefore)
		}
	}
}

func (suite *LoggerTester) Test08Params() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	uniqService := strconv.Itoa(time.Now().Nanosecond())
	uniqDebug := strconv.Itoa(time.Now().Nanosecond() * 3)
	uniqError := strconv.Itoa(time.Now().Nanosecond() * 5)
	uniqFatal := strconv.Itoa(time.Now().Nanosecond() * 7)

	client.SetService(piazza.ServiceName(uniqService), "1.2.3.4")

	now := time.Now()
	sec3 := time.Second * 3
	tstart := now.Add(-sec3)

	client.Debug(uniqDebug)
	client.Error(uniqError)
	client.Fatal(uniqFatal)

	sleep()

	format := &piazza.JsonPagination{
		PerPage: 256,
		Page:    0,
		Order:   piazza.SortOrderDescending,
		SortBy:  "createdOn",
	}

	// test date range params
	{
		tend := now.Add(sec3)

		params := &piazza.HttpQueryParams{}
		params.AddTime("after", tstart)
		params.AddTime("before", tend)

		msgs, cnt, err := client.GetMessages(format, params)

		assert.NoError(err)
		assert.True(cnt >= 3)
		assert.True(len(msgs) >= 3)
	}

	// test service param
	{
		params := &piazza.HttpQueryParams{}
		params.AddString("service", uniqService)

		msgs, _, err := client.GetMessages(format, params)

		assert.NoError(err)
		assert.Len(msgs, 3)
	}

	// test contains param
	{
		params := &piazza.HttpQueryParams{}
		params.AddString("contains", uniqDebug)

		msgs, _, err := client.GetMessages(format, params)

		assert.NoError(err)
		assert.True(len(msgs) == 1)
	}
}
<commit_msg>use GetApiServer() now<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// 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 logger_demo

import (
	"bytes"
	"io"
	"net/http"
	"strconv"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
	"github.com/venicegeo/pz-gocommon/gocommon"
	"github.com/venicegeo/pz-logger/logger"
)

func sleep() {
	time.Sleep(1 * time.Second)
}

type LoggerTester struct {
	suite.Suite
	client    *logger.Client
	url       string
	apiKey    string
	apiServer string
}

func (suite *LoggerTester) setupFixture() {
	t := suite.T()
	assert := assert.New(t)

	var err error

	suite.apiServer, err = piazza.GetApiServer()
	assert.NoError(err)

	i := strings.Index(suite.apiServer, ".")
	assert.NotEqual(1, i)
	host := "pz-logger" + suite.apiServer[i:]
	suite.url = "https://" + host

	suite.apiKey, err = piazza.GetApiKey(suite.apiServer)
	assert.NoError(err)

	client, err := logger.NewClient2(suite.url, suite.apiKey)
	assert.NoError(err)
	suite.client = client
}

func (suite *LoggerTester) teardownFixture() {
}

func TestRunSuite(t *testing.T) {
	s := &LoggerTester{}
	suite.Run(t, s)
}

func (suite *LoggerTester) verifyMessageExists(expected *logger.Message) bool {
	t := suite.T()
	assert := assert.New(t)

	client := suite.client

	format := &piazza.JsonPagination{
		PerPage: 100,
		Page:    0,
		Order:   piazza.SortOrderDescending,
		SortBy:  "createdOn",
	}
	ms, _, err := client.GetMessages(format, nil)
	assert.NoError(err)
	assert.Len(ms, format.PerPage)

	for _, m := range ms {
		if m.String() == expected.String() {
			return true
		}
	}
	return false
}

func (suite *LoggerTester) Test00Version() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	version, err := client.GetVersion()
	assert.NoError(err)
	assert.EqualValues("1.0.0", version.Version)
}

func (suite *LoggerTester) Test01RawGet() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	resp, err := http.Get(suite.url + "/message?perPage=13&page=&0")
	assert.NoError(err)
	assert.True(resp.ContentLength >= 0)
	if resp.ContentLength == -1 {
		assert.FailNow("bonk")
	}
	assert.True(resp.ContentLength > 0)

	raw := make([]byte, resp.ContentLength)
	_, err = io.ReadFull(resp.Body, raw)
	defer resp.Body.Close()
	if err != nil && err != io.EOF {
		assert.NoError(err)
	}

	assert.Equal(200, resp.StatusCode)
}

func (suite *LoggerTester) Test02RawPost() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	jsn := `
	{
		"address":"XXX",
		"createdOn":"2016-07-22T16:44:58.065583138-04:00",
		"message":"XXX",
		"service":"XXX",
		"severity":"XXX"
	}`
	reader := bytes.NewReader([]byte(jsn))

	resp, err := http.Post(suite.url+"/message",
		piazza.ContentTypeJSON, reader)
	assert.NoError(err)

	raw := make([]byte, resp.ContentLength)
	_, err = io.ReadFull(resp.Body, raw)
	defer resp.Body.Close()
	if err != nil && err != io.EOF {
		assert.NoError(err)
	}

	//err = json.Unmarshal(raw, output)
	//assett.NoError(err)

	assert.Equal(200, resp.StatusCode)
}

func (suite *LoggerTester) Test03Get() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	format := &piazza.JsonPagination{
		PerPage: 12,
		Page:    0,
		Order:   piazza.SortOrderAscending,
		SortBy:  "createdOn",
	}
	ms, _, err := client.GetMessages(format, nil)
	assert.NoError(err)
	assert.Len(ms, format.PerPage)
}

func (suite *LoggerTester) Test04Post() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	var err error

	key := time.Now().String()

	data := &logger.Message{
		Service:   "log-tester",
		Address:   "128.1.2.3",
		CreatedOn: time.Now(),
		Severity:  "Info",
		Message:   key,
	}

	err = client.PostMessage(data)
	assert.NoError(err, "PostToMessages")

	sleep()

	assert.True(suite.verifyMessageExists(data))
}

func (suite *LoggerTester) Test05PostHelpers() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	uniq := time.Now().String()
	client.Info(uniq)

	sleep()

	{
		format := &piazza.JsonPagination{
			PerPage: 100,
			Page:    0,
			Order:   piazza.SortOrderDescending,
			SortBy:  "createdOn",
		}
		ms, _, err := client.GetMessages(format, nil)
		assert.NoError(err)
		assert.True(len(ms) <= format.PerPage)

		ok := false
		for _, m := range ms {
			if m.Message == uniq {
				ok = true
				break
			}
		}
		assert.True(ok)
	}
}

func (suite *LoggerTester) Test06Admin() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	stats, err := client.GetStats()
	assert.NoError(err)
	assert.NotZero(stats.NumMessages)
}

func (suite *LoggerTester) Test07Pagination() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	format := &piazza.JsonPagination{
		PerPage: 10,
		Page:    0,
		SortBy:  "createdOn",
		Order:   piazza.SortOrderAscending,
	}
	params := &piazza.HttpQueryParams{}

	// check per-page
	{
		format.PerPage = 17
		ms, _, err := client.GetMessages(format, params)
		assert.NoError(err)
		assert.Len(ms, 17)
	}

	// check sort order
	{
		format.PerPage = 10
		format.Order = piazza.SortOrderAscending
		ms, _, err := client.GetMessages(format, params)
		assert.NoError(err)
		last := len(ms) - 1
		assert.True(last <= 9)

		// we can't check "before", because two createdOn's might be the same
		isBefore := ms[0].CreatedOn.Before(ms[last].CreatedOn)
		isEqual := ms[0].CreatedOn.Equal(ms[last].CreatedOn)
		assert.True(isBefore || isEqual)

		format.Order = piazza.SortOrderDescending
		ms, _, err = client.GetMessages(format, params)
		assert.NoError(err)
		last = len(ms) - 1
		assert.True(last <= 9)

		isAfter := ms[0].CreatedOn.After(ms[last].CreatedOn)
		isEqual = ms[0].CreatedOn.Equal(ms[last].CreatedOn)
		assert.True(isAfter || isEqual)
	}

	// check sort-by
	{
		format.Order = piazza.SortOrderAscending
		format.SortBy = "severity"
		format.PerPage = 100
		format.Page = 0
		ms, _, err := client.GetMessages(format, params)
		if err != nil {
			panic(88)
		}
		assert.NoError(err)

		last := len(ms) - 1
		for i := 0; i < last; i++ {
			a, b := string(ms[i].Severity), string(ms[i+1].Severity)
			isBefore := (a <= b)
			assert.True(isBefore)
		}
	}
}

func (suite *LoggerTester) Test08Params() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	uniqService := strconv.Itoa(time.Now().Nanosecond())
	uniqDebug := strconv.Itoa(time.Now().Nanosecond() * 3)
	uniqError := strconv.Itoa(time.Now().Nanosecond() * 5)
	uniqFatal := strconv.Itoa(time.Now().Nanosecond() * 7)

	client.SetService(piazza.ServiceName(uniqService), "1.2.3.4")

	now := time.Now()
	sec3 := time.Second * 3
	tstart := now.Add(-sec3)

	client.Debug(uniqDebug)
	client.Error(uniqError)
	client.Fatal(uniqFatal)

	sleep()

	format := &piazza.JsonPagination{
		PerPage: 256,
		Page:    0,
		Order:   piazza.SortOrderDescending,
		SortBy:  "createdOn",
	}

	// test date range params
	{
		tend := now.Add(sec3)

		params := &piazza.HttpQueryParams{}
		params.AddTime("after", tstart)
		params.AddTime("before", tend)

		msgs, cnt, err := client.GetMessages(format, params)

		assert.NoError(err)
		assert.True(cnt >= 3)
		assert.True(len(msgs) >= 3)
	}

	// test service param
	{
		params := &piazza.HttpQueryParams{}
		params.AddString("service", uniqService)

		msgs, _, err := client.GetMessages(format, params)

		assert.NoError(err)
		assert.Len(msgs, 3)
	}

	// test contains param
	{
		params := &piazza.HttpQueryParams{}
		params.AddString("contains", uniqDebug)

		msgs, _, err := client.GetMessages(format, params)

		assert.NoError(err)
		assert.True(len(msgs) == 1)
	}
}
<|endoftext|>


<commit_before>package writer

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

	"github.com/tonglil/labeler/types"

	"github.com/golang/glog"
	"github.com/google/go-github/github"
	yaml "gopkg.in/yaml.v2"
)

// Run executes the write actions against the repo.
func Run(client *github.Client, file string, opt *types.Options) error {
	lf, err := ReadConfigFile(file)
	if err != nil {
		return err
	}

	opt.Repo, err = GetRepo(opt, lf)
	if err != nil {
		glog.V(0).Infof("No repo provided")
		return err
	}

	err = opt.ValidateRepo()
	if err != nil {
		glog.V(0).Infof("Failed to parse repo format: owner/name")
		return err
	}

	// Get all remote labels from repo
	labelsRemote, err := GetRemoteLabels(client, opt)
	if err != nil {
		return err
	}

	var n, total int

	// Rename
	labels, n, err := Rename(client, opt, lf.Labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished renaming %d labels", n)
	total += n

	// Update
	labels, n, err = Update(client, opt, labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished updating %d labels", n)
	total += n

	// Create
	labels, n, err = Create(client, opt, labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished creating %d labels", n)
	total += n

	// Delete
	n, err = Delete(client, opt, lf.Labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished deleting %d labels", n)
	total += n

	glog.V(6).Infof("Processed %d labels in total", total)

	return nil
}

// GetRemoteLabels fetches all labels in a repository, iterating over pages for 50 at a time.
func GetRemoteLabels(client *github.Client, opt *types.Options) ([]*github.Label, error) {
	var labelsRemote []*github.Label

	pagination := &github.ListOptions{
		PerPage: 50,
		Page:    1,
	}

	for {
		glog.V(4).Infof("Fetching labels from Github, page %d", pagination.Page)

		labels, resp, err := client.Issues.ListLabels(opt.RepoOwner(), opt.RepoName(), pagination)
		if err != nil {
			glog.V(0).Infof("Failed to fetch labels from Github")
			return nil, err
		}
		glog.V(4).Infof("Response: %s", resp)

		labelsRemote = append(labelsRemote, labels...)

		if resp.NextPage == 0 {
			glog.V(4).Info("Fetched all labels from Github")
			break
		}
		pagination.Page = resp.NextPage
	}

	return labelsRemote, nil
}

// GetRepo configures the repo being used as determined by the option, and then the label file.
func GetRepo(opt *types.Options, lf *types.LabelFile) (string, error) {
	if opt.Repo != "" {
		return opt.Repo, nil
	}

	if lf.Repo != "" {
		return lf.Repo, nil
	}

	return "", fmt.Errorf("no repo")
}

// ReadConfigFile opens the label file and reads its contents into a LabelFile.
func ReadConfigFile(file string) (*types.LabelFile, error) {
	path, err := filepath.Abs(file)
	if err != nil {
		glog.V(0).Infof("Failed to find %s", file)
		return nil, err
	}

	f, err := os.Open(path)
	if err != nil {
		glog.V(0).Infof("Failed to open %s", path)
		return nil, err
	}
	defer f.Close()

	data, err := ioutil.ReadAll(f)
	if err != nil {
		glog.V(0).Infof("Failed to read %s", path)
		return nil, err
	}

	glog.V(4).Infof("Read file %s", path)

	lf := types.LabelFile{}

	err = yaml.Unmarshal(data, &lf)
	if err != nil {
		glog.V(0).Infof("Failed to unmarshal %s", path)
		return nil, err
	}

	return &lf, nil
}
<commit_msg>bump response logging to 6<commit_after>package writer

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

	"github.com/tonglil/labeler/types"

	"github.com/golang/glog"
	"github.com/google/go-github/github"
	yaml "gopkg.in/yaml.v2"
)

// Run executes the write actions against the repo.
func Run(client *github.Client, file string, opt *types.Options) error {
	lf, err := ReadConfigFile(file)
	if err != nil {
		return err
	}

	opt.Repo, err = GetRepo(opt, lf)
	if err != nil {
		glog.V(0).Infof("No repo provided")
		return err
	}

	err = opt.ValidateRepo()
	if err != nil {
		glog.V(0).Infof("Failed to parse repo format: owner/name")
		return err
	}

	// Get all remote labels from repo
	labelsRemote, err := GetRemoteLabels(client, opt)
	if err != nil {
		return err
	}

	var n, total int

	// Rename
	labels, n, err := Rename(client, opt, lf.Labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished renaming %d labels", n)
	total += n

	// Update
	labels, n, err = Update(client, opt, labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished updating %d labels", n)
	total += n

	// Create
	labels, n, err = Create(client, opt, labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished creating %d labels", n)
	total += n

	// Delete
	n, err = Delete(client, opt, lf.Labels, labelsRemote)
	if err != nil {
		return err
	}

	glog.V(6).Infof("Finished deleting %d labels", n)
	total += n

	glog.V(6).Infof("Processed %d labels in total", total)

	return nil
}

// GetRemoteLabels fetches all labels in a repository, iterating over pages for 50 at a time.
func GetRemoteLabels(client *github.Client, opt *types.Options) ([]*github.Label, error) {
	var labelsRemote []*github.Label

	pagination := &github.ListOptions{
		PerPage: 50,
		Page:    1,
	}

	for {
		glog.V(4).Infof("Fetching labels from Github, page %d", pagination.Page)

		labels, resp, err := client.Issues.ListLabels(opt.RepoOwner(), opt.RepoName(), pagination)
		if err != nil {
			glog.V(0).Infof("Failed to fetch labels from Github")
			return nil, err
		}
		glog.V(6).Infof("Response: %s", resp)

		labelsRemote = append(labelsRemote, labels...)

		if resp.NextPage == 0 {
			glog.V(4).Info("Fetched all labels from Github")
			break
		}
		pagination.Page = resp.NextPage
	}

	return labelsRemote, nil
}

// GetRepo configures the repo being used as determined by the option, and then the label file.
func GetRepo(opt *types.Options, lf *types.LabelFile) (string, error) {
	if opt.Repo != "" {
		return opt.Repo, nil
	}

	if lf.Repo != "" {
		return lf.Repo, nil
	}

	return "", fmt.Errorf("no repo")
}

// ReadConfigFile opens the label file and reads its contents into a LabelFile.
func ReadConfigFile(file string) (*types.LabelFile, error) {
	path, err := filepath.Abs(file)
	if err != nil {
		glog.V(0).Infof("Failed to find %s", file)
		return nil, err
	}

	f, err := os.Open(path)
	if err != nil {
		glog.V(0).Infof("Failed to open %s", path)
		return nil, err
	}
	defer f.Close()

	data, err := ioutil.ReadAll(f)
	if err != nil {
		glog.V(0).Infof("Failed to read %s", path)
		return nil, err
	}

	glog.V(4).Infof("Read file %s", path)

	lf := types.LabelFile{}

	err = yaml.Unmarshal(data, &lf)
	if err != nil {
		glog.V(0).Infof("Failed to unmarshal %s", path)
		return nil, err
	}

	return &lf, nil
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package tailer

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/go-cmp/cmp"
	"github.com/google/mtail/watcher"

	"github.com/spf13/afero"
)

func makeTestTail(t *testing.T) (*Tailer, chan *LogLine, *watcher.FakeWatcher, afero.Fs) {
	fs := afero.NewMemMapFs()
	w := watcher.NewFakeWatcher()
	lines := make(chan *LogLine, 1)
	o := Options{lines, false, w, fs}
	ta, err := New(o)
	if err != nil {
		t.Fatal(err)
	}
	return ta, lines, w, fs
}

func makeTestTailReal(t *testing.T, prefix string) (*Tailer, chan *LogLine, *watcher.LogWatcher, afero.Fs, string) {
	if testing.Short() {
		t.Skip("skipping real fs test in short mode")
	}
	dir, err := ioutil.TempDir("", prefix)
	if err != nil {
		t.Fatalf("can't create tempdir: %v", err)
	}

	fs := afero.NewOsFs()
	w, err := watcher.NewLogWatcher()
	if err != nil {
		t.Fatalf("can't create watcher: %v", err)
	}
	lines := make(chan *LogLine, 1)
	o := Options{lines, false, w, fs}
	ta, err := New(o)
	if err != nil {
		t.Fatal(err)
	}
	return ta, lines, w, fs, dir
}

func TestTail(t *testing.T) {
	ta, _, w, fs := makeTestTail(t)
	fs.Mkdir("tail_test", os.ModePerm)
	logfile := "/tmp/log"
	f, err := fs.Create(logfile)
	if err != nil {
		t.Error(err)
	}
	defer f.Close()
	defer w.Close()

	err = ta.TailPath(logfile)
	if err != nil {
		t.Fatal(err)
	}
	// Tail also causes the log to be read, so no need to inject an event.

	if _, ok := ta.files[logfile]; !ok {
		t.Errorf("path not found in files map: %+#v", ta.files)
	}
}

func TestHandleLogUpdate(t *testing.T) {
	ta, lines, w, fs := makeTestTail(t)

	err := fs.Mkdir("/tail_test", os.ModePerm)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	logfile := "/tail_test/log"
	f, err := fs.Create(logfile)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	result := []*LogLine{}
	done := make(chan struct{})
	wg := sync.WaitGroup{}
	go func() {
		for line := range lines {
			result = append(result, line)
			wg.Done()
		}
		close(done)
	}()

	err = ta.TailPath(logfile)
	if err != nil {
		t.Fatal(err)
	}

	wg.Add(4)
	_, err = f.WriteString("a\nb\nc\nd\n")
	if err != nil {
		t.Fatal(err)
	}
	f.Seek(0, 0) // afero in-memory files share the same offset
	w.InjectUpdate(logfile)

	wg.Wait()
	if err := w.Close(); err != nil {
		t.Log(err)
	}
	<-done

	expected := []*LogLine{
		{logfile, "a"},
		{logfile, "b"},
		{logfile, "c"},
		{logfile, "d"},
	}
	if diff := cmp.Diff(expected, result); diff != "" {
		t.Errorf("result didn't match:\n%s", diff)
	}
}

// TestHandleLogTruncate writes to a file, waits for those
// writes to be seen, then truncates the file and writes some more.
// At the end all lines written must be reported by the tailer.
func TestHandleLogTruncate(t *testing.T) {
	ta, lines, w, fs, dir := makeTestTailReal(t, "truncate")
	defer func() {
		if err := os.RemoveAll(dir); err != nil {
			t.Log(err)
		}
	}()

	logfile := filepath.Join(dir, "log")
	f, err := fs.Create(logfile)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	result := []*LogLine{}
	done := make(chan struct{})
	wg := sync.WaitGroup{}
	go func() {
		for line := range lines {
			result = append(result, line)
			wg.Done()
		}
		close(done)
	}()

	if err = ta.TailPath(logfile); err != nil {
		t.Fatal(err)
	}

	wg.Add(3)
	if _, err = f.WriteString("a\nb\nc\n"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	wg.Wait()

	if err = f.Truncate(0); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)

	wg.Add(2)
	if _, err = f.WriteString("d\ne\n"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)

	wg.Wait()
	if err := w.Close(); err != nil {
		t.Log(err)
	}
	<-done

	expected := []*LogLine{
		{logfile, "a"},
		{logfile, "b"},
		{logfile, "c"},
		{logfile, "d"},
		{logfile, "e"},
	}
	if diff := cmp.Diff(expected, result); diff != "" {
		t.Errorf("result didn't match:\n%s", diff)
	}
}

func TestHandleLogUpdatePartialLine(t *testing.T) {
	ta, lines, w, fs := makeTestTail(t)

	err := fs.Mkdir("/tail_test", os.ModePerm)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	logfile := "/tail_test/log"
	f, err := fs.Create(logfile)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	result := []*LogLine{}
	done := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(1)
	go func() {
		for line := range lines {
			result = append(result, line)
			wg.Done()
		}
		close(done)
	}()

	err = ta.TailPath(logfile)
	if err != nil {
		t.Fatal(err)
	}

	_, err = f.WriteString("a")
	if err != nil {
		t.Fatal(err)
	}
	f.Seek(0, 0)
	w.InjectUpdate(logfile)

	f.Seek(1, 0)
	_, err = f.WriteString("b")
	if err != nil {
		t.Error(err)
	}
	f.Seek(1, 0)
	w.InjectUpdate(logfile)

	f.Seek(2, 0)
	_, err = f.WriteString("\n")
	if err != nil {
		t.Error(err)
	}
	f.Seek(2, 0)
	w.InjectUpdate(logfile)

	wg.Wait()
	w.Close()
	<-done

	expected := []*LogLine{
		{logfile, "ab"},
	}
	diff := cmp.Diff(expected, result)
	if diff != "" {
		t.Errorf("result didn't match:\n%s", diff)
	}

}

func TestReadPartial(t *testing.T) {
	ta, lines, w, fs := makeTestTail(t)
	defer w.Close()

	f, err := fs.Create("t")
	if err != nil {
		t.Fatal(err)
	}
	p := bytes.NewBufferString("")
	err = ta.read(f, p)
	if p.String() != "" {
		t.Errorf("partial line returned not empty: %q", p)
	}
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
	p.Reset()
	p.WriteString("o")
	f.WriteString("hi")
	f.Seek(0, 0)
	err = ta.read(f, p)
	if p.String() != "ohi" {
		t.Errorf("partial line returned not expected: %q", p)
	}
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
	p.Reset()
	err = ta.read(f, p)
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
	f.WriteString("\n")
	f.Seek(-1, io.SeekEnd)
	p.Reset()
	p.WriteString("ohi")
	err = ta.read(f, p)
	l := <-lines
	if l.Line != "ohi" {
		t.Errorf("line emitted not ohi: %q", l)
	}
	if p.String() != "" {
		t.Errorf("partial not empty: %q", p)
	}
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
}

func TestReadPipe(t *testing.T) {
	ta, lines, wa, _ := makeTestTail(t)
	defer wa.Close()

	r, w, err := os.Pipe()
	if err != nil {
		t.Fatal(err)
	}

	err = ta.TailFile(r)
	if err != nil {
		t.Fatal(err)
	}
	n, err := w.WriteString("hi\n")
	if err != nil {
		t.Fatal(err)
	}
	if n < 2 {
		t.Fatalf("Didn't write enough bytes: %d", n)
	}
	l := <-lines
	if l.Line != "hi" {
		t.Errorf("line not expected: %q", l)
	}
}

func TestOpenRetries(t *testing.T) {
	// Use the real filesystem because afero doesn't implement correct
	// permissions checking on OpenFile in the memfile implementation.
	ta, lines, w, fs, dir := makeTestTailReal(t, "retries")
	defer func() {
		if err := os.RemoveAll(dir); err != nil {
			t.Log(err)
		}
	}()

	logfile := filepath.Join(dir, "log")
	if _, err := fs.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0); err != nil {
		t.Fatal(err)
	}

	done := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(1) // lines written
	go func() {
		for range lines {
			wg.Done()
		}
		close(done)
	}()

	if err := ta.TailPath(logfile); err == nil {
		t.Fatal("Expected a permission denied error here.")
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("remove")
	if err := fs.Remove(logfile); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("openfile")
	f, err := fs.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("chmod")
	if err := fs.Chmod(logfile, 0666); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("write string")
	if _, err := f.WriteString("\n"); err != nil {
		t.Fatal(err)
	}
	wg.Wait()
	if err := w.Close(); err != nil {
		t.Log(err)
	}
	<-done
}

func TestTailerInitErrors(t *testing.T) {
	o := Options{}
	_, err := New(o)
	if err == nil {
		t.Error("expected error")
	}
	o.Lines = make(chan *LogLine)
	_, err = New(o)
	if err == nil {
		t.Error("expected error")
	}
	o.FS = afero.NewMemMapFs()
	_, err = New(o)
	if err == nil {
		t.Error("expected error")
	}
	o.W = watcher.NewFakeWatcher()
	_, err = New(o)
	if err != nil {
		t.Errorf("unexpected error %s", err)
	}
}
<commit_msg>Fix truncate issue.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package tailer

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/go-cmp/cmp"
	"github.com/google/mtail/watcher"

	"github.com/spf13/afero"
)

func makeTestTail(t *testing.T) (*Tailer, chan *LogLine, *watcher.FakeWatcher, afero.Fs) {
	fs := afero.NewMemMapFs()
	w := watcher.NewFakeWatcher()
	lines := make(chan *LogLine, 1)
	o := Options{lines, false, w, fs}
	ta, err := New(o)
	if err != nil {
		t.Fatal(err)
	}
	return ta, lines, w, fs
}

func makeTestTailReal(t *testing.T, prefix string) (*Tailer, chan *LogLine, *watcher.LogWatcher, afero.Fs, string) {
	if testing.Short() {
		t.Skip("skipping real fs test in short mode")
	}
	dir, err := ioutil.TempDir("", prefix)
	if err != nil {
		t.Fatalf("can't create tempdir: %v", err)
	}

	fs := afero.NewOsFs()
	w, err := watcher.NewLogWatcher()
	if err != nil {
		t.Fatalf("can't create watcher: %v", err)
	}
	lines := make(chan *LogLine, 1)
	o := Options{lines, false, w, fs}
	ta, err := New(o)
	if err != nil {
		t.Fatal(err)
	}
	return ta, lines, w, fs, dir
}

func TestTail(t *testing.T) {
	ta, _, w, fs := makeTestTail(t)
	fs.Mkdir("tail_test", os.ModePerm)
	logfile := "/tmp/log"
	f, err := fs.Create(logfile)
	if err != nil {
		t.Error(err)
	}
	defer f.Close()
	defer w.Close()

	err = ta.TailPath(logfile)
	if err != nil {
		t.Fatal(err)
	}
	// Tail also causes the log to be read, so no need to inject an event.

	if _, ok := ta.files[logfile]; !ok {
		t.Errorf("path not found in files map: %+#v", ta.files)
	}
}

func TestHandleLogUpdate(t *testing.T) {
	ta, lines, w, fs := makeTestTail(t)

	err := fs.Mkdir("/tail_test", os.ModePerm)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	logfile := "/tail_test/log"
	f, err := fs.Create(logfile)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	result := []*LogLine{}
	done := make(chan struct{})
	wg := sync.WaitGroup{}
	go func() {
		for line := range lines {
			result = append(result, line)
			wg.Done()
		}
		close(done)
	}()

	err = ta.TailPath(logfile)
	if err != nil {
		t.Fatal(err)
	}

	wg.Add(4)
	_, err = f.WriteString("a\nb\nc\nd\n")
	if err != nil {
		t.Fatal(err)
	}
	f.Seek(0, 0) // afero in-memory files share the same offset
	w.InjectUpdate(logfile)

	wg.Wait()
	if err := w.Close(); err != nil {
		t.Log(err)
	}
	<-done

	expected := []*LogLine{
		{logfile, "a"},
		{logfile, "b"},
		{logfile, "c"},
		{logfile, "d"},
	}
	if diff := cmp.Diff(expected, result); diff != "" {
		t.Errorf("result didn't match:\n%s", diff)
	}
}

// TestHandleLogTruncate writes to a file, waits for those
// writes to be seen, then truncates the file and writes some more.
// At the end all lines written must be reported by the tailer.
func TestHandleLogTruncate(t *testing.T) {
	ta, lines, w, fs, dir := makeTestTailReal(t, "truncate")
	defer func() {
		if err := os.RemoveAll(dir); err != nil {
			t.Log(err)
		}
	}()

	logfile := filepath.Join(dir, "log")
	f, err := fs.Create(logfile)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	result := []*LogLine{}
	done := make(chan struct{})
	wg := sync.WaitGroup{}
	go func() {
		for line := range lines {
			result = append(result, line)
			wg.Done()
		}
		close(done)
	}()

	if err = ta.TailPath(logfile); err != nil {
		t.Fatal(err)
	}

	wg.Add(3)
	if _, err = f.WriteString("a\nb\nc\n"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	wg.Wait()

	if err = f.Truncate(0); err != nil {
		t.Fatal(err)
	}
	// "File.Truncate" does not change the file offset.
	f.Seek(0, 0)
	time.Sleep(10 * time.Millisecond)

	wg.Add(2)
	if _, err = f.WriteString("d\ne\n"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)

	wg.Wait()
	if err := w.Close(); err != nil {
		t.Log(err)
	}
	<-done

	expected := []*LogLine{
		{logfile, "a"},
		{logfile, "b"},
		{logfile, "c"},
		{logfile, "d"},
		{logfile, "e"},
	}
	if diff := cmp.Diff(expected, result); diff != "" {
		t.Errorf("result didn't match:\n%s", diff)
	}
}

func TestHandleLogUpdatePartialLine(t *testing.T) {
	ta, lines, w, fs := makeTestTail(t)

	err := fs.Mkdir("/tail_test", os.ModePerm)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	logfile := "/tail_test/log"
	f, err := fs.Create(logfile)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	result := []*LogLine{}
	done := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(1)
	go func() {
		for line := range lines {
			result = append(result, line)
			wg.Done()
		}
		close(done)
	}()

	err = ta.TailPath(logfile)
	if err != nil {
		t.Fatal(err)
	}

	_, err = f.WriteString("a")
	if err != nil {
		t.Fatal(err)
	}
	f.Seek(0, 0)
	w.InjectUpdate(logfile)

	f.Seek(1, 0)
	_, err = f.WriteString("b")
	if err != nil {
		t.Error(err)
	}
	f.Seek(1, 0)
	w.InjectUpdate(logfile)

	f.Seek(2, 0)
	_, err = f.WriteString("\n")
	if err != nil {
		t.Error(err)
	}
	f.Seek(2, 0)
	w.InjectUpdate(logfile)

	wg.Wait()
	w.Close()
	<-done

	expected := []*LogLine{
		{logfile, "ab"},
	}
	diff := cmp.Diff(expected, result)
	if diff != "" {
		t.Errorf("result didn't match:\n%s", diff)
	}

}

func TestReadPartial(t *testing.T) {
	ta, lines, w, fs := makeTestTail(t)
	defer w.Close()

	f, err := fs.Create("t")
	if err != nil {
		t.Fatal(err)
	}
	p := bytes.NewBufferString("")
	err = ta.read(f, p)
	if p.String() != "" {
		t.Errorf("partial line returned not empty: %q", p)
	}
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
	p.Reset()
	p.WriteString("o")
	f.WriteString("hi")
	f.Seek(0, 0)
	err = ta.read(f, p)
	if p.String() != "ohi" {
		t.Errorf("partial line returned not expected: %q", p)
	}
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
	p.Reset()
	err = ta.read(f, p)
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
	f.WriteString("\n")
	f.Seek(-1, io.SeekEnd)
	p.Reset()
	p.WriteString("ohi")
	err = ta.read(f, p)
	l := <-lines
	if l.Line != "ohi" {
		t.Errorf("line emitted not ohi: %q", l)
	}
	if p.String() != "" {
		t.Errorf("partial not empty: %q", p)
	}
	if err != io.EOF {
		t.Errorf("error returned not EOF: %v", err)
	}
}

func TestReadPipe(t *testing.T) {
	ta, lines, wa, _ := makeTestTail(t)
	defer wa.Close()

	r, w, err := os.Pipe()
	if err != nil {
		t.Fatal(err)
	}

	err = ta.TailFile(r)
	if err != nil {
		t.Fatal(err)
	}
	n, err := w.WriteString("hi\n")
	if err != nil {
		t.Fatal(err)
	}
	if n < 2 {
		t.Fatalf("Didn't write enough bytes: %d", n)
	}
	l := <-lines
	if l.Line != "hi" {
		t.Errorf("line not expected: %q", l)
	}
}

func TestOpenRetries(t *testing.T) {
	// Use the real filesystem because afero doesn't implement correct
	// permissions checking on OpenFile in the memfile implementation.
	ta, lines, w, fs, dir := makeTestTailReal(t, "retries")
	defer func() {
		if err := os.RemoveAll(dir); err != nil {
			t.Log(err)
		}
	}()

	logfile := filepath.Join(dir, "log")
	if _, err := fs.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0); err != nil {
		t.Fatal(err)
	}

	done := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(1) // lines written
	go func() {
		for range lines {
			wg.Done()
		}
		close(done)
	}()

	if err := ta.TailPath(logfile); err == nil {
		t.Fatal("Expected a permission denied error here.")
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("remove")
	if err := fs.Remove(logfile); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("openfile")
	f, err := fs.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("chmod")
	if err := fs.Chmod(logfile, 0666); err != nil {
		t.Fatal(err)
	}
	time.Sleep(10 * time.Millisecond)
	glog.Info("write string")
	if _, err := f.WriteString("\n"); err != nil {
		t.Fatal(err)
	}
	wg.Wait()
	if err := w.Close(); err != nil {
		t.Log(err)
	}
	<-done
}

func TestTailerInitErrors(t *testing.T) {
	o := Options{}
	_, err := New(o)
	if err == nil {
		t.Error("expected error")
	}
	o.Lines = make(chan *LogLine)
	_, err = New(o)
	if err == nil {
		t.Error("expected error")
	}
	o.FS = afero.NewMemMapFs()
	_, err = New(o)
	if err == nil {
		t.Error("expected error")
	}
	o.W = watcher.NewFakeWatcher()
	_, err = New(o)
	if err != nil {
		t.Errorf("unexpected error %s", err)
	}
}
<|endoftext|>


<commit_before>package reviewboard

import (
	// Stdlib
	"bytes"
	"errors"
	"fmt"
	"regexp"
	"strconv"

	// Internal
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules/common"
	"github.com/salsaflow/salsaflow/repo"
	"github.com/salsaflow/salsaflow/shell"
)

const Id = "review_board"

func init() {
	repo.AddInitHook(ensureRbtVersion)
}

type codeReviewTool struct{}

func Factory() (common.CodeReviewTool, error) {
	return &codeReviewTool{}, nil
}

func (tool *codeReviewTool) PostReviewRequestForCommit(
	ctx *common.CommitReviewContext,
	opts map[string]interface{},
) error {

	var (
		commit = ctx.Commit
		story  = ctx.Story
	)

	// Assert that certain field are set.
	switch {
	case commit.SHA == "":
		panic("SHA not set for the commit being posted")
	case commit.StoryIdTag == "":
		panic("story ID not set for the commit being posted")
	}

	// Load the RB config.
	config, err := LoadConfig()
	if err != nil {
		return err
	}

	// Parse the options.
	var (
		fixes  = formatOptInteger(opts["fixes"])
		update = formatOptInteger(opts["update"])
		open   bool
	)
	if _, ok := opts["open"]; ok {
		open = true
	}

	// Post the review request.
	args := []string{"post",
		"--server", config.ServerURL().String(),
		"--guess-fields", "yes",
	}

	if story != nil {
		args = append(args, "--bugs-closed", commit.StoryIdTag)
	}
	if fixes != "" {
		args = append(args, "--depends-on", fixes)
	}
	if update != "" {
		args = append(args, "--review-request-id", update)
	}
	if open {
		args = append(args, "--open")
	}
	args = append(args, commit.SHA)

	task := "Create a Review Board review request for commit " + commit.SHA
	log.Run(task)
	stdout, stderr, err := shell.Run("rbt", args...)
	if err != nil {
		// rbt is retarded and sometimes prints stderr to stdout.
		// That is why we return stdout when stderr is empty.
		if stderr.Len() == 0 {
			return errs.NewError(task, err, stdout)
		} else {
			return errs.NewError(task, err, stderr)
		}
	}
	logger := log.V(log.Info)
	logger.Lock()
	logger.UnsafeNewLine("")
	logger.UnsafeOk(task)
	fmt.Print(stdout)
	logger.Unlock()
	return nil
}

func (tool *codeReviewTool) PostReviewRequestForBranch(
	branch string,
	ctxs []*common.CommitReviewContext,
	opts map[string]interface{},
) (err error) {

	// Use PostReviewRequestForCommit for every commit on the branch.
	// Try to post a review request for every commit and keep printing the errors.
	// Return a common error in case there is any partial error encountered.
	for _, ctx := range ctxs {
		if ex := tool.PostReviewRequestForCommit(ctx, opts); ex != nil {
			log.NewLine("")
			errs.Log(ex)
			err = errors.New("failed to post a review request")
		}
	}
	return
}

func (tool *codeReviewTool) PostReviewFollowupMessage() string {
	return `
Now, please, take some time to go through all the review requests
to check and annotate them for the reviewers to make their part easier.

If you find any issues you want to fix (even before publishing),
do so now, and if you haven't pushed into any shared branch yet,
amend the relevant commit and use

  $ salsaflow review post -update REVIEW_REQUEST_ID [REVISION]

to update (replace) the associated review request. Do this for every review
request you want to overwrite.

In case you cannot amend the relevant commit any more, make sure the affected
review request is published, and use the process for fixing review issues:

  $ salsaflow review post -fixes REVIEW_REQUEST_ID [REVISION]

This will create a new review request that is linked to the one being fixed.

  ##########################################################
  # IMPORTANT: Your code has not been merged anywhere yet. #
  ##########################################################
`
}

func formatOptInteger(value interface{}) string {
	// Return an empty string on nil.
	if value == nil {
		return ""
	}

	// Return an empty string in case the value is not an integer.
	switch value := value.(type) {
	case string:
		return value
	case int:
	case int32:
	case int64:
	case uint:
	case uint32:
	case uint64:
	default:
		return ""
	}

	// Format the integer and return the string representation.
	return fmt.Sprintf("%v", value)
}

func ensureRbtVersion() error {
	hint := bytes.NewBufferString(`
You need to install RBTools version 0.7. Please run

  $ pip install rbtools==0.7 --allow-external rbtools --allow-unverified rbtools

to install the correct version.

`)
	// Load configuration and check the RBTools version only if Review Board is being used.
	config, err := common.LoadConfig()
	if err != nil {
		return err
	}
	if config.CodeReviewToolId() != Id {
		return nil
	}

	// Check the RBTools version being used.
	task := "Check the RBTools version being used"
	log.Run(task)

	// rbt 0.5.x prints the version string to stdout,
	// rbt 0.6.x prints the version string to stderr.
	stdout, stderr, err := shell.Run("rbt", "--version")
	if err != nil {
		// Return the hint instead of stderr.
		// Failing to run rbt --version probably means that it's not installed.
		return errs.NewError(task, err, hint)
	}

	var outputBuffer *bytes.Buffer
	if stdout.Len() != 0 {
		outputBuffer = stdout
	} else {
		outputBuffer = stderr
	}
	output := outputBuffer.String()

	pattern := regexp.MustCompile("^RBTools (([0-9]+)[.]([0-9]+).*)")
	parts := pattern.FindStringSubmatch(output)
	if len(parts) != 4 {
		err := fmt.Errorf("failed to parse 'rbt --version' output: %v", output)
		return errs.NewError(task, err, nil)
	}
	rbtVersion := parts[1]
	// No need to check errors, we know the format is correct.
	major, _ := strconv.Atoi(parts[2])
	minor, _ := strconv.Atoi(parts[3])

	if !(major == 0 && minor == 7) {
		return errs.NewError(
			task, errors.New("unsupported rbt version detected: "+rbtVersion), hint)
	}

	return nil
}
<commit_msg>reviewboard: Make a user message more precise<commit_after>package reviewboard

import (
	// Stdlib
	"bytes"
	"errors"
	"fmt"
	"regexp"
	"strconv"

	// Internal
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules/common"
	"github.com/salsaflow/salsaflow/repo"
	"github.com/salsaflow/salsaflow/shell"
)

const Id = "review_board"

func init() {
	repo.AddInitHook(ensureRbtVersion)
}

type codeReviewTool struct{}

func Factory() (common.CodeReviewTool, error) {
	return &codeReviewTool{}, nil
}

func (tool *codeReviewTool) PostReviewRequestForCommit(
	ctx *common.CommitReviewContext,
	opts map[string]interface{},
) error {

	var (
		commit = ctx.Commit
		story  = ctx.Story
	)

	// Assert that certain field are set.
	switch {
	case commit.SHA == "":
		panic("SHA not set for the commit being posted")
	case commit.StoryIdTag == "":
		panic("story ID not set for the commit being posted")
	}

	// Load the RB config.
	config, err := LoadConfig()
	if err != nil {
		return err
	}

	// Parse the options.
	var (
		fixes  = formatOptInteger(opts["fixes"])
		update = formatOptInteger(opts["update"])
		open   bool
	)
	if _, ok := opts["open"]; ok {
		open = true
	}

	// Post the review request.
	args := []string{"post",
		"--server", config.ServerURL().String(),
		"--guess-fields", "yes",
	}

	if story != nil {
		args = append(args, "--bugs-closed", commit.StoryIdTag)
	}
	if fixes != "" {
		args = append(args, "--depends-on", fixes)
	}
	if update != "" {
		args = append(args, "--review-request-id", update)
	}
	if open {
		args = append(args, "--open")
	}
	args = append(args, commit.SHA)

	var task string
	if update != "" {
		task = "Update a Review Board review request with commit " + commit.SHA
	} else {
		task = "Create a Review Board review request for commit " + commit.SHA
	}
	log.Run(task)
	stdout, stderr, err := shell.Run("rbt", args...)
	if err != nil {
		// rbt is retarded and sometimes prints stderr to stdout.
		// That is why we return stdout when stderr is empty.
		if stderr.Len() == 0 {
			return errs.NewError(task, err, stdout)
		} else {
			return errs.NewError(task, err, stderr)
		}
	}
	logger := log.V(log.Info)
	logger.Lock()
	logger.UnsafeNewLine("")
	logger.UnsafeOk(task)
	fmt.Print(stdout)
	logger.Unlock()
	return nil
}

func (tool *codeReviewTool) PostReviewRequestForBranch(
	branch string,
	ctxs []*common.CommitReviewContext,
	opts map[string]interface{},
) (err error) {

	// Use PostReviewRequestForCommit for every commit on the branch.
	// Try to post a review request for every commit and keep printing the errors.
	// Return a common error in case there is any partial error encountered.
	for _, ctx := range ctxs {
		if ex := tool.PostReviewRequestForCommit(ctx, opts); ex != nil {
			log.NewLine("")
			errs.Log(ex)
			err = errors.New("failed to post a review request")
		}
	}
	return
}

func (tool *codeReviewTool) PostReviewFollowupMessage() string {
	return `
Now, please, take some time to go through all the review requests
to check and annotate them for the reviewers to make their part easier.

If you find any issues you want to fix (even before publishing),
do so now, and if you haven't pushed into any shared branch yet,
amend the relevant commit and use

  $ salsaflow review post -update REVIEW_REQUEST_ID [REVISION]

to update (replace) the associated review request. Do this for every review
request you want to overwrite.

In case you cannot amend the relevant commit any more, make sure the affected
review request is published, and use the process for fixing review issues:

  $ salsaflow review post -fixes REVIEW_REQUEST_ID [REVISION]

This will create a new review request that is linked to the one being fixed.

  ##########################################################
  # IMPORTANT: Your code has not been merged anywhere yet. #
  ##########################################################
`
}

func formatOptInteger(value interface{}) string {
	// Return an empty string on nil.
	if value == nil {
		return ""
	}

	// Return an empty string in case the value is not an integer.
	switch value := value.(type) {
	case string:
		return value
	case int:
	case int32:
	case int64:
	case uint:
	case uint32:
	case uint64:
	default:
		return ""
	}

	// Format the integer and return the string representation.
	return fmt.Sprintf("%v", value)
}

func ensureRbtVersion() error {
	hint := bytes.NewBufferString(`
You need to install RBTools version 0.7. Please run

  $ pip install rbtools==0.7 --allow-external rbtools --allow-unverified rbtools

to install the correct version.

`)
	// Load configuration and check the RBTools version only if Review Board is being used.
	config, err := common.LoadConfig()
	if err != nil {
		return err
	}
	if config.CodeReviewToolId() != Id {
		return nil
	}

	// Check the RBTools version being used.
	task := "Check the RBTools version being used"
	log.Run(task)

	// rbt 0.5.x prints the version string to stdout,
	// rbt 0.6.x prints the version string to stderr.
	stdout, stderr, err := shell.Run("rbt", "--version")
	if err != nil {
		// Return the hint instead of stderr.
		// Failing to run rbt --version probably means that it's not installed.
		return errs.NewError(task, err, hint)
	}

	var outputBuffer *bytes.Buffer
	if stdout.Len() != 0 {
		outputBuffer = stdout
	} else {
		outputBuffer = stderr
	}
	output := outputBuffer.String()

	pattern := regexp.MustCompile("^RBTools (([0-9]+)[.]([0-9]+).*)")
	parts := pattern.FindStringSubmatch(output)
	if len(parts) != 4 {
		err := fmt.Errorf("failed to parse 'rbt --version' output: %v", output)
		return errs.NewError(task, err, nil)
	}
	rbtVersion := parts[1]
	// No need to check errors, we know the format is correct.
	major, _ := strconv.Atoi(parts[2])
	minor, _ := strconv.Atoi(parts[3])

	if !(major == 0 && minor == 7) {
		return errs.NewError(
			task, errors.New("unsupported rbt version detected: "+rbtVersion), hint)
	}

	return nil
}
<|endoftext|>


<commit_before>package image

import (
	"io"
	"os"
	"time"

	"github.com/dnephin/dobi/tasks/context"
	docker "github.com/fsouza/go-dockerclient"
)

// RunPull builds or pulls an image if it is out of date
func RunPull(ctx *context.ExecuteContext, t *Task, _ bool) (bool, error) {
	record, err := getImageRecord(recordPath(ctx, t.config))
	switch {
	case !t.config.Pull.Required(record.LastPull):
		t.logger().Debugf("Pull not required")
		return false, nil
	case err != nil:
		t.logger().Warnf("Failed to get image record: %s", err)
	}

	pullTag := func(tag string) error {
		return pullImage(ctx, t, tag)
	}
	if err := t.ForEachTag(ctx, pullTag); err != nil {
		return false, err
	}

	record = imageModifiedRecord{LastPull: now()}
	if err := updateImageRecord(recordPath(ctx, t.config), record); err != nil {
		t.logger().Warnf("Failed to update image record: %s", err)
	}

	t.logger().Info("Pulled")
	return true, nil
}

func now() *time.Time {
	now := time.Now()
	return &now
}

func pullImage(ctx *context.ExecuteContext, t *Task, imageTag string) error {
	registry := parseAuthRepo(t.config.Image)
	repo, tag := docker.ParseRepositoryTag(imageTag)
	return Stream(os.Stdout, func(out io.Writer) error {
		return ctx.Client.PullImage(docker.PullImageOptions{
			Repository:    repo,
			Tag:           tag,
			OutputStream:  out,
			RawJSONStream: true,
			// TODO: timeout
		}, ctx.GetAuthConfig(registry))
	})
}
<commit_msg>Write imageid to .dobi dir on pull action<commit_after>package image

import (
	"io"
	"os"
	"time"

	"github.com/dnephin/dobi/tasks/context"
	docker "github.com/fsouza/go-dockerclient"
)

// RunPull builds or pulls an image if it is out of date
func RunPull(ctx *context.ExecuteContext, t *Task, _ bool) (bool, error) {
	record, err := getImageRecord(recordPath(ctx, t.config))
	switch {
	case !t.config.Pull.Required(record.LastPull):
		t.logger().Debugf("Pull not required")
		return false, nil
	case err != nil:
		t.logger().Warnf("Failed to get image record: %s", err)
	}

	pullTag := func(tag string) error {
		return pullImage(ctx, t, tag)
	}
	if err := t.ForEachTag(ctx, pullTag); err != nil {
		return false, err
	}

	image, err := GetImage(ctx, t.config)
	if err != nil {
		return false, err
	}
	record = imageModifiedRecord{LastPull: now(), ImageID: image.ID}

	if err := updateImageRecord(recordPath(ctx, t.config), record); err != nil {
		t.logger().Warnf("Failed to update image record: %s", err)
	}

	t.logger().Info("Pulled")
	return true, nil
}

func now() *time.Time {
	now := time.Now()
	return &now
}

func pullImage(ctx *context.ExecuteContext, t *Task, imageTag string) error {
	registry := parseAuthRepo(t.config.Image)
	repo, tag := docker.ParseRepositoryTag(imageTag)
	return Stream(os.Stdout, func(out io.Writer) error {
		return ctx.Client.PullImage(docker.PullImageOptions{
			Repository:    repo,
			Tag:           tag,
			OutputStream:  out,
			RawJSONStream: true,
			// TODO: timeout
		}, ctx.GetAuthConfig(registry))
	})
}
<|endoftext|>