<commit_before>package test161

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/satori/go.uuid"
	"os"
	"sync"
	"time"
)

type SubmissionUserInfo struct {
	Email string `yaml:"email"`
	Token string `yaml:"token"`
}

// SubmissionRequests are created by clients and used to generate Submissions.
// A SubmissionRequest represents the data required to run a test161 target
// for evaluation by the test161 server.
type SubmissionRequest struct {
	Target     string                // Name of the target
	Users      []*SubmissionUserInfo // Email addresses of users
	Repository string                // Git repository to clone
	CommitID   string                // Git commit id to checkout after cloning
}

const (
	SUBMISSION_SUBMITTED = "submitted" // Submitted and queued
	SUBMISSION_BUILDING  = "building"  // Building the kernel
	SUBMISSION_RUNNING   = "running"   // The tests started running
	SUBMISSION_ABORTED   = "aborted"   // Aborted because one or more tests failed to error
	SUBMISSION_COMPLETED = "completed" // Completed
)

type Submission struct {

	// Configuration
	ID         string   `bson:"_id,omitempty"`
	Users      []string `bson:"users"`
	Repository string   `bson:"repository"`
	CommitID   string   `bson:"commit_id"`

	// Target details
	TargetID        string `bson:"-"` //TODO: Use this?
	TargetName      string `bson:"target_name"`
	TargetVersion   uint   `bson:"target_version"`
	PointsAvailable uint   `bson:"max_score"`
	TargetType      string `bson:"target_type"`

	// Results
	Status      string   `bson:"status"`
	Score       uint     `bson:"score"`
	Performance float64  `bson:"performance"`
	TestIDs     []string `bson:"tests"`
	Errors      []string `bson:"errors"`

	SubmissionTime time.Time `bson:"submission_time"`
	CompletionTime time.Time `bson:"completion_time"`

	Env *TestEnvironment `bson:"-"`

	BuildTest *BuildTest `bson:"-"`
	Tests     *TestGroup `bson:"-"`

	students []*Student
}

type TargetResult struct {
	TargetName     string    `bson:"target_name"`
	TargetVersion  uint      `bson:"target_version"`
	TargetType     string    `bson:"target_type"`
	Status         string    `bson:"status"`
	Score          uint      `bson:"score"`
	MaxScore       uint      `bson:"max_score"`
	Performance    float64   `bson:"performance"`
	SubmissionTime time.Time `bson:"submission_time"`
	CompletionTime time.Time `bson:"completion_time"`
	SubmissionID   string    `bson:"submission_id"`
}

type Student struct {
	ID             string                   `bson:"_id"`
	Email          string                   `bson:"email"`
	Token          string                   `bson:"token"`
	LastSubmission *TargetResult            `bson:"last_submission"`
	TargetResults  map[string]*TargetResult `bson:"target_results"`
}

// Keep track of pending submissions.  Keep this out of the database in case there are
// communication issues so that we don't need to manually reset things in the DB.
var userLock = &sync.Mutex{}
var pendingSubmissions = make(map[string]bool)

// Check users against users database.  Don't lock them until we run though
func (req *SubmissionRequest) validateUsers(env *TestEnvironment) ([]*Student, error) {

	allStudents := make([]*Student, 0)

	for _, user := range req.Users {
		request := map[string]interface{}{
			"email": user.Email,
			"token": user.Token,
		}

		fmt.Println("Received:", user.Email, user.Token)

		students := []*Student{}
		if err := env.Persistence.Retrieve(PERSIST_TYPE_STUDENTS, request, &students); err != nil {
			return nil, err
		}

		if len(students) != 1 || students[0].Email != user.Email || students[0].Token != user.Token {
			return nil, errors.New("Unable to authenticate student: " + user.Email)
		}
		allStudents = append(allStudents, students[0])
	}

	return allStudents, nil
}

func (req *SubmissionRequest) validate(env *TestEnvironment) ([]*Student, error) {

	students := []*Student{}
	var err error

	if _, ok := env.Targets[req.Target]; !ok {
		return students, errors.New("Invalid target: " + req.Target)
	}

	if len(req.Users) == 0 {
		return students, errors.New("No usernames specified")
	}

	if env.Persistence != nil && env.Persistence.CanRetrieve() {
		if students, err = req.validateUsers(env); err != nil {
			return students, err
		}
	}

	if len(req.Repository) == 0 || len(req.CommitID) == 0 {
		return students, errors.New("Must specify a Git repository and commit id")
	}

	return students, nil
}

// Create a new Submission that can be evaluated by the test161 server or client.
func NewSubmission(request *SubmissionRequest, env *TestEnvironment) (*Submission, []error) {
	var students []*Student
	var err error

	if students, err = request.validate(env); err != nil {
		return nil, []error{err}
	}

	// First, get the target because there is some build info there
	target := env.Targets[request.Target]

	conf := &BuildConf{}
	conf.Repo = request.Repository
	conf.CommitID = request.CommitID
	conf.KConfig = target.KConfig
	conf.CacheDir = env.CacheDir
	conf.RequiredCommit = target.RequiredCommit
	conf.RequiresUserland = target.RequiresUserland

	// Add first test (build)
	buildTest, err := conf.ToBuildTest()
	if err != nil {
		return nil, []error{err}
	}

	// Get the TestGroup. The root dir won't be set yet, but that's OK.  We'll
	// change it after the build

	tg, errs := target.Instance(env)
	if err != nil {
		return nil, errs
	}

	s := &Submission{
		ID:              uuid.NewV4().String(),
		Repository:      request.Repository,
		CommitID:        request.CommitID,
		TargetName:      target.Name,
		TargetVersion:   target.Version,
		PointsAvailable: target.Points,
		TargetType:      target.Type,

		Status:      SUBMISSION_SUBMITTED,
		Score:       uint(0),
		Performance: float64(0.0),
		TestIDs:     []string{buildTest.ID},
		Errors:      []string{},

		SubmissionTime: time.Now(),

		Env:       env,
		BuildTest: buildTest,
		Tests:     tg,
	}

	s.students = students
	s.Users = make([]string, 0, len(request.Users))
	for _, u := range request.Users {
		s.Users = append(s.Users, u.Email)
	}

	// Try and lock students now so we don't
	userLock.Lock()
	defer userLock.Unlock()

	// First pass - just check
	for _, student := range students {
		if running := pendingSubmissions[student.Email]; running {
			msg := fmt.Sprintf("Cannot submit at this time: User %v has a submission pending.", student.Email)
			env.Log.Println(msg)
			return nil, []error{errors.New(msg)}
		}
	}

	// Now lock
	for _, student := range students {
		pendingSubmissions[student.Email] = true
	}

	if env.Persistence != nil {
		if buildTest != nil {
			// If we get an error here, we can still hopefully recover
			env.notifyAndLogErr("Create Build Test", buildTest, MSG_PERSIST_CREATE, 0)
		}
		// This we can't recover from
		err = env.Persistence.Notify(s, MSG_PERSIST_CREATE, 0)
	}

	// Unlock so they can resubmit
	if err != nil {
		for _, student := range students {
			delete(pendingSubmissions, student.Email)
		}
		return nil, []error{err}
	}

	return s, nil
}

func (s *Submission) persistFailure() {
	// TODO: handle failures
	s.Status = SUBMISSION_ABORTED
}

func (s *Submission) TargetResult() (result *TargetResult) {
	result = &TargetResult{
		TargetName:     s.TargetName,
		TargetVersion:  s.TargetVersion,
		TargetType:     s.TargetType,
		Status:         s.Status,
		Score:          s.Score,
		MaxScore:       s.PointsAvailable,
		Performance:    s.Performance,
		SubmissionTime: s.SubmissionTime,
		CompletionTime: s.CompletionTime,
		SubmissionID:   s.ID,
	}
	return
}

// Update students.  We copy metadata to make this quick and store the
// submision id to look up the full details.
func (s *Submission) updateStudents() {

	res := s.TargetResult()
	for _, student := range s.students {
		// This might be nil coming out of Mongo
		if student.TargetResults == nil {
			student.TargetResults = make(map[string]*TargetResult)
		}

		student.LastSubmission = res
		if s.Status == SUBMISSION_COMPLETED {
			// Update the high score for the target
			if s.TargetType == TARGET_ASST {
				if prev, ok := student.TargetResults[s.TargetName]; !ok || prev.Score < s.Score {
					student.TargetResults[s.TargetName] = res
				}
			} else if s.TargetType == TARGET_PERF && s.Score == s.PointsAvailable {
				if prev, ok := student.TargetResults[s.TargetName]; !ok || prev.Performance < s.Performance {
					student.TargetResults[s.TargetName] = res
				}
			}
		}
		if s.Env.Persistence != nil {
			if err := s.Env.Persistence.Notify(student, MSG_PERSIST_UPDATE, 0); err != nil {
				if sbytes, jerr := json.Marshal(student); jerr != nil {
					s.Env.Log.Printf("Error updating student: %v  (%v)\n", student.Email, err)
				} else {
					s.Env.Log.Printf("Error updating student: %v  (%v)\n", string(sbytes), err)
				}
			}
		}
	}

	userLock.Lock()
	defer userLock.Unlock()

	// Unblock the students from resubmitting
	for _, student := range s.students {
		delete(pendingSubmissions, student.Email)
	}
}

func (s *Submission) finish() {

	s.CompletionTime = time.Now()
	if s.Status == SUBMISSION_RUNNING {
		s.Status = SUBMISSION_COMPLETED
	}

	// Send the final submission update to the db
	s.Env.notifyAndLogErr("Finish Submission", s, MSG_PERSIST_COMPLETE, 0)

	if len(s.students) > 0 {
		s.updateStudents()
	}
}

// Synchronous submission runner
func (s *Submission) Run() error {
	// Run the build first.  Right now this is the only thing the front-end sees.
	// We'll add the rest of the tests if this passes, otherwise we don't waste the
	// disk space.

	var err error

	// So we know it's not nil
	if s.Env.Persistence == nil {
		s.Env.Persistence = &DoNothingPersistence{}
	}

	defer s.finish()

	// Build os161
	if s.BuildTest != nil {
		s.Status = SUBMISSION_BUILDING
		s.Env.notifyAndLogErr("Submission Status Building", s, MSG_PERSIST_UPDATE, MSG_FIELD_STATUS)

		res, err := s.BuildTest.Run(s.Env)
		if err != nil {
			s.Status = SUBMISSION_ABORTED
			s.Env.notifyAndLogErr("Submission Complete (Aborted)", s, MSG_PERSIST_COMPLETE, 0)
			return err
		}

		// Build output
		s.Env.RootDir = res.RootDir
		s.Env.KeyMap = res.KeyMap

		// Clean up temp build directory
		if len(res.TempDir) > 0 {
			defer os.RemoveAll(res.TempDir)
		}
	}

	// Build succeeded, update things accordingly
	for _, test := range s.Tests.Tests {
		// Add test IDs to DB
		s.TestIDs = append(s.TestIDs, test.ID)

		// Create the test object in the DB
		// If this fails, we abort the submission beacase we can't verify the results
		err = s.Env.Persistence.Notify(test, MSG_PERSIST_CREATE, 0)
		if err != nil {
			s.Status = SUBMISSION_ABORTED
			return err
		}
	}

	// Run it
	s.Status = SUBMISSION_RUNNING
	s.Env.notifyAndLogErr("Submission Status (Running) ", s, MSG_PERSIST_UPDATE, MSG_FIELD_TESTS|MSG_FIELD_STATUS)

	runner := NewDependencyRunner(s.Tests)
	done := runner.Run()

	// Update the score unless a test aborts, then it's 0 and we abort (eventually)
	for r := range done {
		if s.Status == SUBMISSION_RUNNING {
			if r.Test.Result == TEST_RESULT_ABORT {
				s.Status = SUBMISSION_ABORTED
				s.Score = 0
				s.Performance = float64(0)
			} else {
				s.Score += r.Test.PointsEarned
				s.Env.Persistence.Notify(s, MSG_PERSIST_UPDATE, MSG_FIELD_SCORE)
			}
		}
		if r.Err != nil {
			s.Errors = append(s.Errors, fmt.Sprintf("%v", r.Err))
		}
	}

	return err
}
<commit_msg>Changed student target result map to an array, which will be better for mongodb.<commit_after>package test161

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/satori/go.uuid"
	"os"
	"sync"
	"time"
)

type SubmissionUserInfo struct {
	Email string `yaml:"email"`
	Token string `yaml:"token"`
}

// SubmissionRequests are created by clients and used to generate Submissions.
// A SubmissionRequest represents the data required to run a test161 target
// for evaluation by the test161 server.
type SubmissionRequest struct {
	Target     string                // Name of the target
	Users      []*SubmissionUserInfo // Email addresses of users
	Repository string                // Git repository to clone
	CommitID   string                // Git commit id to checkout after cloning
}

const (
	SUBMISSION_SUBMITTED = "submitted" // Submitted and queued
	SUBMISSION_BUILDING  = "building"  // Building the kernel
	SUBMISSION_RUNNING   = "running"   // The tests started running
	SUBMISSION_ABORTED   = "aborted"   // Aborted because one or more tests failed to error
	SUBMISSION_COMPLETED = "completed" // Completed
)

