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

// Parse Plan 9 timezone(2) files.

package time

import (
	"errors"
	"runtime"
	"syscall"
)

func isSpace(r rune) bool {
	return r == ' ' || r == '\t' || r == '\n'
}

// Copied from strings to avoid a dependency.
func fields(s string) []string {
	// First count the fields.
	n := 0
	inField := false
	for _, rune := range s {
		wasInField := inField
		inField = !isSpace(rune)
		if inField && !wasInField {
			n++
		}
	}

	// Now create them.
	a := make([]string, n)
	na := 0
	fieldStart := -1 // Set to -1 when looking for start of field.
	for i, rune := range s {
		if isSpace(rune) {
			if fieldStart >= 0 {
				a[na] = s[fieldStart:i]
				na++
				fieldStart = -1
			}
		} else if fieldStart == -1 {
			fieldStart = i
		}
	}
	if fieldStart >= 0 { // Last field might end at EOF.
		a[na] = s[fieldStart:]
	}
	return a
}

func loadZoneDataPlan9(s string) (l *Location, err error) {
	f := fields(s)
	if len(f) < 4 {
		if len(f) == 2 && f[0] == "GMT" {
			return UTC, nil
		}
		return nil, badData
	}

	var zones [2]zone

	// standard timezone offset
	o, err := atoi(f[1])
	if err != nil {
		return nil, badData
	}
	zones[0] = zone{name: f[0], offset: o, isDST: false}

	// alternate timezone offset
	o, err = atoi(f[3])
	if err != nil {
		return nil, badData
	}
	zones[1] = zone{name: f[2], offset: o, isDST: true}

	// transition time pairs
	var tx []zoneTrans
	f = f[4:]
	for i := 0; i < len(f); i++ {
		zi := 0
		if i%2 == 0 {
			zi = 1
		}
		t, err := atoi(f[i])
		if err != nil {
			return nil, badData
		}
		t -= zones[0].offset
		tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)})
	}

	// Committed to succeed.
	l = &Location{zone: zones[:], tx: tx}

	// Fill in the cache with information about right now,
	// since that will be the most common lookup.
	sec, _ := now()
	for i := range tx {
		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
			l.cacheStart = tx[i].when
			l.cacheEnd = omega
			if i+1 < len(tx) {
				l.cacheEnd = tx[i+1].when
			}
			l.cacheZone = &l.zone[tx[i].index]
		}
	}

	return l, nil
}

func loadZoneFilePlan9(name string) (*Location, error) {
	b, err := readFile(name)
	if err != nil {
		return nil, err
	}
	return loadZoneDataPlan9(string(b))
}

func initTestingZone() {
	z, err := loadLocation("America/Los_Angeles")
	if err != nil {
		panic("cannot load America/Los_Angeles for testing: " + err.Error())
	}
	z.name = "Local"
	localLoc = *z
}

func initLocal() {
	t, ok := syscall.Getenv("timezone")
	if ok {
		if z, err := loadZoneDataPlan9(t); err == nil {
			localLoc = *z
			return
		}
	} else {
		if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil {
			localLoc = *z
			localLoc.name = "Local"
			return
		}
	}

	// Fall back to UTC.
	localLoc.name = "UTC"
}

func loadLocation(name string) (*Location, error) {
	z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
	if err != nil {
		return nil, err
	}
	z.name = name
	return z, nil
}

func forceZipFileForTesting(zipOnly bool) {
	// We only use the zip file anyway.
}
<commit_msg>Build fix for plan9 after 8bf13838eb21.<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Parse Plan 9 timezone(2) files.

package time

import (
	"runtime"
	"syscall"
)

func isSpace(r rune) bool {
	return r == ' ' || r == '\t' || r == '\n'
}

// Copied from strings to avoid a dependency.
func fields(s string) []string {
	// First count the fields.
	n := 0
	inField := false
	for _, rune := range s {
		wasInField := inField
		inField = !isSpace(rune)
		if inField && !wasInField {
			n++
		}
	}

	// Now create them.
	a := make([]string, n)
	na := 0
	fieldStart := -1 // Set to -1 when looking for start of field.
	for i, rune := range s {
		if isSpace(rune) {
			if fieldStart >= 0 {
				a[na] = s[fieldStart:i]
				na++
				fieldStart = -1
			}
		} else if fieldStart == -1 {
			fieldStart = i
		}
	}
	if fieldStart >= 0 { // Last field might end at EOF.
		a[na] = s[fieldStart:]
	}
	return a
}

func loadZoneDataPlan9(s string) (l *Location, err error) {
	f := fields(s)
	if len(f) < 4 {
		if len(f) == 2 && f[0] == "GMT" {
			return UTC, nil
		}
		return nil, badData
	}

	var zones [2]zone

	// standard timezone offset
	o, err := atoi(f[1])
	if err != nil {
		return nil, badData
	}
	zones[0] = zone{name: f[0], offset: o, isDST: false}

	// alternate timezone offset
	o, err = atoi(f[3])
	if err != nil {
		return nil, badData
	}
	zones[1] = zone{name: f[2], offset: o, isDST: true}

	// transition time pairs
	var tx []zoneTrans
	f = f[4:]
	for i := 0; i < len(f); i++ {
		zi := 0
		if i%2 == 0 {
			zi = 1
		}
		t, err := atoi(f[i])
		if err != nil {
			return nil, badData
		}
		t -= zones[0].offset
		tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)})
	}

	// Committed to succeed.
	l = &Location{zone: zones[:], tx: tx}

	// Fill in the cache with information about right now,
	// since that will be the most common lookup.
	sec, _ := now()
	for i := range tx {
		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
			l.cacheStart = tx[i].when
			l.cacheEnd = omega
			if i+1 < len(tx) {
				l.cacheEnd = tx[i+1].when
			}
			l.cacheZone = &l.zone[tx[i].index]
		}
	}

	return l, nil
}

func loadZoneFilePlan9(name string) (*Location, error) {
	b, err := readFile(name)
	if err != nil {
		return nil, err
	}
	return loadZoneDataPlan9(string(b))
}

func initTestingZone() {
	z, err := loadLocation("America/Los_Angeles")
	if err != nil {
		panic("cannot load America/Los_Angeles for testing: " + err.Error())
	}
	z.name = "Local"
	localLoc = *z
}

func initLocal() {
	t, ok := syscall.Getenv("timezone")
	if ok {
		if z, err := loadZoneDataPlan9(t); err == nil {
			localLoc = *z
			return
		}
	} else {
		if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil {
			localLoc = *z
			localLoc.name = "Local"
			return
		}
	}

	// Fall back to UTC.
	localLoc.name = "UTC"
}

func loadLocation(name string) (*Location, error) {
	z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
	if err != nil {
		return nil, err
	}
	z.name = name
	return z, nil
}

func forceZipFileForTesting(zipOnly bool) {
	// We only use the zip file anyway.
}
<|endoftext|>


<commit_before>package helpers

import (
	"errors"
	"github.com/koding/logging"
	"net/http"
	"net/url"
	"socialapi/models"
	"strconv"

	"github.com/jinzhu/gorm"
)

// type ApiResponse struct {
// 	Status   int
// 	Header   http.Header
// 	Response interface{}
// 	Error    error
// }

// type ApiRequest struct {
// 	URL     *url.URL
// 	Header  http.Header
// 	Request interface{}
// }

// func NewResponse() *ApiResponse {
// 	return &ApiResponse{
// 		Status:   http.StatusOK,
// 		Header:   nil,
// 		Response: nil,
// 		Error:    nil,
// 	}
// }

var Log logging.Logger

func NewBadRequestResponse(err error) (int, http.Header, interface{}, error) {
	if err == nil {
		err = errors.New("Request is not valid")
	}
	if Log != nil {
		Log.Error("Bad Request: %s", err)
	}

	return http.StatusBadRequest, nil, nil, err
}

func HandleResultAndError(res interface{}, err error) (int, http.Header, interface{}, error) {
	if err != nil {
		if err == gorm.RecordNotFound {
			return NewNotFoundResponse()
		}
		return NewBadRequestResponse(err)
	}
	return NewOKResponse(res)
}

func NewOKResponse(res interface{}) (int, http.Header, interface{}, error) {
	return http.StatusOK, nil, res, nil
}

func NewNotFoundResponse() (int, http.Header, interface{}, error) {
	return http.StatusNotFound, nil, nil, errors.New("Data not found")
}

func NewDeletedResponse() (int, http.Header, interface{}, error) {
	return http.StatusAccepted, nil, nil, nil
}

func NewDefaultOKResponse() (int, http.Header, interface{}, error) {
	res := map[string]interface{}{
		"status": true,
	}

	return http.StatusOK, nil, res, nil
}

func GetId(u *url.URL) (int64, error) {
	return strconv.ParseInt(u.Query().Get("id"), 10, 64)
}

func GetURIInt64(u *url.URL, queryParam string) (int64, error) {
	return strconv.ParseInt(u.Query().Get(queryParam), 10, 64)
}

