<commit_before>package db

import (
	"database/sql"
	"errors"
	"testing"

	sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1"
)

func TestNewSQLVolumeDatabase_default(t *testing.T) {
	t.Parallel()

	var queries VolumeDatabaseQueries

	foo := NewSQLVolumeDatabase("type", "datasource", queries)
	if foo.DBType != "type" {
		t.Error("type was not configured")
	}

	if foo.DBDataSource != "datasource" {
		t.Error("datasource was not configured")
	}

	if foo.DBQueries != DefaultSQLQueries {
		t.Error("queries are not set to the defaults")
	}
}

func TestNewSQLVolumeDatabase_modifications(t *testing.T) {
	t.Parallel()

	queries := VolumeDatabaseQueries{
		// Volumes SQL statements
		volumesCreateTableSQL:              "a",
		volumesInsertSQL:                   "b",
		volumesGetNameAndMountpointListSQL: "c",
		volumesGetVolumeByNameSQL:          "d",
		volumesUpdateMountpointSQL:         "e",
		volumesDeleteByIDSQL:               "f",

		// Mounts SQL statements
		mountsCreateTableSQL:                        "g",
		mountsInsertSQL:                             "h",
		mountsGetRequesterAndCountByVolumeIDListSQL: "i",
		mountsUpdateCountByVolumeIDAndRequesterSQL:  "j",
		mountsDeleteByVolumeIDSQL:                   "k",
		mountsDeleteByVolumeIDAndRequesterSQL:       "l",
	}

	foo := NewSQLVolumeDatabase("type", "datasource", queries)
	if foo.DBType != "type" {
		t.Error("type was not configured")
	}

	if foo.DBDataSource != "datasource" {
		t.Error("datasource was not configured")
	}

	if foo.DBQueries == DefaultSQLQueries {
		t.Error("queries are set to the defaults")
	}

	if foo.DBQueries != queries {
		t.Error("queries are not set to the overrides")
	}
}

func createMockVolumeDatabase(t *testing.T) (*sql.DB, sqlmock.Sqlmock, VolumeDatabase) {
	// Create mock for a random sql db
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}

	// now we execute our method
	volumeDatabase := NewSQLVolumeDatabase("mock", "mock", VolumeDatabaseQueries{})
	sqlDB = db

	return db, mock, volumeDatabase
}

func TestValidateOrCrash(t *testing.T) {
	volumeDatabase := NewSQLVolumeDatabase("mock", "mock", VolumeDatabaseQueries{})

	var tests = []struct {
		name string
		f    func() error
	}{
		{"Disconnect", func() error {
			return volumeDatabase.Disconnect()
		}},

		{"Create", func() error {
			return volumeDatabase.Create("volumeName", map[string]string{})
		}},

		{"List", func() error {
			_, err := volumeDatabase.List()
			return err
		}},

		{"Get", func() error {
			_, err := volumeDatabase.Get("volumeName")
			return err
		}},

		{"Path", func() error {
			_, err := volumeDatabase.Path("volumeName")
			return err
		}},

		{"Remove", func() error {
			return volumeDatabase.Remove("volumeName")
		}},

		{"Mount", func() error {
			return volumeDatabase.Mount("volumeName", "id", "mointpoint")
		}},

		{"Unmount", func() error {
			return volumeDatabase.Unmount("volumeName", "id")
		}},
	}
	for _, test := range tests {
		if err := test.f(); err == nil {
			t.Errorf("%s should have retuned an error.", test.name)
		}
	}
}