type Submission struct {

	// Configuration
	ID         string   `bson:"_id,omitempty"`
	Users      []string `bson:"users"`
	Repository string   `bson:"repository"`
	CommitID   string   `bson:"commit_id"`

	// Target details
	TargetID        string `bson:"-"` //TODO: Use this?
	TargetName      string `bson:"target_name"`
	TargetVersion   uint   `bson:"target_version"`
	PointsAvailable uint   `bson:"max_score"`
	TargetType      string `bson:"target_type"`

	// Results
	Status      string   `bson:"status"`
	Score       uint     `bson:"score"`
	Performance float64  `bson:"performance"`
	TestIDs     []string `bson:"tests"`
	Errors      []string `bson:"errors"`

	SubmissionTime time.Time `bson:"submission_time"`
	CompletionTime time.Time `bson:"completion_time"`

	Env *TestEnvironment `bson:"-"`

	BuildTest *BuildTest `bson:"-"`
	Tests     *TestGroup `bson:"-"`

	students []*Student
}

type TargetResult struct {
	TargetName     string    `bson:"target_name"`
	TargetVersion  uint      `bson:"target_version"`
	TargetType     string    `bson:"target_type"`
	Status         string    `bson:"status"`
	Score          uint      `bson:"score"`
	MaxScore       uint      `bson:"max_score"`
	Performance    float64   `bson:"performance"`
	SubmissionTime time.Time `bson:"submission_time"`
	CompletionTime time.Time `bson:"completion_time"`
	SubmissionID   string    `bson:"submission_id"`
}

type Student struct {
	ID             string          `bson:"_id"`
	Email          string          `bson:"email"`
	Token          string          `bson:"token"`
	LastSubmission *TargetResult   `bson:"last_submission"`
	TargetResults  []*TargetResult `bson:"target_results"`
}

// Keep track of pending submissions.  Keep this out of the database in case there are
// communication issues so that we don't need to manually reset things in the DB.
var userLock = &sync.Mutex{}
var pendingSubmissions = make(map[string]bool)

// Check users against users database.  Don't lock them until we run though
func (req *SubmissionRequest) validateUsers(env *TestEnvironment) ([]*Student, error) {

	allStudents := make([]*Student, 0)

	for _, user := range req.Users {
		request := map[string]interface{}{
			"email": user.Email,
			"token": user.Token,
		}

		students := []*Student{}
		if err := env.Persistence.Retrieve(PERSIST_TYPE_STUDENTS, request, &students); err != nil {
			return nil, err
		}

		if len(students) != 1 || students[0].Email != user.Email || students[0].Token != user.Token {
			return nil, errors.New("Unable to authenticate student: " + user.Email)
		}
		allStudents = append(allStudents, students[0])
	}

	return allStudents, nil
}

func (req *SubmissionRequest) validate(env *TestEnvironment) ([]*Student, error) {

	students := []*Student{}
	var err error

	if _, ok := env.Targets[req.Target]; !ok {
		return students, errors.New("Invalid target: " + req.Target)
	}

	if len(req.Users) == 0 {
		return students, errors.New("No usernames specified")
	}

	if env.Persistence != nil && env.Persistence.CanRetrieve() {
		if students, err = req.validateUsers(env); err != nil {
			return students, err
		}
	}

	if len(req.Repository) == 0 || len(req.CommitID) == 0 {
		return students, errors.New("Must specify a Git repository and commit id")
	}

	return students, nil
}

// Create a new Submission that can be evaluated by the test161 server or client.
func NewSubmission(request *SubmissionRequest, env *TestEnvironment) (*Submission, []error) {
	var students []*Student
	var err error

	if students, err = request.validate(env); err != nil {
		return nil, []error{err}
	}

	// First, get the target because there is some build info there
	target := env.Targets[request.Target]

	conf := &BuildConf{}
	conf.Repo = request.Repository
	conf.CommitID = request.CommitID
	conf.KConfig = target.KConfig
	conf.CacheDir = env.CacheDir
	conf.RequiredCommit = target.RequiredCommit
	conf.RequiresUserland = target.RequiresUserland

	// Add first test (build)
	buildTest, err := conf.ToBuildTest()
	if err != nil {
		return nil, []error{err}
	}

	// Get the TestGroup. The root dir won't be set yet, but that's OK.  We'll
	// change it after the build

	tg, errs := target.Instance(env)
	if err != nil {
		return nil, errs
	}

	s := &Submission{
		ID:              uuid.NewV4().String(),
		Repository:      request.Repository,
		CommitID:        request.CommitID,
		TargetName:      target.Name,
		TargetVersion:   target.Version,
		PointsAvailable: target.Points,
		TargetType:      target.Type,

		Status:      SUBMISSION_SUBMITTED,
		Score:       uint(0),
		Performance: float64(0.0),
		TestIDs:     []string{buildTest.ID},
		Errors:      []string{},

		SubmissionTime: time.Now(),

		Env:       env,
		BuildTest: buildTest,
		Tests:     tg,
	}

	s.students = students
	s.Users = make([]string, 0, len(request.Users))
	for _, u := range request.Users {
		s.Users = append(s.Users, u.Email)
	}

	// Try and lock students now so we don't
	userLock.Lock()
	defer userLock.Unlock()

	// First pass - just check
	for _, student := range students {
		if running := pendingSubmissions[student.Email]; running {
			msg := fmt.Sprintf("Cannot submit at this time: User %v has a submission pending.", student.Email)
			env.Log.Println(msg)
			return nil, []error{errors.New(msg)}
		}
	}

	// Now lock
	for _, student := range students {
		pendingSubmissions[student.Email] = true
	}

	if env.Persistence != nil {
		if buildTest != nil {
			// If we get an error here, we can still hopefully recover
			env.notifyAndLogErr("Create Build Test", buildTest, MSG_PERSIST_CREATE, 0)
		}
		// This we can't recover from
		err = env.Persistence.Notify(s, MSG_PERSIST_CREATE, 0)
	}

	// Unlock so they can resubmit
	if err != nil {
		for _, student := range students {
			delete(pendingSubmissions, student.Email)
		}
		return nil, []error{err}
	}

	return s, nil
}

func (s *Submission) persistFailure() {
	// TODO: handle failures
	s.Status = SUBMISSION_ABORTED
}

func (s *Submission) TargetResult() (result *TargetResult) {
	result = &TargetResult{
		TargetName:     s.TargetName,
		TargetVersion:  s.TargetVersion,
		TargetType:     s.TargetType,
		Status:         s.Status,
		Score:          s.Score,
		MaxScore:       s.PointsAvailable,
		Performance:    s.Performance,
		SubmissionTime: s.SubmissionTime,
		CompletionTime: s.CompletionTime,
		SubmissionID:   s.ID,
	}
	return
}

// Update students.  We copy metadata to make this quick and store the
// submision id to look up the full details.
func (s *Submission) updateStudents() {

	res := s.TargetResult()
	for _, student := range s.students {
		// This might be nil coming out of Mongo
		if student.TargetResults == nil {
			student.TargetResults = make([]*TargetResult, 0)
		}

		student.LastSubmission = res

		// Update the high score for the target
		if s.Status == SUBMISSION_COMPLETED &&
			(s.TargetType == TARGET_ASST || s.Score == s.PointsAvailable) {
			found := false
			var prev *TargetResult
			for _, prev = range student.TargetResults {
				if prev.TargetName == s.TargetName {
					found = true
					break
				}
			}
			if !found || (s.TargetType == TARGET_ASST && prev.Score < s.Score) ||
				(s.TargetType == TARGET_PERF && prev.Performance < s.Performance) {
				student.TargetResults = append(student.TargetResults, res)
			}
		}

		if s.Env.Persistence != nil {
			if err := s.Env.Persistence.Notify(student, MSG_PERSIST_UPDATE, 0); err != nil {
				if sbytes, jerr := json.Marshal(student); jerr != nil {
					s.Env.Log.Printf("Error updating student: %v  (%v)\n", student.Email, err)
				} else {
					s.Env.Log.Printf("Error updating student: %v  (%v)\n", string(sbytes), err)
				}
			}
		}
	}

	userLock.Lock()
	defer userLock.Unlock()

	// Unblock the students from resubmitting
	for _, student := range s.students {
		delete(pendingSubmissions, student.Email)
	}
}

func (s *Submission) finish() {

	s.CompletionTime = time.Now()
	if s.Status == SUBMISSION_RUNNING {
		s.Status = SUBMISSION_COMPLETED
	}

	// Send the final submission update to the db
	s.Env.notifyAndLogErr("Finish Submission", s, MSG_PERSIST_COMPLETE, 0)

	if len(s.students) > 0 {
		s.updateStudents()
	}
}

// Synchronous submission runner
func (s *Submission) Run() error {
	// Run the build first.  Right now this is the only thing the front-end sees.
	// We'll add the rest of the tests if this passes, otherwise we don't waste the
	// disk space.

	var err error

	// So we know it's not nil
	if s.Env.Persistence == nil {
		s.Env.Persistence = &DoNothingPersistence{}
	}

	defer s.finish()

	// Build os161
	if s.BuildTest != nil {
		s.Status = SUBMISSION_BUILDING
		s.Env.notifyAndLogErr("Submission Status Building", s, MSG_PERSIST_UPDATE, MSG_FIELD_STATUS)

		res, err := s.BuildTest.Run(s.Env)
		if err != nil {
			s.Status = SUBMISSION_ABORTED
			s.Env.notifyAndLogErr("Submission Complete (Aborted)", s, MSG_PERSIST_COMPLETE, 0)
			return err
		}

		// Build output
		s.Env.RootDir = res.RootDir
		s.Env.KeyMap = res.KeyMap

		// Clean up temp build directory
		if len(res.TempDir) > 0 {
			defer os.RemoveAll(res.TempDir)
		}
	}

	// Build succeeded, update things accordingly
	for _, test := range s.Tests.Tests {
		// Add test IDs to DB
		s.TestIDs = append(s.TestIDs, test.ID)

		// Create the test object in the DB
		// If this fails, we abort the submission beacase we can't verify the results
		err = s.Env.Persistence.Notify(test, MSG_PERSIST_CREATE, 0)
		if err != nil {
			s.Status = SUBMISSION_ABORTED
			return err
		}
	}

	// Run it
	s.Status = SUBMISSION_RUNNING
	s.Env.notifyAndLogErr("Submission Status (Running) ", s, MSG_PERSIST_UPDATE, MSG_FIELD_TESTS|MSG_FIELD_STATUS)

	runner := NewDependencyRunner(s.Tests)
	done := runner.Run()

	// Update the score unless a test aborts, then it's 0 and we abort (eventually)
	for r := range done {
		if s.Status == SUBMISSION_RUNNING {
			if r.Test.Result == TEST_RESULT_ABORT {
				s.Status = SUBMISSION_ABORTED
				s.Score = 0
				s.Performance = float64(0)
			} else {
				s.Score += r.Test.PointsEarned
				s.Env.Persistence.Notify(s, MSG_PERSIST_UPDATE, MSG_FIELD_SCORE)
			}
		}
		if r.Err != nil {
			s.Errors = append(s.Errors, fmt.Sprintf("%v", r.Err))
		}
	}

	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/justone/pmb/api"
)

type NotifyCommand struct {
	Message   string `short:"m" long:"message" description:"Message to send."`
	Pid       int    `short:"p" long:"pid" description:"Notify after PID exits."`
	Important bool   `short:"i" long:"importan" description:"Label the notification as important."`
}

var notifyCommand NotifyCommand

func (x *NotifyCommand) Execute(args []string) error {
	bus := pmb.GetPMB(urisFromOpts(globalOptions))

	if len(args) == 0 && len(notifyCommand.Message) == 0 && notifyCommand.Pid == 0 {
		return fmt.Errorf("A message is required")
	}

	// fail fast if pid isn't found
	if notifyCommand.Pid > 0 {
		found, _ := findProcess(notifyCommand.Pid)

		if !found {
			return fmt.Errorf("Process %d not found.", notifyCommand.Pid)
		}
	}

	id := generateRandomID("notify")

	conn, err := bus.ConnectClient(id, !globalOptions.TrustKey)
	if err != nil {
		return err
	}

	return runNotify(conn, id, args)
}

func init() {
	parser.AddCommand("notify",
		"Send a notification.",
		"",
		&notifyCommand)
}

func runNotify(conn *pmb.Connection, id string, args []string) error {

	message := notifyCommand.Message

	if len(args) > 0 {
		cmd := exec.Command(args[0], args[1:]...)

		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout

		err := cmd.Run()

		result := "successfully"
		if err != nil {
			result = fmt.Sprintf("with error '%s'", err.Error())
		}

		if len(message) == 0 {
			message = fmt.Sprintf("Command [%s] completed %s.", strings.Join(args, " "), result)
		}
	} else if notifyCommand.Pid != 0 {

		notifyExecutable := ""
		fmt.Printf("Waiting for pid %d to finish...\n", notifyCommand.Pid)
		for {
			found, exec := findProcess(notifyCommand.Pid)

			// capture the name of the executable for the notification
			if len(notifyExecutable) == 0 {
				notifyExecutable = exec
			}

			if !found {
				break
			} else {
				time.Sleep(1 * time.Second)
			}
		}

		if len(message) == 0 {
			message = fmt.Sprintf("Command [%s] completed.", notifyExecutable)
		}
	}

	notificationId := generateRandomID("notify")
	notifyData := map[string]interface{}{
		"type":            "Notification",
		"notification-id": notificationId,
		"message":         message,
		"important":       notifyCommand.Important,
	}
	conn.Out <- pmb.Message{Contents: notifyData}

	timeout := time.After(2 * time.Second)
	for {
		select {
		case message := <-conn.In:
			data := message.Contents
			if data["type"].(string) == "NotificationDisplayed" && data["origin"].(string) == id {
				return nil
			}
		case _ = <-timeout:
			return fmt.Errorf("Unable to determine if message was displayed...")
		}
	}

	return nil
}