func GetQuery(u *url.URL) *models.Query {
	return models.NewQuery().MapURL(u).SetDefaults()
}
<commit_msg>Social: Responsehelper now uses a[i/helper logger<commit_after>package helpers

import (
	"errors"
	"github.com/koding/api/helpers"
	"net/http"
	"net/url"
	"socialapi/models"
	"strconv"

	"github.com/jinzhu/gorm"
)

// type ApiResponse struct {
// 	Status   int
// 	Header   http.Header
// 	Response interface{}
// 	Error    error
// }

// type ApiRequest struct {
// 	URL     *url.URL
// 	Header  http.Header
// 	Request interface{}
// }

// func NewResponse() *ApiResponse {
// 	return &ApiResponse{
// 		Status:   http.StatusOK,
// 		Header:   nil,
// 		Response: nil,
// 		Error:    nil,
// 	}
// }
func NewBadRequestResponse(err error) (int, http.Header, interface{}, error) {
	if err == nil {
		err = errors.New("Request is not valid")
	}

	helpers.MustGetLogger().Error("Bad Request: %s", err)

	return http.StatusBadRequest, nil, nil, err
}

func HandleResultAndError(res interface{}, err error) (int, http.Header, interface{}, error) {
	if err != nil {
		if err == gorm.RecordNotFound {
			return NewNotFoundResponse()
		}
		return NewBadRequestResponse(err)
	}
	return NewOKResponse(res)
}

func NewOKResponse(res interface{}) (int, http.Header, interface{}, error) {
	return http.StatusOK, nil, res, nil
}

func NewNotFoundResponse() (int, http.Header, interface{}, error) {
	return http.StatusNotFound, nil, nil, errors.New("Data not found")
}

func NewDeletedResponse() (int, http.Header, interface{}, error) {
	return http.StatusAccepted, nil, nil, nil
}

func NewDefaultOKResponse() (int, http.Header, interface{}, error) {
	res := map[string]interface{}{
		"status": true,
	}

	return http.StatusOK, nil, res, nil
}

func GetId(u *url.URL) (int64, error) {
	return strconv.ParseInt(u.Query().Get("id"), 10, 64)
}

func GetURIInt64(u *url.URL, queryParam string) (int64, error) {
	return strconv.ParseInt(u.Query().Get(queryParam), 10, 64)
}

func GetQuery(u *url.URL) *models.Query {
	return models.NewQuery().MapURL(u).SetDefaults()
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Matt Tracy (matt@cockroachlabs.com)

package storage

import (
	"encoding/json"
	"time"

	"github.com/cockroachdb/cockroach/internal/client"
	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/pkg/errors"
)

// TODO(mrtracy): All of this logic should probably be moved into the SQL
// package; there are going to be additional event log tables which will not be
// strongly associated with a store, and it would be better to keep event log
// tables close together in the code.

// RangeEventLogType describes a specific event type recorded in the range log
// table.
type RangeEventLogType string

const (
	// RangeEventLogSplit is the event type recorded when a range splits.
	RangeEventLogSplit RangeEventLogType = "split"
	// RangeEventLogAdd is the event type recorded when a range adds a
	// new replica.
	RangeEventLogAdd RangeEventLogType = "add"
	// RangeEventLogRemove is the event type recorded when a range removes a
	// replica.
	RangeEventLogRemove RangeEventLogType = "remove"
)

// RangeEventTableSchema defines the schema of the event log table. It is
// currently envisioned as a wide table; many different event types can be
// recorded to the table.
const RangeEventTableSchema = `
CREATE TABLE system.rangelog (
  timestamp     TIMESTAMP  NOT NULL,
  rangeID       INT        NOT NULL,
  storeID       INT        NOT NULL,
  eventType     STRING     NOT NULL,
  otherRangeID  INT,
  info          STRING,
  uniqueID      INT        DEFAULT unique_rowid(),
  PRIMARY KEY (timestamp, uniqueID)
);`

type rangeLogEvent struct {
	timestamp    time.Time
	rangeID      roachpb.RangeID
	storeID      roachpb.StoreID
	eventType    RangeEventLogType
	otherRangeID *roachpb.RangeID
	info         *string
}

func (s *Store) insertRangeLogEvent(txn *client.Txn, event rangeLogEvent) error {
	// Record range log event to console log.
	var info string
	if event.info != nil {
		info = *event.info
	}
	log.Infof(txn.Context, "Range Event: %q, range: %d, info: %s",
		event.eventType,
		event.rangeID,
		info)

	const insertEventTableStmt = `
INSERT INTO system.rangelog (
  timestamp, rangeID, storeID, eventType, otherRangeID, info
)
VALUES(
  $1, $2, $3, $4, $5, $6
)
`
	args := []interface{}{
		event.timestamp,
		event.rangeID,
		event.storeID,
		event.eventType,
		nil, // otherRangeID
		nil, // info
	}
	if event.otherRangeID != nil {
		args[4] = *event.otherRangeID
	}
	if event.info != nil {
		args[5] = *event.info
	}

	// Update range event metrics. We do this close to the insertion of the
	// corresponding range log entry to reduce potential skew between metrics and
	// range log.
	switch event.eventType {
	case RangeEventLogSplit:
		s.metrics.RangeSplits.Inc(1)
	case RangeEventLogAdd:
		s.metrics.RangeAdds.Inc(1)
	case RangeEventLogRemove:
		s.metrics.RangeRemoves.Inc(1)
	}

	rows, err := s.ctx.SQLExecutor.ExecuteStatementInTransaction(txn, insertEventTableStmt, args...)
	if err != nil {
		return err
	}
	if rows != 1 {
		return errors.Errorf("%d rows affected by log insertion; expected exactly one row affected.", rows)
	}
	return nil
}

// logSplit logs a range split event into the event table. The affected range is
// the range which previously existed and is being split in half; the "other"
// range is the new range which is being created.
// TODO(mrtracy): There are several different reasons that a replica split
// could occur, and that information should be logged.
func (s *Store) logSplit(txn *client.Txn, updatedDesc, newDesc roachpb.RangeDescriptor) error {
	if !s.ctx.LogRangeEvents {
		return nil
	}
	info := struct {
		UpdatedDesc roachpb.RangeDescriptor
		NewDesc     roachpb.RangeDescriptor
	}{updatedDesc, newDesc}
	infoBytes, err := json.Marshal(info)
	if err != nil {
		return err
	}
	infoStr := string(infoBytes)
	return s.insertRangeLogEvent(txn, rangeLogEvent{
		timestamp:    selectEventTimestamp(s, txn.Proto.Timestamp),
		rangeID:      updatedDesc.RangeID,
		eventType:    RangeEventLogSplit,
		storeID:      s.StoreID(),
		otherRangeID: &newDesc.RangeID,
		info:         &infoStr,
	})
}

// logChange logs a replica change event, which represents a replica being added
// to or removed from a range.
// TODO(mrtracy): There are several different reasons that a replica change
// could occur, and that information should be logged.
func (s *Store) logChange(txn *client.Txn, changeType roachpb.ReplicaChangeType, replica roachpb.ReplicaDescriptor,
	desc roachpb.RangeDescriptor) error {
	if !s.ctx.LogRangeEvents {
		return nil
	}

	var logType RangeEventLogType
	var infoStruct interface{}
	switch changeType {
	case roachpb.ADD_REPLICA:
		logType = RangeEventLogAdd
		infoStruct = struct {
			AddReplica  roachpb.ReplicaDescriptor
			UpdatedDesc roachpb.RangeDescriptor
		}{replica, desc}
	case roachpb.REMOVE_REPLICA:
		logType = RangeEventLogRemove
		infoStruct = struct {
			RemovedReplica roachpb.ReplicaDescriptor
			UpdatedDesc    roachpb.RangeDescriptor
		}{replica, desc}
	default:
		return errors.Errorf("unknown replica change type %s", changeType)
	}

	infoBytes, err := json.Marshal(infoStruct)
	if err != nil {
		return err
	}
	infoStr := string(infoBytes)
	return s.insertRangeLogEvent(txn, rangeLogEvent{
		timestamp: selectEventTimestamp(s, txn.Proto.Timestamp),
		rangeID:   desc.RangeID,
		eventType: logType,
		storeID:   s.StoreID(),
		info:      &infoStr,
	})
}

// selectEventTimestamp selects a timestamp for this log message. If the
// transaction this event is being written in has a non-zero timestamp, then that
// timestamp should be used; otherwise, the store's physical clock is used.
// This helps with testing; in normal usage, the logging of an event will never
// be the first action in the transaction, and thus the transaction will have an
// assigned database timestamp. However, in the case of our tests log events
// *are* the first action in a transaction, and we must elect to use the store's
// physical time instead.
func selectEventTimestamp(s *Store, input hlc.Timestamp) time.Time {
	if input == hlc.ZeroTimestamp {
		return s.Clock().PhysicalTime()
	}
	return input.GoTime()
}
<commit_msg>storage: move range-event logs under V(1)<commit_after>// Copyright 2015 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Matt Tracy (matt@cockroachlabs.com)

package storage

import (
	"encoding/json"
	"time"

	"github.com/cockroachdb/cockroach/internal/client"
	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/pkg/errors"
)

// TODO(mrtracy): All of this logic should probably be moved into the SQL
// package; there are going to be additional event log tables which will not be
// strongly associated with a store, and it would be better to keep event log
// tables close together in the code.

// RangeEventLogType describes a specific event type recorded in the range log
// table.
type RangeEventLogType string

const (
	// RangeEventLogSplit is the event type recorded when a range splits.
	RangeEventLogSplit RangeEventLogType = "split"
	// RangeEventLogAdd is the event type recorded when a range adds a
	// new replica.
	RangeEventLogAdd RangeEventLogType = "add"
	// RangeEventLogRemove is the event type recorded when a range removes a
	// replica.
	RangeEventLogRemove RangeEventLogType = "remove"
)

// RangeEventTableSchema defines the schema of the event log table. It is
// currently envisioned as a wide table; many different event types can be
// recorded to the table.
const RangeEventTableSchema = `
CREATE TABLE system.rangelog (
  timestamp     TIMESTAMP  NOT NULL,
  rangeID       INT        NOT NULL,
  storeID       INT        NOT NULL,
  eventType     STRING     NOT NULL,
  otherRangeID  INT,
  info          STRING,
  uniqueID      INT        DEFAULT unique_rowid(),
  PRIMARY KEY (timestamp, uniqueID)
);`

type rangeLogEvent struct {
	timestamp    time.Time
	rangeID      roachpb.RangeID
	storeID      roachpb.StoreID
	eventType    RangeEventLogType
	otherRangeID *roachpb.RangeID
	info         *string
}

func (s *Store) insertRangeLogEvent(txn *client.Txn, event rangeLogEvent) error {
	// Record range log event to console log.
	var info string
	if event.info != nil {
		info = *event.info
	}
	if log.V(1) {
		log.Infof(txn.Context, "Range Event: %q, range: %d, info: %s",
			event.eventType,
			event.rangeID,
			info)
	}

	const insertEventTableStmt = `
INSERT INTO system.rangelog (
  timestamp, rangeID, storeID, eventType, otherRangeID, info
)
VALUES(
  $1, $2, $3, $4, $5, $6
)
`
	args := []interface{}{
		event.timestamp,
		event.rangeID,
		event.storeID,
		event.eventType,
		nil, // otherRangeID
		nil, // info
	}
	if event.otherRangeID != nil {
		args[4] = *event.otherRangeID
	}
	if event.info != nil {
		args[5] = *event.info
	}

	// Update range event metrics. We do this close to the insertion of the
	// corresponding range log entry to reduce potential skew between metrics and
	// range log.
	switch event.eventType {
	case RangeEventLogSplit:
		s.metrics.RangeSplits.Inc(1)
	case RangeEventLogAdd:
		s.metrics.RangeAdds.Inc(1)
	case RangeEventLogRemove:
		s.metrics.RangeRemoves.Inc(1)
	}

	rows, err := s.ctx.SQLExecutor.ExecuteStatementInTransaction(txn, insertEventTableStmt, args...)
	if err != nil {
		return err
	}
	if rows != 1 {
		return errors.Errorf("%d rows affected by log insertion; expected exactly one row affected.", rows)
	}
	return nil
}

// logSplit logs a range split event into the event table. The affected range is
// the range which previously existed and is being split in half; the "other"
// range is the new range which is being created.
// TODO(mrtracy): There are several different reasons that a replica split
// could occur, and that information should be logged.
func (s *Store) logSplit(txn *client.Txn, updatedDesc, newDesc roachpb.RangeDescriptor) error {
	if !s.ctx.LogRangeEvents {
		return nil
	}
	info := struct {
		UpdatedDesc roachpb.RangeDescriptor
		NewDesc     roachpb.RangeDescriptor
	}{updatedDesc, newDesc}
	infoBytes, err := json.Marshal(info)
	if err != nil {
		return err
	}
	infoStr := string(infoBytes)
	return s.insertRangeLogEvent(txn, rangeLogEvent{
		timestamp:    selectEventTimestamp(s, txn.Proto.Timestamp),
		rangeID:      updatedDesc.RangeID,
		eventType:    RangeEventLogSplit,
		storeID:      s.StoreID(),
		otherRangeID: &newDesc.RangeID,
		info:         &infoStr,
	})
}

// logChange logs a replica change event, which represents a replica being added
// to or removed from a range.
// TODO(mrtracy): There are several different reasons that a replica change
// could occur, and that information should be logged.
func (s *Store) logChange(txn *client.Txn, changeType roachpb.ReplicaChangeType, replica roachpb.ReplicaDescriptor,
	desc roachpb.RangeDescriptor) error {
	if !s.ctx.LogRangeEvents {
		return nil
	}

	var logType RangeEventLogType
	var infoStruct interface{}
	switch changeType {
	case roachpb.ADD_REPLICA:
		logType = RangeEventLogAdd
		infoStruct = struct {
			AddReplica  roachpb.ReplicaDescriptor
			UpdatedDesc roachpb.RangeDescriptor
		}{replica, desc}
	case roachpb.REMOVE_REPLICA:
		logType = RangeEventLogRemove
		infoStruct = struct {
			RemovedReplica roachpb.ReplicaDescriptor
			UpdatedDesc    roachpb.RangeDescriptor
		}{replica, desc}
	default:
		return errors.Errorf("unknown replica change type %s", changeType)
	}

	infoBytes, err := json.Marshal(infoStruct)
	if err != nil {
		return err
	}
	infoStr := string(infoBytes)
	return s.insertRangeLogEvent(txn, rangeLogEvent{
		timestamp: selectEventTimestamp(s, txn.Proto.Timestamp),
		rangeID:   desc.RangeID,
		eventType: logType,
		storeID:   s.StoreID(),
		info:      &infoStr,
	})
}

// selectEventTimestamp selects a timestamp for this log message. If the
// transaction this event is being written in has a non-zero timestamp, then that
// timestamp should be used; otherwise, the store's physical clock is used.
// This helps with testing; in normal usage, the logging of an event will never
// be the first action in the transaction, and thus the transaction will have an
// assigned database timestamp. However, in the case of our tests log events
// *are* the first action in a transaction, and we must elect to use the store's
// physical time instead.
func selectEventTimestamp(s *Store, input hlc.Timestamp) time.Time {
	if input == hlc.ZeroTimestamp {
		return s.Clock().PhysicalTime()
	}
	return input.GoTime()
}
<|endoftext|>


<commit_before>package repositories

import (
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"log"
	"net/http"
	"os"
)

var sessionStore sessions.Store

// Initialize the session store with authentication
// and encryption keys.
//
// Keys are read from the environment variables
// SESSION_AUTH_KEY and SESSION_ENCRYPTION_KEY
// If not set, temporary keys will be used.
//
// Using temporary keys will invalidate all sessions
// when the server restarts.
func EnableSessions() {
	auth_key := []byte(os.Getenv("SESSION_AUTH_KEY"))

	if len(auth_key) == 0 {
		log.Println("Using temporary authentication key for session")
		auth_key = securecookie.GenerateRandomKey(64)
	}

	encryption_key := []byte(os.Getenv("SESSION_ENCRYPTION_KEY"))

	if len(encryption_key) == 0 {
		log.Println("Using temporary encryption key for session")
		encryption_key = securecookie.GenerateRandomKey(32)
	}

	sessionStore = sessions.NewCookieStore(auth_key, encryption_key)
}

type SessionRepository interface {
	Value(key string) interface{}
	SetValue(key string, value interface{})
	Save() error
}

func Session(res http.ResponseWriter, req *http.Request) SessionRepository {
	session, _ := sessionStore.Get(req, "bones_session")
	return &CookieSessionRepository{session, res, req}
}

type CookieSessionRepository struct {
	session        *sessions.Session
	responseWriter http.ResponseWriter
	request        *http.Request
}

func (s *CookieSessionRepository) Value(key string) interface{} {
	return s.session.Values[key]
}

func (s *CookieSessionRepository) SetValue(key string, value interface{}) {
	s.session.Values[key] = value
}

func (s *CookieSessionRepository) Save() error {
	return s.session.Save(s.request, s.responseWriter)
}
<commit_msg>Add Clear method to SessionRepository<commit_after>package repositories

import (
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"log"
	"net/http"
	"os"
)

var sessionStore sessions.Store

// Initialize the session store with authentication
// and encryption keys.
//
// Keys are read from the environment variables
// SESSION_AUTH_KEY and SESSION_ENCRYPTION_KEY
// If not set, temporary keys will be used.
//
// Using temporary keys will invalidate all sessions
// when the server restarts.
func EnableSessions() {
	auth_key := []byte(os.Getenv("SESSION_AUTH_KEY"))

	if len(auth_key) == 0 {
		log.Println("Using temporary authentication key for session")
		auth_key = securecookie.GenerateRandomKey(64)
	}

	encryption_key := []byte(os.Getenv("SESSION_ENCRYPTION_KEY"))

	if len(encryption_key) == 0 {
		log.Println("Using temporary encryption key for session")
		encryption_key = securecookie.GenerateRandomKey(32)
	}

	sessionStore = sessions.NewCookieStore(auth_key, encryption_key)
}

type SessionRepository interface {
	Value(key string) interface{}
	SetValue(key string, value interface{})
	Save() error
	Clear()
}

func Session(res http.ResponseWriter, req *http.Request) SessionRepository {
	session, _ := sessionStore.Get(req, "bones_session")
	return &CookieSessionRepository{session, res, req}
}

type CookieSessionRepository struct {
	session        *sessions.Session
	responseWriter http.ResponseWriter
	request        *http.Request
}

func (s *CookieSessionRepository) Value(key string) interface{} {
	return s.session.Values[key]
}

func (s *CookieSessionRepository) SetValue(key string, value interface{}) {
	s.session.Values[key] = value
}

func (s *CookieSessionRepository) Save() error {
	return s.session.Save(s.request, s.responseWriter)
}

func (s *CookieSessionRepository) Clear() {
	s.session.Values = nil
}
<|endoftext|>


<commit_before><commit_msg>Remove SetDebug<commit_after><|endoftext|>


<commit_before>package windows_test

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"net/http"

	"github.com/cloudfoundry/bosh-agent/integration/windows/utils"
	"github.com/masterzen/winrm"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"testing"
	"text/template"
)

var (
	VagrantProvider             = os.Getenv("VAGRANT_PROVIDER")
	OsVersion                   = getOsVersion()
	AgentPublicIP, NATSPublicIP string
	dirname                     = filepath.Join(
		os.Getenv("GOPATH"),
		"src/github.com/cloudfoundry/bosh-agent/integration/windows/fixtures",
	)
	agent *WindowsEnvironment
)

type BoshAgentSettings struct {
	NatsPrivateIP       string
	EphemeralDiskConfig string
}

func getOsVersion() string {
	osVersion := os.Getenv("WINDOWS_OS_VERSION")
	if osVersion == "" {
		osVersion = "2012R2"
	}

	return osVersion
}

func TestWindows(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Windows Suite")
}

func tarFixtures(fixturesDir, filename string) error {
	fixtures := []string{
		"service_wrapper.xml",
		"service_wrapper.exe",
		"job-service-wrapper.exe",
		"bosh-blobstore-dav.exe",
		"bosh-agent.exe",
		"pipe.exe",
		"agent-configuration/agent.json",
		"agent-configuration/root-partition-agent.json",
		"agent-configuration/root-partition-agent-ephemeral-disabled.json",
		"agent-configuration/root-disk-settings.json",
		"agent-configuration/second-disk-settings.json",
		"agent-configuration/second-disk-digit-settings.json",
		"agent-configuration/third-disk-settings.json",
		"psFixture/psFixture.psd1",
		"psFixture/psFixture.psm1",
	}

	archive, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer archive.Close()

	gzipWriter := gzip.NewWriter(archive)
	tarWriter := tar.NewWriter(gzipWriter)

	for _, name := range fixtures {
		path := filepath.Join(fixturesDir, name)
		fi, err := os.Stat(path)
		if err != nil {
			return err
		}

		hdr, err := tar.FileInfoHeader(fi, "")
		if err != nil {
			return err
		}
		hdr.Name = name

		if err := tarWriter.WriteHeader(hdr); err != nil {
			return err
		}

		f, err := os.Open(path)
		if err != nil {
			return err
		}
		defer f.Close()

		if _, err := io.Copy(tarWriter, f); err != nil {
			return err
		}
	}

	if err := tarWriter.Close(); err != nil {
		return err
	}

	return gzipWriter.Close()
}

var _ = BeforeSuite(func() {
	if os.Getenv("GOPATH") == "" {
		Fail("Environment variable GOPATH not set", 1)
	}

	if err := utils.BuildAgent(); err != nil {
		Fail(fmt.Sprintln("Could not build the bosh-agent project.\nError is:", err))
	}

	err := utils.StartVagrant("nats", VagrantProvider, OsVersion)
	natsPrivateIP, err := utils.RetrievePrivateIP("nats")
	Expect(err).NotTo(HaveOccurred())
	Expect(natsPrivateIP).NotTo(BeEmpty(), "Couldn't retrieve NATS private IP")

	templateSettings(natsPrivateIP, `""`, "root-disk-settings.json")
	templateSettings(natsPrivateIP, `"/dev/sdb"`, "second-disk-settings.json")
	templateSettings(natsPrivateIP, `"1"`, "second-disk-digit-settings.json")
	templateSettings(natsPrivateIP, `"/dev/sdc"`, "third-disk-settings.json")

	filename := filepath.Join(dirname, "fixtures.tgz")
	if err := tarFixtures(dirname, filename); err != nil {
		Fail(fmt.Sprintln("Creating fixtures TGZ::", err))
	}

	err = utils.StartVagrant("agent", VagrantProvider, OsVersion)

	AgentPublicIP, err = utils.RetrievePublicIP("agent")
	Expect(err).NotTo(HaveOccurred())

	NATSPublicIP, err = utils.RetrievePublicIP("nats")
	Expect(err).NotTo(HaveOccurred())

	if err != nil {
		Fail(fmt.Sprintln("Could not setup and run vagrant.\nError is:", err))
	}

	endpoint := winrm.NewEndpoint(AgentPublicIP, 5985, false, false, nil, nil, nil, 0)
	client, err := winrm.NewClientWithParameters(
		endpoint,
		"vagrant",
		"Password123!",
		winrm.NewParameters("PT5M", "en-US", 153600),
	)
	Expect(err).NotTo(HaveOccurred())

	agent = &WindowsEnvironment{
		Client: client,
	}

	// We do this so that both 2012R2 and 1709 run ephemeral disk tests against raw disks.
	// 2012R2 additional disks start formatted on AWS for some reason.
	agent.EnsureDiskCleared("1")
	agent.EnsureDiskCleared("2")

	goSourcePath := filepath.Join(dirname, "templates", "go", "go1.7.1.windows-amd64.zip")
	os.RemoveAll(goSourcePath)
	downloadFile(goSourcePath, "https://dl.google.com/go/go1.7.1.windows-amd64.zip")
})

func templateSettings(natsPrivateIP, ephemeralDiskConfig, filename string) {
	agentSettings := BoshAgentSettings{
		NatsPrivateIP:       natsPrivateIP,
		EphemeralDiskConfig: ephemeralDiskConfig,
	}
	settingsTmpl, err := template.ParseFiles(
		filepath.Join(dirname, "templates", "agent-configuration", "settings.json.tmpl"),
	)
	Expect(err).NotTo(HaveOccurred())
	outputFile, err := os.Create(filepath.Join(dirname, "agent-configuration", filename))
	defer outputFile.Close()

	Expect(err).NotTo(HaveOccurred())
	err = settingsTmpl.Execute(outputFile, agentSettings)
	Expect(err).NotTo(HaveOccurred())
}

func downloadFile(localPath, sourceUrl string) error {
	f, err := os.OpenFile(localPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer f.Close()

	res, err := http.Get(sourceUrl)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if _, err := io.Copy(f, res.Body); err != nil {
		return err
	}

	return nil
}
<commit_msg>golint prefers URL<commit_after>package windows_test

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"net/http"

	"github.com/cloudfoundry/bosh-agent/integration/windows/utils"
	"github.com/masterzen/winrm"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"testing"
	"text/template"
)

var (
	VagrantProvider             = os.Getenv("VAGRANT_PROVIDER")
	OsVersion                   = getOsVersion()
	AgentPublicIP, NATSPublicIP string
	dirname                     = filepath.Join(
		os.Getenv("GOPATH"),
		"src/github.com/cloudfoundry/bosh-agent/integration/windows/fixtures",
	)
	agent *WindowsEnvironment
)

type BoshAgentSettings struct {
	NatsPrivateIP       string
	EphemeralDiskConfig string
}

func getOsVersion() string {
	osVersion := os.Getenv("WINDOWS_OS_VERSION")
	if osVersion == "" {
		osVersion = "2012R2"
	}

	return osVersion
}

func TestWindows(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Windows Suite")
}

func tarFixtures(fixturesDir, filename string) error {
	fixtures := []string{
		"service_wrapper.xml",
		"service_wrapper.exe",
		"job-service-wrapper.exe",
		"bosh-blobstore-dav.exe",
		"bosh-agent.exe",
		"pipe.exe",
		"agent-configuration/agent.json",
		"agent-configuration/root-partition-agent.json",
		"agent-configuration/root-partition-agent-ephemeral-disabled.json",
		"agent-configuration/root-disk-settings.json",
		"agent-configuration/second-disk-settings.json",
		"agent-configuration/second-disk-digit-settings.json",
		"agent-configuration/third-disk-settings.json",
		"psFixture/psFixture.psd1",
		"psFixture/psFixture.psm1",
	}

	archive, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer archive.Close()

	gzipWriter := gzip.NewWriter(archive)
	tarWriter := tar.NewWriter(gzipWriter)

	for _, name := range fixtures {
		path := filepath.Join(fixturesDir, name)
		fi, err := os.Stat(path)
		if err != nil {
			return err
		}

		hdr, err := tar.FileInfoHeader(fi, "")
		if err != nil {
			return err
		}
		hdr.Name = name

		if err := tarWriter.WriteHeader(hdr); err != nil {
			return err
		}

		f, err := os.Open(path)
		if err != nil {
			return err
		}
		defer f.Close()

		if _, err := io.Copy(tarWriter, f); err != nil {
			return err
		}
	}

	if err := tarWriter.Close(); err != nil {
		return err
	}

	return gzipWriter.Close()
}

var _ = BeforeSuite(func() {
	if os.Getenv("GOPATH") == "" {
		Fail("Environment variable GOPATH not set", 1)
	}

	if err := utils.BuildAgent(); err != nil {
		Fail(fmt.Sprintln("Could not build the bosh-agent project.\nError is:", err))
	}

	err := utils.StartVagrant("nats", VagrantProvider, OsVersion)
	natsPrivateIP, err := utils.RetrievePrivateIP("nats")
	Expect(err).NotTo(HaveOccurred())
	Expect(natsPrivateIP).NotTo(BeEmpty(), "Couldn't retrieve NATS private IP")

	templateSettings(natsPrivateIP, `""`, "root-disk-settings.json")
	templateSettings(natsPrivateIP, `"/dev/sdb"`, "second-disk-settings.json")
	templateSettings(natsPrivateIP, `"1"`, "second-disk-digit-settings.json")
	templateSettings(natsPrivateIP, `"/dev/sdc"`, "third-disk-settings.json")

	filename := filepath.Join(dirname, "fixtures.tgz")
	if err := tarFixtures(dirname, filename); err != nil {
		Fail(fmt.Sprintln("Creating fixtures TGZ::", err))
	}

	err = utils.StartVagrant("agent", VagrantProvider, OsVersion)

	AgentPublicIP, err = utils.RetrievePublicIP("agent")
	Expect(err).NotTo(HaveOccurred())

	NATSPublicIP, err = utils.RetrievePublicIP("nats")
	Expect(err).NotTo(HaveOccurred())

	if err != nil {
		Fail(fmt.Sprintln("Could not setup and run vagrant.\nError is:", err))
	}

	endpoint := winrm.NewEndpoint(AgentPublicIP, 5985, false, false, nil, nil, nil, 0)
	client, err := winrm.NewClientWithParameters(
		endpoint,
		"vagrant",
		"Password123!",
		winrm.NewParameters("PT5M", "en-US", 153600),
	)
	Expect(err).NotTo(HaveOccurred())

	agent = &WindowsEnvironment{
		Client: client,
	}

	// We do this so that both 2012R2 and 1709 run ephemeral disk tests against raw disks.
	// 2012R2 additional disks start formatted on AWS for some reason.
	agent.EnsureDiskCleared("1")
	agent.EnsureDiskCleared("2")

	goSourcePath := filepath.Join(dirname, "templates", "go", "go1.7.1.windows-amd64.zip")
	os.RemoveAll(goSourcePath)
	downloadFile(goSourcePath, "https://dl.google.com/go/go1.7.1.windows-amd64.zip")
})

func templateSettings(natsPrivateIP, ephemeralDiskConfig, filename string) {
	agentSettings := BoshAgentSettings{
		NatsPrivateIP:       natsPrivateIP,
		EphemeralDiskConfig: ephemeralDiskConfig,
	}
	settingsTmpl, err := template.ParseFiles(
		filepath.Join(dirname, "templates", "agent-configuration", "settings.json.tmpl"),
	)
	Expect(err).NotTo(HaveOccurred())
	outputFile, err := os.Create(filepath.Join(dirname, "agent-configuration", filename))
	defer outputFile.Close()

	Expect(err).NotTo(HaveOccurred())
	err = settingsTmpl.Execute(outputFile, agentSettings)
	Expect(err).NotTo(HaveOccurred())
}

func downloadFile(localPath, sourceURL string) error {
	f, err := os.OpenFile(localPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer f.Close()

	res, err := http.Get(sourceURL)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if _, err := io.Copy(f, res.Body); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


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

package migrations

import (
	"os"

	"code.gitea.io/gitea/models"
	"xorm.io/builder"
	"xorm.io/xorm"
)

func removeAttachmentMissedRepo(x *xorm.Engine) error {
	type Attachment struct {
		UUID string `xorm:"uuid"`
	}
	var start int
	attachments := make([]*Attachment, 0, 50)
	for {
		err := x.Select("uuid").Where(builder.NotIn("release_id", builder.Select("id").From("`release`"))).
			OrderBy("id").Limit(50, start).Find(&attachments)
		if err != nil {
			return err
		}

		for i := 0; i < len(attachments); i++ {
			os.RemoveAll(models.AttachmentLocalPath(attachments[i].UUID))
		}

		if len(attachments) < 50 {
			break
		}
		start += 50
		attachments = attachments[:0]
	}

	_, err := x.Exec("DELETE FROM attachment WHERE release_id NOT IN (SELECT id FROM `release`)")
	return err
}
<commit_msg>fix wrong migration (#9381)<commit_after>// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package migrations

import (
	"os"

	"code.gitea.io/gitea/models"
	"xorm.io/builder"
	"xorm.io/xorm"
)

func removeAttachmentMissedRepo(x *xorm.Engine) error {
	type Attachment struct {
		UUID string `xorm:"uuid"`
	}
	var start int
	attachments := make([]*Attachment, 0, 50)
	for {
		err := x.Select("uuid").Where(builder.NotIn("release_id", builder.Select("id").From("`release`"))).
			And("release_id > 0").
			OrderBy("id").Limit(50, start).Find(&attachments)
		if err != nil {
			return err
		}

		for i := 0; i < len(attachments); i++ {
			os.RemoveAll(models.AttachmentLocalPath(attachments[i].UUID))
		}

		if len(attachments) < 50 {
			break
		}
		start += 50
		attachments = attachments[:0]
	}

	_, err := x.Exec("DELETE FROM attachment WHERE release_id > 0 AND release_id NOT IN (SELECT id FROM `release`)")
	return err
}
<|endoftext|>


<commit_before>package doubleratchet

import (
	"github.com/stretchr/testify/require"
	"testing"
)

func TestDefaultCrypto_GenerateDH(t *testing.T) {
	// Arrange.
	c := DefaultCrypto{}

	// Act.
	pair, err := c.GenerateDH()

	// Assert.
	require.Nil(t, err)

	require.Equal(t, byte(0), pair.PrivateKey[0]&7)
	require.Equal(t, byte(0), pair.PrivateKey[31]&128)
	require.Equal(t, byte(64), pair.PrivateKey[31]&64)

	require.Len(t, pair.PrivateKey, 32)
	require.Len(t, pair.PublicKey, 32)
}
<commit_msg>Wrote TestDefaultCrypto_DH<commit_after>package doubleratchet

import (
	"github.com/stretchr/testify/require"
	"testing"
)

func TestDefaultCrypto_GenerateDH(t *testing.T) {
	// Arrange.
	c := DefaultCrypto{}

	// Act.
	pair, err := c.GenerateDH()
	require.Nil(t, err)

	// Assert.
	require.EqualValues(t, 0, pair.PrivateKey[0]&7)
	require.EqualValues(t, 0, pair.PrivateKey[31]&128)
	require.EqualValues(t, 64, pair.PrivateKey[31]&64)

	require.Len(t, pair.PrivateKey, 32)
	require.Len(t, pair.PublicKey, 32)
}

func TestDefaultCrypto_DH(t *testing.T) {
	// Arrange.
	c := DefaultCrypto{}

	// Act.
	var (
		alicePair, err1 = c.GenerateDH()
		bobPair, err2   = c.GenerateDH()
		aliceSK         = c.DH(alicePair, bobPair.PublicKey)
		bobSK           = c.DH(bobPair, alicePair.PublicKey)
	)

	// Assert.
	require.Nil(t, err1)
	require.Nil(t, err2)
	require.NotEqual(t, [32]byte{}, aliceSK)
	require.Equal(t, aliceSK, bobSK)
}
<|endoftext|>


<commit_before>package sudoku

import (
	"testing"
)

func TestHumanSolveSearcher(t *testing.T) {

	grid := NewGrid()
	grid.LoadSDK(TEST_GRID)

	searcher := newHumanSolveSearcher(grid, nil, DefaultHumanSolveOptions())

	if searcher.Len() != 1 {
		t.Error("Expected new frontier to have exactly one item in it, but got", searcher.Len())
	}

	if searcher.grid == nil {
		t.Error("No grid in frontier")
	}

	basePotentialNextStep := searcher.NextPossibleStep()

	if basePotentialNextStep == nil {
		t.Error("Didn'get base potential next step")
	}

	baseGrid := basePotentialNextStep.Grid()

	if baseGrid.DataString() != grid.DataString() {
		t.Error("the grid in the base item in the frontier was not right. Got", baseGrid.DataString(), "wanted", grid.DataString())
	}

	if searcher.Len() != 0 {
		t.Error("Getting the base potential next step should have emptied it, but len is", searcher.Len())
	}

	nInRowTechnique := techniquesByName["Necessary In Row"]

	simpleFillStep := &SolveStep{
		Technique: nInRowTechnique,
		TargetCells: CellSlice{
			grid.Cell(0, 0),
		},
		TargetNums: IntSlice{1},
	}

	if simpleFillStep.Technique == nil {
		t.Fatal("couldn't find necessary in row technique")
	}

	simpleFillStepItem := basePotentialNextStep.AddStep(simpleFillStep)

	if simpleFillStepItem == nil {
		t.Fatal("Adding fill step didn't return anything")
	}

	if simpleFillStepItem.heapIndex != -1 {
		t.Fatal("Adding completed item to frontier didn't have -1 index")
	}

	if len(searcher.completedItems) != 1 {
		t.Error("Expected the completed item to go into CompletedItems,but it's empty")
	}

	if len(searcher.itemsToExplore) != 0 {
		t.Error("Expected the completed item to go into COmpletedItems, but it apparently went into items.")
	}

	//TODO: this is a fragile test. Whenever we change twiddlers it will change.
	//Curerntly 5 for common numbers, 22.5 for Human Likelihood, and 1 for chained steps.
	expectedGoodness := 112.5

	if simpleFillStepItem.Goodness() != expectedGoodness {
		t.Error("Goodness of simple fill step was wrong. Execpted", expectedGoodness, "got", simpleFillStepItem.Goodness(), simpleFillStepItem.explainGoodness())
	}

	cell := simpleFillStepItem.Grid().Cell(0, 0)

	if cell.Number() != 1 {
		t.Error("Cell in grid was not set correctly. Got", cell.Number(), "wanted 1")
	}

	nonFillStep := &SolveStep{
		Technique: techniquesByName["Pointing Pair Row"],
		TargetCells: CellSlice{
			grid.Cell(0, 1),
		},
		TargetNums: IntSlice{2},
	}

	if nonFillStep.Technique == nil {
		t.Fatal("Couldn't find pointing pair row techhnique")
	}

	nonFillStepItem := basePotentialNextStep.AddStep(nonFillStep)

	if nonFillStepItem == nil {
		t.Fatal("Adding non fill step didn't return a frontier object")
	}

	if searcher.Len() != 1 {
		t.Error("Frontier had wrong length after adding one complete and one incomplete items. Got", searcher.Len(), "expected 1")
	}

	if searcher.itemsToExplore[0] != nonFillStepItem {
		t.Error("We though that simpleFillStep should be at the end of the queue but it wasn't.")
	}

	expensiveStep := &SolveStep{
		Technique: techniquesByName["Hidden Quad Block"],
		TargetCells: CellSlice{
			grid.Cell(0, 2),
		},
		TargetNums: IntSlice{3},
	}

	expensiveStepItem := basePotentialNextStep.AddStep(expensiveStep)

	if searcher.Len() != 2 {
		t.Error("Wrong length after adding two items to frontier. Got", searcher.Len(), "expected 2")
	}

	if searcher.itemsToExplore[1] != nonFillStepItem {
		t.Error("We expected the expensive step to be worse", searcher.String())
	}

	expensiveStepItem.Twiddle(0.00000000000000001, "Very small amount to make this #1")

	if searcher.itemsToExplore[1] != expensiveStepItem {
		t.Error("Even after twiddling up guess step by a lot it still wasn't in the top position in frontier", searcher.itemsToExplore[0], searcher.itemsToExplore[1])
	}

	poppedItem := searcher.NextPossibleStep()

	if poppedItem != expensiveStepItem {
		t.Error("Expected popped item to be the non-fill step now that its goodness is higher, but got", poppedItem)
	}

	if searcher.Len() != 1 {
		t.Error("Wrong frontier length after popping item. Got", searcher.Len(), "expected 1")
	}

	poppedItem = searcher.NextPossibleStep()
	//Should be nonFillStepItem

	currentGoodness := nonFillStepItem.Goodness()

	completedNonFillStemItem := nonFillStepItem.AddStep(simpleFillStep)

	if completedNonFillStemItem.Goodness() == currentGoodness {
		t.Error("Adding a step to end of nonfill step didn't change goodness.")
	}

	if searcher.Len() != 0 {
		t.Error("Adding an item gave wrong len. Got", searcher.Len(), "wanted 0")
	}

	if len(searcher.completedItems) != 2 {
		t.Error("Got wrong number of completed items. Got", len(searcher.completedItems), "expected 2")
	}

	steps := completedNonFillStemItem.Steps()

	if len(steps) != 2 {
		t.Error("Expected two steps back, got", len(steps))
	}

	if steps[0] != nonFillStepItem.step {
		t.Error("Expected first step to be the step of nonFillStepItem. Got", steps[0])
	}

}
<commit_msg>Demoted one TODO to just normal comment.<commit_after>package sudoku

import (
	"testing"
)

func TestHumanSolveSearcher(t *testing.T) {

	grid := NewGrid()
	grid.LoadSDK(TEST_GRID)

	searcher := newHumanSolveSearcher(grid, nil, DefaultHumanSolveOptions())

	if searcher.Len() != 1 {
		t.Error("Expected new frontier to have exactly one item in it, but got", searcher.Len())
	}

	if searcher.grid == nil {
		t.Error("No grid in frontier")
	}

	basePotentialNextStep := searcher.NextPossibleStep()

	if basePotentialNextStep == nil {
		t.Error("Didn'get base potential next step")
	}

	baseGrid := basePotentialNextStep.Grid()

	if baseGrid.DataString() != grid.DataString() {
		t.Error("the grid in the base item in the frontier was not right. Got", baseGrid.DataString(), "wanted", grid.DataString())
	}

	if searcher.Len() != 0 {
		t.Error("Getting the base potential next step should have emptied it, but len is", searcher.Len())
	}

	nInRowTechnique := techniquesByName["Necessary In Row"]

	simpleFillStep := &SolveStep{
		Technique: nInRowTechnique,
		TargetCells: CellSlice{
			grid.Cell(0, 0),
		},
		TargetNums: IntSlice{1},
	}

	if simpleFillStep.Technique == nil {
		t.Fatal("couldn't find necessary in row technique")
	}

	simpleFillStepItem := basePotentialNextStep.AddStep(simpleFillStep)

	if simpleFillStepItem == nil {
		t.Fatal("Adding fill step didn't return anything")
	}

	if simpleFillStepItem.heapIndex != -1 {
		t.Fatal("Adding completed item to frontier didn't have -1 index")
	}

	if len(searcher.completedItems) != 1 {
		t.Error("Expected the completed item to go into CompletedItems,but it's empty")
	}

	if len(searcher.itemsToExplore) != 0 {
		t.Error("Expected the completed item to go into COmpletedItems, but it apparently went into items.")
	}

	//This is a fragile way to test this; it will need to be updated every
	//time we change the twiddlers. :-( Currently 5 for common numbers, 22.5
	//for Human Likelihood, and 1 for chained steps.
	expectedGoodness := 112.5

	if simpleFillStepItem.Goodness() != expectedGoodness {
		t.Error("Goodness of simple fill step was wrong. Execpted", expectedGoodness, "got", simpleFillStepItem.Goodness(), simpleFillStepItem.explainGoodness())
	}

	cell := simpleFillStepItem.Grid().Cell(0, 0)

	if cell.Number() != 1 {
		t.Error("Cell in grid was not set correctly. Got", cell.Number(), "wanted 1")
	}

	nonFillStep := &SolveStep{
		Technique: techniquesByName["Pointing Pair Row"],
		TargetCells: CellSlice{
			grid.Cell(0, 1),
		},
		TargetNums: IntSlice{2},
	}

	if nonFillStep.Technique == nil {
		t.Fatal("Couldn't find pointing pair row techhnique")
	}

	nonFillStepItem := basePotentialNextStep.AddStep(nonFillStep)

	if nonFillStepItem == nil {
		t.Fatal("Adding non fill step didn't return a frontier object")
	}

	if searcher.Len() != 1 {
		t.Error("Frontier had wrong length after adding one complete and one incomplete items. Got", searcher.Len(), "expected 1")
	}

	if searcher.itemsToExplore[0] != nonFillStepItem {
		t.Error("We though that simpleFillStep should be at the end of the queue but it wasn't.")
	}

	expensiveStep := &SolveStep{
		Technique: techniquesByName["Hidden Quad Block"],
		TargetCells: CellSlice{
			grid.Cell(0, 2),
		},
		TargetNums: IntSlice{3},
	}

	expensiveStepItem := basePotentialNextStep.AddStep(expensiveStep)

	if searcher.Len() != 2 {
		t.Error("Wrong length after adding two items to frontier. Got", searcher.Len(), "expected 2")
	}

	if searcher.itemsToExplore[1] != nonFillStepItem {
		t.Error("We expected the expensive step to be worse", searcher.String())
	}

	expensiveStepItem.Twiddle(0.00000000000000001, "Very small amount to make this #1")

	if searcher.itemsToExplore[1] != expensiveStepItem {
		t.Error("Even after twiddling up guess step by a lot it still wasn't in the top position in frontier", searcher.itemsToExplore[0], searcher.itemsToExplore[1])
	}

	poppedItem := searcher.NextPossibleStep()

	if poppedItem != expensiveStepItem {
		t.Error("Expected popped item to be the non-fill step now that its goodness is higher, but got", poppedItem)
	}

	if searcher.Len() != 1 {
		t.Error("Wrong frontier length after popping item. Got", searcher.Len(), "expected 1")
	}

	poppedItem = searcher.NextPossibleStep()
	//Should be nonFillStepItem

	currentGoodness := nonFillStepItem.Goodness()

	completedNonFillStemItem := nonFillStepItem.AddStep(simpleFillStep)

	if completedNonFillStemItem.Goodness() == currentGoodness {
		t.Error("Adding a step to end of nonfill step didn't change goodness.")
	}

	if searcher.Len() != 0 {
		t.Error("Adding an item gave wrong len. Got", searcher.Len(), "wanted 0")
	}

	if len(searcher.completedItems) != 2 {
		t.Error("Got wrong number of completed items. Got", len(searcher.completedItems), "expected 2")
	}

	steps := completedNonFillStemItem.Steps()

	if len(steps) != 2 {
		t.Error("Expected two steps back, got", len(steps))
	}

	if steps[0] != nonFillStepItem.step {
		t.Error("Expected first step to be the step of nonFillStepItem. Got", steps[0])
	}

}
/<|endoftext|>


<commit_before>package store

import (
	"encoding/json"
	"fmt"
	"io/ioutil"

	"golang.org/x/oauth2"
)

// Project type
type Project struct {
	Name string
}

// User type
type User struct {
	Username  string
	Token     oauth2.Token
	AvatarURL string
	Projects  []Project
}

// GetUser returns an user info
func GetUser(username string) (user User, err error) {
	buf, err := ioutil.ReadFile("./data/" + username + ".json")
	err = json.Unmarshal(buf, &user)
	if err != nil {
		return user, err
	}
	return user, err
}

// SaveUser saves user info
func SaveUser(user User) error {
	b, err := json.Marshal(user)
	if err != nil {
		fmt.Println(err)
		return err
	}
	err = ioutil.WriteFile("./data/"+user.Username+".json", b, 0644)
	return err
}
<commit_msg>Added Icon to Project<commit_after>package store

import (
	"encoding/json"
	"fmt"
	"io/ioutil"

	"golang.org/x/oauth2"
)

// Project type
type Project struct {
	Name string
	Icon string
}

// User type
type User struct {
	Username  string
	Token     oauth2.Token
	AvatarURL string
	Projects  []Project
}

// GetUser returns an user info
func GetUser(username string) (user User, err error) {
	buf, err := ioutil.ReadFile("./data/" + username + ".json")
	err = json.Unmarshal(buf, &user)
	if err != nil {
		return user, err
	}
	return user, err
}

// SaveUser saves user info
func SaveUser(user User) error {
	b, err := json.Marshal(user)
	if err != nil {
		fmt.Println(err)
		return err
	}
	err = ioutil.WriteFile("./data/"+user.Username+".json", b, 0644)
	return err
}
<|endoftext|>


<commit_before>// Copyright 2019 NetApp, Inc. All Rights Reserved.

package persistentstore

import (
	"errors"
	"fmt"

	log "github.com/sirupsen/logrus"

	"github.com/netapp/trident/config"
	"github.com/netapp/trident/storage"
)

type CRDDataMigrator struct {
	etcdClient  EtcdClient
	crdClient   CRDClient
	dryRun      bool
	transformer *EtcdDataTransformer
}

func NewCRDDataMigrator(etcdClient EtcdClient, crdClient CRDClient, dryRun bool, t *EtcdDataTransformer) *CRDDataMigrator {
	return &CRDDataMigrator{
		etcdClient:  etcdClient,
		crdClient:   crdClient,
		dryRun:      dryRun,
		transformer: t,
	}
}

func (m *CRDDataMigrator) RunPrechecks() error {

	// Ensure we have valid etcd V3 data present
	etcdVersion, err := m.etcdClient.GetVersion()
	if err != nil {
		if MatchKeyNotFoundErr(err) {
			return fmt.Errorf("etcdv3 data not found, install an earlier Trident version in the range " +
				"[v18.01, v19.01] to automatically upgrade from etcdv2 to etcdv3")
		} else {
			return fmt.Errorf("could not check for etcdv3 data; %v", err)
		}
	} else {
		log.WithFields(log.Fields{
			"PersistentStoreVersion": etcdVersion.PersistentStoreVersion,
			"OrchestratorAPIVersion": etcdVersion.OrchestratorAPIVersion,
		}).Debug("Found etcdv3 persistent state version.")

		if etcdVersion.PersistentStoreVersion != string(EtcdV3Store) {
			return fmt.Errorf("etcd persistent state version is %s, not %s",
				etcdVersion.PersistentStoreVersion, EtcdV3Store)
		}
	}

	// Ensure there are no CRD-based backends
	if hasBackends, err := m.crdClient.HasBackends(); err != nil {
		return fmt.Errorf("could not check for CRD-based backends; %v", err)
	} else if hasBackends {
		return errors.New("CRD-based backends are already present, aborting migration")
	} else {
		log.Debug("No CRD-based backends found.")
	}

	// Ensure there are no CRD-based storage classes
	if hasStorageClasses, err := m.crdClient.HasStorageClasses(); err != nil {
		return fmt.Errorf("could not check for CRD-based storage classes; %v", err)
	} else if hasStorageClasses {
		return errors.New("CRD-based storage classes are already present, aborting migration")
	} else {
		log.Debug("No CRD-based storage classes found.")
	}

	// Ensure there are no CRD-based volumes
	if hasVolumes, err := m.crdClient.HasVolumes(); err != nil {
		return fmt.Errorf("could not check for CRD-based volumes; %v", err)
	} else if hasVolumes {
		return errors.New("CRD-based volumes are already present, aborting migration")
	} else {
		log.Debug("No CRD-based volumes found.")
	}

	// Ensure there are no CRD-based volume transactions
	if hasVolumeTransactions, err := m.crdClient.HasVolumeTransactions(); err != nil {
		return fmt.Errorf("could not check for CRD-based volume transactions; %v", err)
	} else if hasVolumeTransactions {
		return errors.New("CRD-based volume transactions are already present, aborting migration")
	} else {
		log.Debug("No CRD-based volume transactions found.")
	}

	// Ensure there is no CRD-based version
	crdVersion, err := m.crdClient.GetVersion()
	if err != nil {
		if MatchKeyNotFoundErr(err) {
			log.Debug("Trident CRDs not found, migration can proceed.")
		} else {
			return fmt.Errorf("could not check for Trident CRDs; %v", err)
		}
	} else {
		log.WithFields(log.Fields{
			"PersistentStoreVersion": crdVersion.PersistentStoreVersion,
			"OrchestratorAPIVersion": crdVersion.OrchestratorAPIVersion,
		}).Debug("Found CRD-based persistent state version.")
		return errors.New("Trident CRDs are already present, aborting migration")
	}

	if err := m.transformer.RunPrechecks(); err != nil {
		return err
	}

	return nil
}

func (m *CRDDataMigrator) Run() error {

	transformerResult, err := m.transformer.Run()
	if err != nil {
		return err
	}

	if err := m.migrateBackends(transformerResult.Backends); err != nil {
		return err
	}

	if err := m.migrateStorageClasses(); err != nil {
		return err
	}

	if err := m.migrateVolumes(transformerResult.Volumes); err != nil {
		return err
	}

	if err := m.migrateTransactions(); err != nil {
		return err
	}

	if err := m.writeCRDSchemaVersion(); err != nil {
		return err
	}

	if m.dryRun {
		log.Info("Migration dry run completed, no problems found.")
	} else {
		log.Info("Migration succeeded.")
	}

	return nil
}

func (m *CRDDataMigrator) migrateBackends(backends []*storage.BackendPersistent) error {

	if backends == nil || len(backends) == 0 {
		if m.dryRun {
			log.Info("Dry run: no backends found.")
		} else {
			log.Info("No backends found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(backends)).Info("Dry run: read all backends.")
		return nil
	}

	for _, backend := range backends {
		if err := m.crdClient.AddBackendPersistent(backend); err != nil {
			return fmt.Errorf("could not write backend resource; %v", err)
		}
		log.WithField("backend", backend.Name).Debug("Copied backend.")
	}
	log.WithField("count", len(backends)).Info("Copied all backends to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) migrateStorageClasses() error {

	storageClasses, err := m.etcdClient.GetStorageClasses()
	if err != nil {
		return fmt.Errorf("could not read storage classes from etcd; %v", err)
	}

	if len(storageClasses) == 0 {
		if m.dryRun {
			log.Info("Dry run: no storage classes found.")
		} else {
			log.Info("No storage classes found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(storageClasses)).Info("Dry run: read all storage classes.")
		return nil
	}

	for _, sc := range storageClasses {
		if err = m.crdClient.AddStorageClassPersistent(sc); err != nil {
			return fmt.Errorf("could not write storage class resource; %v", err)
		}
		log.WithField("sc", sc.GetName()).Debug("Copied storage class.")
	}
	log.WithField("count", len(storageClasses)).Info("Copied all storage classes to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) migrateVolumes(volumes []*storage.VolumeExternal) error {

	if volumes == nil || len(volumes) == 0 {
		if m.dryRun {
			log.Info("Dry run: no volumes found.")
		} else {
			log.Info("No volumes found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(volumes)).Info("Dry run: read all volumes.")
		return nil
	}

	for _, volume := range volumes {
		if err := m.crdClient.AddVolumePersistent(volume); err != nil {
			return fmt.Errorf("could not write volume resource; %v", err)
		}
		log.WithField("volume", volume.Config.Name).Debug("Copied volume.")
	}
	log.WithField("count", len(volumes)).Info("Copied all volumes to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) migrateTransactions() error {

	transactions, err := m.etcdClient.GetVolumeTransactions()
	if err != nil {
		return fmt.Errorf("could not read transactions from etcd; %v", err)
	}

	if len(transactions) == 0 {
		if m.dryRun {
			log.Info("Dry run: no transactions found.")
		} else {
			log.Info("No transactions found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(transactions)).Info("Dry run: read all transactions.")
		return nil
	}

	for _, txn := range transactions {
		if err = m.crdClient.AddVolumeTransaction(txn); err != nil {
			return fmt.Errorf("could not write transaction resource; %v", err)
		}
		log.WithField("volume", txn.Config.Name).Debug("Copied transaction.")
	}
	log.WithField("count", len(transactions)).Info("Copied all transactions to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) writeCRDSchemaVersion() error {

	if m.dryRun {
		return nil
	}

	crdVersion := &config.PersistentStateVersion{
		PersistentStoreVersion: string(CRDV1Store),
		OrchestratorAPIVersion: config.OrchestratorAPIVersion,
	}
	if err := m.crdClient.SetVersion(crdVersion); err != nil {
		return fmt.Errorf("failed to set the persistent state version after migration: %v", err)
	}

	log.WithFields(log.Fields{
		"PersistentStoreVersion": crdVersion.PersistentStoreVersion,
		"OrchestratorAPIVersion": crdVersion.OrchestratorAPIVersion,
	}).Info("Wrote CRD-based persistent state version.")

	return nil
}

func (m *CRDDataMigrator) writeEtcdSchemaVersion() error {

	if m.dryRun {
		return nil
	}

	etcdVersion := &config.PersistentStateVersion{
		PersistentStoreVersion: string(EtcdV3bStore),
		OrchestratorAPIVersion: config.OrchestratorAPIVersion,
	}
	if err := m.etcdClient.SetVersion(etcdVersion); err != nil {
		return fmt.Errorf("failed to set the persistent state version after migration: %v", err)
	}

	log.WithFields(log.Fields{
		"PersistentStoreVersion": etcdVersion.PersistentStoreVersion,
		"OrchestratorAPIVersion": etcdVersion.OrchestratorAPIVersion,
	}).Info("Wrote Etcd-based persistent state version.")

	return nil
}
<commit_msg>Added time estimates to etcd-CRD migrator (#73)<commit_after>// Copyright 2019 NetApp, Inc. All Rights Reserved.

package persistentstore

import (
	"errors"
	"fmt"
	"time"

	log "github.com/sirupsen/logrus"

	"github.com/netapp/trident/config"
	"github.com/netapp/trident/storage"
	storageclass "github.com/netapp/trident/storage_class"
)

type CRDDataMigrator struct {
	etcdClient    EtcdClient
	crdClient     CRDClient
	dryRun        bool
	transformer   *EtcdDataTransformer
	totalCount    int
	migratedCount int
	startTime     time.Time
}

func NewCRDDataMigrator(etcdClient EtcdClient, crdClient CRDClient, dryRun bool, t *EtcdDataTransformer) *CRDDataMigrator {
	return &CRDDataMigrator{
		etcdClient:    etcdClient,
		crdClient:     crdClient,
		dryRun:        dryRun,
		transformer:   t,
		totalCount:    0,
		migratedCount: 0,
	}
}

func (m *CRDDataMigrator) RunPrechecks() error {

	// Ensure we have valid etcd V3 data present
	etcdVersion, err := m.etcdClient.GetVersion()
	if err != nil {
		if MatchKeyNotFoundErr(err) {
			return fmt.Errorf("etcdv3 data not found, install an earlier Trident version in the range " +
				"[v18.01, v19.01] to automatically upgrade from etcdv2 to etcdv3")
		} else {
			return fmt.Errorf("could not check for etcdv3 data; %v", err)
		}
	} else {
		log.WithFields(log.Fields{
			"PersistentStoreVersion": etcdVersion.PersistentStoreVersion,
			"OrchestratorAPIVersion": etcdVersion.OrchestratorAPIVersion,
		}).Debug("Found etcdv3 persistent state version.")

		if etcdVersion.PersistentStoreVersion != string(EtcdV3Store) {
			return fmt.Errorf("etcd persistent state version is %s, not %s",
				etcdVersion.PersistentStoreVersion, EtcdV3Store)
		}
	}

	// Ensure there are no CRD-based backends
	if hasBackends, err := m.crdClient.HasBackends(); err != nil {
		return fmt.Errorf("could not check for CRD-based backends; %v", err)
	} else if hasBackends {
		return errors.New("CRD-based backends are already present, aborting migration")
	} else {
		log.Debug("No CRD-based backends found.")
	}

	// Ensure there are no CRD-based storage classes
	if hasStorageClasses, err := m.crdClient.HasStorageClasses(); err != nil {
		return fmt.Errorf("could not check for CRD-based storage classes; %v", err)
	} else if hasStorageClasses {
		return errors.New("CRD-based storage classes are already present, aborting migration")
	} else {
		log.Debug("No CRD-based storage classes found.")
	}

	// Ensure there are no CRD-based volumes
	if hasVolumes, err := m.crdClient.HasVolumes(); err != nil {
		return fmt.Errorf("could not check for CRD-based volumes; %v", err)
	} else if hasVolumes {
		return errors.New("CRD-based volumes are already present, aborting migration")
	} else {
		log.Debug("No CRD-based volumes found.")
	}

	// Ensure there are no CRD-based volume transactions
	if hasVolumeTransactions, err := m.crdClient.HasVolumeTransactions(); err != nil {
		return fmt.Errorf("could not check for CRD-based volume transactions; %v", err)
	} else if hasVolumeTransactions {
		return errors.New("CRD-based volume transactions are already present, aborting migration")
	} else {
		log.Debug("No CRD-based volume transactions found.")
	}

	// Ensure there is no CRD-based version
	crdVersion, err := m.crdClient.GetVersion()
	if err != nil {
		if MatchKeyNotFoundErr(err) {
			log.Debug("Trident CRDs not found, migration can proceed.")
		} else {
			return fmt.Errorf("could not check for Trident CRDs; %v", err)
		}
	} else {
		log.WithFields(log.Fields{
			"PersistentStoreVersion": crdVersion.PersistentStoreVersion,
			"OrchestratorAPIVersion": crdVersion.OrchestratorAPIVersion,
		}).Debug("Found CRD-based persistent state version.")
		return errors.New("Trident CRDs are already present, aborting migration")
	}

	if err := m.transformer.RunPrechecks(); err != nil {
		return err
	}

	return nil
}

func (m *CRDDataMigrator) Run() error {

	var (
		backends       []*storage.BackendPersistent
		storageClasses []*storageclass.Persistent
		volumes        []*storage.VolumeExternal
		transactions   []*VolumeTransaction
	)

	// Transform data into the latest schema
	transformerResult, err := m.transformer.Run()
	if err != nil {
		return err
	}

	// Backends and volumes are returned by the schema transformer
	backends = transformerResult.Backends
	volumes = transformerResult.Volumes

	// Read storage classes from etcd
	storageClasses, err = m.etcdClient.GetStorageClasses()
	if err != nil {
		return fmt.Errorf("could not read storage classes from etcd; %v", err)
	}

	// Read transactions from etcd
	transactions, err = m.etcdClient.GetVolumeTransactions()
	if err != nil {
		return fmt.Errorf("could not read transactions from etcd; %v", err)
	}

	// Determine number of objects to migrate
	m.totalCount = len(backends) + len(storageClasses) + len(volumes) + len(transactions)

	// Save start time
	m.startTime = time.Now()

	log.Infof("Migrating %d objects. Please do not interrupt this operation!", m.totalCount)

	// Migrate backends
	if err := m.migrateBackends(backends); err != nil {
		return err
	}

	// Migrate storage classes
	if err := m.migrateStorageClasses(storageClasses); err != nil {
		return err
	}

	// Migrate volumes
	if err := m.migrateVolumes(volumes); err != nil {
		return err
	}

	// Migrate transactions
	if err := m.migrateTransactions(transactions); err != nil {
		return err
	}

	// Write schema version to prevent future migrations
	if err := m.writeCRDSchemaVersion(); err != nil {
		return err
	}

	if m.dryRun {
		log.Info("Migration dry run completed, no problems found.")
	} else {
		log.WithField("count", m.migratedCount).Info("Migration succeeded.")
	}

	return nil
}

func (m *CRDDataMigrator) migrateBackends(backends []*storage.BackendPersistent) error {

	if backends == nil || len(backends) == 0 {
		if m.dryRun {
			log.Info("Dry run: no backends found.")
		} else {
			log.Info("No backends found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(backends)).Info("Dry run: read all backends.")
		return nil
	}

	for _, backend := range backends {
		if err := m.crdClient.AddBackendPersistent(backend); err != nil {
			return fmt.Errorf("could not write backend resource; %v", err)
		}
		log.WithField("backend", backend.Name).Debug("Copied backend.")

		m.migratedCount++
		m.logTimeRemainingEstimate()
	}
	log.WithField("count", len(backends)).Info("Copied all backends to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) migrateStorageClasses(storageClasses []*storageclass.Persistent) error {

	if len(storageClasses) == 0 {
		if m.dryRun {
			log.Info("Dry run: no storage classes found.")
		} else {
			log.Info("No storage classes found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(storageClasses)).Info("Dry run: read all storage classes.")
		return nil
	}

	for _, sc := range storageClasses {
		if err := m.crdClient.AddStorageClassPersistent(sc); err != nil {
			return fmt.Errorf("could not write storage class resource; %v", err)
		}
		log.WithField("sc", sc.GetName()).Debug("Copied storage class.")

		m.migratedCount++
		m.logTimeRemainingEstimate()
	}
	log.WithField("count", len(storageClasses)).Info("Copied all storage classes to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) migrateVolumes(volumes []*storage.VolumeExternal) error {

	if volumes == nil || len(volumes) == 0 {
		if m.dryRun {
			log.Info("Dry run: no volumes found.")
		} else {
			log.Info("No volumes found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(volumes)).Info("Dry run: read all volumes.")
		return nil
	}

	for _, volume := range volumes {
		if err := m.crdClient.AddVolumePersistent(volume); err != nil {
			return fmt.Errorf("could not write volume resource; %v", err)
		}
		log.WithField("volume", volume.Config.Name).Debug("Copied volume.")

		m.migratedCount++
		m.logTimeRemainingEstimate()
	}
	log.WithField("count", len(volumes)).Info("Copied all volumes to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) migrateTransactions(transactions []*VolumeTransaction) error {

	if len(transactions) == 0 {
		if m.dryRun {
			log.Info("Dry run: no transactions found.")
		} else {
			log.Info("No transactions found, none will be migrated.")
		}
		return nil
	}

	if m.dryRun {
		log.WithField("count", len(transactions)).Info("Dry run: read all transactions.")
		return nil
	}

	for _, txn := range transactions {
		if err := m.crdClient.AddVolumeTransaction(txn); err != nil {
			return fmt.Errorf("could not write transaction resource; %v", err)
		}
		log.WithField("volume", txn.Config.Name).Debug("Copied transaction.")

		m.migratedCount++
		m.logTimeRemainingEstimate()
	}
	log.WithField("count", len(transactions)).Info("Copied all transactions to CRD resources.")

	return nil
}

func (m *CRDDataMigrator) writeCRDSchemaVersion() error {

	if m.dryRun {
		return nil
	}

	crdVersion := &config.PersistentStateVersion{
		PersistentStoreVersion: string(CRDV1Store),
		OrchestratorAPIVersion: config.OrchestratorAPIVersion,
	}
	if err := m.crdClient.SetVersion(crdVersion); err != nil {
		return fmt.Errorf("failed to set the persistent state version after migration: %v", err)
	}

	log.WithFields(log.Fields{
		"PersistentStoreVersion": crdVersion.PersistentStoreVersion,
		"OrchestratorAPIVersion": crdVersion.OrchestratorAPIVersion,
	}).Info("Wrote CRD-based persistent state version.")

	return nil
}

func (m *CRDDataMigrator) writeEtcdSchemaVersion() error {

	if m.dryRun {
		return nil
	}

	etcdVersion := &config.PersistentStateVersion{
		PersistentStoreVersion: string(EtcdV3bStore),
		OrchestratorAPIVersion: config.OrchestratorAPIVersion,
	}
	if err := m.etcdClient.SetVersion(etcdVersion); err != nil {
		return fmt.Errorf("failed to set the persistent state version after migration: %v", err)
	}

	log.WithFields(log.Fields{
		"PersistentStoreVersion": etcdVersion.PersistentStoreVersion,
		"OrchestratorAPIVersion": etcdVersion.OrchestratorAPIVersion,
	}).Info("Wrote Etcd-based persistent state version.")

	return nil
}

func (m *CRDDataMigrator) logTimeRemainingEstimate() {

	// Ensure we have migrated something, and log the time remaining every 100 objects
	if (m.migratedCount%100) != 0 || m.migratedCount <= 0 {
		return
	}

	// Determine time elapsed and ensure it is positive
	timeElapsed := time.Since(m.startTime)
	if timeElapsed <= 0 {
		return
	}

	// Determine average time per object
	nanosecondsPerObject := timeElapsed.Nanoseconds() / int64(m.migratedCount)

	// Determine time remaining
	objectsRemaining := m.totalCount - m.migratedCount
	timeRemaining := time.Duration(nanosecondsPerObject * int64(objectsRemaining)).Truncate(time.Second)

	log.WithField("estimatedTimeRemaining", timeRemaining).Infof("Migrated %d of %d objects.",
		m.migratedCount, m.totalCount)
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"database/sql"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"

	"github.com/andrewstuart/bible-http-server/osis"
	_ "github.com/lib/pq"
)

const (
	versionInsert = `INSERT INTO version (extid, name) VALUES ($1, $2) RETURNING id`
)

var db *sql.DB

const PassEnvName = "PGPASSWORD"

func init() {
	var err error

	pass := strings.TrimSpace(os.Getenv(PassEnvName))
	if pass == "" {
		log.Fatalf("Please set %s environment variable with postgres password.", PassEnvName)
	}

	dbHost := stringDef(getLinkedPort(), "localhost")

	dbConn := fmt.Sprintf("postgres://bible:%s@%s/bible?sslmode=disable", pass, dbHost)

	db, err = sql.Open("postgres", dbConn)
	if err != nil {
		log.Fatal(err)
	}
}

func store(b *osis.Bible) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	var versionId int
	err = tx.QueryRow(versionInsert, b.Version.ID, b.Version.Title).Scan(&versionId)
	if err != nil {
		tx.Rollback()
		return err
	}

	wg := &sync.WaitGroup{}

	for i, bk := range b.Books {
		wg.Add(1)
		go func(i int, bk *osis.Book) {
			defer wg.Done()

			for j, ch := range bk.Chs {
				for k, vs := range ch.Vrs {

					//Handle words (osis uses for greek/hebrew)
					if len(vs.Words) != 0 {
						txt := make([]string, len(vs.Words))
						for i := range vs.Words {
							txt[i] = vs.Words[i].Text
						}

						vs.Text = strings.Join(txt, " ")
					}

					var verseId int
					err = tx.QueryRow(`SELECT id FROM verse  where book = $1 and chapter = $2 and verse = $3`, bk.ID, j+1, k+1).Scan(&verseId)

					if err != nil {
						log.Printf("Could not find %s %d:%d, inserting.\n", bk.ID, j+1, k+1)
						err = tx.QueryRow(`INSERT INTO verse (book, chapter, verse) values ($1, $2, $3) RETURNING id`, bk.ID, j+1, k+1).Scan(&verseId)
						continue
					}

					_, err = tx.Exec(`INSERT INTO verse_version (versionId, verseId, text) values ($1, $2, $3)`, versionId, verseId, vs.Text)
					if err != nil {
						return
					}
				}
			}
		}(i, bk)
	}

	wg.Wait()

	if err != nil {
		tx.Rollback()
		return err
	}

	err = tx.Commit()
	if err != nil {
		return err
	}

	return nil
}

func getLinkedPort() string {
	e := os.Getenv("POSTGRES_PORT")
	if e == "" {
		return ""
	}

	vals := strings.Split(e, "://")
	if len(vals) < 2 {
		return ""
	}

	return vals[1]
}

func loadFromGzippedFile(path string) (*osis.Bible, error) {
	zipped, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	r, err := gzip.NewReader(zipped)
	if err != nil {
		return nil, err
	}

	return osis.NewBible(r)
}
<commit_msg>Update some variable names<commit_after>package main

import (
	"compress/gzip"
	"database/sql"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"

	"github.com/andrewstuart/bible-http-server/osis"
	_ "github.com/lib/pq"
)

const (
	versionInsert = `INSERT INTO version (extid, name) VALUES ($1, $2) RETURNING id`
)

var db *sql.DB

const passEnvName = "PGPASSWORD"

func init() {
	var err error

	pass := strings.TrimSpace(os.Getenv(passEnvName))
	if pass == "" {
		log.Fatalf("Please set %s environment variable with postgres password.", passEnvName)
	}

	dbHost := stringDef(getLinkedPort(), "localhost")

	dbConn := fmt.Sprintf("postgres://bible:%s@%s/bible?sslmode=disable", pass, dbHost)

	db, err = sql.Open("postgres", dbConn)
	if err != nil {
		log.Fatal(err)
	}
}

func store(b *osis.Bible) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	var versionID int
	err = tx.QueryRow(versionInsert, b.Version.ID, b.Version.Title).Scan(&versionID)
	if err != nil {
		tx.Rollback()
		return err
	}

	wg := &sync.WaitGroup{}

	for i, bk := range b.Books {
		wg.Add(1)
		go func(i int, bk *osis.Book) {
			defer wg.Done()

			for j, ch := range bk.Chs {
				for k, vs := range ch.Vrs {

					//Handle words (osis uses for greek/hebrew)
					if len(vs.Words) != 0 {
						txt := make([]string, len(vs.Words))
						for i := range vs.Words {
							txt[i] = vs.Words[i].Text
						}

						vs.Text = strings.Join(txt, " ")
					}

					var verseID int
					err = tx.QueryRow(`SELECT id FROM verse  where book = $1 and chapter = $2 and verse = $3`, bk.ID, j+1, k+1).Scan(&verseID)

					if err != nil {
						log.Printf("Could not find %s %d:%d, inserting.\n", bk.ID, j+1, k+1)
						err = tx.QueryRow(`INSERT INTO verse (book, chapter, verse) values ($1, $2, $3) RETURNING id`, bk.ID, j+1, k+1).Scan(&verseID)
						continue
					}

					_, err = tx.Exec(`INSERT INTO verse_version (versionId, verseId, text) values ($1, $2, $3)`, versionID, verseID, vs.Text)
					if err != nil {
						return
					}
				}
			}
		}(i, bk)
	}

	wg.Wait()

	if err != nil {
		tx.Rollback()
		return err
	}

	err = tx.Commit()
	if err != nil {
		return err
	}

	return nil
}

func getLinkedPort() string {
	e := os.Getenv("POSTGRES_PORT")
	if e == "" {
		return ""
	}

	vals := strings.Split(e, "://")
	if len(vals) < 2 {
		return ""
	}

	return vals[1]
}

func loadFromGzippedFile(path string) (*osis.Bible, error) {
	zipped, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	r, err := gzip.NewReader(zipped)
	if err != nil {
		return nil, err
	}

	return osis.NewBible(r)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net"
	"net/rpc"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"regexp"
	"runtime"
	"syscall"
)

func createPidFile(filename string) (*os.File, error) {

	file, err := os.OpenFile(filename,
		os.O_WRONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC,
		syscall.S_IRUSR|syscall.S_IWUSR)

	if err != nil {
		return nil, err
	}

	err = syscall.Flock(int(file.Fd()), syscall.F_WRLCK)
	if err != nil {
		file.Close()
		return nil, err
	}

	_, err = file.WriteString(fmt.Sprintf("%d", os.Getpid()))
	if err != nil {
		file.Close()
		return nil, err
	}

	return file, nil
}

func removePidFile(file *os.File) {

	err := syscall.Flock(int(file.Fd()), syscall.F_UNLCK)
	if err != nil {
		return
	}

	file.Close()
	os.Remove(file.Name())
}

type TranscodeQueue struct {
	Requests chan string
}

func NewTranscodeQueue() *TranscodeQueue {
	return &TranscodeQueue{
		Requests: make(chan string, 100),
	}
}

func (this *TranscodeQueue) DoTranscode(file string, reply *bool) error {
	log.Println("Asked to transcode:", file)
	this.Requests <- file
	*reply = true
	return nil
}

func performTranscode(infile, outfile string, isDone chan<- error) {

	//transcodeCommand := exec.Command("/bin/sleep", "10")
	transcodeCommand := exec.Command(
		"/usr/local/bin/HandBrakeCLI",
		"-O", "-I",
		"-f", "mp4",
		"--encoder", "x264",
		"--x264-preset", "faster",
		"--x264-tune", "film",
		"--h264-profile", "auto",
		"--h264-level", "auto",
		"--quality", "20",
		"--large-file",
		"--aencoder", "ca_aac,copy:ac3",
		"-B", "160",
		"--mixdown", "dpl2",
		"--aname", "English",
		"--loose-anamorphic",
		"--decomb",
		"--modulus", "2",
		"-i", infile,
		"-o", outfile)

	//transferCommand := exec.Command("/bin/sleep", "5")
	transferCommand := exec.Command(
		"/usr/bin/scp", "-B", "-C", "-q", outfile,
		"guy@mediaserver.local:/srv/Media/Movies/0\\ -\\ Inbox/TV")

	log.Println("Performing transcode of", infile)
	log.Println("Writing file", outfile)

	err := transcodeCommand.Run()
	if err != nil {
		log.Println(err.Error())
		isDone <- err
		return
	}

	log.Println("Done transcoding file")
	log.Println("Transfering file to server")

	err = transferCommand.Run()
	if err == nil {
		os.Remove(infile)
		//os.Remove(outfile)
		// leave commented out until im sure i understand the scp problem
	} else {
		log.Println(err.Error())
		isDone <- err
		return
	}

	log.Println("Done transfering file to server")
	isDone <- nil
}

func requestTranscode(infile, unixSocket string) (reply bool, err error) {

	client, err := rpc.Dial("unix", unixSocket)
	if err != nil {
		return
	}
	err = client.Call("TranscodeQueue.DoTranscode", infile, &reply)
	return
}

func createTranscodeServer(pidfile *os.File, unixSocket string) error {

	sigc := make(chan os.Signal, 10)
	signal.Notify(sigc,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)
	defer signal.Stop(sigc)

	q := NewTranscodeQueue()
	server := rpc.NewServer()
	server.Register(q)

	l, err := net.Listen("unix", unixSocket)
	if err != nil {
		return err
	}

	defer l.Close()

	go server.Accept(l)

	isDone := make(chan error)
	rxp, err := regexp.Compile(`(.*)(\.mpg)$`)

	if err != nil {
		return err
	}

	q.Requests <- os.Args[1]

	for {
		select {
		case <-sigc:
			return nil
		case req := <-q.Requests:

			outfile := rxp.ReplaceAllString(req, "$1.m4v")
			go performTranscode(req, outfile, isDone)

			select {
			case <-sigc:
				return nil
			case e := <-isDone:
				if e != nil {
					return e
				}
			}
		default:
			return nil
		}
	}
}

func main() {

	if len(os.Args) != 2 {
		return
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	log.Println("Starting...")

	toTranscode := os.Args[1]
	pidFileName := path.Join(os.TempDir(), "transcodequeue.pid")
	unixSocket := path.Join(os.TempDir(), "transcodequeue.sock")

	pidFile, err := createPidFile(pidFileName)

	if err != nil {
		log.Println("Sending server request to transcode", toTranscode)

		reply, err := requestTranscode(toTranscode, unixSocket)
		if err != nil {
			log.Panicln(err.Error())
		}

		if reply {
			log.Println("Successfully requested transcode")
		}
	} else {
		log.Println("Creating Server")

		defer removePidFile(pidFile)

		err = createTranscodeServer(pidFile, unixSocket)
		if err != nil {
			log.Panicln(err.Error())
		}
	}

	log.Println("Finished")
}
<commit_msg>cacnel running backgrund job on ctrlc<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/rpc"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"regexp"
	"runtime"
	"syscall"
)

func createPidFile(filename string) (*os.File, error) {

	file, err := os.OpenFile(filename,
		os.O_WRONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC,
		syscall.S_IRUSR|syscall.S_IWUSR)

	if err != nil {
		return nil, err
	}

	err = syscall.Flock(int(file.Fd()), syscall.F_WRLCK)
	if err != nil {
		file.Close()
		return nil, err
	}

	_, err = file.WriteString(fmt.Sprintf("%d", os.Getpid()))
	if err != nil {
		file.Close()
		return nil, err
	}

	return file, nil
}

func removePidFile(file *os.File) {

	err := syscall.Flock(int(file.Fd()), syscall.F_UNLCK)
	if err != nil {
		return
	}

	file.Close()
	os.Remove(file.Name())
}

type TranscodeQueue struct {
	Requests chan string
}

func NewTranscodeQueue() *TranscodeQueue {
	return &TranscodeQueue{
		Requests: make(chan string, 100),
	}
}

func (this *TranscodeQueue) DoTranscode(file string, reply *bool) error {
	log.Println("Asked to transcode:", file)
	this.Requests <- file
	*reply = true
	return nil
}

func runCommand(cmd *exec.Cmd, die <-chan os.Signal) (bool, error) {

	isDone := make(chan error)
	if err := cmd.Start(); err != nil {
		return false, err
	}

	go func() {
		if err := cmd.Wait(); err != nil {
			isDone <- err
		}
		isDone <- nil
	}()

	select {
	case err := <-isDone:
		return true, err
	case <-die:
		log.Println("Killing process")
		if err := cmd.Process.Kill(); err != nil {
			return false, err
		}
		return false, nil
	}

}

var wasCanceled error = errors.New("Was Canceled")

func performTranscode(infile, outfile string, isDone chan<- error, sigc <-chan os.Signal) {

	//transcodeCommand := exec.Command("/bin/sleep", "10")
	transcodeCommand := exec.Command(
		"/usr/local/bin/HandBrakeCLI",
		"-O", "-I",
		"-f", "mp4",
		"--encoder", "x264",
		"--x264-preset", "faster",
		"--x264-tune", "film",
		"--h264-profile", "auto",
		"--h264-level", "auto",
		"--quality", "20",
		"--large-file",
		"--aencoder", "ca_aac,copy:ac3",
		"-B", "160",
		"--mixdown", "dpl2",
		"--aname", "English",
		"--loose-anamorphic",
		"--decomb",
		"--modulus", "2",
		"-i", infile,
		"-o", outfile)

	//transferCommand := exec.Command("/bin/sleep", "5")
	transferCommand := exec.Command(
		"/usr/bin/scp", "-B", "-C", "-q", outfile,
		"guy@mediaserver.local:/srv/Media/Movies/0\\ -\\ Inbox/TV")

	log.Println("Performing transcode of", infile)
	log.Println("Writing file", outfile)

	done, err := runCommand(transcodeCommand, sigc)

	if err != nil {
		log.Println(err.Error())
		isDone <- err
		return
	}
	if !done {
		isDone <- wasCanceled
		return
	}

	log.Println("Done transcoding file")
	log.Println("Transfering file to server")

	done, err = runCommand(transferCommand, sigc)

	if err == nil && done {
		os.Remove(infile)
		//os.Remove(outfile)
		// leave commented out until im sure i understand the scp problem
	} else {
		if err != nil {
			log.Println(err.Error())
			isDone <- err

		} else {
			isDone <- wasCanceled
		}
		return
	}

	log.Println("Done transfering file to server")
	isDone <- nil
}

func requestTranscode(infile, unixSocket string) (reply bool, err error) {

	client, err := rpc.Dial("unix", unixSocket)
	if err != nil {
		return
	}
	err = client.Call("TranscodeQueue.DoTranscode", infile, &reply)
	return
}

func createTranscodeServer(pidfile *os.File, unixSocket string) error {

	sigc := make(chan os.Signal, 10)
	signal.Notify(sigc,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)
	defer signal.Stop(sigc)

	q := NewTranscodeQueue()
	server := rpc.NewServer()
	server.Register(q)

	l, err := net.Listen("unix", unixSocket)
	if err != nil {
		return err
	}

	defer l.Close()

	go server.Accept(l)

	isDone := make(chan error)
	rxp, err := regexp.Compile(`(.*)(\.mpg)$`)

	if err != nil {
		return err
	}

	q.Requests <- os.Args[1]

	for {
		select {
		case req := <-q.Requests:

			outfile := rxp.ReplaceAllString(req, "$1.m4v")
			go performTranscode(req, outfile, isDone, sigc)

			select {
			case e := <-isDone:
				if e != nil {
					return e
				}
			}
		default:
			return nil
		}
	}
}

func main() {

	if len(os.Args) != 2 {
		return
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	log.Println("Starting...")

	toTranscode := os.Args[1]
	pidFileName := path.Join(os.TempDir(), "transcodequeue.pid")
	unixSocket := path.Join(os.TempDir(), "transcodequeue.sock")

	pidFile, err := createPidFile(pidFileName)

	if err != nil {
		log.Println("Sending server request to transcode", toTranscode)

		reply, err := requestTranscode(toTranscode, unixSocket)
		if err != nil {
			log.Panicln(err.Error())
		}

		if reply {
			log.Println("Successfully requested transcode")
		}
	} else {
		log.Println("Creating Server")

		defer removePidFile(pidFile)

		err = createTranscodeServer(pidFile, unixSocket)
		if err != nil {
			log.Println(err.Error())
		}
	}

	log.Println("Finished")
}
<|endoftext|>


<commit_before>package datastore

import (
	"testing"

	"github.com/stretchr/testify/suite"
)

type UsersTestSuite struct {
	suite.Suite
}

func (s *UsersTestSuite) SetupTest() {
	Init(testDB)
	createTables()
	newTestUsers()
}

func (s *UsersTestSuite) TearDownTest() {
	dropTables()
	Exit()
}

func (s *UsersTestSuite) TestGetByUsername() {
	user, err := testStore.UserStore.GetByUsername(testSenderUname)
	s.Equal(testSender.Username, user.Username)
	s.Equal(testSender.Email, user.Email)
	s.Equal(testSender.PhoneNumber, user.PhoneNumber)
	s.Equal(testSender.Password, user.Password)
	s.Nil(err)
}

func TestUsers(t *testing.T) {
	suite.Run(t, new(UsersTestSuite))
}
<commit_msg>Finish tests for datastore/users<commit_after>package datastore

import (
	"testing"

	"github.com/stretchr/testify/suite"
	"gitlab.com/wujiang/asapp"
)

type UsersTestSuite struct {
	suite.Suite
}

func (s *UsersTestSuite) SetupTest() {
	Init(testDB)
	createTables()
	newTestUsers()
}

func (s *UsersTestSuite) TearDownTest() {
	dropTables()
	Exit()
}

func (s *UsersTestSuite) TestGetByUsername() {
	user, err := testStore.UserStore.GetByUsername(testSenderUname)
	s.Equal(testSender.Username, user.Username)
	s.Equal(testSender.Email, user.Email)
	s.Equal(testSender.PhoneNumber, user.PhoneNumber)
	s.Equal(testSender.Password, user.Password)
	s.Nil(err)
}

func (s *UsersTestSuite) TestCreate() {
	user := asapp.NewUser("test", "last", "username", "password123",
		"test@last.com", "1357902468", "0.0.0.0")
	s.Nil(testStore.UserStore.Create(user))
	u, err := testStore.UserStore.GetByUsername("username")
	s.Nil(err)
	s.Equal("test", u.FirstName)
	s.Equal("username", u.Username)

	// duplicates
	s.NotNil(testStore.UserStore.Create(user))
	ct, err := testStore.dbh.Delete(user)
	s.Equal(int64(1), ct)
	s.Nil(err)
}

func (s *UsersTestSuite) TestUpdate() {
	u := testSender
	u.Email = "changed@send.com"
	ct, err := testStore.UserStore.Update(u)
	s.Equal(int64(1), ct)
	s.Nil(err)

	user, err := testStore.UserStore.GetByUsername(testSenderUname)
	s.Equal(testSender.Username, user.Username)
	s.Equal(testSender.Email, "changed@send.com")
}

func TestUsers(t *testing.T) {
	suite.Run(t, new(UsersTestSuite))
}
<|endoftext|>