func TestCreate_trivial(t *testing.T) {
	t.Parallel()
	createSQL := `[INSERT INTO volumes(name) VALUES (?);]`

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	// Configure Mock
	mock.ExpectBegin()
	prepared := mock.ExpectPrepare(createSQL)
	prepared.ExpectExec().WithArgs("volume_name").WillReturnResult(sqlmock.NewResult(1, 1))
	mock.ExpectCommit()

	if err := volumeDatabase.Create("volume_name", map[string]string{}); err != nil {
		t.Errorf("error was not expected while creating volume: %s", err)
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}

func TestCreate_badNoName(t *testing.T) {
	t.Parallel()

	db, _, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	err := volumeDatabase.Create("", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "volume name cannot be empty" {
		t.Error("error msg was expected to be 'volume name cannot be empty', was '" + err.Error() + "'")
	}
}

func TestCreate_failBegin(t *testing.T) {
	t.Parallel()

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	mock.ExpectBegin().WillReturnError(errors.New("ExampleError"))

	err := volumeDatabase.Create("volume_name", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "ExampleError" {
		t.Error("error msg was expected to be 'ExampleError', was '" + err.Error() + "'")
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}

func TestCreate_failPrepare(t *testing.T) {
	t.Parallel()
	createSQL := `[INSERT INTO volumes(name) VALUES (?);]`

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	mock.ExpectBegin()
	mock.ExpectPrepare(createSQL).WillReturnError(errors.New("ExampleError"))
	mock.ExpectRollback()

	err := volumeDatabase.Create("volume_name", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "ExampleError" {
		t.Error("error msg was expected to be 'ExampleError', was '" + err.Error() + "'")
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}

func TestCreate_failExec(t *testing.T) {
	t.Parallel()
	createSQL := `[INSERT INTO volumes(name) VALUES (?);]`

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	mock.ExpectBegin()
	prepare := mock.ExpectPrepare(createSQL)
	prepare.ExpectExec().WithArgs("volume_name").WillReturnError(errors.New("ExampleError"))
	mock.ExpectRollback()

	err := volumeDatabase.Create("volume_name", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "ExampleError" {
		t.Error("error msg was expected to be 'ExampleError', was '" + err.Error() + "'")
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}
<commit_msg>Actually fix tests ;)<commit_after>package db

import (
	"database/sql"
	"errors"
	"testing"

	sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1"
)

func TestNewSQLVolumeDatabase_default(t *testing.T) {
	t.Parallel()

	var queries VolumeDatabaseQueries

	foo := NewSQLVolumeDatabase("type", "datasource", queries)
	if foo.DBType != "type" {
		t.Error("type was not configured")
	}

	if foo.DBDataSource != "datasource" {
		t.Error("datasource was not configured")
	}

	if foo.DBQueries != DefaultSQLQueries {
		t.Error("queries are not set to the defaults")
	}
}

func TestNewSQLVolumeDatabase_modifications(t *testing.T) {
	t.Parallel()

	queries := VolumeDatabaseQueries{
		// Volumes SQL statements
		volumesCreateTableSQL:              "a",
		volumesInsertSQL:                   "b",
		volumesGetNameAndMountpointListSQL: "c",
		volumesGetVolumeByNameSQL:          "d",
		volumesUpdateMountpointSQL:         "e",
		volumesDeleteByIDSQL:               "f",

		// Mounts SQL statements
		mountsCreateTableSQL:                        "g",
		mountsInsertSQL:                             "h",
		mountsGetRequesterAndCountByVolumeIDListSQL: "i",
		mountsUpdateCountByVolumeIDAndRequesterSQL:  "j",
		mountsDeleteByVolumeIDSQL:                   "k",
		mountsDeleteByVolumeIDAndRequesterSQL:       "l",
	}

	foo := NewSQLVolumeDatabase("type", "datasource", queries)
	if foo.DBType != "type" {
		t.Error("type was not configured")
	}

	if foo.DBDataSource != "datasource" {
		t.Error("datasource was not configured")
	}

	if foo.DBQueries == DefaultSQLQueries {
		t.Error("queries are set to the defaults")
	}

	if foo.DBQueries != queries {
		t.Error("queries are not set to the overrides")
	}
}

func createMockVolumeDatabase(t *testing.T) (*sql.DB, sqlmock.Sqlmock, VolumeDatabase) {
	// Create mock for a random sql db
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}

	// now we execute our method
	volumeDatabase := NewSQLVolumeDatabase("mock", "mock", VolumeDatabaseQueries{})
	sqlDB = db

	return db, mock, volumeDatabase
}

func TestValidateOrCrash(t *testing.T) {
	volumeDatabase := NewSQLVolumeDatabase("mock", "mock", VolumeDatabaseQueries{})

	var tests = []struct {
		name string
		f    func() error
	}{
		{"Disconnect", func() error {
			return volumeDatabase.Disconnect()
		}},

		{"Create", func() error {
			return volumeDatabase.Create("volumeName", map[string]string{})
		}},

		{"List", func() error {
			_, err := volumeDatabase.List()
			return err
		}},

		{"Get", func() error {
			_, err := volumeDatabase.Get("volumeName")
			return err
		}},

		{"Path", func() error {
			_, err := volumeDatabase.Path("volumeName")
			return err
		}},

		{"Remove", func() error {
			return volumeDatabase.Remove("volumeName")
		}},

		{"Mount", func() error {
			return volumeDatabase.Mount("volumeName", "id", "mointpoint")
		}},

		{"Unmount", func() error {
			return volumeDatabase.Unmount("volumeName", "id")
		}},
	}
	for _, test := range tests {
		if err := test.f(); err == nil {
			t.Errorf("%s should have retuned an error.", test.name)
		}
	}
}

func TestCreate_trivial(t *testing.T) {
	createSQL := `[INSERT INTO volumes(name) VALUES (?);]`

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	// Configure Mock
	mock.ExpectBegin()
	prepared := mock.ExpectPrepare(createSQL)
	prepared.ExpectExec().WithArgs("volume_name").WillReturnResult(sqlmock.NewResult(1, 1))
	mock.ExpectCommit()

	if err := volumeDatabase.Create("volume_name", map[string]string{}); err != nil {
		t.Errorf("error was not expected while creating volume: %s", err)
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}

func TestCreate_badNoName(t *testing.T) {
	t.Parallel()

	db, _, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	err := volumeDatabase.Create("", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "volume name cannot be empty" {
		t.Error("error msg was expected to be 'volume name cannot be empty', was '" + err.Error() + "'")
	}
}

func TestCreate_failBegin(t *testing.T) {
	t.Parallel()

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	mock.ExpectBegin().WillReturnError(errors.New("ExampleError"))

	err := volumeDatabase.Create("volume_name", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "ExampleError" {
		t.Error("error msg was expected to be 'ExampleError', was '" + err.Error() + "'")
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}

func TestCreate_failPrepare(t *testing.T) {
	createSQL := `[INSERT INTO volumes(name) VALUES (?);]`

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	mock.ExpectBegin()
	mock.ExpectPrepare(createSQL).WillReturnError(errors.New("ExampleError"))
	mock.ExpectRollback()

	err := volumeDatabase.Create("volume_name", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "ExampleError" {
		t.Error("error msg was expected to be 'ExampleError', was '" + err.Error() + "'")
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}

func TestCreate_failExec(t *testing.T) {
	createSQL := `[INSERT INTO volumes(name) VALUES (?);]`

	db, mock, volumeDatabase := createMockVolumeDatabase(t)
	defer db.Close()

	mock.ExpectBegin()
	prepare := mock.ExpectPrepare(createSQL)
	prepare.ExpectExec().WithArgs("volume_name").WillReturnError(errors.New("ExampleError"))
	mock.ExpectRollback()

	err := volumeDatabase.Create("volume_name", map[string]string{})
	if err == nil {
		t.Error("error was expected while creating volume as name cannot be nil.")
	}

	if err.Error() != "ExampleError" {
		t.Error("error msg was expected to be 'ExampleError', was '" + err.Error() + "'")
	}

	// we make sure that all expectations were met
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expections: %s", err)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 statscollector

import (
	"fmt"
	"github.com/contiv/vpp/plugins/contiv/containeridx"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/idxmap"
	"github.com/onsi/gomega"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/common/model/interfaces"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"testing"
	"github.com/contiv/vpp/plugins/contiv/containeridx/model"
	"github.com/contiv/vpp/mock/contiv"
	"github.com/contiv/vpp/plugins/ksr/model/pod"
)

const (
	testIfPodName  = "tapcli-1"
	testCntvIfName = "GigabitEthernet0/1/1"
)

type mockPrometheus struct {
	statsPath        string
	newRegistryError error
	registerError    error
}

type CollectorTestVars struct {
	plugin *Plugin
	pmts   *mockPrometheus
	cntv   *contiv.MockContiv
}

var testVars = CollectorTestVars{
	pmts: &mockPrometheus{
		statsPath:        "",
		newRegistryError: nil,
		registerError:    nil,
	},
	cntv: contiv.NewMockContiv(),
}

// TestStatsCollector tests the Statistics collector
func TestStatsCollector(t *testing.T) {
	gomega.RegisterTestingT(t)

	fl := &local.FlavorLocal{}
	fl.Inject()

	testVars.plugin = &Plugin{
		Deps: Deps{
			Contiv:          testVars.cntv,
			Prometheus:      testVars.pmts,
			PluginInfraDeps: *fl.InfraDeps("stats-test"),
		},
	}

	// Check error handling if prometheus.NewRegistry returns error
	testVars.pmts.injectNewRegistryFuncError(fmt.Errorf("%s", "NewRegistry Error"))
	err := testVars.plugin.Init()
	gomega.Expect(err).To(gomega.MatchError("NewRegistry Error"))

	testVars.pmts.injectNewRegistryFuncError(nil)

	// Check error handling if prometheus.Register returns error
	testVars.pmts.injectRegisterFuncError(fmt.Errorf("%s", "Register Error"))
	err = testVars.plugin.Init()
	gomega.Expect(err).To(gomega.MatchError("Register Error"))

	testVars.pmts.injectRegisterFuncError(nil)

	// Check the Init() sunny path and do plugin init for the rest of the tests.
	testVars.pmts.injectNewRegistryFuncError(nil)
	err = testVars.plugin.Init()
	gomega.Expect(err).To(gomega.BeNil())

	testVars.cntv.SetPodIfName(pod.ID{"test-pod", "test-namespace"},testIfPodName)

	t.Run("testPutWithWrongArgumentType", testPutWithWrongArgumentType)
	t.Run("testPutNewPodEntry", testPutNewPodEntry)
	t.Run("testPutExistingPodEntry", testPutExistingPodEntry)
	t.Run("testPutNewContivEntry", testPutNewContivEntry)
	t.Run("testIsContivSystemInterface", testIsContivSystemInterface)
	t.Run("testDeletePodEntry", testDeletePodEntry)

	testVars.plugin.Close()
}

func testPutWithWrongArgumentType(t *testing.T) {
	key := interfaces.InterfaceStateKeyPrefix() + "stat1"

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{}
	testVars.plugin.Put(key, stat)
}

func testPutNewPodEntry(t *testing.T) {

	key := interfaces.InterfaceStateKeyPrefix() + testIfPodName

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{
		InPackets:       1,
		InBytes:         2,
		OutPackets:      3,
		OutBytes:        4,
		DropPackets:     5,
		PuntPackets:     6,
		Ipv4Packets:     7,
		Ipv6Packets:     8,
		InNobufPackets:  9,
		InMissPackets:   10,
		InErrorPackets:  11,
		OutErrorPackets: 12,
	}

	ifState := &interfaces.InterfacesState_Interface{
		Name:       testIfPodName,
		Statistics: stat,
	}

	testVars.plugin.Put(key, ifState)
	entry, exists := testVars.plugin.ifStats[key]

	gomega.Expect(exists).To(gomega.BeTrue())
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(1))
	checkEntry(stat, entry)
}

func testPutExistingPodEntry(t *testing.T) {

	key := interfaces.InterfaceStateKeyPrefix() + testIfPodName

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{
		InPackets:       21,
		InBytes:         22,
		OutPackets:      23,
		OutBytes:        24,
		DropPackets:     25,
		PuntPackets:     26,
		Ipv4Packets:     27,
		Ipv6Packets:     28,
		InNobufPackets:  29,
		InMissPackets:   30,
		InErrorPackets:  31,
		OutErrorPackets: 32,
	}

	ifState := &interfaces.InterfacesState_Interface{
		Name:       testIfPodName,
		Statistics: stat,
	}

	testVars.plugin.Put(key, ifState)

	entry, exists := testVars.plugin.ifStats[key]

	gomega.Expect(exists).To(gomega.BeTrue())
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(1))
	checkEntry(stat, entry)
}

func testPutNewContivEntry(t *testing.T) {

	key := interfaces.InterfaceStateKeyPrefix() + testCntvIfName

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{
		InPackets:       1,
		InBytes:         2,
		OutPackets:      3,
		OutBytes:        4,
		DropPackets:     5,
		PuntPackets:     6,
		Ipv4Packets:     7,
		Ipv6Packets:     8,
		InNobufPackets:  9,
		InMissPackets:   10,
		InErrorPackets:  11,
		OutErrorPackets: 12,
	}

	ifState := &interfaces.InterfacesState_Interface{
		Name:       testCntvIfName,
		Statistics: stat,
	}

	testVars.plugin.Put(key, ifState)
	entry, exists := testVars.plugin.ifStats[key]

	gomega.Expect(exists).To(gomega.BeTrue())
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))
	checkEntry(stat, entry)
}

func testDeletePodEntry(t *testing.T) {
	evt := containeridx.ChangeEvent{
		NamedMappingEvent: idxmap.NamedMappingEvent{
			Del: false,
		},
		Value: &container.Persisted{
			PodName:      "bogusPodName",
			PodNamespace: "bogusPodNamespace",
		},
	}

	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test non-delete event - delete should not happen
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test Delete event where delete succeeds, but invalid Pod name
	evt.Del = true
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test Delete event where delete succeeds, but invalid Pod name
	_,evt.Value.PodName, _ = testVars.cntv.GetPodByIf(testIfPodName)
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test Delete event where delete succeeds, but invalid Pod name
	evt.Value.PodNamespace,_,_ = testVars.cntv.GetPodByIf(testIfPodName)
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(1))
}

func testIsContivSystemInterface(t *testing.T) {
	for _, ifName := range systemIfNames {
		tf := testVars.plugin.isContivSystemInterface(ifName)
		gomega.Expect(tf).To(gomega.BeTrue())
	}
	tf := testVars.plugin.isContivSystemInterface("tapcli-1")
	gomega.Expect(tf).To(gomega.BeFalse())
}

func checkEntry(stat *interfaces.InterfacesState_Interface_Statistics, entry *stats) {
	_, exists := entry.metrics[inPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[outPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inBytesMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[outBytesMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[dropPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[puntPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[ipv4PacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[ipv6PacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inNobufPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inMissPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inErrorPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[outErrorPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())

	gomega.Expect(stat.DropPackets).To(gomega.Equal(entry.data.Statistics.DropPackets))
	gomega.Expect(stat.InBytes).To(gomega.Equal(entry.data.Statistics.InBytes))
	gomega.Expect(stat.InErrorPackets).To(gomega.Equal(entry.data.Statistics.InErrorPackets))
	gomega.Expect(stat.InMissPackets).To(gomega.Equal(entry.data.Statistics.InMissPackets))
	gomega.Expect(stat.InNobufPackets).To(gomega.Equal(entry.data.Statistics.InNobufPackets))
	gomega.Expect(stat.InPackets).To(gomega.Equal(entry.data.Statistics.InPackets))
	gomega.Expect(stat.Ipv4Packets).To(gomega.Equal(entry.data.Statistics.Ipv4Packets))
	gomega.Expect(stat.Ipv6Packets).To(gomega.Equal(entry.data.Statistics.Ipv6Packets))
	gomega.Expect(stat.OutBytes).To(gomega.Equal(entry.data.Statistics.OutBytes))
	gomega.Expect(stat.OutErrorPackets).To(gomega.Equal(entry.data.Statistics.OutErrorPackets))
	gomega.Expect(stat.OutPackets).To(gomega.Equal(entry.data.Statistics.OutPackets))
	gomega.Expect(stat.PuntPackets).To(gomega.Equal(entry.data.Statistics.PuntPackets))
}

// NewRegistry creates new registry exposed at defined URL path (must begin
// with '/' character), path is used to reference registry while adding new
// metrics into registry, opts adjust the behavior of exposed registry. Must
// be called before AfterInit phase of the Prometheus plugin. An attempt to
// create  a registry with path that is already used
// by different registry returns an error.
func (mp *mockPrometheus) NewRegistry(path string, opts promhttp.HandlerOpts) error {
	mp.statsPath = path
	return mp.newRegistryError
}

// Register registers prometheus metric (e.g.: created by prometheus.NewGaugeVec,
// prometheus.NewHistogram,...)  to a specified registry
func (mp *mockPrometheus) Register(registryPath string, collector prometheus.Collector) error {
	return mp.registerError
}

// Unregister unregisters the given metric. The function returns whether a
// Collector was unregistered.
func (mp *mockPrometheus) Unregister(registryPath string, collector prometheus.Collector) bool {
	return false
}

// RegisterGauge registers custom gauge with specific valueFunc to report
// status when invoked. RegistryPath identifies the registry. The aim of this
// method is to simply common use case - adding Gauge with value func.
func (mp *mockPrometheus) RegisterGaugeFunc(registryPath string, namespace string, subsystem string,
	name string, help string, labels prometheus.Labels, valueFunc func() float64) error {
	return nil
}

func (mp *mockPrometheus) injectNewRegistryFuncError(err error) {
	mp.newRegistryError = err
}

func (mp *mockPrometheus) injectRegisterFuncError(err error) {
	mp.registerError = err
}
<commit_msg>Address gofmt<commit_after>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 statscollector

import (
	"fmt"
	"github.com/contiv/vpp/plugins/contiv/containeridx"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/idxmap"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/common/model/interfaces"
	"github.com/onsi/gomega"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"github.com/contiv/vpp/mock/contiv"
	"github.com/contiv/vpp/plugins/contiv/containeridx/model"
	"github.com/contiv/vpp/plugins/ksr/model/pod"
	"testing"
)

const (
	testIfPodName  = "tapcli-1"
	testCntvIfName = "GigabitEthernet0/1/1"
)

type mockPrometheus struct {
	statsPath        string
	newRegistryError error
	registerError    error
}

type CollectorTestVars struct {
	plugin *Plugin
	pmts   *mockPrometheus
	cntv   *contiv.MockContiv
}

var testVars = CollectorTestVars{
	pmts: &mockPrometheus{
		statsPath:        "",
		newRegistryError: nil,
		registerError:    nil,
	},
	cntv: contiv.NewMockContiv(),
}

// TestStatsCollector tests the Statistics collector
func TestStatsCollector(t *testing.T) {
	gomega.RegisterTestingT(t)

	fl := &local.FlavorLocal{}
	fl.Inject()

	testVars.plugin = &Plugin{
		Deps: Deps{
			Contiv:          testVars.cntv,
			Prometheus:      testVars.pmts,
			PluginInfraDeps: *fl.InfraDeps("stats-test"),
		},
	}

	// Check error handling if prometheus.NewRegistry returns error
	testVars.pmts.injectNewRegistryFuncError(fmt.Errorf("%s", "NewRegistry Error"))
	err := testVars.plugin.Init()
	gomega.Expect(err).To(gomega.MatchError("NewRegistry Error"))

	testVars.pmts.injectNewRegistryFuncError(nil)

	// Check error handling if prometheus.Register returns error
	testVars.pmts.injectRegisterFuncError(fmt.Errorf("%s", "Register Error"))
	err = testVars.plugin.Init()
	gomega.Expect(err).To(gomega.MatchError("Register Error"))

	testVars.pmts.injectRegisterFuncError(nil)

	// Check the Init() sunny path and do plugin init for the rest of the tests.
	testVars.pmts.injectNewRegistryFuncError(nil)
	err = testVars.plugin.Init()
	gomega.Expect(err).To(gomega.BeNil())

	testVars.cntv.SetPodIfName(pod.ID{"test-pod", "test-namespace"}, testIfPodName)

	t.Run("testPutWithWrongArgumentType", testPutWithWrongArgumentType)
	t.Run("testPutNewPodEntry", testPutNewPodEntry)
	t.Run("testPutExistingPodEntry", testPutExistingPodEntry)
	t.Run("testPutNewContivEntry", testPutNewContivEntry)
	t.Run("testIsContivSystemInterface", testIsContivSystemInterface)
	t.Run("testDeletePodEntry", testDeletePodEntry)

	testVars.plugin.Close()
}

func testPutWithWrongArgumentType(t *testing.T) {
	key := interfaces.InterfaceStateKeyPrefix() + "stat1"

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{}
	testVars.plugin.Put(key, stat)
}

func testPutNewPodEntry(t *testing.T) {

	key := interfaces.InterfaceStateKeyPrefix() + testIfPodName

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{
		InPackets:       1,
		InBytes:         2,
		OutPackets:      3,
		OutBytes:        4,
		DropPackets:     5,
		PuntPackets:     6,
		Ipv4Packets:     7,
		Ipv6Packets:     8,
		InNobufPackets:  9,
		InMissPackets:   10,
		InErrorPackets:  11,
		OutErrorPackets: 12,
	}

	ifState := &interfaces.InterfacesState_Interface{
		Name:       testIfPodName,
		Statistics: stat,
	}

	testVars.plugin.Put(key, ifState)
	entry, exists := testVars.plugin.ifStats[key]

	gomega.Expect(exists).To(gomega.BeTrue())
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(1))
	checkEntry(stat, entry)
}

func testPutExistingPodEntry(t *testing.T) {

	key := interfaces.InterfaceStateKeyPrefix() + testIfPodName

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{
		InPackets:       21,
		InBytes:         22,
		OutPackets:      23,
		OutBytes:        24,
		DropPackets:     25,
		PuntPackets:     26,
		Ipv4Packets:     27,
		Ipv6Packets:     28,
		InNobufPackets:  29,
		InMissPackets:   30,
		InErrorPackets:  31,
		OutErrorPackets: 32,
	}

	ifState := &interfaces.InterfacesState_Interface{
		Name:       testIfPodName,
		Statistics: stat,
	}

	testVars.plugin.Put(key, ifState)

	entry, exists := testVars.plugin.ifStats[key]

	gomega.Expect(exists).To(gomega.BeTrue())
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(1))
	checkEntry(stat, entry)
}

func testPutNewContivEntry(t *testing.T) {

	key := interfaces.InterfaceStateKeyPrefix() + testCntvIfName

	// test with wrong argument type
	stat := &interfaces.InterfacesState_Interface_Statistics{
		InPackets:       1,
		InBytes:         2,
		OutPackets:      3,
		OutBytes:        4,
		DropPackets:     5,
		PuntPackets:     6,
		Ipv4Packets:     7,
		Ipv6Packets:     8,
		InNobufPackets:  9,
		InMissPackets:   10,
		InErrorPackets:  11,
		OutErrorPackets: 12,
	}

	ifState := &interfaces.InterfacesState_Interface{
		Name:       testCntvIfName,
		Statistics: stat,
	}

	testVars.plugin.Put(key, ifState)
	entry, exists := testVars.plugin.ifStats[key]

	gomega.Expect(exists).To(gomega.BeTrue())
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))
	checkEntry(stat, entry)
}

func testDeletePodEntry(t *testing.T) {
	evt := containeridx.ChangeEvent{
		NamedMappingEvent: idxmap.NamedMappingEvent{
			Del: false,
		},
		Value: &container.Persisted{
			PodName:      "bogusPodName",
			PodNamespace: "bogusPodNamespace",
		},
	}

	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test non-delete event - delete should not happen
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test Delete event where delete succeeds, but invalid Pod name
	evt.Del = true
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test Delete event where delete succeeds, but invalid Pod name
	_, evt.Value.PodName, _ = testVars.cntv.GetPodByIf(testIfPodName)
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(2))

	// Test Delete event where delete succeeds, but invalid Pod name
	evt.Value.PodNamespace, _, _ = testVars.cntv.GetPodByIf(testIfPodName)
	testVars.plugin.processPodEvent(evt)
	gomega.Expect(len(testVars.plugin.ifStats)).To(gomega.Equal(1))
}

func testIsContivSystemInterface(t *testing.T) {
	for _, ifName := range systemIfNames {
		tf := testVars.plugin.isContivSystemInterface(ifName)
		gomega.Expect(tf).To(gomega.BeTrue())
	}
	tf := testVars.plugin.isContivSystemInterface("tapcli-1")
	gomega.Expect(tf).To(gomega.BeFalse())
}

func checkEntry(stat *interfaces.InterfacesState_Interface_Statistics, entry *stats) {
	_, exists := entry.metrics[inPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[outPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inBytesMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[outBytesMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[dropPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[puntPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[ipv4PacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[ipv6PacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inNobufPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inMissPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[inErrorPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())
	_, exists = entry.metrics[outErrorPacketsMetric]
	gomega.Expect(exists).To(gomega.BeTrue())

	gomega.Expect(stat.DropPackets).To(gomega.Equal(entry.data.Statistics.DropPackets))
	gomega.Expect(stat.InBytes).To(gomega.Equal(entry.data.Statistics.InBytes))
	gomega.Expect(stat.InErrorPackets).To(gomega.Equal(entry.data.Statistics.InErrorPackets))
	gomega.Expect(stat.InMissPackets).To(gomega.Equal(entry.data.Statistics.InMissPackets))
	gomega.Expect(stat.InNobufPackets).To(gomega.Equal(entry.data.Statistics.InNobufPackets))
	gomega.Expect(stat.InPackets).To(gomega.Equal(entry.data.Statistics.InPackets))
	gomega.Expect(stat.Ipv4Packets).To(gomega.Equal(entry.data.Statistics.Ipv4Packets))
	gomega.Expect(stat.Ipv6Packets).To(gomega.Equal(entry.data.Statistics.Ipv6Packets))
	gomega.Expect(stat.OutBytes).To(gomega.Equal(entry.data.Statistics.OutBytes))
	gomega.Expect(stat.OutErrorPackets).To(gomega.Equal(entry.data.Statistics.OutErrorPackets))
	gomega.Expect(stat.OutPackets).To(gomega.Equal(entry.data.Statistics.OutPackets))
	gomega.Expect(stat.PuntPackets).To(gomega.Equal(entry.data.Statistics.PuntPackets))
}

// NewRegistry creates new registry exposed at defined URL path (must begin
// with '/' character), path is used to reference registry while adding new
// metrics into registry, opts adjust the behavior of exposed registry. Must
// be called before AfterInit phase of the Prometheus plugin. An attempt to
// create  a registry with path that is already used
// by different registry returns an error.
func (mp *mockPrometheus) NewRegistry(path string, opts promhttp.HandlerOpts) error {
	mp.statsPath = path
	return mp.newRegistryError
}

// Register registers prometheus metric (e.g.: created by prometheus.NewGaugeVec,
// prometheus.NewHistogram,...)  to a specified registry
func (mp *mockPrometheus) Register(registryPath string, collector prometheus.Collector) error {
	return mp.registerError
}

// Unregister unregisters the given metric. The function returns whether a
// Collector was unregistered.
func (mp *mockPrometheus) Unregister(registryPath string, collector prometheus.Collector) bool {
	return false
}

// RegisterGauge registers custom gauge with specific valueFunc to report
// status when invoked. RegistryPath identifies the registry. The aim of this
// method is to simply common use case - adding Gauge with value func.
func (mp *mockPrometheus) RegisterGaugeFunc(registryPath string, namespace string, subsystem string,
	name string, help string, labels prometheus.Labels, valueFunc func() float64) error {
	return nil
}

func (mp *mockPrometheus) injectNewRegistryFuncError(err error) {
	mp.newRegistryError = err
}

func (mp *mockPrometheus) injectRegisterFuncError(err error) {
	mp.registerError = err
}
<|endoftext|>


<commit_before>package xorm_test

import (
	"fmt"
	_ "github.com/Go-SQL-Driver/MySQL"
	_ "github.com/mattn/go-sqlite3"
	"os"
	"testing"
	"time"
	"xorm"
)

/*
CREATE TABLE `userinfo` (
	`uid` INT(10) NULL AUTO_INCREMENT,
	`username` VARCHAR(64) NULL,
	`departname` VARCHAR(64) NULL,
	`created` DATE NULL,
	PRIMARY KEY (`uid`)
);
CREATE TABLE `userdeatail` (
	`uid` INT(10) NULL,
	`intro` TEXT NULL,
	`profile` TEXT NULL,
	PRIMARY KEY (`uid`)
);
*/

type Userinfo struct {
	Uid        int64 `xorm:"id pk not null autoincr"`
	Username   string
	Departname string
	Alias      string `xorm:"-"`
	Created    time.Time
	Detail     Userdetail `xorm:"detail_id int(11)"`
	Height     float64
	Avatar     []byte
	IsMan      bool
}

type Userdetail struct {
	Id      int64
	Intro   string `xorm:"text"`
	Profile string `xorm:"varchar(2000)"`
}

var engine xorm.Engine

func directCreateTable(t *testing.T) {
	err := engine.CreateTables(&Userinfo{})
	if err != nil {
		t.Error(err)
	}
}

func mapper(t *testing.T) {
	err := engine.UnMap(&Userinfo{})
	if err != nil {
		t.Error(err)
	}

	err = engine.Map(&Userinfo{}, &Userdetail{})
	if err != nil {
		t.Error(err)
	}

	err = engine.DropAll()
	if err != nil {
		t.Error(err)
	}

	err = engine.CreateAll()
	if err != nil {
		t.Error(err)
	}
}

func insert(t *testing.T) {
	user := Userinfo{1, "xiaolunwen", "dev", "lunny", time.Now(),
		Userdetail{Id: 1}, 1.78, []byte{1, 2, 3}, true}
	_, err := engine.Insert(&user)
	if err != nil {
		t.Error(err)
	}
}

func query(t *testing.T) {
	sql := "select * from userinfo"
	results, err := engine.Query(sql)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(results)
}

func exec(t *testing.T) {
	sql := "update userinfo set username=? where id=?"
	res, err := engine.Exec(sql, "xiaolun", 1)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(res)
}

func insertAutoIncr(t *testing.T) {
	// auto increment insert
	user := Userinfo{Username: "xiaolunwen", Departname: "dev", Alias: "lunny", Created: time.Now(),
		Detail: Userdetail{Id: 1}, Height: 1.78, Avatar: []byte{1, 2, 3}, IsMan: true}
	_, err := engine.Insert(&user)
	if err != nil {
		t.Error(err)
	}
}

func insertMulti(t *testing.T) {
	engine.InsertMany = true
	users := []Userinfo{
		{Username: "xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
		{Username: "xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
		{Username: "xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
		{Username: "xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
	}
	_, err := engine.Insert(&users)
	if err != nil {
		t.Error(err)
	}

	engine.InsertMany = false

	users = []Userinfo{
		{Username: "xlw9", Departname: "dev", Alias: "lunny9", Created: time.Now()},
		{Username: "xlw10", Departname: "dev", Alias: "lunny10", Created: time.Now()},
		{Username: "xlw99", Departname: "dev", Alias: "lunny2", Created: time.Now()},
		{Username: "xlw1010", Departname: "dev", Alias: "lunny3", Created: time.Now()},
	}
	_, err = engine.Insert(&users)
	if err != nil {
		t.Error(err)
	}

	engine.InsertMany = true
}

func insertTwoTable(t *testing.T) {
	userdetail := Userdetail{Id: 1, Intro: "I'm a very beautiful women.", Profile: "sfsaf"}
	userinfo := Userinfo{Username: "xlw3", Departname: "dev", Alias: "lunny4", Created: time.Now(), Detail: userdetail}

	_, err := engine.Insert(&userinfo, &userdetail)
	if err != nil {
		t.Error(err)
	}
}

func update(t *testing.T) {
	// update by id
	user := Userinfo{Username: "xxx"}
	_, err := engine.Id(1).Update(&user)
	if err != nil {
		t.Error(err)
		return
	}

	_, err = engine.Update(&Userinfo{Username: "yyy"}, &user)
	if err != nil {
		t.Error(err)
	}
}

func delete(t *testing.T) {
	user := Userinfo{Uid: 1}
	_, err := engine.Delete(&user)
	if err != nil {
		t.Error(err)
	}
}

func get(t *testing.T) {
	user := Userinfo{Uid: 2}

	err := engine.Get(&user)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(user)
}

func cascadeGet(t *testing.T) {
	user := Userinfo{Uid: 11}

	err := engine.Get(&user)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(user)
}

func find(t *testing.T) {
	users := make([]Userinfo, 0)

	err := engine.Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func findMap(t *testing.T) {
	users := make(map[int64]Userinfo)

	err := engine.Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func count(t *testing.T) {
	user := Userinfo{Departname: "dev"}
	total, err := engine.Count(&user)
	if err != nil {
		t.Error(err)
	}
	fmt.Printf("Total %d records!!!", total)
}

func where(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.Where("id > ?", 2).Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func in(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.In("id", 1, 2, 3).Find(&users)
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(users)

	ids := []interface{}{1, 2, 3}
	err = engine.Where("id > ?", 2).In("id", ids...).Find(&users)
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(users)
}

func limit(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.Limit(2, 1).Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func order(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.OrderBy("id desc").Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func join(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.Join("LEFT", "userdetail", "userinfo.id=userdetail.id").Find(&users)
	if err != nil {
		t.Error(err)
	}
}

func having(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.GroupBy("username").Having("username='xlw'").Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func transaction(t *testing.T) {
	counter := func() {
		total, err := engine.Count(&Userinfo{})
		if err != nil {
			t.Error(err)
		}
		fmt.Printf("----now total %v records\n", total)
	}

	counter()
	defer counter()
	session, err := engine.MakeSession()
	defer session.Close()
	if err != nil {
		t.Error(err)
		return
	}

	session.Begin()
	//session.IsAutoRollback = false
	user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
	_, err = session.Insert(&user1)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}
	user2 := Userinfo{Username: "yyy"}
	_, err = session.Where("uid = ?", 0).Update(&user2)
	if err != nil {
		session.Rollback()
		fmt.Println(err)
		//t.Error(err)
		return
	}

	_, err = session.Delete(&user2)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}

	err = session.Commit()
	if err != nil {
		t.Error(err)
		return
	}
}

func combineTransaction(t *testing.T) {
	counter := func() {
		total, err := engine.Count(&Userinfo{})
		if err != nil {
			t.Error(err)
		}
		fmt.Printf("----now total %v records\n", total)
	}

	counter()
	defer counter()
	session, err := engine.MakeSession()
	defer session.Close()
	if err != nil {
		t.Error(err)
		return
	}

	session.Begin()
	//session.IsAutoRollback = false
	user1 := Userinfo{Username: "xiaoxiao2", Departname: "dev", Alias: "lunny", Created: time.Now()}
	_, err = session.Insert(&user1)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}
	user2 := Userinfo{Username: "zzz"}
	_, err = session.Where("id = ?", 0).Update(&user2)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}

	_, err = session.Exec("delete from userinfo where username = ?", user2.Username)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}

	err = session.Commit()
	if err != nil {
		t.Error(err)
		return
	}
}

func table(t *testing.T) {
	engine.Table("user_user").CreateTables(&Userinfo{})
}

func createMultiTables(t *testing.T) {
	session, err := engine.MakeSession()
	defer session.Close()
	if err != nil {
		t.Error(err)
		return
	}

	user := &Userinfo{}
	session.Begin()
	for i := 0; i < 10; i++ {
		err = session.Table(fmt.Sprintf("user_%v", i)).CreateTable(user)
		if err != nil {
			session.Rollback()
			t.Error(err)
			return
		}
	}
	err = session.Commit()
	if err != nil {
		t.Error(err)
	}
}

func tableOp(t *testing.T) {
	user := Userinfo{Username: "tablexiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
	tableName := fmt.Sprintf("user_%v", len(user.Username))
	id, err := engine.Table(tableName).Insert(&user)
	if err != nil {
		t.Error(err)
	}

	err = engine.Table(tableName).Get(&Userinfo{Username: "tablexiao"})
	if err != nil {
		t.Error(err)
	}

	users := make([]Userinfo, 0)
	err = engine.Table(tableName).Find(&users)
	if err != nil {
		t.Error(err)
	}

	_, err = engine.Table(tableName).Id(id).Update(&Userinfo{Username: "tableda"})
	if err != nil {
		t.Error(err)
	}

	_, err = engine.Table(tableName).Id(id).Delete(&Userinfo{})
	if err != nil {
		t.Error(err)
	}
}

func TestMysql(t *testing.T) {
	// You should drop all tables before executing this testing
	engine = xorm.Create("mysql", "root:123@/test?charset=utf8")
	engine.ShowSQL = true

	directCreateTable(t)
	mapper(t)
	insert(t)
	query(t)
	exec(t)
	insertAutoIncr(t)
	insertMulti(t)
	insertTwoTable(t)
	update(t)
	delete(t)
	get(t)
	cascadeGet(t)
	find(t)
	findMap(t)
	count(t)
	where(t)
	in(t)
	limit(t)
	order(t)
	join(t)
	having(t)
	transaction(t)
	combineTransaction(t)
	table(t)
	createMultiTables(t)
	tableOp(t)
}

func TestSqlite(t *testing.T) {
	os.Remove("./test.db")
	engine = xorm.Create("sqlite3", "./test.db")
	engine.ShowSQL = true

	directCreateTable(t)
	mapper(t)
	insert(t)
	query(t)
	exec(t)
	insertAutoIncr(t)
	insertMulti(t)
	insertTwoTable(t)
	update(t)
	delete(t)
	get(t)
	cascadeGet(t)
	find(t)
	findMap(t)
	count(t)
	where(t)
	in(t)
	limit(t)
	order(t)
	join(t)
	having(t)
	transaction(t)
	combineTransaction(t)
	table(t)
	createMultiTables(t)
	tableOp(t)
}
<commit_msg>fix mysql reference<commit_after>package xorm_test

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/mattn/go-sqlite3"
	"os"
	"testing"
	"time"
	"xorm"
)

/*
CREATE TABLE `userinfo` (
	`uid` INT(10) NULL AUTO_INCREMENT,
	`username` VARCHAR(64) NULL,
	`departname` VARCHAR(64) NULL,
	`created` DATE NULL,
	PRIMARY KEY (`uid`)
);
CREATE TABLE `userdeatail` (
	`uid` INT(10) NULL,
	`intro` TEXT NULL,
	`profile` TEXT NULL,
	PRIMARY KEY (`uid`)
);
*/

type Userinfo struct {
	Uid        int64 `xorm:"id pk not null autoincr"`
	Username   string
	Departname string
	Alias      string `xorm:"-"`
	Created    time.Time
	Detail     Userdetail `xorm:"detail_id int(11)"`
	Height     float64
	Avatar     []byte
	IsMan      bool
}

type Userdetail struct {
	Id      int64
	Intro   string `xorm:"text"`
	Profile string `xorm:"varchar(2000)"`
}

var engine xorm.Engine

func directCreateTable(t *testing.T) {
	err := engine.CreateTables(&Userinfo{})
	if err != nil {
		t.Error(err)
	}
}

func mapper(t *testing.T) {
	err := engine.UnMap(&Userinfo{})
	if err != nil {
		t.Error(err)
	}

	err = engine.Map(&Userinfo{}, &Userdetail{})
	if err != nil {
		t.Error(err)
	}

	err = engine.DropAll()
	if err != nil {
		t.Error(err)
	}

	err = engine.CreateAll()
	if err != nil {
		t.Error(err)
	}
}

func insert(t *testing.T) {
	user := Userinfo{1, "xiaolunwen", "dev", "lunny", time.Now(),
		Userdetail{Id: 1}, 1.78, []byte{1, 2, 3}, true}
	_, err := engine.Insert(&user)
	if err != nil {
		t.Error(err)
	}
}

func query(t *testing.T) {
	sql := "select * from userinfo"
	results, err := engine.Query(sql)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(results)
}

func exec(t *testing.T) {
	sql := "update userinfo set username=? where id=?"
	res, err := engine.Exec(sql, "xiaolun", 1)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(res)
}

func insertAutoIncr(t *testing.T) {
	// auto increment insert
	user := Userinfo{Username: "xiaolunwen", Departname: "dev", Alias: "lunny", Created: time.Now(),
		Detail: Userdetail{Id: 1}, Height: 1.78, Avatar: []byte{1, 2, 3}, IsMan: true}
	_, err := engine.Insert(&user)
	if err != nil {
		t.Error(err)
	}
}

func insertMulti(t *testing.T) {
	engine.InsertMany = true
	users := []Userinfo{
		{Username: "xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
		{Username: "xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
		{Username: "xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
		{Username: "xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
	}
	_, err := engine.Insert(&users)
	if err != nil {
		t.Error(err)
	}

	engine.InsertMany = false

	users = []Userinfo{
		{Username: "xlw9", Departname: "dev", Alias: "lunny9", Created: time.Now()},
		{Username: "xlw10", Departname: "dev", Alias: "lunny10", Created: time.Now()},
		{Username: "xlw99", Departname: "dev", Alias: "lunny2", Created: time.Now()},
		{Username: "xlw1010", Departname: "dev", Alias: "lunny3", Created: time.Now()},
	}
	_, err = engine.Insert(&users)
	if err != nil {
		t.Error(err)
	}

	engine.InsertMany = true
}

func insertTwoTable(t *testing.T) {
	userdetail := Userdetail{Id: 1, Intro: "I'm a very beautiful women.", Profile: "sfsaf"}
	userinfo := Userinfo{Username: "xlw3", Departname: "dev", Alias: "lunny4", Created: time.Now(), Detail: userdetail}

	_, err := engine.Insert(&userinfo, &userdetail)
	if err != nil {
		t.Error(err)
	}
}

func update(t *testing.T) {
	// update by id
	user := Userinfo{Username: "xxx"}
	_, err := engine.Id(1).Update(&user)
	if err != nil {
		t.Error(err)
		return
	}

	_, err = engine.Update(&Userinfo{Username: "yyy"}, &user)
	if err != nil {
		t.Error(err)
	}
}

func delete(t *testing.T) {
	user := Userinfo{Uid: 1}
	_, err := engine.Delete(&user)
	if err != nil {
		t.Error(err)
	}
}

func get(t *testing.T) {
	user := Userinfo{Uid: 2}

	err := engine.Get(&user)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(user)
}

func cascadeGet(t *testing.T) {
	user := Userinfo{Uid: 11}

	err := engine.Get(&user)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(user)
}

func find(t *testing.T) {
	users := make([]Userinfo, 0)

	err := engine.Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func findMap(t *testing.T) {
	users := make(map[int64]Userinfo)

	err := engine.Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func count(t *testing.T) {
	user := Userinfo{Departname: "dev"}
	total, err := engine.Count(&user)
	if err != nil {
		t.Error(err)
	}
	fmt.Printf("Total %d records!!!", total)
}

func where(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.Where("id > ?", 2).Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func in(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.In("id", 1, 2, 3).Find(&users)
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(users)

	ids := []interface{}{1, 2, 3}
	err = engine.Where("id > ?", 2).In("id", ids...).Find(&users)
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(users)
}

func limit(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.Limit(2, 1).Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func order(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.OrderBy("id desc").Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func join(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.Join("LEFT", "userdetail", "userinfo.id=userdetail.id").Find(&users)
	if err != nil {
		t.Error(err)
	}
}

func having(t *testing.T) {
	users := make([]Userinfo, 0)
	err := engine.GroupBy("username").Having("username='xlw'").Find(&users)
	if err != nil {
		t.Error(err)
	}
	fmt.Println(users)
}

func transaction(t *testing.T) {
	counter := func() {
		total, err := engine.Count(&Userinfo{})
		if err != nil {
			t.Error(err)
		}
		fmt.Printf("----now total %v records\n", total)
	}

	counter()
	defer counter()
	session, err := engine.MakeSession()
	defer session.Close()
	if err != nil {
		t.Error(err)
		return
	}

	session.Begin()
	//session.IsAutoRollback = false
	user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
	_, err = session.Insert(&user1)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}
	user2 := Userinfo{Username: "yyy"}
	_, err = session.Where("uid = ?", 0).Update(&user2)
	if err != nil {
		session.Rollback()
		fmt.Println(err)
		//t.Error(err)
		return
	}

	_, err = session.Delete(&user2)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}

	err = session.Commit()
	if err != nil {
		t.Error(err)
		return
	}
}

func combineTransaction(t *testing.T) {
	counter := func() {
		total, err := engine.Count(&Userinfo{})
		if err != nil {
			t.Error(err)
		}
		fmt.Printf("----now total %v records\n", total)
	}

	counter()
	defer counter()
	session, err := engine.MakeSession()
	defer session.Close()
	if err != nil {
		t.Error(err)
		return
	}

	session.Begin()
	//session.IsAutoRollback = false
	user1 := Userinfo{Username: "xiaoxiao2", Departname: "dev", Alias: "lunny", Created: time.Now()}
	_, err = session.Insert(&user1)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}
	user2 := Userinfo{Username: "zzz"}
	_, err = session.Where("id = ?", 0).Update(&user2)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}

	_, err = session.Exec("delete from userinfo where username = ?", user2.Username)
	if err != nil {
		session.Rollback()
		t.Error(err)
		return
	}

	err = session.Commit()
	if err != nil {
		t.Error(err)
		return
	}
}

func table(t *testing.T) {
	engine.Table("user_user").CreateTables(&Userinfo{})
}

func createMultiTables(t *testing.T) {
	session, err := engine.MakeSession()
	defer session.Close()
	if err != nil {
		t.Error(err)
		return
	}

	user := &Userinfo{}
	session.Begin()
	for i := 0; i < 10; i++ {
		err = session.Table(fmt.Sprintf("user_%v", i)).CreateTable(user)
		if err != nil {
			session.Rollback()
			t.Error(err)
			return
		}
	}
	err = session.Commit()
	if err != nil {
		t.Error(err)
	}
}

func tableOp(t *testing.T) {
	user := Userinfo{Username: "tablexiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
	tableName := fmt.Sprintf("user_%v", len(user.Username))
	id, err := engine.Table(tableName).Insert(&user)
	if err != nil {
		t.Error(err)
	}

	err = engine.Table(tableName).Get(&Userinfo{Username: "tablexiao"})
	if err != nil {
		t.Error(err)
	}

	users := make([]Userinfo, 0)
	err = engine.Table(tableName).Find(&users)
	if err != nil {
		t.Error(err)
	}

	_, err = engine.Table(tableName).Id(id).Update(&Userinfo{Username: "tableda"})
	if err != nil {
		t.Error(err)
	}

	_, err = engine.Table(tableName).Id(id).Delete(&Userinfo{})
	if err != nil {
		t.Error(err)
	}
}

func TestMysql(t *testing.T) {
	// You should drop all tables before executing this testing
	engine = xorm.Create("mysql", "root:123@/test?charset=utf8")
	engine.ShowSQL = true

	directCreateTable(t)
	mapper(t)
	insert(t)
	query(t)
	exec(t)
	insertAutoIncr(t)
	insertMulti(t)
	insertTwoTable(t)
	update(t)
	delete(t)
	get(t)
	cascadeGet(t)
	find(t)
	findMap(t)
	count(t)
	where(t)
	in(t)
	limit(t)
	order(t)
	join(t)
	having(t)
	transaction(t)
	combineTransaction(t)
	table(t)
	createMultiTables(t)
	tableOp(t)
}

func TestSqlite(t *testing.T) {
	os.Remove("./test.db")
	engine = xorm.Create("sqlite3", "./test.db")
	engine.ShowSQL = true

	directCreateTable(t)
	mapper(t)
	insert(t)
	query(t)
	exec(t)
	insertAutoIncr(t)
	insertMulti(t)
	insertTwoTable(t)
	update(t)
	delete(t)
	get(t)
	cascadeGet(t)
	find(t)
	findMap(t)
	count(t)
	where(t)
	in(t)
	limit(t)
	order(t)
	join(t)
	having(t)
	transaction(t)
	combineTransaction(t)
	table(t)
	createMultiTables(t)
	tableOp(t)
}
<|endoftext|>


<commit_before>package yobaludum

import (
	"fmt"
	"net/http"
)

func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "YoBA rating!!")
}
<commit_msg>add save players in DS and render template<commit_after>package yobaludum

import (
	"encoding/json"
	"html/template"
	"net/http"
	"strings"
	"time"

	"golang.org/x/net/context"

	"github.com/codegangsta/martini"
	"github.com/codegangsta/martini-contrib/binding"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
)

// PlayerInfo is API object with all info from game
type PlayerInfo struct {
	Name string `json:"name" binding:"required"`
	Time int    `json:"time" binding:"required"`
}

// PlayerData is dataStore object
type PlayerData struct {
	Name        string
	Time        int
	CreatedAt   time.Time
	Country     string
	Region      string
	City        string
	CityLatLong string
	IP          string
}

func appEngine(c martini.Context, r *http.Request) {
	c.Map(appengine.NewContext(r))
}

func init() {
	m := martini.Classic()
	m.Use(appEngine)
	m.Use(martini.Logger())
	m.Get("/", func(c context.Context, res http.ResponseWriter) {
		players, err := getAllPlayers(c)
		if err != nil {
			log.Errorf(c, "Can't load players from DS: %v", err)
		}
		tmplt.Execute(res, players)
	})

	m.Get("/players.json", func(c context.Context, res http.ResponseWriter) {
		if players, err := getAllPlayers(c); err != nil {
			log.Errorf(c, "Can't load players from DS: %v", err)
		} else {
			if b, err := json.Marshal(players); err != nil {
				log.Errorf(c, "Can't convert players to json: %v", err)
			} else {
				res.Write(b)
				return
			}
		}
		res.WriteHeader(404)
	})
	m.Get("/results.json", func(c context.Context, res http.ResponseWriter) {
		if players, err := getAllResults(c); err != nil {
			log.Errorf(c, "Can't load results from DS: %v", err)
		} else {
			if b, err := json.Marshal(players); err != nil {
				log.Errorf(c, "Can't convert results to json: %v", err)
			} else {
				res.Write(b)
				return
			}
		}
		res.WriteHeader(404)
	})
	m.Post("/", binding.Bind(PlayerInfo{}), handlePlayer)

	http.Handle("/", m)
}

func save(c context.Context, data *PlayerData) (err error) {
	id := data.Name + data.IP
	data.CreatedAt = time.Now()
	key := datastore.NewKey(c, "Players", id, 0, nil)
	if oldPlayer, er := findPlayer(c, key); er != nil {
		log.Infof(c, "Saving Player[%s]=%v", id, data)
		_, err = datastore.Put(c, key, data)
	} else {
		if oldPlayer.Time > data.Time {
			log.Infof(c, "Updating Player[%s]=%v", id, data)
			_, err = datastore.Put(c, key, data)
		}
	}

	keyResults := datastore.NewIncompleteKey(c, "Results", nil)
	datastore.Put(c, keyResults, data)

	return
}

func findPlayer(c context.Context, key *datastore.Key) (*PlayerData, error) {
	data := new(PlayerData)
	if err := datastore.Get(c, key, data); err != nil {
		return new(PlayerData), err
	}
	return data, nil
}

func getAllPlayers(c context.Context) ([]PlayerData, error) {
	q := datastore.NewQuery("Players").Order("Time").Limit(200)
	players := make([]PlayerData, 0, 200)
	_, err := q.GetAll(c, &players)
	return players, err
}

func getAllResults(c context.Context) ([]PlayerData, error) {
	q := datastore.NewQuery("Results").Order("Time").Limit(1000)
	players := make([]PlayerData, 0, 1000)
	_, err := q.GetAll(c, &players)
	return players, err
}

func handlePlayer(c context.Context, data PlayerInfo, w http.ResponseWriter, r *http.Request) {
	player := new(PlayerData)
	player.Country = r.Header.Get("X-AppEngine-Country")
	player.Region = r.Header.Get("X-AppEngine-Region")
	player.City = r.Header.Get("X-AppEngine-City")
	player.CityLatLong = r.Header.Get("X-Appengine-Citylatlong")
	player.Name = data.Name
	player.Time = data.Time
	player.IP = strings.Split(r.RemoteAddr, ":")[0]
	log.Infof(c, "RECEIVE: %v", data)
	log.Infof(c, "SAVE: %v", player)

	if err := save(c, player); err != nil {
		log.Errorf(c, "Can't save player[%v] in DS: %v", player, err)
	}
}

var tmplt = template.Must(template.New("players").Parse(`

    <title>YoBA highscores</title>

					Nickname
					Score
					Country

				{{range .}}

						{{.Name}}
						{{.Time}}
						{{.Country}}

				{{end}}

`))
<|endoftext|>


<commit_before>package main

import (
	"os"
	"testing"

	mft "github.com/estafette/estafette-ci-manifest"
	"github.com/stretchr/testify/assert"
)

var (
	pipelineRunner = NewPipelineRunner(envvarHelper, whenEvaluator, dockerRunner, true)
)

func TestRunStages(t *testing.T) {

	t.Run("ReturnsErrorWhenManifestHasNoStages", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		_, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.NotNil(t, err)
	})

	t.Run("ReturnsResultWithInnerResultForEachStageInManifest", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, 1, len(result.StageResults))
	})

	t.Run("ReturnsResultWithoutErrorsWhenStagesSucceeded", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.False(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithSucceededPipelineResultWhenStagesSucceeded", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "SUCCEEDED", result.StageResults[0].Status)
	})

	t.Run("ReturnsResultWithErrorsWhenStagesFailed", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.True(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithFailedPipelineResultWhenStagesFailed", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "FAILED", result.StageResults[0].Status)
	})

	t.Run("ReturnsResultWithoutErrorsWhenStagesSkipped", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.False(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithSkippedStageResultWhenStagesSkipped", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "SKIPPED", result.StageResults[0].Status)
	})

	t.Run("ReturnsResultForAllStagesWhenFirstStageFails", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep2", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep3", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "FAILED", result.StageResults[0].Status)
		assert.Equal(t, "SKIPPED", result.StageResults[1].Status)
		assert.Equal(t, "SUCCEEDED", result.StageResults[2].Status)
	})

	t.Run("ReturnsResultWithErrorsWhenFirstStageFailsAndSecondSucceeds", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep2", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep3", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.True(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithSucceededPipelineResultWhenStagesSucceededAfterRetrial", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		cmd := "if [ -f retried ]; then rm retried && exit 0; else touch retried && exit 1; fi;"
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestRetryStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Retries: 1, Commands: []string{cmd}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.False(t, result.HasErrors())
	})
}
<commit_msg>add test to show failures on all retries lead to a failed final state<commit_after>package main

import (
	"os"
	"testing"

	mft "github.com/estafette/estafette-ci-manifest"
	"github.com/stretchr/testify/assert"
)

var (
	pipelineRunner = NewPipelineRunner(envvarHelper, whenEvaluator, dockerRunner, true)
)

func TestRunStages(t *testing.T) {

	t.Run("ReturnsErrorWhenManifestHasNoStages", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		_, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.NotNil(t, err)
	})

	t.Run("ReturnsResultWithInnerResultForEachStageInManifest", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, 1, len(result.StageResults))
	})

	t.Run("ReturnsResultWithoutErrorsWhenStagesSucceeded", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.False(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithSucceededPipelineResultWhenStagesSucceeded", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "SUCCEEDED", result.StageResults[0].Status)
	})

	t.Run("ReturnsResultWithErrorsWhenStagesFailed", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.True(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithFailedPipelineResultWhenStagesFailed", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "FAILED", result.StageResults[0].Status)
	})

	t.Run("ReturnsResultWithoutErrorsWhenStagesSkipped", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.False(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithSkippedStageResultWhenStagesSkipped", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "SKIPPED", result.StageResults[0].Status)
	})

	t.Run("ReturnsResultForAllStagesWhenFirstStageFails", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep2", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep3", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.Equal(t, "FAILED", result.StageResults[0].Status)
		assert.Equal(t, "SKIPPED", result.StageResults[1].Status)
		assert.Equal(t, "SUCCEEDED", result.StageResults[2].Status)
	})

	t.Run("ReturnsResultWithErrorsWhenFirstStageFailsAndSecondSucceeds", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 1"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep2", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'succeeded'"})
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestStep3", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Commands: []string{"exit 0"}, When: "status == 'failed'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.True(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithoutErrorsWhenStagesSucceededAfterRetrial", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		cmd := "if [ -f retried ]; then rm retried && exit 0; else touch retried && exit 1; fi;"
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestRetryStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Retries: 1, Commands: []string{cmd}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.False(t, result.HasErrors())
	})

	t.Run("ReturnsResultWithErrorsWhenStagesFailedAfterRetrial", func(t *testing.T) {

		envvarHelper.unsetEstafetteEnvvars()
		envvarHelper.setEstafetteEnv("ESTAFETTE_BUILD_STATUS", "succeeded")
		cmd := "exit 1"
		manifest := &mft.EstafetteManifest{}
		manifest.Stages = append(manifest.Stages, &mft.EstafetteStage{Name: "TestRetryStep", ContainerImage: "busybox:latest", Shell: "/bin/sh", WorkingDirectory: "/estafette-work", Retries: 1, Commands: []string{cmd}, When: "status == 'succeeded'"})
		envvars := map[string]string{}
		dir, _ := os.Getwd()

		// act
		result, err := pipelineRunner.runStages(manifest.Stages, dir, envvars)

		assert.Nil(t, err)
		assert.True(t, result.HasErrors())
	})
}
<|endoftext|>