// TODO: use a go-based library for this, maybe gopsutil
func findProcess(pid int) (bool, string) {

	procCmd := exec.Command("/bin/ps", "-o", "pid=", "-p", strconv.Itoa(pid))

	err := procCmd.Run()

	if _, ok := err.(*exec.ExitError); ok {
		return false, ""
	} else if err != nil {
		return false, ""
	} else {
		return true, fmt.Sprintf("pid %d", pid)
	}

	return false, ""
}
<commit_msg>report exit status even if message is specified<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/justone/pmb/api"
)

type NotifyCommand struct {
	Message   string `short:"m" long:"message" description:"Message to send."`
	Pid       int    `short:"p" long:"pid" description:"Notify after PID exits."`
	Important bool   `short:"i" long:"importan" description:"Label the notification as important."`
}

var notifyCommand NotifyCommand

func (x *NotifyCommand) Execute(args []string) error {
	bus := pmb.GetPMB(urisFromOpts(globalOptions))

	if len(args) == 0 && len(notifyCommand.Message) == 0 && notifyCommand.Pid == 0 {
		return fmt.Errorf("A message is required")
	}

	// fail fast if pid isn't found
	if notifyCommand.Pid > 0 {
		found, _ := findProcess(notifyCommand.Pid)

		if !found {
			return fmt.Errorf("Process %d not found.", notifyCommand.Pid)
		}
	}

	id := generateRandomID("notify")

	conn, err := bus.ConnectClient(id, !globalOptions.TrustKey)
	if err != nil {
		return err
	}

	return runNotify(conn, id, args)
}

func init() {
	parser.AddCommand("notify",
		"Send a notification.",
		"",
		&notifyCommand)
}

func runNotify(conn *pmb.Connection, id string, args []string) error {

	message := notifyCommand.Message

	if len(args) > 0 {
		cmd := exec.Command(args[0], args[1:]...)

		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout

		err := cmd.Run()

		result := "successfully"
		if err != nil {
			result = fmt.Sprintf("with error '%s'", err.Error())
		}

		if len(message) == 0 {
			message = fmt.Sprintf("Command [%s] completed %s.", strings.Join(args, " "), result)
		} else {
			message = fmt.Sprintf("%s. Command completed %s.", message, result)
		}
	} else if notifyCommand.Pid != 0 {

		notifyExecutable := ""
		fmt.Printf("Waiting for pid %d to finish...\n", notifyCommand.Pid)
		for {
			found, exec := findProcess(notifyCommand.Pid)

			// capture the name of the executable for the notification
			if len(notifyExecutable) == 0 {
				notifyExecutable = exec
			}

			if !found {
				break
			} else {
				time.Sleep(1 * time.Second)
			}
		}

		if len(message) == 0 {
			message = fmt.Sprintf("Command [%s] completed.", notifyExecutable)
		}
	}

	notificationId := generateRandomID("notify")
	notifyData := map[string]interface{}{
		"type":            "Notification",
		"notification-id": notificationId,
		"message":         message,
		"important":       notifyCommand.Important,
	}
	conn.Out <- pmb.Message{Contents: notifyData}

	timeout := time.After(2 * time.Second)
	for {
		select {
		case message := <-conn.In:
			data := message.Contents
			if data["type"].(string) == "NotificationDisplayed" && data["origin"].(string) == id {
				return nil
			}
		case _ = <-timeout:
			return fmt.Errorf("Unable to determine if message was displayed...")
		}
	}

	return nil
}

// TODO: use a go-based library for this, maybe gopsutil
func findProcess(pid int) (bool, string) {

	procCmd := exec.Command("/bin/ps", "-o", "pid=", "-p", strconv.Itoa(pid))

	err := procCmd.Run()

	if _, ok := err.(*exec.ExitError); ok {
		return false, ""
	} else if err != nil {
		return false, ""
	} else {
		return true, fmt.Sprintf("pid %d", pid)
	}

	return false, ""
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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 historyleveldb

import (
	"os"
	"strconv"
	"testing"

	configtxtest "github.com/hyperledger/fabric/common/configtx/test"
	"github.com/hyperledger/fabric/common/ledger/testutil"
	"github.com/hyperledger/fabric/core/ledger/util"
	"github.com/hyperledger/fabric/protos/common"
	"github.com/hyperledger/fabric/protos/ledger/queryresult"
	"github.com/hyperledger/fabric/protos/peer"
	"github.com/spf13/viper"
)

func TestMain(m *testing.M) {
	viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger/history/historydb/historyleveldb")
	os.Exit(m.Run())
}

//TestSavepoint tests that save points get written after each block and get returned via GetBlockNumfromSavepoint
func TestSavepoint(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()

	// read the savepoint, it should not exist and should return nil Height object
	savepoint, err := env.testHistoryDB.GetLastSavepoint()
	testutil.AssertNoError(t, err, "Error upon historyDatabase.GetLastSavepoint()")
	testutil.AssertNil(t, savepoint)

	bg, gb := testutil.NewBlockGenerator(t, "testLedger", false)
	testutil.AssertNoError(t, env.testHistoryDB.Commit(gb), "")
	// read the savepoint, it should now exist and return a Height object with BlockNum 0
	savepoint, err = env.testHistoryDB.GetLastSavepoint()
	testutil.AssertNoError(t, err, "Error upon historyDatabase.GetLastSavepoint()")
	testutil.AssertEquals(t, savepoint.BlockNum, uint64(0))

	// create the next block (block 1)
	simulator, _ := env.txmgr.NewTxSimulator()
	simulator.SetState("ns1", "key1", []byte("value1"))
	simulator.Done()
	simRes, _ := simulator.GetTxSimulationResults()
	block1 := bg.NextBlock([][]byte{simRes})
	testutil.AssertNoError(t, env.testHistoryDB.Commit(block1), "")
	savepoint, err = env.testHistoryDB.GetLastSavepoint()
	testutil.AssertNoError(t, err, "Error upon historyDatabase.GetLastSavepoint()")
	testutil.AssertEquals(t, savepoint.BlockNum, uint64(1))
}

func TestHistory(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()
	provider := env.testBlockStorageEnv.provider
	ledger1id := "ledger1"
	store1, err := provider.OpenBlockStore(ledger1id)
	testutil.AssertNoError(t, err, "Error upon provider.OpenBlockStore()")
	defer store1.Shutdown()

	bg, gb := testutil.NewBlockGenerator(t, ledger1id, false)
	testutil.AssertNoError(t, store1.AddBlock(gb), "")
	testutil.AssertNoError(t, env.testHistoryDB.Commit(gb), "")

	//block1
	simulator, _ := env.txmgr.NewTxSimulator()
	value1 := []byte("value1")
	simulator.SetState("ns1", "key7", value1)
	simulator.Done()
	simRes, _ := simulator.GetTxSimulationResults()
	block1 := bg.NextBlock([][]byte{simRes})
	err = store1.AddBlock(block1)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block1)
	testutil.AssertNoError(t, err, "")

	//block2 tran1
	simulationResults := [][]byte{}
	simulator, _ = env.txmgr.NewTxSimulator()
	value2 := []byte("value2")
	simulator.SetState("ns1", "key7", value2)
	simulator.Done()
	simRes, _ = simulator.GetTxSimulationResults()
	simulationResults = append(simulationResults, simRes)
	//block2 tran2
	simulator2, _ := env.txmgr.NewTxSimulator()
	value3 := []byte("value3")
	simulator2.SetState("ns1", "key7", value3)
	simulator2.Done()
	simRes2, _ := simulator2.GetTxSimulationResults()
	simulationResults = append(simulationResults, simRes2)
	block2 := bg.NextBlock(simulationResults)
	err = store1.AddBlock(block2)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block2)
	testutil.AssertNoError(t, err, "")

	//block3
	simulator, _ = env.txmgr.NewTxSimulator()
	simulator.DeleteState("ns1", "key7")
	simulator.Done()
	simRes, _ = simulator.GetTxSimulationResults()
	block3 := bg.NextBlock([][]byte{simRes})
	err = store1.AddBlock(block3)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block3)
	testutil.AssertNoError(t, err, "")
	t.Logf("Inserted all 3 blocks")

	qhistory, err := env.testHistoryDB.NewHistoryQueryExecutor(store1)
	testutil.AssertNoError(t, err, "Error upon NewHistoryQueryExecutor")

	itr, err2 := qhistory.GetHistoryForKey("ns1", "key7")
	testutil.AssertNoError(t, err2, "Error upon GetHistoryForKey()")

	count := 0
	for {
		kmod, _ := itr.Next()
		if kmod == nil {
			break
		}
		txid := kmod.(*queryresult.KeyModification).TxId
		retrievedValue := kmod.(*queryresult.KeyModification).Value
		retrievedTimestamp := kmod.(*queryresult.KeyModification).Timestamp
		retrievedIsDelete := kmod.(*queryresult.KeyModification).IsDelete
		t.Logf("Retrieved history record for key=key7 at TxId=%s with value %v and timestamp %v",
			txid, retrievedValue, retrievedTimestamp)
		count++
		if count != 4 {
			expectedValue := []byte("value" + strconv.Itoa(count))
			testutil.AssertEquals(t, retrievedValue, expectedValue)
			testutil.AssertNotEquals(t, retrievedTimestamp, nil)
			testutil.AssertEquals(t, retrievedIsDelete, false)
		} else {
			testutil.AssertEquals(t, retrievedValue, nil)
			testutil.AssertNotEquals(t, retrievedTimestamp, nil)
			testutil.AssertEquals(t, retrievedIsDelete, true)
		}
	}
	testutil.AssertEquals(t, count, 4)
}

func TestHistoryForInvalidTran(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()
	provider := env.testBlockStorageEnv.provider
	ledger1id := "ledger1"
	store1, err := provider.OpenBlockStore(ledger1id)
	testutil.AssertNoError(t, err, "Error upon provider.OpenBlockStore()")
	defer store1.Shutdown()

	bg, gb := testutil.NewBlockGenerator(t, ledger1id, false)
	testutil.AssertNoError(t, store1.AddBlock(gb), "")
	testutil.AssertNoError(t, env.testHistoryDB.Commit(gb), "")

	//block1
	simulator, _ := env.txmgr.NewTxSimulator()
	value1 := []byte("value1")
	simulator.SetState("ns1", "key7", value1)
	simulator.Done()
	simRes, _ := simulator.GetTxSimulationResults()
	block1 := bg.NextBlock([][]byte{simRes})

	//for this invalid tran test, set the transaction to invalid
	txsFilter := util.TxValidationFlags(block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
	txsFilter.SetFlag(0, peer.TxValidationCode_INVALID_OTHER_REASON)
	block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter

	err = store1.AddBlock(block1)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block1)
	testutil.AssertNoError(t, err, "")

	qhistory, err := env.testHistoryDB.NewHistoryQueryExecutor(store1)
	testutil.AssertNoError(t, err, "Error upon NewHistoryQueryExecutor")

	itr, err2 := qhistory.GetHistoryForKey("ns1", "key7")
	testutil.AssertNoError(t, err2, "Error upon GetHistoryForKey()")

	// test that there are no history values, since the tran was marked as invalid
	kmod, _ := itr.Next()
	testutil.AssertNil(t, kmod)
}

//TestSavepoint tests that save points get written after each block and get returned via GetBlockNumfromSavepoint
func TestHistoryDisabled(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()

	viper.Set("ledger.history.enableHistoryDatabase", "false")

	//no need to pass blockstore into history executore, it won't be used in this test
	qhistory, err := env.testHistoryDB.NewHistoryQueryExecutor(nil)
	testutil.AssertNoError(t, err, "Error upon NewHistoryQueryExecutor")

	_, err2 := qhistory.GetHistoryForKey("ns1", "key7")
	testutil.AssertError(t, err2, "Error should have been returned for GetHistoryForKey() when history disabled")
}

//TestGenesisBlockNoError tests that Genesis blocks are ignored by history processing
// since we only persist history of chaincode key writes
func TestGenesisBlockNoError(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()

	block, err := configtxtest.MakeGenesisBlock("test_chainid")
	testutil.AssertNoError(t, err, "")

	err = env.testHistoryDB.Commit(block)
	testutil.AssertNoError(t, err, "")
}
<commit_msg>FAB-3401: Improve unit tests for kvledger/history pkgs<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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 historyleveldb

import (
	"os"
	"strconv"
	"testing"

	configtxtest "github.com/hyperledger/fabric/common/configtx/test"
	"github.com/hyperledger/fabric/common/ledger/testutil"
	"github.com/hyperledger/fabric/core/ledger/util"
	"github.com/hyperledger/fabric/protos/common"
	"github.com/hyperledger/fabric/protos/ledger/queryresult"
	"github.com/hyperledger/fabric/protos/peer"
	"github.com/spf13/viper"
)

func TestMain(m *testing.M) {
	viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger/history/historydb/historyleveldb")
	os.Exit(m.Run())
}

//TestSavepoint tests that save points get written after each block and get returned via GetBlockNumfromSavepoint
func TestSavepoint(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()

	// read the savepoint, it should not exist and should return nil Height object
	savepoint, err := env.testHistoryDB.GetLastSavepoint()
	testutil.AssertNoError(t, err, "Error upon historyDatabase.GetLastSavepoint()")
	testutil.AssertNil(t, savepoint)

	// ShouldRecover should return true when no savepoint is found and recovery from block 0
	status, blockNum, err := env.testHistoryDB.ShouldRecover(0)
	testutil.AssertNoError(t, err, "Error upon historyDatabase.ShouldRecover()")
	testutil.AssertEquals(t, status, true)
	testutil.AssertEquals(t, blockNum, uint64(0))

	bg, gb := testutil.NewBlockGenerator(t, "testLedger", false)
	testutil.AssertNoError(t, env.testHistoryDB.Commit(gb), "")
	// read the savepoint, it should now exist and return a Height object with BlockNum 0
	savepoint, err = env.testHistoryDB.GetLastSavepoint()
	testutil.AssertNoError(t, err, "Error upon historyDatabase.GetLastSavepoint()")
	testutil.AssertEquals(t, savepoint.BlockNum, uint64(0))

	// create the next block (block 1)
	simulator, _ := env.txmgr.NewTxSimulator()
	simulator.SetState("ns1", "key1", []byte("value1"))
	simulator.Done()
	simRes, _ := simulator.GetTxSimulationResults()
	block1 := bg.NextBlock([][]byte{simRes})
	testutil.AssertNoError(t, env.testHistoryDB.Commit(block1), "")
	savepoint, err = env.testHistoryDB.GetLastSavepoint()
	testutil.AssertNoError(t, err, "Error upon historyDatabase.GetLastSavepoint()")
	testutil.AssertEquals(t, savepoint.BlockNum, uint64(1))

	// Should Recover should return false
	status, blockNum, err = env.testHistoryDB.ShouldRecover(1)
	testutil.AssertNoError(t, err, "Error upon historyDatabase.ShouldRecover()")
	testutil.AssertEquals(t, status, false)
	testutil.AssertEquals(t, blockNum, uint64(2))

	// create the next block (block 2)
	simulator, _ = env.txmgr.NewTxSimulator()
	simulator.SetState("ns1", "key1", []byte("value2"))
	simulator.Done()
	simRes, _ = simulator.GetTxSimulationResults()
	block2 := bg.NextBlock([][]byte{simRes})

	// assume that the peer failed to commit this block to historyDB and is being recovered now
	env.testHistoryDB.CommitLostBlock(block2)
	savepoint, err = env.testHistoryDB.GetLastSavepoint()
	testutil.AssertNoError(t, err, "Error upon historyDatabase.GetLastSavepoint()")
	testutil.AssertEquals(t, savepoint.BlockNum, uint64(2))

	//Pass high blockNum, ShouldRecover should return true with 3 as blocknum to recover from
	status, blockNum, err = env.testHistoryDB.ShouldRecover(10)
	testutil.AssertNoError(t, err, "Error upon historyDatabase.ShouldRecover()")
	testutil.AssertEquals(t, status, true)
	testutil.AssertEquals(t, blockNum, uint64(3))
}

func TestHistory(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()
	provider := env.testBlockStorageEnv.provider
	ledger1id := "ledger1"
	store1, err := provider.OpenBlockStore(ledger1id)
	testutil.AssertNoError(t, err, "Error upon provider.OpenBlockStore()")
	defer store1.Shutdown()

	bg, gb := testutil.NewBlockGenerator(t, ledger1id, false)
	testutil.AssertNoError(t, store1.AddBlock(gb), "")
	testutil.AssertNoError(t, env.testHistoryDB.Commit(gb), "")

	//block1
	simulator, _ := env.txmgr.NewTxSimulator()
	value1 := []byte("value1")
	simulator.SetState("ns1", "key7", value1)
	simulator.Done()
	simRes, _ := simulator.GetTxSimulationResults()
	block1 := bg.NextBlock([][]byte{simRes})
	err = store1.AddBlock(block1)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block1)
	testutil.AssertNoError(t, err, "")

	//block2 tran1
	simulationResults := [][]byte{}
	simulator, _ = env.txmgr.NewTxSimulator()
	value2 := []byte("value2")
	simulator.SetState("ns1", "key7", value2)
	simulator.Done()
	simRes, _ = simulator.GetTxSimulationResults()
	simulationResults = append(simulationResults, simRes)
	//block2 tran2
	simulator2, _ := env.txmgr.NewTxSimulator()
	value3 := []byte("value3")
	simulator2.SetState("ns1", "key7", value3)
	simulator2.Done()
	simRes2, _ := simulator2.GetTxSimulationResults()
	simulationResults = append(simulationResults, simRes2)
	block2 := bg.NextBlock(simulationResults)
	err = store1.AddBlock(block2)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block2)
	testutil.AssertNoError(t, err, "")

	//block3
	simulator, _ = env.txmgr.NewTxSimulator()
	simulator.DeleteState("ns1", "key7")
	simulator.Done()
	simRes, _ = simulator.GetTxSimulationResults()
	block3 := bg.NextBlock([][]byte{simRes})
	err = store1.AddBlock(block3)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block3)
	testutil.AssertNoError(t, err, "")
	t.Logf("Inserted all 3 blocks")

	qhistory, err := env.testHistoryDB.NewHistoryQueryExecutor(store1)
	testutil.AssertNoError(t, err, "Error upon NewHistoryQueryExecutor")

	itr, err2 := qhistory.GetHistoryForKey("ns1", "key7")
	testutil.AssertNoError(t, err2, "Error upon GetHistoryForKey()")

	count := 0
	for {
		kmod, _ := itr.Next()
		if kmod == nil {
			break
		}
		txid := kmod.(*queryresult.KeyModification).TxId
		retrievedValue := kmod.(*queryresult.KeyModification).Value
		retrievedTimestamp := kmod.(*queryresult.KeyModification).Timestamp
		retrievedIsDelete := kmod.(*queryresult.KeyModification).IsDelete
		t.Logf("Retrieved history record for key=key7 at TxId=%s with value %v and timestamp %v",
			txid, retrievedValue, retrievedTimestamp)
		count++
		if count != 4 {
			expectedValue := []byte("value" + strconv.Itoa(count))
			testutil.AssertEquals(t, retrievedValue, expectedValue)
			testutil.AssertNotEquals(t, retrievedTimestamp, nil)
			testutil.AssertEquals(t, retrievedIsDelete, false)
		} else {
			testutil.AssertEquals(t, retrievedValue, nil)
			testutil.AssertNotEquals(t, retrievedTimestamp, nil)
			testutil.AssertEquals(t, retrievedIsDelete, true)
		}
	}
	testutil.AssertEquals(t, count, 4)
}

func TestHistoryForInvalidTran(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()
	provider := env.testBlockStorageEnv.provider
	ledger1id := "ledger1"
	store1, err := provider.OpenBlockStore(ledger1id)
	testutil.AssertNoError(t, err, "Error upon provider.OpenBlockStore()")
	defer store1.Shutdown()

	bg, gb := testutil.NewBlockGenerator(t, ledger1id, false)
	testutil.AssertNoError(t, store1.AddBlock(gb), "")
	testutil.AssertNoError(t, env.testHistoryDB.Commit(gb), "")

	//block1
	simulator, _ := env.txmgr.NewTxSimulator()
	value1 := []byte("value1")
	simulator.SetState("ns1", "key7", value1)
	simulator.Done()
	simRes, _ := simulator.GetTxSimulationResults()
	block1 := bg.NextBlock([][]byte{simRes})

	//for this invalid tran test, set the transaction to invalid
	txsFilter := util.TxValidationFlags(block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
	txsFilter.SetFlag(0, peer.TxValidationCode_INVALID_OTHER_REASON)
	block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter

	err = store1.AddBlock(block1)
	testutil.AssertNoError(t, err, "")
	err = env.testHistoryDB.Commit(block1)
	testutil.AssertNoError(t, err, "")

	qhistory, err := env.testHistoryDB.NewHistoryQueryExecutor(store1)
	testutil.AssertNoError(t, err, "Error upon NewHistoryQueryExecutor")

	itr, err2 := qhistory.GetHistoryForKey("ns1", "key7")
	testutil.AssertNoError(t, err2, "Error upon GetHistoryForKey()")

	// test that there are no history values, since the tran was marked as invalid
	kmod, _ := itr.Next()
	testutil.AssertNil(t, kmod)
}

//TestSavepoint tests that save points get written after each block and get returned via GetBlockNumfromSavepoint
func TestHistoryDisabled(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()

	viper.Set("ledger.history.enableHistoryDatabase", "false")

	//no need to pass blockstore into history executore, it won't be used in this test
	qhistory, err := env.testHistoryDB.NewHistoryQueryExecutor(nil)
	testutil.AssertNoError(t, err, "Error upon NewHistoryQueryExecutor")

	_, err2 := qhistory.GetHistoryForKey("ns1", "key7")
	testutil.AssertError(t, err2, "Error should have been returned for GetHistoryForKey() when history disabled")
}

//TestGenesisBlockNoError tests that Genesis blocks are ignored by history processing
// since we only persist history of chaincode key writes
func TestGenesisBlockNoError(t *testing.T) {

	env := NewTestHistoryEnv(t)
	defer env.cleanup()

	block, err := configtxtest.MakeGenesisBlock("test_chainid")
	testutil.AssertNoError(t, err, "")

	err = env.testHistoryDB.Commit(block)
	testutil.AssertNoError(t, err, "")
}
<|endoftext|>


<commit_before>package mkdirp

import (
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

var c = Convey

func TestMkdirp(t *testing.T) {
	c("mkTree should", t, func() {
		c("return tree from straight path", func() {
			root := mkTree("Users/me/somefolder")
			So(root, ShouldNotBeNil)
			So(len(root.branches), ShouldEqual, 0)
			So(root.name, ShouldEqual, "Users/me/somefolder")
		})
		c("return tree with subtrees", func() {
			root := mkTree("Users/me/{somefolder,somefolder2}/test/{data1,data2}")

			So(root.name, ShouldEqual, "Users/me/")
			subtree := root.branches
			So(len(subtree), ShouldEqual, 2)
			So(subtree[0].name, ShouldEqual, "somefolder")
			So(subtree[1].name, ShouldEqual, "somefolder2")

			sstree := subtree[0]
			sstree2 := subtree[1]
			So(len(sstree.branches), ShouldEqual, 1)
			So(sstree.branches[0].name, ShouldEqual, "test/")
			So(len(sstree2.branches), ShouldEqual, 1)
			So(sstree2.branches[0].name, ShouldEqual, "test/")

			test := sstree.branches[0]
			So(len(test.branches), ShouldEqual, 2)
			So(test.branches[0].name, ShouldEqual, "data1")
			So(test.branches[1].name, ShouldEqual, "data2")

		})
	})
}
<commit_msg>removed empty line<commit_after>package mkdirp

import (
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

var c = Convey

func TestMkdirp(t *testing.T) {
	c("mkTree should", t, func() {
		c("return tree from straight path", func() {
			root := mkTree("Users/me/somefolder")
			So(root, ShouldNotBeNil)
			So(len(root.branches), ShouldEqual, 0)
			So(root.name, ShouldEqual, "Users/me/somefolder")
		})
		c("return tree with subtrees", func() {
			root := mkTree("Users/me/{somefolder,somefolder2}/test/{data1,data2}")

			So(root.name, ShouldEqual, "Users/me/")
			subtree := root.branches
			So(len(subtree), ShouldEqual, 2)
			So(subtree[0].name, ShouldEqual, "somefolder")
			So(subtree[1].name, ShouldEqual, "somefolder2")

			sstree := subtree[0]
			sstree2 := subtree[1]
			So(len(sstree.branches), ShouldEqual, 1)
			So(sstree.branches[0].name, ShouldEqual, "test/")
			So(len(sstree2.branches), ShouldEqual, 1)
			So(sstree2.branches[0].name, ShouldEqual, "test/")

			test := sstree.branches[0]
			So(len(test.branches), ShouldEqual, 2)
			So(test.branches[0].name, ShouldEqual, "data1")
			So(test.branches[1].name, ShouldEqual, "data2")
		})
	})
}
<|endoftext|>


<commit_before>package model

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"
)

type Metadata struct {
	APIVersion          string
	EndpointPrefix      string
	JSONVersion         string
	ServiceAbbreviation string
	ServiceFullName     string
	SignatureVersion    string
	TargetPrefix        string
	Protocol            string
}

type HTTPOptions struct {
	Method     string
	RequestURI string
}

type Operation struct {
	Name          string
	Documentation string
	HTTP          HTTPOptions
	InputRef      *ShapeRef `json:"Input"`
	OutputRef     *ShapeRef `json:"Output"`
}

func (o Operation) Input() *Shape {
	return o.InputRef.Shape()
}

func (o Operation) Output() *Shape {
	return o.OutputRef.Shape()
}

type Error struct {
	Code           string
	HTTPStatusCode int
	SenderFault    bool
}

type ShapeRef struct {
	ShapeName     string `json:"Shape"`
	Documentation string
	LocationName  string
	Wrapper       bool
	ResultWrapper string
}

func (ref *ShapeRef) WrappedType() string {
	if ref.ResultWrapper != "" {
		return ref.ResultWrapper
	}
	return ref.Shape().Type()
}

func (ref *ShapeRef) Shape() *Shape {
	if ref == nil {
		return nil
	}
	return service.Shapes[ref.ShapeName]
}

type Member struct {
	Name     string
	Shape    *Shape
	Required bool
}

func (m Member) JSONTag() string {
	if !m.Required {
		return fmt.Sprintf("`json:\"%s,omitempty\"`", m.Name)
	}
	return fmt.Sprintf("`json:\"%s\"`", m.Name)
}

func (m Member) XMLTag(wrapper string) string {
	var path []string
	if wrapper != "" {
		path = append(path, wrapper)
	}

	path = append(path, m.Name)

	if m.Shape.ShapeType == "list" {
		loc := m.Shape.MemberRef.LocationName
		if loc == "" {
			loc = "member"
		}
		path = append(path, loc)
	}

	return fmt.Sprintf("`xml:\"%s\"`", strings.Join(path, ">"))
}

func (m Member) Type() string {
	return m.Shape.Type()
}

type Shape struct {
	Name          string
	ShapeType     string `json:"Type"`
	Required      []string
	MemberRefs    map[string]ShapeRef `json:"Members"`
	MemberRef     *ShapeRef           `json:"Member"`
	KeyRef        *ShapeRef           `json:"Key"`
	ValueRef      *ShapeRef           `json:"Value"`
	Error         Error
	Exception     bool
	Documentation string
	Min           int
	Max           int
	Pattern       string
	Sensitive     bool
	Wrapper       bool
}

func (s *Shape) Message() bool {
	return strings.HasSuffix(s.Name, "Message") && s.ResultWrapper() != ""
}

func (s *Shape) MessageTag() string {
	tag := strings.TrimSuffix(s.ResultWrapper(), "Result") + "Response"
	return fmt.Sprintf("`xml:\"%s\"`", tag)
}

func (s *Shape) Key() *Shape {
	return s.KeyRef.Shape()
}

func (s *Shape) Member() *Shape {
	return s.MemberRef.Shape()
}

func (s *Shape) Members() map[string]Member {
	required := func(v string) bool {
		for _, s := range s.Required {
			if s == v {
				return true
			}
		}
		return false
	}

	members := map[string]Member{}
	for name, ref := range s.MemberRefs {
		members[name] = Member{
			Name:     name,
			Shape:    ref.Shape(),
			Required: required(name),
		}
	}
	return members
}

func (s *Shape) ResultWrapper() string {
	var wrappers []string

	for _, op := range service.Operations {
		if op.OutputRef != nil && op.OutputRef.ShapeName == s.Name {
			wrappers = append(wrappers, op.OutputRef.ResultWrapper)
		}
	}

	if len(wrappers) == 1 {
		return wrappers[0]
	}

	return ""
}

func (s *Shape) Value() *Shape {
	return s.ValueRef.Shape()
}

func (s *Shape) Type() string {
	switch s.ShapeType {
	case "structure":
		return exportable(s.Name)
	case "integer":
		return "int"
	case "long":
		return "int64"
	case "double":
		return "float64"
	case "string":
		return "string"
	case "map":
		return "map[" + s.Key().Type() + "]" + s.Value().Type()
	case "list":
		return "[]" + s.Member().Type()
	case "boolean":
		return "bool"
	case "blob":
		return "[]byte"
	case "timestamp":
		return "time.Time"
	}

	panic(fmt.Errorf("type %q (%q) not found", s.Name, s.ShapeType))
}

type Service struct {
	Name          string
	FullName      string
	PackageName   string
	Metadata      Metadata
	Documentation string
	Operations    map[string]Operation
	Shapes        map[string]*Shape
}

func (s Service) Wrappers() map[string]*Shape {
	wrappers := map[string]*Shape{}

	// collect all wrapper types
	for _, op := range s.Operations {
		if op.InputRef != nil && op.InputRef.ResultWrapper != "" {
			wrappers[op.InputRef.ResultWrapper] = op.Input()
		}

		if op.OutputRef != nil && op.OutputRef.ResultWrapper != "" {
			wrappers[op.OutputRef.ResultWrapper] = op.Output()
		}
	}

	// remove all existing types?
	for name := range wrappers {
		if _, ok := s.Shapes[name]; ok {
			delete(wrappers, name)
		}
	}

	return wrappers
}

var service Service

func Load(name string, r io.Reader) error {
	service = Service{}
	if err := json.NewDecoder(r).Decode(&service); err != nil {
		return err
	}

	for name, shape := range service.Shapes {
		shape.Name = name
	}

	service.FullName = service.Metadata.ServiceFullName
	service.PackageName = strings.ToLower(name)
	service.Name = name

	return nil
}
<commit_msg>Support floats.<commit_after>package model

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"
)

type Metadata struct {
	APIVersion          string
	EndpointPrefix      string
	JSONVersion         string
	ServiceAbbreviation string
	ServiceFullName     string
	SignatureVersion    string
	TargetPrefix        string
	Protocol            string
}

type HTTPOptions struct {
	Method     string
	RequestURI string
}

type Operation struct {
	Name          string
	Documentation string
	HTTP          HTTPOptions
	InputRef      *ShapeRef `json:"Input"`
	OutputRef     *ShapeRef `json:"Output"`
}

func (o Operation) Input() *Shape {
	return o.InputRef.Shape()
}

func (o Operation) Output() *Shape {
	return o.OutputRef.Shape()
}

type Error struct {
	Code           string
	HTTPStatusCode int
	SenderFault    bool
}

type ShapeRef struct {
	ShapeName     string `json:"Shape"`
	Documentation string
	LocationName  string
	Wrapper       bool
	ResultWrapper string
}

func (ref *ShapeRef) WrappedType() string {
	if ref.ResultWrapper != "" {
		return ref.ResultWrapper
	}
	return ref.Shape().Type()
}

func (ref *ShapeRef) Shape() *Shape {
	if ref == nil {
		return nil
	}
	return service.Shapes[ref.ShapeName]
}

type Member struct {
	Name     string
	Shape    *Shape
	Required bool
}

func (m Member) JSONTag() string {
	if !m.Required {
		return fmt.Sprintf("`json:\"%s,omitempty\"`", m.Name)
	}
	return fmt.Sprintf("`json:\"%s\"`", m.Name)
}

func (m Member) XMLTag(wrapper string) string {
	var path []string
	if wrapper != "" {
		path = append(path, wrapper)
	}

	path = append(path, m.Name)

	if m.Shape.ShapeType == "list" {
		loc := m.Shape.MemberRef.LocationName
		if loc == "" {
			loc = "member"
		}
		path = append(path, loc)
	}

	return fmt.Sprintf("`xml:\"%s\"`", strings.Join(path, ">"))
}

func (m Member) Type() string {
	return m.Shape.Type()
}

type Shape struct {
	Name          string
	ShapeType     string `json:"Type"`
	Required      []string
	MemberRefs    map[string]ShapeRef `json:"Members"`
	MemberRef     *ShapeRef           `json:"Member"`
	KeyRef        *ShapeRef           `json:"Key"`
	ValueRef      *ShapeRef           `json:"Value"`
	Error         Error
	Exception     bool
	Documentation string
	Min           int
	Max           int
	Pattern       string
	Sensitive     bool
	Wrapper       bool
}

func (s *Shape) Message() bool {
	return strings.HasSuffix(s.Name, "Message") && s.ResultWrapper() != ""
}

func (s *Shape) MessageTag() string {
	tag := strings.TrimSuffix(s.ResultWrapper(), "Result") + "Response"
	return fmt.Sprintf("`xml:\"%s\"`", tag)
}

func (s *Shape) Key() *Shape {
	return s.KeyRef.Shape()
}

func (s *Shape) Member() *Shape {
	return s.MemberRef.Shape()
}

func (s *Shape) Members() map[string]Member {
	required := func(v string) bool {
		for _, s := range s.Required {
			if s == v {
				return true
			}
		}
		return false
	}

	members := map[string]Member{}
	for name, ref := range s.MemberRefs {
		members[name] = Member{
			Name:     name,
			Shape:    ref.Shape(),
			Required: required(name),
		}
	}
	return members
}

func (s *Shape) ResultWrapper() string {
	var wrappers []string

	for _, op := range service.Operations {
		if op.OutputRef != nil && op.OutputRef.ShapeName == s.Name {
			wrappers = append(wrappers, op.OutputRef.ResultWrapper)
		}
	}

	if len(wrappers) == 1 {
		return wrappers[0]
	}

	return ""
}

func (s *Shape) Value() *Shape {
	return s.ValueRef.Shape()
}

func (s *Shape) Type() string {
	switch s.ShapeType {
	case "structure":
		return exportable(s.Name)
	case "integer":
		return "int"
	case "long":
		return "int64"
	case "float":
		return "float32"
	case "double":
		return "float64"
	case "string":
		return "string"
	case "map":
		return "map[" + s.Key().Type() + "]" + s.Value().Type()
	case "list":
		return "[]" + s.Member().Type()
	case "boolean":
		return "bool"
	case "blob":
		return "[]byte"
	case "timestamp":
		return "time.Time"
	}

	panic(fmt.Errorf("type %q (%q) not found", s.Name, s.ShapeType))
}

type Service struct {
	Name          string
	FullName      string
	PackageName   string
	Metadata      Metadata
	Documentation string
	Operations    map[string]Operation
	Shapes        map[string]*Shape
}

func (s Service) Wrappers() map[string]*Shape {
	wrappers := map[string]*Shape{}

	// collect all wrapper types
	for _, op := range s.Operations {
		if op.InputRef != nil && op.InputRef.ResultWrapper != "" {
			wrappers[op.InputRef.ResultWrapper] = op.Input()
		}

		if op.OutputRef != nil && op.OutputRef.ResultWrapper != "" {
			wrappers[op.OutputRef.ResultWrapper] = op.Output()
		}
	}

	// remove all existing types?
	for name := range wrappers {
		if _, ok := s.Shapes[name]; ok {
			delete(wrappers, name)
		}
	}

	return wrappers
}

var service Service

func Load(name string, r io.Reader) error {
	service = Service{}
	if err := json.NewDecoder(r).Decode(&service); err != nil {
		return err
	}

	for name, shape := range service.Shapes {
		shape.Name = name
	}

	service.FullName = service.Metadata.ServiceFullName
	service.PackageName = strings.ToLower(name)
	service.Name = name

	return nil
}
<|endoftext|>


<commit_before>package model

import (
	"errors"
	"time"
)

type Job struct {
	ID         uint64    `gorm:"column:id; primary_key:yes"`
	JoinDate   time.Time `sql:"DEFAULT:null"`
	EndDate    time.Time `sql:"DEFAULT:null"`
	LeaveYears []LeaveYear
	LeaveAlloc []LeaveAlloc
	CreatedAt  time.Time
	UpdatedAt  time.Time
	DeletedAt  time.Time
}

type LeaveAlloc struct {
	ID          uint64 `gorm:"column:id; primary_key:yes"`
	AddedBy     User
	Days        float64
	Description string
	StartDate   time.Time `sql:"DEFAULT:null"`
}

type LeaveYear struct {
	ID        uint64    `gorm:"column:id; primary_key:yes"`
	StartDate time.Time `sql:"DEFAULT:null"`
	Days      float64
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt time.Time
}

type User struct {
	ID        uint64 `gorm:"column:id; primary_key:yes"`
	Name      string `sql:"type:text;"`
	GitHubID  uint64
	Email     string `sql:"type:text;"`
	TimeZone  int
	Jobs      []Job `gorm:"many2many:users_employments;"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt time.Time
}

func (u *User) UpdateOrCreate() error {
	if u.GitHubID == 0 {
		return errors.New("GitHub user ID was set to zero; cannot match")
	}

	res := db.Where(User{GitHubID: u.GitHubID}).FirstOrInit(u)

	if res.Error != nil {
		return res.Error
	}

	res = db.Save(u)
	return res.Error
}

func FindUser(id uint64) (user User, err error) {
	res := db.First(&user, id)
	return user, res.Error
}
<commit_msg>Make User.Jobs one-to-many relationship<commit_after>package model

import (
	"errors"
	"time"
)

type Job struct {
	ID         uint64    `gorm:"column:id; primary_key:yes"`
	JoinDate   time.Time `sql:"DEFAULT:null"`
	EndDate    time.Time `sql:"DEFAULT:null"`
	LeaveYears []LeaveYear
	LeaveAlloc []LeaveAlloc
	CreatedAt  time.Time
	UpdatedAt  time.Time
	DeletedAt  time.Time
}

type LeaveAlloc struct {
	ID          uint64 `gorm:"column:id; primary_key:yes"`
	AddedBy     User
	Days        float64
	Description string
	StartDate   time.Time `sql:"DEFAULT:null"`
}

type LeaveYear struct {
	ID        uint64    `gorm:"column:id; primary_key:yes"`
	StartDate time.Time `sql:"DEFAULT:null"`
	Days      float64
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt time.Time
}

type User struct {
	ID        uint64 `gorm:"column:id; primary_key:yes"`
	Name      string `sql:"type:text;"`
	GitHubID  uint64
	Email     string `sql:"type:text;"`
	TimeZone  int
	Jobs      []Job
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt time.Time
}

func (u *User) UpdateOrCreate() error {
	if u.GitHubID == 0 {
		return errors.New("GitHub user ID was set to zero; cannot match")
	}

	res := db.Where(User{GitHubID: u.GitHubID}).FirstOrInit(u)

	if res.Error != nil {
		return res.Error
	}

	res = db.Save(u)
	return res.Error
}

func FindUser(id uint64) (user User, err error) {
	res := db.First(&user, id)
	return user, res.Error
}
<|endoftext|>


<commit_before>package model

// NewTable create a new table with the given name
func NewTable(name string) Table {
	return &table{
		name: name,
		columnNameToIndex: make(map[string]int),
	}
}

func (t *table) ID() string {
	return "table#" + t.name
}

func (t *table) LookupColumn(name string) (TableColumn, bool) {
	t.mu.RLock()
	defer t.mu.RUnlock()

	idx, ok := t.columnNameToIndex[name]
	if !ok {
		return nil, false
	}

	return t.columns[idx], true
}

func (t *table) LookupColumnBefore(name string) (TableColumn, bool) {
	t.mu.RLock()
	defer t.mu.RUnlock()

	idx, ok := t.columnNameToIndex[name]
	if !ok || idx == 0 {
		return nil, false
	}

	return t.columns[idx-1], true
}

func (t *table) LookupIndex(id string) (Index, bool) {
	for idx := range t.Indexes() {
		if idx.ID() == id {
			return idx, true
		}
	}
	return nil, false
}

func (t *table) AddColumn(v TableColumn) Table {
	t.mu.Lock()
	defer t.mu.Unlock()

	// Avoid adding the same TableColumn to multiple tables
	if tblID := v.TableID(); tblID != "" {
		v = v.Clone()
	}
	v.SetTableID(t.ID())
	t.columns = append(t.columns, v)
	t.columnNameToIndex[v.ID()] = len(t.columns) - 1
	return t
}

func (t *table) AddIndex(v Index) Table {
	t.indexes = append(t.indexes, v)
	return t
}

func (t *table) AddOption(v TableOption) Table {
	t.options = append(t.options, v)
	return t
}

func (t *table) Name() string {
	return t.name
}

func (t *table) IsIfNotExists() bool {
	return t.ifnotexists
}

func (t *table) IsTemporary() bool {
	return t.temporary
}

func (t *table) SetIfNotExists(v bool) Table {
	t.ifnotexists = v
	return t
}

func (t *table) HasLikeTable() bool {
	return t.likeTable.Valid
}

func (t *table) SetLikeTable(s string) Table {
	t.likeTable.Valid = true
	t.likeTable.Value = s
	return t
}

func (t *table) LikeTable() string {
	return t.likeTable.Value
}

func (t *table) SetTemporary(v bool) Table {
	t.temporary = v
	return t
}

func (t *table) Columns() chan TableColumn {
	ch := make(chan TableColumn, len(t.columns))
	for _, col := range t.columns {
		ch <- col
	}
	close(ch)
	return ch
}

func (t *table) Indexes() chan Index {
	ch := make(chan Index, len(t.indexes))
	for _, idx := range t.indexes {
		ch <- idx
	}
	close(ch)
	return ch
}

func (t *table) Options() chan TableOption {
	ch := make(chan TableOption, len(t.options))
	for _, idx := range t.options {
		ch <- idx
	}
	close(ch)
	return ch
}

func (t *table) Normalize() (Table, bool) {
	var clone bool
	var additionalIndexes []Index
	var columns []TableColumn
	for col := range t.Columns() {
		ncol, modified := col.Normalize()
		if modified {
			clone = true
		}

		// column_definition [UNIQUE [KEY] | [PRIMARY] KEY]
		// they mean same as INDEX or CONSTRAINT
		switch {
		case ncol.IsPrimary():
			// we have to move off the index declaration from the
			// primary key column to an index associated with the table
			index := NewIndex(IndexKindPrimaryKey, t.ID())
			index.SetType(IndexTypeNone)
			idxCol := NewIndexColumn(ncol.Name())
			index.AddColumns(idxCol)
			additionalIndexes = append(additionalIndexes, index)
			if !modified {
				clone = true
			}
			ncol = ncol.Clone()
			ncol.SetPrimary(false)
		case ncol.IsUnique():
			index := NewIndex(IndexKindUnique, t.ID())
			// if you do not assign a name, the index is assigned the same name as the first indexed column
			index.SetName(ncol.Name())
			index.SetType(IndexTypeNone)
			idxCol := NewIndexColumn(ncol.Name())
			index.AddColumns(idxCol)
			additionalIndexes = append(additionalIndexes, index)
			if !modified {
				clone = true
			}
			ncol = ncol.Clone()
			ncol.SetUnique(false)
		}

		columns = append(columns, ncol)
	}

	var indexes []Index
	for idx := range t.Indexes() {
		nidx, modified := idx.Normalize()
		if modified {
			clone = true
		}

		// if Not defined CONSTRAINT symbol, then resolve
		// implicitly created INDEX too difficult.
		// (lestrrat) this comment is confusing. Please add
		// actual examples somewhere
		if nidx.IsForeginKey() && nidx.Symbol() != "" {
			clone = true
			// add implicitly created INDEX
			index := NewIndex(IndexKindNormal, t.ID())
			index.SetName(nidx.Symbol())
			index.SetType(IndexTypeNone)
			columns := []IndexColumn{}
			for c := range nidx.Columns() {
				columns = append(columns, c)
			}
			index.AddColumns(columns...)
			indexes = append(indexes, index)
		}
		indexes = append(indexes, nidx)
	}

	if !clone {
		return t, false
	}

	tbl := NewTable(t.Name())
	tbl.SetIfNotExists(t.IsIfNotExists())
	tbl.SetTemporary(t.IsTemporary())

	for _, index := range additionalIndexes {
		tbl.AddIndex(index)
	}

	for _, col := range columns {
		tbl.AddColumn(col)
	}

	for _, idx := range indexes {
		tbl.AddIndex(idx)
	}

	for opt := range t.Options() {
		tbl.AddOption(opt)
	}
	return tbl, true
}

// NewTableOption creates a new table option with the given name, value, and a flag indicating if quoting is necessary
func NewTableOption(k, v string, q bool) TableOption {
	return &tableopt{
		key:        k,
		value:      v,
		needQuotes: q,
	}
}

func (t *tableopt) ID() string       { return "tableopt#" + t.key }
func (t *tableopt) Key() string      { return t.key }
func (t *tableopt) Value() string    { return t.value }
func (t *tableopt) NeedQuotes() bool { return t.needQuotes }
<commit_msg>Use variable name that matches the use case<commit_after>package model

// NewTable create a new table with the given name
func NewTable(name string) Table {
	return &table{
		name: name,
		columnNameToIndex: make(map[string]int),
	}
}

func (t *table) ID() string {
	return "table#" + t.name
}

func (t *table) LookupColumn(id string) (TableColumn, bool) {
	t.mu.RLock()
	defer t.mu.RUnlock()

	idx, ok := t.columnNameToIndex[id]
	if !ok {
		return nil, false
	}

	return t.columns[idx], true
}

func (t *table) LookupColumnBefore(id string) (TableColumn, bool) {
	t.mu.RLock()
	defer t.mu.RUnlock()

	idx, ok := t.columnNameToIndex[id]
	if !ok || idx == 0 {
		return nil, false
	}

	return t.columns[idx-1], true
}

func (t *table) LookupIndex(id string) (Index, bool) {
	for idx := range t.Indexes() {
		if idx.ID() == id {
			return idx, true
		}
	}
	return nil, false
}

func (t *table) AddColumn(v TableColumn) Table {
	t.mu.Lock()
	defer t.mu.Unlock()

	// Avoid adding the same TableColumn to multiple tables
	if tblID := v.TableID(); tblID != "" {
		v = v.Clone()
	}
	v.SetTableID(t.ID())
	t.columns = append(t.columns, v)
	t.columnNameToIndex[v.ID()] = len(t.columns) - 1
	return t
}

func (t *table) AddIndex(v Index) Table {
	t.indexes = append(t.indexes, v)
	return t
}

func (t *table) AddOption(v TableOption) Table {
	t.options = append(t.options, v)
	return t
}

func (t *table) Name() string {
	return t.name
}

func (t *table) IsIfNotExists() bool {
	return t.ifnotexists
}

func (t *table) IsTemporary() bool {
	return t.temporary
}

func (t *table) SetIfNotExists(v bool) Table {
	t.ifnotexists = v
	return t
}

func (t *table) HasLikeTable() bool {
	return t.likeTable.Valid
}

func (t *table) SetLikeTable(s string) Table {
	t.likeTable.Valid = true
	t.likeTable.Value = s
	return t
}

func (t *table) LikeTable() string {
	return t.likeTable.Value
}

func (t *table) SetTemporary(v bool) Table {
	t.temporary = v
	return t
}

func (t *table) Columns() chan TableColumn {
	ch := make(chan TableColumn, len(t.columns))
	for _, col := range t.columns {
		ch <- col
	}
	close(ch)
	return ch
}

func (t *table) Indexes() chan Index {
	ch := make(chan Index, len(t.indexes))
	for _, idx := range t.indexes {
		ch <- idx
	}
	close(ch)
	return ch
}

func (t *table) Options() chan TableOption {
	ch := make(chan TableOption, len(t.options))
	for _, idx := range t.options {
		ch <- idx
	}
	close(ch)
	return ch
}

func (t *table) Normalize() (Table, bool) {
	var clone bool
	var additionalIndexes []Index
	var columns []TableColumn
	for col := range t.Columns() {
		ncol, modified := col.Normalize()
		if modified {
			clone = true
		}

		// column_definition [UNIQUE [KEY] | [PRIMARY] KEY]
		// they mean same as INDEX or CONSTRAINT
		switch {
		case ncol.IsPrimary():
			// we have to move off the index declaration from the
			// primary key column to an index associated with the table
			index := NewIndex(IndexKindPrimaryKey, t.ID())
			index.SetType(IndexTypeNone)
			idxCol := NewIndexColumn(ncol.Name())
			index.AddColumns(idxCol)
			additionalIndexes = append(additionalIndexes, index)
			if !modified {
				clone = true
			}
			ncol = ncol.Clone()
			ncol.SetPrimary(false)
		case ncol.IsUnique():
			index := NewIndex(IndexKindUnique, t.ID())
			// if you do not assign a name, the index is assigned the same name as the first indexed column
			index.SetName(ncol.Name())
			index.SetType(IndexTypeNone)
			idxCol := NewIndexColumn(ncol.Name())
			index.AddColumns(idxCol)
			additionalIndexes = append(additionalIndexes, index)
			if !modified {
				clone = true
			}
			ncol = ncol.Clone()
			ncol.SetUnique(false)
		}

		columns = append(columns, ncol)
	}

	var indexes []Index
	for idx := range t.Indexes() {
		nidx, modified := idx.Normalize()
		if modified {
			clone = true
		}

		// if Not defined CONSTRAINT symbol, then resolve
		// implicitly created INDEX too difficult.
		// (lestrrat) this comment is confusing. Please add
		// actual examples somewhere
		if nidx.IsForeginKey() && nidx.Symbol() != "" {
			clone = true
			// add implicitly created INDEX
			index := NewIndex(IndexKindNormal, t.ID())
			index.SetName(nidx.Symbol())
			index.SetType(IndexTypeNone)
			columns := []IndexColumn{}
			for c := range nidx.Columns() {
				columns = append(columns, c)
			}
			index.AddColumns(columns...)
			indexes = append(indexes, index)
		}
		indexes = append(indexes, nidx)
	}

	if !clone {
		return t, false
	}

	tbl := NewTable(t.Name())
	tbl.SetIfNotExists(t.IsIfNotExists())
	tbl.SetTemporary(t.IsTemporary())

	for _, index := range additionalIndexes {
		tbl.AddIndex(index)
	}

	for _, col := range columns {
		tbl.AddColumn(col)
	}

	for _, idx := range indexes {
		tbl.AddIndex(idx)
	}

	for opt := range t.Options() {
		tbl.AddOption(opt)
	}
	return tbl, true
}

// NewTableOption creates a new table option with the given name, value, and a flag indicating if quoting is necessary
func NewTableOption(k, v string, q bool) TableOption {
	return &tableopt{
		key:        k,
		value:      v,
		needQuotes: q,
	}
}

func (t *tableopt) ID() string       { return "tableopt#" + t.key }
func (t *tableopt) Key() string      { return t.key }
func (t *tableopt) Value() string    { return t.value }
func (t *tableopt) NeedQuotes() bool { return t.needQuotes }
<|endoftext|>


<commit_before>package model

import (
	"encoding/json"
	"fmt"
	"time"
)

//go:generate msgp
//go:generate ffjson $GOFILE

type Priority int
type Facility int
type Severity int
type Version int

type AuditSubMessage struct {
	Type uint16 `json:"type" msg:"type"`
	Data string `json:"data" msg:"data"`
}

type AuditMessageGroup struct {
	Seq       int               `json:"sequence" msg:"sequence"`
	AuditTime string            `json:"timestamp" msg:"timestamp"`
	Msgs      []AuditSubMessage `json:"messages" msg:"messages"`
	UidMap    map[string]string `json:"uid_map" msg:"uid_map"`
}

// ffjson: nodecoder
type SyslogMessage struct {
	Priority         Priority                     `json:"priority,string" msg:"priority"`
	Facility         Facility                     `json:"facility,string" msg:"facility"`
	Severity         Severity                     `json:"severity,string" msg:"severity"`
	Version          Version                      `json:"version,string" msg:"version"`
	TimeReported     int64                        `json:"-" msg:"timereported"`
	TimeGenerated    int64                        `json:"-" msg:"timegenerated"`
	Hostname         string                       `json:"hostname" msg:"hostname"`
	Appname          string                       `json:"appname" msg:"appname"`
	Procid           string                       `json:"procid,omitempty" msg:"procid"`
	Msgid            string                       `json:"msgid,omitempty" msg:"msgid"`
	Structured       string                       `json:"structured,omitempty" msg:"structured"`
	Message          string                       `json:"message" msg:"message"`
	AuditSubMessages []AuditSubMessage            `json:"audit,omitempty" msg:"audit"`
	Properties       map[string]map[string]string `json:"properties,omitempty" msg:"properties"`
}

// ffjson: nodecoder
type ParsedMessage struct {
	Fields         SyslogMessage `json:"fields" msg:"fields"`
	Client         string        `json:"client,omitempty" msg:"client"`
	LocalPort      int           `json:"local_port,string" msg:"local_port"`
	UnixSocketPath string        `json:"unix_socket_path,omitempty" msg:"unix_socket_path"`
}

// ffjson: nodecoder
type ExportedMessage struct {
	ParsedMessage
	TimeReported  time.Time `json:"timereported"`
	TimeGenerated time.Time `json:"timegenerated"`
}

// ffjson: skip
type TcpUdpParsedMessage struct {
	Parsed ParsedMessage `json:"parsed" msg:"parsed"`
	Uid    string        `json:"uid" msg:"uid"`
	ConfId string        `json:"conf_id" msg:"conf_id"`
}

// ffjson: skip
type RelpParsedMessage struct {
	Parsed ParsedMessage `json:"parsed" msg:"parsed"`
	Txnr   int           `json:"txnr" msg:"txnr"`
}

var SyslogMessageFmt string = `Facility: %d
Severity: %d
Version: %d
TimeReported: %s
TimeGenerated: %s
Hostname: %s
Appname: %s
ProcID: %s
MsgID: %s
Structured: %s
Message: %s
AuditSubMessages: %s
Properties: %s`

func (m *SyslogMessage) String() string {
	props := ""
	// todo: remove json
	b, err := json.Marshal(m.Properties)
	if err == nil {
		props = string(b)
	}
	subs := ""
	b, err = json.Marshal(m.AuditSubMessages)
	if err == nil {
		subs = string(b)
	}
	return fmt.Sprintf(
		SyslogMessageFmt,
		m.Facility,
		m.Severity,
		m.Version,
		time.Unix(0, m.TimeReported).UTC().Format(time.RFC3339),
		time.Unix(0, m.TimeGenerated).UTC().Format(time.RFC3339),
		m.Hostname,
		m.Appname,
		m.Procid,
		m.Msgid,
		m.Structured,
		m.Message,
		subs,
		props,
	)
}
<commit_msg>remove json import<commit_after>package model

import (
	"fmt"
	"time"
)

//go:generate msgp
//go:generate ffjson $GOFILE

type Priority int
type Facility int
type Severity int
type Version int

type AuditSubMessage struct {
	Type uint16 `json:"type" msg:"type"`
	Data string `json:"data" msg:"data"`
}

type AuditMessageGroup struct {
	Seq       int               `json:"sequence" msg:"sequence"`
	AuditTime string            `json:"timestamp" msg:"timestamp"`
	Msgs      []AuditSubMessage `json:"messages" msg:"messages"`
	UidMap    map[string]string `json:"uid_map" msg:"uid_map"`
}

// ffjson: nodecoder
type SyslogMessage struct {
	Priority         Priority                     `json:"priority,string" msg:"priority"`
	Facility         Facility                     `json:"facility,string" msg:"facility"`
	Severity         Severity                     `json:"severity,string" msg:"severity"`
	Version          Version                      `json:"version,string" msg:"version"`
	TimeReported     int64                        `json:"-" msg:"timereported"`
	TimeGenerated    int64                        `json:"-" msg:"timegenerated"`
	Hostname         string                       `json:"hostname" msg:"hostname"`
	Appname          string                       `json:"appname" msg:"appname"`
	Procid           string                       `json:"procid,omitempty" msg:"procid"`
	Msgid            string                       `json:"msgid,omitempty" msg:"msgid"`
	Structured       string                       `json:"structured,omitempty" msg:"structured"`
	Message          string                       `json:"message" msg:"message"`
	AuditSubMessages []AuditSubMessage            `json:"audit,omitempty" msg:"audit"`
	Properties       map[string]map[string]string `json:"properties,omitempty" msg:"properties"`
}

// ffjson: nodecoder
type ParsedMessage struct {
	Fields         SyslogMessage `json:"fields" msg:"fields"`
	Client         string        `json:"client,omitempty" msg:"client"`
	LocalPort      int           `json:"local_port,string" msg:"local_port"`
	UnixSocketPath string        `json:"unix_socket_path,omitempty" msg:"unix_socket_path"`
}

// ffjson: nodecoder
type ExportedMessage struct {
	ParsedMessage
	TimeReported  time.Time `json:"timereported"`
	TimeGenerated time.Time `json:"timegenerated"`
}

// ffjson: skip
type TcpUdpParsedMessage struct {
	Parsed ParsedMessage `json:"parsed" msg:"parsed"`
	Uid    string        `json:"uid" msg:"uid"`
	ConfId string        `json:"conf_id" msg:"conf_id"`
}

// ffjson: skip
type RelpParsedMessage struct {
	Parsed ParsedMessage `json:"parsed" msg:"parsed"`
	Txnr   int           `json:"txnr" msg:"txnr"`
}

var SyslogMessageFmt string = `Facility: %d
Severity: %d
Version: %d
TimeReported: %s
TimeGenerated: %s
Hostname: %s
Appname: %s
ProcID: %s
MsgID: %s
Structured: %s
Message: %s
AuditSubMessages: %s
Properties: %s`

func (m *SyslogMessage) String() string {
	return fmt.Sprintf(
		SyslogMessageFmt,
		m.Facility,
		m.Severity,
		m.Version,
		time.Unix(0, m.TimeReported).UTC().Format(time.RFC3339),
		time.Unix(0, m.TimeGenerated).UTC().Format(time.RFC3339),
		m.Hostname,
		m.Appname,
		m.Procid,
		m.Msgid,
		m.Structured,
		m.Message,
		m.Properties,
	)
}
<|endoftext|>


<commit_before>package models

import (
	"encoding/json"

	"github.com/graphql-go/graphql"
	"github.com/phenax/diary-pwa/db"
	"github.com/phenax/diary-pwa/libs"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

//
// Post type
//
type Post struct {
	OID     bson.ObjectId `bson:"_id,omitempty"`
	ID      string        `bson:"pid,omitempty"`
	UserID  string        `bson:"user_id,omitempty"`
	Title   string        `bson:"title"`
	Content string        `bson:"content"`
	Rating  int           `bson:"rating"`
}

// PostWithUser type (post with the user)
type PostWithUser struct {
	Post,
	User User `bson:"Users"`
}

//
// Validate - Validator for user
func (post *Post) Validate() map[string]string {

	// if user.Name == "" && len(user.Name) < 5 {
	// 	return err("The Name you entered was too short")
	// }

	return map[string]string{"Message": "", "IsValid": "1"}
}

//
//
//
/// ########################  GraphQL stuff  ######################## ///
//

//
// GraphQLPost - Post type for graphql
//
var GraphQLPost = graphql.NewObject(graphql.ObjectConfig{
	Name:        "Post",
	Description: "An entry in the diary",
	Fields: graphql.Fields{
		"ID":      &graphql.Field{Type: graphql.String},
		"Title":   &graphql.Field{Type: graphql.String},
		"Content": &graphql.Field{Type: graphql.String},
		"Rating":  &graphql.Field{Type: graphql.Int},
		"UserID":  &graphql.Field{Type: graphql.String},
		// "Users": &graphql.Field{ Type: graphql.NewList(GraphQLUser) },
	},
})

//
// GraphQLPostField - GraphQL Field information for post
//
var GraphQLPostField *graphql.Field

//
// GraphQLCreatePostField - GraphQL Field information for post
//
var GraphQLCreatePostField *graphql.Field

func init() {

	GraphQLPostField = &graphql.Field{
		Type: GraphQLPost,
		Args: graphql.FieldConfigArgument{
			"pageId": &graphql.ArgumentConfig{
				Type:         graphql.String,
				DefaultValue: -1,
			},
		},
		Resolve: func(params graphql.ResolveParams) (interface{}, error) {
			var authUser SessionUser
			var post Post
			args := params.Args

			userSession := libs.GraphQLGetSession(params)
			// User logged in checked
			if userSession.Values["User"] == nil {
				return nil, error("Unauthorized")
			}

			json.Unmarshal([]byte(userSession.Values["User"].(string)), &authUser)

			query := Posts.Find(&bson.M{
				"pid": args["pageId"],
				"user_id": authUser.ID,
			})

			if n, err := query.Count(); n == 0 {
				if err != nil {
					return nil, err
				}
				return nil, nil
			}

			query.One(&post)
			return post, nil
		},
	}

	GraphQLCreatePostField = &graphql.Field{
		Type: GraphQLResponseType,
		Args: graphql.FieldConfigArgument{
			"Title":   &graphql.ArgumentConfig{Type: graphql.String},
			"Content": &graphql.ArgumentConfig{Type: graphql.String},
			"Rating":  &graphql.ArgumentConfig{Type: graphql.Int},
		},
		Resolve: func(params graphql.ResolveParams) (interface{}, error) {
			var authUser SessionUser
			args := params.Args

			userSession := libs.GraphQLGetSession(params)

			// User logged in checked
			if userSession.Values["User"] == nil {
				return NewResponse(401, "Unauthorized"), nil
			}

			json.Unmarshal([]byte(userSession.Values["User"].(string)), &authUser)

			post := &Post{
				ID:      bson.NewObjectId().Hex(),
				UserID:  authUser.ID,
				Title:   libs.Stringify(args["Title"]),
				Content: libs.Stringify(args["Content"]),
				Rating:  libs.Intify(args["Rating"]),
			}

			validation := post.Validate()

			if validation["IsValid"] != "1" {
				return NewResponse(400, validation["Message"]), nil
			}

			err := Posts.Insert(post)

			if err != nil {
				return NewResponse(500, "Something went wrong"), nil
			}

			return NewResponse(200, "Post saved successfully"), nil
		},
	}
}

//
//
//
/// ########################  Package stuff  ######################## ///
//

//
// Posts - Post Collection
var Posts *mgo.Collection

const (
	// PostCollectionName - Collection name
	PostCollectionName = "posts"
)

func init() {

	dbObj, _ := db.GetDB()

	Posts = dbObj.C(PostCollectionName)

	index := mgo.Index{
		Key:        []string{"pid"},
		Unique:     true,
		DropDups:   true,
		Background: true,
		Sparse:     true,
	}

	err := Posts.EnsureIndex(index)

	if err != nil {
		panic(err)
	}
}
<commit_msg>Added update support to the newpost query<commit_after>package models

import (
	"encoding/json"

	"github.com/graphql-go/graphql"
	"github.com/phenax/diary-pwa/db"
	"github.com/phenax/diary-pwa/libs"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

//
// Post type
//
type Post struct {
	OID     bson.ObjectId `bson:"_id,omitempty"`
	ID      string        `bson:"pid,omitempty"`
	UserID  string        `bson:"user_id,omitempty"`
	Title   string        `bson:"title"`
	Content string        `bson:"content"`
	Rating  int           `bson:"rating"`
}

// PostWithUser type (post with the user)
type PostWithUser struct {
	Post,
	User User `bson:"Users"`
}

//
// Validate - Validator for user
func (post *Post) Validate() map[string]string {

	// if user.Name == "" && len(user.Name) < 5 {
	// 	return err("The Name you entered was too short")
	// }

	return map[string]string{"Message": "", "IsValid": "1"}
}

//
//
//
/// ########################  GraphQL stuff  ######################## ///
//

//
// GraphQLPost - Post type for graphql
//
var GraphQLPost = graphql.NewObject(graphql.ObjectConfig{
	Name:        "Post",
	Description: "An entry in the diary",
	Fields: graphql.Fields{
		"ID":      &graphql.Field{Type: graphql.String},
		"Title":   &graphql.Field{Type: graphql.String},
		"Content": &graphql.Field{Type: graphql.String},
		"Rating":  &graphql.Field{Type: graphql.Int},
		"UserID":  &graphql.Field{Type: graphql.String},
		// "Users": &graphql.Field{ Type: graphql.NewList(GraphQLUser) },
	},
})

//
// GraphQLPostField - GraphQL Field information for post
//
var GraphQLPostField *graphql.Field

//
// GraphQLCreatePostField - GraphQL Field information for post
//
var GraphQLCreatePostField *graphql.Field

func init() {

	GraphQLPostField = &graphql.Field{
		Type: GraphQLPost,
		Args: graphql.FieldConfigArgument{
			"pageId": &graphql.ArgumentConfig{
				Type:         graphql.String,
				DefaultValue: -1,
			},
		},
		Resolve: func(params graphql.ResolveParams) (interface{}, error) {
			var authUser SessionUser
			var post Post
			args := params.Args

			userSession := libs.GraphQLGetSession(params)
			// User logged in checked
			if userSession.Values["User"] == nil {
				return nil, error("Unauthorized")
			}

			json.Unmarshal([]byte(userSession.Values["User"].(string)), &authUser)

			query := Posts.Find(&bson.M{
				"pid": args["pageId"],
				"user_id": authUser.ID,
			})

			if n, err := query.Count(); n == 0 {
				if err != nil {
					return nil, err
				}
				return nil, nil
			}

			query.One(&post)
			return post, nil
		},
	}

	GraphQLCreatePostField = &graphql.Field{
		Type: GraphQLResponseType,
		Args: graphql.FieldConfigArgument{
			"ID":   &graphql.ArgumentConfig{Type: graphql.String},
			"Title":   &graphql.ArgumentConfig{Type: graphql.String},
			"Content": &graphql.ArgumentConfig{Type: graphql.String},
			"Rating":  &graphql.ArgumentConfig{Type: graphql.Int},
		},
		Resolve: func(params graphql.ResolveParams) (interface{}, error) {
			var authUser SessionUser
			args := params.Args

			userSession := libs.GraphQLGetSession(params)

			postId := args["ID"].(string)
			isUpdateQuery := updatePostId != ""

			// User logged in checked
			if userSession.Values["User"] == nil {
				return NewResponse(401, "Unauthorized"), nil
			}

			json.Unmarshal([]byte(userSession.Values["User"].(string)), &authUser)

			if !isUpdateQuery {
				postId = bson.NewObjectId().Hex()
			}

			post := &Post{
				ID:      postId,
				UserID:  authUser.ID,
				Title:   libs.Stringify(args["Title"]),
				Content: libs.Stringify(args["Content"]),
				Rating:  libs.Intify(args["Rating"]),
			}

			validation := post.Validate()

			if validation["IsValid"] != "1" {
				return NewResponse(400, validation["Message"]), nil
			}

			var err error

			if isUpdateQuery {
				err := Posts.Update(&bson.M{ "pid": postId }, post)
			} else {
				err := Posts.Insert(post)
			}

			if err != nil {
				return NewResponse(500, "Something went wrong"), nil
			}

			return NewResponse(200, "Post saved successfully"), nil
		},
	}
}

//
//
//
/// ########################  Package stuff  ######################## ///
//

//
// Posts - Post Collection
var Posts *mgo.Collection

const (
	// PostCollectionName - Collection name
	PostCollectionName = "posts"
)

func init() {

	dbObj, _ := db.GetDB()

	Posts = dbObj.C(PostCollectionName)

	index := mgo.Index{
		Key:        []string{"pid"},
		Unique:     true,
		DropDups:   true,
		Background: true,
		Sparse:     true,
	}

	err := Posts.EnsureIndex(index)

	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/alex1sz/shotcharter-go/db"
	"log"
)

type Team struct {
	ID        string `db:"id" json:"id"`
	Name      string `db:"name" json:"name"`
	CreatedAt string `db:"created_at" json:"created_at"`
	UpdatedAt string `db:"updated_at" json:"updated_at"`
	Players   []*Player
	Games     []Game
}

func (team *Team) Create() (err error) {
	err = db.Db.QueryRow("insert into teams (name) values ($1) returning id", team.Name).Scan(&team.ID)

	if err != nil {
		log.Println(err)
		return
	}
	return
}

func (team *Team) GetPlayers() {
	players := []*Player{}
	db.Db.Select(&players, "SELECT id, name, active, jersey_number, created_at, updated_at from players where team_id = $1", &team.ID)

	team.Players = players
	return
}

func FindTeamByID(id string) (team Team, err error) {
	err = db.Db.Get(&team, "select id, name from teams where id = $1", id)

	if err != nil {
		log.Println(err)
		return
	}
	team.GetPlayers()

	return
}
<commit_msg>Add omit empty statements to team struct<commit_after>package models

import (
	"github.com/alex1sz/shotcharter-go/db"
	"log"
)

type Team struct {
	ID   string `db:"id" json:"id"`
	Name string `db:"name" json:"name"`
	// CreatedAt string `db:"created_at" json:"created_at"`
	// UpdatedAt string `db:"updated_at" json:"updated_at"`
	Players []*Player //`json:"players,omitempty"`
	Games   []Game    `json:"games,omitempty"`
}

func (team *Team) Create() (err error) {
	err = db.Db.QueryRow("insert into teams (name) values ($1) returning id", team.Name).Scan(&team.ID)

	if err != nil {
		log.Println(err)
		return
	}
	return
}

func (team *Team) GetPlayers() {
	players := []*Player{}
	db.Db.Select(&players, "SELECT id, name AS full_name, active, jersey_number, created_at, updated_at from players where team_id = $1", &team.ID)

	team.Players = players
	return
}

func FindTeamByID(id string) (team Team, err error) {
	err = db.Db.Get(&team, "select id, name from teams where id = $1", id)

	if err != nil {
		log.Println(err)
		return team, err
	}
	team.GetPlayers()

	return
}
<|endoftext|>


<commit_before>package sync

import (
	"radiusd/config"
	"database/sql"
	"fmt"
)

var (
	acct *sql.Stmt
	usage *sql.Stmt
)

func Init() error {
	var e error
	acct, e = config.DB.Prepare(
		`INSERT INTO
			accounting
		(user, date, bytes_in, bytes_out, hostname)
		VALUES (?, ?, ?, ?, ?)`,
	)
	if e != nil {
		return e
	}

	usage, e = config.DB.Prepare(
		`UPDATE
			user
		SET
			block_remaining = IF(CAST(block_remaining as SIGNED) - ? < 0, 0, block_remaining - ?)
		WHERE
			user = ?`,
	)
	return e
}

func SessionAcct(user string, date string, octetIn uint32, octetOut uint32, hostname string) error {
	res, e := acct.Exec(user, date, octetIn, octetOut, hostname)
	if e != nil {
		return e
	}
	affect, e := res.RowsAffected()
	if e != nil {
		return e
	}
	if affect != 1 {
		return fmt.Errorf(
			"Affect fail for user=%s",
			user,
		)
	}
	return nil
}

func UpdateRemaining(user string, remain uint32) error {
	if remain == 0 {
		return nil
	}

	res, e := usage.Exec(remain, remain, user)
	if e != nil {
		return e
	}
	affect, e := res.RowsAffected()
	if e != nil {
		return e
	}
	if affect != 1 {
		// TODO: zero check?
		return fmt.Errorf(
			"Affect fail for user=%s",
			user,
		)
	}
	return nil
}
<commit_msg>Bugfix. Affected check extended<commit_after>package sync

import (
	"radiusd/config"
	"database/sql"
	"fmt"
)

var (
	acct *sql.Stmt
	usage *sql.Stmt
)

func Init() error {
	var e error
	acct, e = config.DB.Prepare(
		`INSERT INTO
			accounting
		(user, date, bytes_in, bytes_out, hostname)
		VALUES (?, ?, ?, ?, ?)`,
	)
	if e != nil {
		return e
	}

	usage, e = config.DB.Prepare(
		`UPDATE
			user
		SET
			block_remaining = IF(CAST(block_remaining as SIGNED) - ? < 0, 0, block_remaining - ?)
		WHERE
			user = ?`,
	)
	return e
}

func SessionAcct(user string, date string, octetIn uint32, octetOut uint32, hostname string) error {
	res, e := acct.Exec(user, date, octetIn, octetOut, hostname)
	if e != nil {
		return e
	}
	affect, e := res.RowsAffected()
	if e != nil {
		return e
	}
	if affect != 1 {
		return fmt.Errorf(
			"Affect fail for user=%s",
			user,
		)
	}
	return nil
}

func UpdateRemaining(user string, remain uint32) error {
	if remain == 0 {
		return nil
	}

	res, e := usage.Exec(remain, remain, user)
	if e != nil {
		return e
	}
	affect, e := res.RowsAffected()
	if e != nil {
		return e
	}
	if affect != 1 {
		// Nothing changed, check if this behaviour is correct
		remain, e := checkRemain(user)
		if e != nil {
			return e
		}
		if (! remain) {
			return fmt.Errorf(
				"Affect fail for user=%s",
				user,
			)
		}
	}
	return nil
}

func checkRemain(user string) (bool, error) {
	var remain *int64
	e := config.DB.QueryRow(
		`SELECT
			block_remaining
		FROM
			user
		WHERE
			user = ?`,
		user,
	).Scan(remain)
	if remain == nil || *remain == 0 {
		return true, e
	}
	return false, e
}
<|endoftext|>


<commit_before>package orm

import (
	"flag"
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"
	"github.com/nerdzeu/nerdz-api/utils"
	"os"
)

var db gorm.DB

func init() {
	flag.Parse()

	args := flag.Args()
	envVar := os.Getenv("CONF_FILE")

	var file string

	if len(args) == 1 {
		file = args[0]
	} else if envVar != "" {
		file = envVar
	} else {
		panic(fmt.Sprintln("Configuration file is required.\nUse: CONF_FILE environment variable or cli args"))
	}

	connStr, err := utils.Parse(file)

	if err != nil {
		panic(fmt.Sprintf("[!] %v\n", err))
	}

	db, err = gorm.Open("postgres", connStr)

	if err != nil {
		panic(fmt.Sprintf("Got error when connect database: '%v'\n", err))
	}
}
<commit_msg>Add logger<commit_after>package orm

import (
	"flag"
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"
	"github.com/nerdzeu/nerdz-api/utils"
	"os"
)

var db gorm.DB

func init() {
	flag.Parse()

	args := flag.Args()
	envVar := os.Getenv("CONF_FILE")

	var file string

	if len(args) == 1 {
		file = args[0]
	} else if envVar != "" {
		file = envVar
	} else {
		panic(fmt.Sprintln("Configuration file is required.\nUse: CONF_FILE environment variable or cli args"))
	}

	connStr, err := utils.Parse(file)

	if err != nil {
		panic(fmt.Sprintf("[!] %v\n", err))
	}

	db, err = gorm.Open("postgres", connStr)

	if err != nil {
		panic(fmt.Sprintf("Got error when connect database: '%v'\n", err))
	}

    enableLog := os.Getenv("ENABLE_LOG")
    if enableLog != "" {
        db.LogMode(true)
    }
}
<|endoftext|>


<commit_before>// Copyright 2009 The GoMPD Authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package mpd

import "io"

// Subsystem represents a subsystem that can be watched.
// See http://www.musicpd.org/doc/protocol/ch03.html#command_idle
// for valid subsystem names.
type Subsystem string

// Watcher represents a MPD client connection that can be watched for events.
type Watcher struct {
	conn *Client          // client connection to MPD
	names chan []string   //
	Event chan Subsystem  // event channel
	Error chan error      // error channel
}

// NewWatcher connects to MPD server and watches for changes in subsystems
// subsystems. If no subsystem is specified, all changes are reported.
func NewWatcher(net, addr, passwd string, names ...string) (w *Watcher, err error) {
	conn, err := DialAuthenticated(net, addr, passwd)
	if err != nil {
		return
	}
	w = &Watcher{
		conn: conn,
		// Buffered channel to avoid race conditions in Watcher.Subsystems().
		names: make(chan []string, 10),
		Event: make(chan Subsystem),
		Error: make(chan error),
	}
	go w.watch(names...)
	return
}

func(w *Watcher) watch(names ...string) {
	defer close(w.names)
	defer close(w.Event)
	defer close(w.Error)

	for {
		switch changed, err := w.conn.idle(names...); {
		case err == io.EOF:
			// Connection closed.
			return
		case err != nil:
			w.Error <- err
		default:
			for _, sub := range changed {
				w.Event <- Subsystem(sub)
			}
		}

		select {
		case names = <-w.names:
			// Received new subsystems to watch.
		default:
			// continue
		}
	}
}

// Subsystems changes the subsystems to watch for.
func (w *Watcher) Subsystems(names ...string) {
	w.names <- names
	w.conn.noIdle()
}

// Close closes the connection to MPD and stops watching for events.
func (w *Watcher) Close() error {
	return w.conn.Close()
}
<commit_msg>go fmt<commit_after>// Copyright 2009 The GoMPD Authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package mpd

import "io"

// Subsystem represents a subsystem that can be watched.
// See http://www.musicpd.org/doc/protocol/ch03.html#command_idle
// for valid subsystem names.
type Subsystem string

// Watcher represents a MPD client connection that can be watched for events.
type Watcher struct {
	conn  *Client        // client connection to MPD
	names chan []string  // channel to set new subsystems to watch
	Event chan Subsystem // event channel
	Error chan error     // error channel
}

// NewWatcher connects to MPD server and watches for changes in subsystems
// subsystems. If no subsystem is specified, all changes are reported.
func NewWatcher(net, addr, passwd string, names ...string) (w *Watcher, err error) {
	conn, err := DialAuthenticated(net, addr, passwd)
	if err != nil {
		return
	}
	w = &Watcher{
		conn: conn,
		// Buffered channel to avoid race conditions in Watcher.Subsystems().
		names: make(chan []string, 10),
		Event: make(chan Subsystem),
		Error: make(chan error),
	}
	go w.watch(names...)
	return
}

func (w *Watcher) watch(names ...string) {
	defer close(w.names)
	defer close(w.Event)
	defer close(w.Error)

	for {
		switch changed, err := w.conn.idle(names...); {
		case err == io.EOF:
			// Connection closed.
			return
		case err != nil:
			w.Error <- err
		default:
			for _, sub := range changed {
				w.Event <- Subsystem(sub)
			}
		}

		select {
		case names = <-w.names:
			// Received new subsystems to watch.
		default:
			// continue
		}
	}
}

// Subsystems changes the subsystems to watch for.
func (w *Watcher) Subsystems(names ...string) {
	w.names <- names
	w.conn.noIdle()
}

// Close closes the connection to MPD and stops watching for events.
func (w *Watcher) Close() error {
	return w.conn.Close()
}
<|endoftext|>