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

package view

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/google/shenzhen-go/dev/dom"
	"github.com/google/shenzhen-go/dev/model"
	"github.com/google/shenzhen-go/dev/model/parts"
	"github.com/google/shenzhen-go/dev/model/pin"
)

type fakeGraphController struct{}

func (c fakeGraphController) Graph() *model.Graph                   { return nil }
func (c fakeGraphController) PartTypes() map[string]*model.PartType { return nil }
func (c fakeGraphController) Nodes(f func(NodeController))          { f(fakeNodeController{}) }

func (c fakeGraphController) Node(name string) NodeController {
	if name != "Node 1" {
		return nil
	}
	return fakeNodeController{}
}

func (c fakeGraphController) NumNodes() int                                           { return 1 }
func (c fakeGraphController) Channel(name string) ChannelController                   { return nil }
func (c fakeGraphController) Channels(f func(ChannelController))                      {}
func (c fakeGraphController) NumChannels() int                                        { return 0 }
func (c fakeGraphController) CreateChannel(string, string) (ChannelController, error) { return nil, nil }
func (c fakeGraphController) CreateNode(ctx context.Context, partType string) (NodeController, error) {
	return nil, nil
}
func (c fakeGraphController) Save(ctx context.Context) error           { return nil }
func (c fakeGraphController) SaveProperties(ctx context.Context) error { return nil }

type fakeNodeController struct{}

func (f fakeNodeController) Node() *model.Node {
	return &model.Node{
		Name:         "Node 1",
		Multiplicity: 1,
		Part: parts.NewCode(nil, "", "", "", pin.Map{
			"input": {
				Name:      "input",
				Direction: pin.Input,
				Type:      "int",
			},
			"output": {
				Name:      "output",
				Direction: pin.Output,
				Type:      "int",
			},
			"output 2": {
				Name:      "output 2",
				Direction: pin.Output,
				Type:      "int",
			},
		})}
}

func (f fakeNodeController) Name() string             { return "Node 1" }
func (f fakeNodeController) Position() (x, y float64) { return 150, 150 }

func (f fakeNodeController) Delete(ctx context.Context) error { return nil }
func (f fakeNodeController) Save(ctx context.Context) error   { return nil }

func TestGraphRefreshFromEmpty(t *testing.T) {
	doc := dom.MakeFakeDocument()
	v := &View{doc: doc}
	v.diagram = &Diagram{
		View:    v,
		Element: doc.MakeSVGElement("svg"),
	}
	v.graph = &Graph{
		view: v,
		gc:   fakeGraphController{},
		doc:  doc,
	}
	v.graph.makeElements(doc, v.diagram)
	v.graph.refresh()

	if v.graph.Channels == nil {
		t.Fatal("g.Channels = nil, want non-nil map")
	}
	if v.graph.Nodes == nil {
		t.Fatal("g.Nodes = nil, want non-nil map")
	}
	node1 := v.graph.Nodes["Node 1"]
	if node1 == nil {
		t.Fatal("g.Nodes[Node 1] = nil, want non-nil node")
	}
	if got, want := len(node1.Inputs), 1; got != want {
		t.Errorf("len(Nodes[Node 1].Inputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.Outputs), 2; got != want {
		t.Errorf("len(Nodes[Node 1].Outputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.AllPins), 3; got != want {
		t.Errorf("len(Nodes[Node 1].AllPins) = %d, want %d", got, want)
	}

	// Was checking "wholeText" property before, but this is with the fakes - how did that ever pass?
	if got, want := node1.TextBox.TextNode.Get("nodeValue").String(), "Node 1"; got != want {
		t.Errorf("Node 1 text = %q, want %q", got, want)
	}
}
<commit_msg>Tweak failure messages<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package view

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/google/shenzhen-go/dev/dom"
	"github.com/google/shenzhen-go/dev/model"
	"github.com/google/shenzhen-go/dev/model/parts"
	"github.com/google/shenzhen-go/dev/model/pin"
)

type fakeGraphController struct{}

func (c fakeGraphController) Graph() *model.Graph                   { return nil }
func (c fakeGraphController) PartTypes() map[string]*model.PartType { return nil }
func (c fakeGraphController) Nodes(f func(NodeController))          { f(fakeNodeController{}) }

func (c fakeGraphController) Node(name string) NodeController {
	if name != "Node 1" {
		return nil
	}
	return fakeNodeController{}
}

func (c fakeGraphController) NumNodes() int                                           { return 1 }
func (c fakeGraphController) Channel(name string) ChannelController                   { return nil }
func (c fakeGraphController) Channels(f func(ChannelController))                      {}
func (c fakeGraphController) NumChannels() int                                        { return 0 }
func (c fakeGraphController) CreateChannel(string, string) (ChannelController, error) { return nil, nil }
func (c fakeGraphController) CreateNode(ctx context.Context, partType string) (NodeController, error) {
	return nil, nil
}
func (c fakeGraphController) Save(ctx context.Context) error           { return nil }
func (c fakeGraphController) SaveProperties(ctx context.Context) error { return nil }

type fakeNodeController struct{}

func (f fakeNodeController) Node() *model.Node {
	return &model.Node{
		Name:         "Node 1",
		Multiplicity: 1,
		Part: parts.NewCode(nil, "", "", "", pin.Map{
			"input": {
				Name:      "input",
				Direction: pin.Input,
				Type:      "int",
			},
			"output": {
				Name:      "output",
				Direction: pin.Output,
				Type:      "int",
			},
			"output 2": {
				Name:      "output 2",
				Direction: pin.Output,
				Type:      "int",
			},
		})}
}

func (f fakeNodeController) Name() string             { return "Node 1" }
func (f fakeNodeController) Position() (x, y float64) { return 150, 150 }

func (f fakeNodeController) Delete(ctx context.Context) error { return nil }
func (f fakeNodeController) Save(ctx context.Context) error   { return nil }

func TestGraphRefreshFromEmpty(t *testing.T) {
	doc := dom.MakeFakeDocument()
	v := &View{doc: doc}
	v.diagram = &Diagram{
		View:    v,
		Element: doc.MakeSVGElement("svg"),
	}
	v.graph = &Graph{
		view: v,
		gc:   fakeGraphController{},
		doc:  doc,
	}
	v.graph.makeElements(doc, v.diagram)
	v.graph.refresh()

	if v.graph.Channels == nil {
		t.Fatal("v.graph.Channels = nil, want non-nil map")
	}
	if v.graph.Nodes == nil {
		t.Fatal("v.graph.Nodes = nil, want non-nil map")
	}
	node1 := v.graph.Nodes["Node 1"]
	if node1 == nil {
		t.Fatal("v.graph.Nodes[Node 1] = nil, want non-nil node")
	}
	if got, want := len(node1.Inputs), 1; got != want {
		t.Errorf("len(Nodes[Node 1].Inputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.Outputs), 2; got != want {
		t.Errorf("len(Nodes[Node 1].Outputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.AllPins), 3; got != want {
		t.Errorf("len(Nodes[Node 1].AllPins) = %d, want %d", got, want)
	}

	// Was checking "wholeText" property before, but this is with the fakes - how did that ever pass?
	if got, want := node1.TextBox.TextNode.Get("nodeValue").String(), "Node 1"; got != want {
		t.Errorf("Node 1 text = %q, want %q", got, want)
	}
}
<|endoftext|>


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

package tests

import (
	"fmt"
	"math/rand"
	"testing"

	"github.com/google/go-github/github"
)

func TestUsers_List(t *testing.T) {
	u, _, err := client.Users.ListAll(nil)
	if err != nil {
		t.Fatalf("Users.ListAll returned error: %v", err)
	}

	if len(u) == 0 {
		t.Errorf("Users.ListAll returned no users")
	}

	// mojombo is user #1
	if want := "mojombo"; want != *u[0].Login {
		t.Errorf("user[0].Login was %q, wanted %q", *u[0].Login, want)
	}
}

func TestUsers_Get(t *testing.T) {
	u, _, err := client.Users.Get("octocat")
	if err != nil {
		t.Fatalf("Users.Get('octocat') returned error: %v", err)
	}

	if want := "octocat"; want != *u.Login {
		t.Errorf("user.Login was %q, wanted %q", *u.Login, want)
	}
	if want := "The Octocat"; want != *u.Name {
		t.Errorf("user.Name was %q, wanted %q", *u.Name, want)
	}

	if checkAuth("TestUsers_Get") {
		u, _, err := client.Users.Get("")
		if err != nil {
			t.Fatalf("Users.Get('') returned error: %v", err)
		}

		if *u.Login == "" {
			t.Errorf("wanted non-empty values for user.Login")
		}
	}
}

func TestUsers_Emails(t *testing.T) {
	if !checkAuth("TestUsers_Emails") {
		return
	}

	emails, _, err := client.Users.ListEmails()
	if err != nil {
		t.Fatalf("Users.ListEmails() returned error: %v", err)
	}

	// create random address not currently in user's emails
	var email string
EmailLoop:
	for {
		email = fmt.Sprintf("test-%d@example.com", rand.Int())
		for _, e := range emails {
			if e.Email != nil && *e.Email == email {
				continue EmailLoop
			}
		}
		break
	}

	// Add new address
	_, _, err = client.Users.AddEmails([]string{email})
	if err != nil {
		t.Fatalf("Users.AddEmails() returned error: %v", err)
	}

	// List emails again and verify new email is present
	emails, _, err = client.Users.ListEmails()
	if err != nil {
		t.Fatalf("Users.ListEmails() returned error: %v", err)
	}

	var found bool
	for _, e := range emails {
		if e.Email != nil && *e.Email == email {
			found = true
			break
		}
	}

	if !found {
		t.Fatalf("Users.ListEmails() does not contain new addres: %v", email)
	}

	// Remove new address
	_, err = client.Users.DeleteEmails([]string{email})
	if err != nil {
		t.Fatalf("Users.DeleteEmails() returned error: %v", err)
	}

	// List emails again and verify new email was removed
	emails, _, err = client.Users.ListEmails()
	if err != nil {
		t.Fatalf("Users.ListEmails() returned error: %v", err)
	}

	for _, e := range emails {
		if e.Email != nil && *e.Email == email {
			t.Fatalf("Users.ListEmails() still contains address %v after removing it", email)
		}
	}
}

func TestUsers_Keys(t *testing.T) {
	keys, _, err := client.Users.ListKeys("willnorris")
	if err != nil {
		t.Fatalf("Users.ListKeys('willnorris') returned error: %v", err)
	}

	if len(keys) == 0 {
		t.Errorf("Users.ListKeys('willnorris') returned no keys")
	}

	// the rest of the tests requires auth
	if !checkAuth("TestUsers_Keys") {
		return
	}

	keys, _, err = client.Users.ListKeys("")
	if err != nil {
		t.Fatalf("Users.ListKeys('') returned error: %v", err)
	}

	// ssh public key for testing (fingerprint: 04:11:3a:3d:65:ed:f5:c8:29:90:2d:9c:9f:25:ca:7a)
	key := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQDThS/Tvat+hiKTsZ0fuaSkd/o8cMMufy70BXE2/UPZhUx/M4/XBGGiHGXwEbxcRpSTmEsAyN5vGt7nnZrHsjq/WhZmCjVcNlyfnEMGD0UgfsjwVDTT3Y4BYN62bhW4LfM="
	for _, k := range keys {
		if k.Key != nil && *k.Key == key {
			t.Fatalf("Test key already exists for user.  Please manually remove it first.")
		}
	}

	// Add new key
	_, _, err = client.Users.CreateKey(&github.Key{
		Title: github.String("go-github test key"),
		Key:   github.String(key),
	})
	if err != nil {
		t.Fatalf("Users.CreateKey() returned error: %v", err)
	}

	// List keys again and verify new key is present
	keys, _, err = client.Users.ListKeys("")
	if err != nil {
		t.Fatalf("Users.ListKeys('') returned error: %v", err)
	}

	var id int
	for _, k := range keys {
		if k.Key != nil && *k.Key == key {
			id = *k.ID
			break
		}
	}

	if id == 0 {
		t.Fatalf("Users.ListKeys('') does not contain added test key")
	}

	// Remove test key
	_, err = client.Users.DeleteKey(id)
	if err != nil {
		t.Fatalf("Users.DeleteKey(%d) returned error: %v", id, err)
	}

	// List keys again and verify test key was removed
	keys, _, err = client.Users.ListKeys("")
	if err != nil {
		t.Fatalf("Users.ListKeys('') returned error: %v", err)
	}

	for _, k := range keys {
		if k.Key != nil && *k.Key == key {
			t.Fatalf("Users.ListKeys('') still contains test key after removing it")
		}
	}
}
<commit_msg>update user integration test<commit_after>// Copyright 2014 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tests

import (
	"fmt"
	"math/rand"
	"testing"

	"github.com/google/go-github/github"
)

func TestUsers_Get(t *testing.T) {
	// list all users
	users, _, err := client.Users.ListAll(nil)
	if err != nil {
		t.Fatalf("Users.ListAll returned error: %v", err)
	}

	if len(users) == 0 {
		t.Errorf("Users.ListAll returned no users")
	}

	// mojombo is user #1
	if want := "mojombo"; want != *users[0].Login {
		t.Errorf("user[0].Login was %q, wanted %q", *users[0].Login, want)
	}

	// get individual user
	u, _, err := client.Users.Get("octocat")
	if err != nil {
		t.Fatalf("Users.Get('octocat') returned error: %v", err)
	}

	if want := "octocat"; want != *u.Login {
		t.Errorf("user.Login was %q, wanted %q", *u.Login, want)
	}
	if want := "The Octocat"; want != *u.Name {
		t.Errorf("user.Name was %q, wanted %q", *u.Name, want)
	}
}

func TestUsers_Update(t *testing.T) {
	if !checkAuth("TestUsers_Get") {
		return
	}

	u, _, err := client.Users.Get("")
	if err != nil {
		t.Fatalf("Users.Get('') returned error: %v", err)
	}

	if *u.Login == "" {
		t.Errorf("wanted non-empty values for user.Login")
	}

	// save original location
	var location string
	if u.Location != nil {
		location = *u.Location
	}

	// update location to test value
	testLoc := fmt.Sprintf("test-%d", rand.Int())
	u.Location = &testLoc

	_, _, err = client.Users.Edit(u)
	if err != nil {
		t.Fatalf("Users.Update returned error: %v", err)
	}

	// refetch user and check location value
	u, _, err = client.Users.Get("")
	if err != nil {
		t.Fatalf("Users.Get('') returned error: %v", err)
	}

	if testLoc != *u.Location {
		t.Errorf("Users.Get('') has location: %v, want: %v", *u.Location, testLoc)
	}

	// set location back to the original value
	u.Location = &location
	_, _, err = client.Users.Edit(u)
}

func TestUsers_Emails(t *testing.T) {
	if !checkAuth("TestUsers_Emails") {
		return
	}

	emails, _, err := client.Users.ListEmails()
	if err != nil {
		t.Fatalf("Users.ListEmails() returned error: %v", err)
	}

	// create random address not currently in user's emails
	var email string
EmailLoop:
	for {
		email = fmt.Sprintf("test-%d@example.com", rand.Int())
		for _, e := range emails {
			if e.Email != nil && *e.Email == email {
				continue EmailLoop
			}
		}
		break
	}

	// Add new address
	_, _, err = client.Users.AddEmails([]string{email})
	if err != nil {
		t.Fatalf("Users.AddEmails() returned error: %v", err)
	}

	// List emails again and verify new email is present
	emails, _, err = client.Users.ListEmails()
	if err != nil {
		t.Fatalf("Users.ListEmails() returned error: %v", err)
	}

	var found bool
	for _, e := range emails {
		if e.Email != nil && *e.Email == email {
			found = true
			break
		}
	}

	if !found {
		t.Fatalf("Users.ListEmails() does not contain new addres: %v", email)
	}

	// Remove new address
	_, err = client.Users.DeleteEmails([]string{email})
	if err != nil {
		t.Fatalf("Users.DeleteEmails() returned error: %v", err)
	}

	// List emails again and verify new email was removed
	emails, _, err = client.Users.ListEmails()
	if err != nil {
		t.Fatalf("Users.ListEmails() returned error: %v", err)
	}

	for _, e := range emails {
		if e.Email != nil && *e.Email == email {
			t.Fatalf("Users.ListEmails() still contains address %v after removing it", email)
		}
	}
}

func TestUsers_Keys(t *testing.T) {
	keys, _, err := client.Users.ListKeys("willnorris")
	if err != nil {
		t.Fatalf("Users.ListKeys('willnorris') returned error: %v", err)
	}

	if len(keys) == 0 {
		t.Errorf("Users.ListKeys('willnorris') returned no keys")
	}

	// the rest of the tests requires auth
	if !checkAuth("TestUsers_Keys") {
		return
	}

	keys, _, err = client.Users.ListKeys("")
	if err != nil {
		t.Fatalf("Users.ListKeys('') returned error: %v", err)
	}

	// ssh public key for testing (fingerprint: 04:11:3a:3d:65:ed:f5:c8:29:90:2d:9c:9f:25:ca:7a)
	key := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQDThS/Tvat+hiKTsZ0fuaSkd/o8cMMufy70BXE2/UPZhUx/M4/XBGGiHGXwEbxcRpSTmEsAyN5vGt7nnZrHsjq/WhZmCjVcNlyfnEMGD0UgfsjwVDTT3Y4BYN62bhW4LfM="
	for _, k := range keys {
		if k.Key != nil && *k.Key == key {
			t.Fatalf("Test key already exists for user.  Please manually remove it first.")
		}
	}

	// Add new key
	_, _, err = client.Users.CreateKey(&github.Key{
		Title: github.String("go-github test key"),
		Key:   github.String(key),
	})
	if err != nil {
		t.Fatalf("Users.CreateKey() returned error: %v", err)
	}

	// List keys again and verify new key is present
	keys, _, err = client.Users.ListKeys("")
	if err != nil {
		t.Fatalf("Users.ListKeys('') returned error: %v", err)
	}

	var id int
	for _, k := range keys {
		if k.Key != nil && *k.Key == key {
			id = *k.ID
			break
		}
	}

	if id == 0 {
		t.Fatalf("Users.ListKeys('') does not contain added test key")
	}

	// Verify that fetching individual key works
	k, _, err := client.Users.GetKey(id)
	if err != nil {
		t.Fatalf("Users.GetKey(%q) returned error: %v", id, err)
	}
	if *k.Key != key {
		t.Fatalf("Users.GetKey(%q) returned key %v, want %v", id, *k.Key, key)
	}

	// Remove test key
	_, err = client.Users.DeleteKey(id)
	if err != nil {
		t.Fatalf("Users.DeleteKey(%d) returned error: %v", id, err)
	}

	// List keys again and verify test key was removed
	keys, _, err = client.Users.ListKeys("")
	if err != nil {
		t.Fatalf("Users.ListKeys('') returned error: %v", err)
	}

	for _, k := range keys {
		if k.Key != nil && *k.Key == key {
			t.Fatalf("Users.ListKeys('') still contains test key after removing it")
		}
	}
}
<|endoftext|>


<commit_before>// zmon notifies the local server admin when there's a problem.
// Design: http://goo.gl/l1Y36T
package main

import (
	"bytes"
	"container/ring"
	"fmt"
	"log"
	"net"
	"net/smtp"
	"net/url"
	"os"
	"time"

	"bitbucket.org/kisom/gopush/pushover"
)

// listenPort is used a simple lock mechanism for zmon. If it can't listen to
// this port, interrupt the startup.
const listenPort = "127.0.0.1:61510"

// TODO: Prober must not warn after the first error.
// TODO: Warn user when service restored?

type Probe interface {
	// Check must never take more than 10s.
	Check() error
	Scheme() string
	Encode(url.Values)
}

type ServiceConfig struct {
	Frequency time.Duration
	Probes    []Probe
	esc       escalator
}

type escalator struct {
	lastEscalation     time.Time
	escalationInterval time.Duration
	// queued holds messages that will be sent at some point, even if they are old. When the
	// queue gets to 20 messages, older ones are dropped.
	queued       *ring.Ring
	Notificators []notificator
}

func (e *escalator) escalate(err error) {
	e.queued = e.queued.Next()
	e.queued.Value = notification{time.Now(), err}
	if time.Since(e.lastEscalation) > e.escalationInterval {
		// Merge all queued notifications.
		// Optimization todo: cache msg.
		msg := make([]byte, 0, 200)
		e.queued.Do(func(v interface{}) {
			if notif, ok := v.(notification); ok {
				msg = append(msg, []byte(notif.String())...)
			}

		})
		for _, n := range e.Notificators {
			if err := n.notify(msg); err != nil {
				log.Println("notification error:", err)
				log.Println("Would have written: %q", string(msg))
			} else {
				e.queued = ring.New(maxNotificationLines)
				e.lastEscalation = time.Now()
				log.Println("escalation successful")
				return
			}
		}
		log.Println("IMPORTANT: all escalation methods failed.")
	}
}

type notificator interface {
	notify(msg []byte) error
	encode(v url.Values)
}

type smtpNotification struct {
	// If addr is empty, uses localhost:25 and doesn't try to use TLS.
	addr string
	from string
	to   string
}

func (s *smtpNotification) encode(v url.Values) {
	// Using Set and not Add. If more than one config of this type are
	// found, use only the last one.
	v.Set("sa", s.addr)
	v.Set("sf", s.from)
	v.Set("st", s.to)
}

var subject = []byte("Subject:Alert from zmon")

func (s *smtpNotification) notify(msg []byte) error {
	msg = bytes.Join([][]byte{subject, msg}, []byte("\n\n"))
	if s.addr == "" {
		return localSendMail(s.from, []string{s.to}, msg)
	}
	return smtp.SendMail(s.addr, nil, s.from, []string{s.to}, msg)
}

func decodeSMTPNotification(v url.Values) *smtpNotification {
	s := &smtpNotification{
		addr: v.Get("sa"),
		from: v.Get("sf"),
		to:   v.Get("st"),
	}
	if s.from == "" || s.to == "" {
		return nil
	}
	return s
}

func decodePushoverNotification(v url.Values) *pushoverNotification {
	p := &pushoverNotification{
		pt: v.Get("pt"),
	}
	if p.pt == "" {
		return nil
	}
	p.identity = pushover.Authenticate(pushoverKey, p.pt)
	return p
}

type pushoverNotification struct {
	pt       string
	identity pushover.Identity
}

func (p *pushoverNotification) notify(msg []byte) error {
	sent := pushover.Notify(p.identity, string(msg))
	if !sent {
		return fmt.Errorf("pushover notification failed.")
	}
	return nil
}
func (p *pushoverNotification) encode(v url.Values) {
	// Using Set and not Add. If more than one config of this type are
	// found, use only the last one.
	v.Set("pt", p.pt)
}

type notification struct {
	time time.Time
	m    error
}

func (n notification) String() string {
	return fmt.Sprintf("%v: %v\n", n.time, n.m)
}

func main() {

	if len(os.Args) != 2 {
		log.Fatalf("Not enough arguments\nUsage: %v <encoded config string>", os.Args[0])
	}
	if fd, err := net.Listen("tcp", listenPort); err != nil {
		// Assume that this is a "address already in use" error and just exit without
		// printing anything to avoid excessive logging. If there was a nice way to test for
		// that error I'd use it.
		os.Exit(1)
	} else {
		defer fd.Close()
	}

	input, err := url.ParseQuery(os.Args[1])
	if err != nil {
		log.Fatalf("Input parse error: %v", err)
	}

	monitoring := Decode(input)

	t := time.Tick(monitoring.Frequency)
	for {
		for _, probe := range monitoring.Probes {
			if err := probe.Check(); err != nil {
				monitoring.esc.escalate(fmt.Errorf("%v: %v", probe.Scheme(), err))
			} else {
				// DEBUG
				// log.Println(probe.Scheme(), "went fine")
			}
		}
		<-t
	}
}
<commit_msg>Improve the notification message<commit_after>// zmon notifies the local server admin when there's a problem.
// Design: http://goo.gl/l1Y36T
package main

import (
	"bytes"
	"container/ring"
	"fmt"
	"log"
	"net"
	"net/smtp"
	"net/url"
	"os"
	"time"

	"bitbucket.org/kisom/gopush/pushover"
)

// listenPort is used a simple lock mechanism for zmon. If it can't listen to
// this port, interrupt the startup.
const listenPort = "127.0.0.1:61510"

var hostname string

// TODO: Prober must not warn after the first error.
// TODO: Warn user when service restored?

type Probe interface {
	// Check must never take more than 10s.
	Check() error
	Scheme() string
	Encode(url.Values)
}

type ServiceConfig struct {
	Frequency time.Duration
	Probes    []Probe
	esc       escalator
}

type escalator struct {
	lastEscalation     time.Time
	escalationInterval time.Duration
	// queued holds messages that will be sent at some point, even if they are old. When the
	// queue gets to 20 messages, older ones are dropped.
	queued       *ring.Ring
	Notificators []notificator
}

func (e *escalator) escalate(err error) {
	e.queued = e.queued.Next()
	e.queued.Value = notification{time.Now(), hostname, err}
	if time.Since(e.lastEscalation) > e.escalationInterval {
		// Merge all queued notifications.
		// Optimization todo: cache msg.
		msg := make([]byte, 0, 200)
		e.queued.Do(func(v interface{}) {
			if notif, ok := v.(notification); ok {
				msg = append(msg, []byte(notif.String())...)
			}

		})
		for _, n := range e.Notificators {
			if err := n.notify(msg); err != nil {
				log.Println("notification error:", err)
				log.Println("Would have written: %q", string(msg))
			} else {
				e.queued = ring.New(maxNotificationLines)
				e.lastEscalation = time.Now()
				log.Println("escalation successful")
				return
			}
		}
		log.Println("IMPORTANT: all escalation methods failed.")
	}
}

type notificator interface {
	notify(msg []byte) error
	encode(v url.Values)
}

type smtpNotification struct {
	// If addr is empty, uses localhost:25 and doesn't try to use TLS.
	addr string
	from string
	to   string
}

func (s *smtpNotification) encode(v url.Values) {
	// Using Set and not Add. If more than one config of this type are
	// found, use only the last one.
	v.Set("sa", s.addr)
	v.Set("sf", s.from)
	v.Set("st", s.to)
}

var subject = []byte("Subject:Alert from zmon")

func (s *smtpNotification) notify(msg []byte) error {
	msg = bytes.Join([][]byte{subject, msg}, []byte("\n\n"))
	if s.addr == "" {
		return localSendMail(s.from, []string{s.to}, msg)
	}
	return smtp.SendMail(s.addr, nil, s.from, []string{s.to}, msg)
}

func decodeSMTPNotification(v url.Values) *smtpNotification {
	s := &smtpNotification{
		addr: v.Get("sa"),
		from: v.Get("sf"),
		to:   v.Get("st"),
	}
	if s.from == "" || s.to == "" {
		return nil
	}
	return s
}

func decodePushoverNotification(v url.Values) *pushoverNotification {
	p := &pushoverNotification{
		pt: v.Get("pt"),
	}
	if p.pt == "" {
		return nil
	}
	p.identity = pushover.Authenticate(pushoverKey, p.pt)
	return p
}

type pushoverNotification struct {
	pt       string
	identity pushover.Identity
}

func (p *pushoverNotification) notify(msg []byte) error {
	sent := pushover.Notify(p.identity, string(msg))
	if !sent {
		return fmt.Errorf("pushover notification failed.")
	}
	return nil
}
func (p *pushoverNotification) encode(v url.Values) {
	// Using Set and not Add. If more than one config of this type are
	// found, use only the last one.
	v.Set("pt", p.pt)
}

type notification struct {
	time time.Time
	host string
	m    error
}

func (n notification) String() string {
	return fmt.Sprintf("%v: @%v: %v\n", n.time.Format("2006-01-02 15:04:05 -0700 MST"), n.host, n.m)
}

func main() {

	if len(os.Args) != 2 {
		log.Fatalf("Not enough arguments\nUsage: %v <encoded config string>", os.Args[0])
	}
	if fd, err := net.Listen("tcp", listenPort); err != nil {
		// Assume that this is a "address already in use" error and just exit without
		// printing anything to avoid excessive logging. If there was a nice way to test for
		// that error I'd use it.
		os.Exit(1)
	} else {
		defer fd.Close()
	}

	var err error
	hostname, err = os.Hostname()
	if err != nil {
		log.Printf("os.Hostname failed: %v. Using 'unknown' hostname", err)
		hostname = "unknown"
	}

	input, err := url.ParseQuery(os.Args[1])
	if err != nil {
		log.Fatalf("Input parse error: %v", err)
	}

	monitoring := Decode(input)

	t := time.Tick(monitoring.Frequency)
	for {
		for _, probe := range monitoring.Probes {
			if err := probe.Check(); err != nil {
				monitoring.esc.escalate(fmt.Errorf("%v: %v", probe.Scheme(), err))
			} else {
				// DEBUG
				// log.Println(probe.Scheme(), "went fine")
			}
		}
		<-t
	}
}
<|endoftext|>


<commit_before>package utils

import (
	"encoding/binary"
	"errors"
	"net"
	"net/http"
	"os"
	"time"

	ping "github.com/charliemaiors/go-fastping"
	wol "github.com/sabhiram/go-wol"
	log "github.com/sirupsen/logrus"
)

var pinger *ping.Pinger

func init() {
	pinger = ping.NewPinger()
}

func SendPacket(mac, ip string) error {
	bCastIP, err := getBcastAddr(ip)
	if err != nil {
		return err
	}
	bCastAddr := bCastIP + ":9" //9 is the default port for wake on lan
	err = wol.SendMagicPacket(mac, bCastAddr, "")
	if err != nil {
		return err
	}
	return nil
}

func TurnOffDev(ip, turnOffPort, solcommand string) error {
	resp, err := http.Post("http://"+ip+":"+turnOffPort+"/"+solcommand, "application/json", nil)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return errors.New(resp.Status)
	}
	return nil
}

func PingHost(ip string, alive bool) (map[time.Time]bool, error) {
	pinger.AddIP(ip)
	defer pinger.RemoveIP(ip)
	stopped := false
	report := make(map[time.Time]bool)
	if alive {
		pinger.OnIdle = func() {
			report[time.Now()] = true
			log.Debugf("No answer, the device is aslepp")
			stopped = true
			pinger.Stop()
		}

		pinger.OnRecv = func(ip *net.IPAddr, tdur time.Duration) {
			report[time.Now()] = false
		}
	} else {
		pinger.OnIdle = func() {
			report[time.Now()] = false
		}

		pinger.OnRecv = func(ip *net.IPAddr, tdur time.Duration) {
			report[time.Now()] = true
			log.Debugf("Got answer from %v", ip.String())
			stopped = true
			pinger.Stop()
		}
	}

	pinger.RunLoop()
	ticker := time.NewTicker(time.Second * 75)
	select {
	case <-pinger.Done():
		if err := pinger.Err(); err != nil {
			log.Errorf("Ping failed: %v", err)
			return nil, err
		}
		log.Debugf("Got stop for ping!!!")
	case <-ticker.C:
		break
	}
	ticker.Stop()
	if !stopped {
		pinger.Stop()
	}
	return report, nil
} //TODO refactor

func CheckHealt(ip string) bool {
	pinger.AddIP(ip)
	defer pinger.RemoveIP(ip)
	alive := false
	pinger.OnRecv = func(ip *net.IPAddr, tdur time.Duration) {
		log.Debugf("Device with ip %s is alive", ip)
		alive = true
		pinger.Stop()
	}
	pinger.OnIdle = func() {
		log.Debug("Terminated ping")
	}

	pinger.RunLoop()
	ticker := time.NewTicker(time.Second * 10)
	select {
	case <-pinger.Done():
		if err := pinger.Err(); err != nil {
			log.Errorf("Ping failed: %v", err)
			return false
		}
		log.Debugf("Got stop for ping alive!!!")
	case <-ticker.C:
		break
	}
	ticker.Stop()
	if !alive {
		pinger.Stop()
	}
	return alive
}

func CheckIfFolderExist(loc string) error {
	info, err := os.Stat(loc)
	if os.IsNotExist(err) {
		err = os.MkdirAll(loc, os.ModeDir)
		return err
	} else if !info.IsDir() {
		return errors.New("Exist but is not a folder")
	}
	return nil
}

func getBcastAddr(ipAddr string) (string, error) { // works when the n is a prefix, otherwise...

	ipParsed := net.ParseIP(ipAddr)
	mask := ipParsed.DefaultMask() //weak assumption, but server MUST be able to reach target address otherwise ping will fail
	log.Debugf("Passed ip: %s, ipParsed: %v, mask: %v", ipAddr, ipParsed, mask)

	n := &net.IPNet{IP: ipParsed, Mask: mask}
	log.Debugf("IpNet: %v", n)
	if n.IP.To4() == nil {
		return "", errors.New("does not support IPv6 addresses")
	}
	ip := make(net.IP, len(n.IP.To4()))
	binary.BigEndian.PutUint32(ip, binary.BigEndian.Uint32(n.IP.To4())|^binary.BigEndian.Uint32(net.IP(n.Mask).To4()))
	return ip.String(), nil
}
<commit_msg>testing<commit_after>package utils

import (
	"encoding/binary"
	"errors"
	"net"
	"net/http"
	"os"
	"time"

	ping "github.com/charliemaiors/go-fastping"
	wol "github.com/sabhiram/go-wol"
	log "github.com/sirupsen/logrus"
)

var pinger *ping.Pinger

func init() {
	pinger = ping.NewPinger()
}

func SendPacket(mac, ip string) error {
	bCastIP, err := getBcastAddr(ip)
	if err != nil {
		return err
	}
	bCastAddr := bCastIP + ":9" //9 is the default port for wake on lan
	err = wol.SendMagicPacket(mac, bCastAddr, "")
	if err != nil {
		return err
	}
	return nil
}

func TurnOffDev(ip, turnOffPort, solcommand string) error {
	resp, err := http.Post("http://"+ip+":"+turnOffPort+"/"+solcommand, "application/json", nil)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return errors.New(resp.Status)
	}
	return nil
}

func PingHost(ip string, alive bool) (map[time.Time]bool, error) {
	pinger.AddIP(ip)
	defer pinger.RemoveIP(ip)
	stopped := false
	report := make(map[time.Time]bool)
	if alive {
		pinger.OnIdle = func() {
			report[time.Now()] = true
			log.Debugf("No answer, the device is aslepp")
			stopped = true
			pinger.Stop()
		}

		pinger.OnRecv = func(ip *net.IPAddr, tdur time.Duration) {
			report[time.Now()] = false
		}
	} else {
		pinger.OnIdle = func() {
			report[time.Now()] = false
		}

		pinger.OnRecv = func(ip *net.IPAddr, tdur time.Duration) {
			report[time.Now()] = true
			log.Debugf("Got answer from %v", ip.String())
			stopped = true
			pinger.Stop()
		}
	}

	pinger.RunLoop()
	ticker := time.NewTicker(time.Second * 75)
	select {
	case <-pinger.Done():
		if err := pinger.Err(); err != nil {
			log.Errorf("Ping failed: %v", err)
			return nil, err
		}
		log.Debugf("Got stop for ping!!!")
	case <-ticker.C:
		break
	}
	ticker.Stop()
	if !stopped {
		pinger.Stop()
	}
	return report, nil
} //TODO refactor

func CheckHealt(ip string) bool {
	pinger.AddIP(ip)
	defer pinger.RemoveIP(ip)
	alive := false
	pinger.OnRecv = func(ip *net.IPAddr, tdur time.Duration) {
		log.Debugf("Device with ip %s is alive", ip)
		alive = true
		pinger.Stop()
	}
	pinger.OnIdle = func() {
		log.Debug("Terminated ping")
	}

	pinger.RunLoop()
	ticker := time.NewTicker(time.Second * 10)
	select {
	case <-pinger.Done():
		if err := pinger.Err(); err != nil {
			log.Errorf("Ping failed: %v", err)
			return false
		}
		log.Debugf("Got stop for ping alive!!!")
	case <-ticker.C:
		break
	}
	ticker.Stop()
	// if !alive {
	// 	pinger.Stop()
	// }
	return alive
}

func CheckIfFolderExist(loc string) error {
	info, err := os.Stat(loc)
	if os.IsNotExist(err) {
		err = os.MkdirAll(loc, os.ModeDir)
		return err
	} else if !info.IsDir() {
		return errors.New("Exist but is not a folder")
	}
	return nil
}

func getBcastAddr(ipAddr string) (string, error) { // works when the n is a prefix, otherwise...

	ipParsed := net.ParseIP(ipAddr)
	mask := ipParsed.DefaultMask() //weak assumption, but server MUST be able to reach target address otherwise ping will fail
	log.Debugf("Passed ip: %s, ipParsed: %v, mask: %v", ipAddr, ipParsed, mask)

	n := &net.IPNet{IP: ipParsed, Mask: mask}
	log.Debugf("IpNet: %v", n)
	if n.IP.To4() == nil {
		return "", errors.New("does not support IPv6 addresses")
	}
	ip := make(net.IP, len(n.IP.To4()))
	binary.BigEndian.PutUint32(ip, binary.BigEndian.Uint32(n.IP.To4())|^binary.BigEndian.Uint32(net.IP(n.Mask).To4()))
	return ip.String(), nil
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 @ z3q.net.
 * name : json_c.go
 * author : jarryliu
 * date : 2016-04-25 23:09
 * description :
 * history :
 */
package shared

import (
	"encoding/gob"
	"encoding/json"
	"fmt"
	"github.com/jsix/gof"
	"github.com/jsix/gof/crypto"
	"github.com/jsix/gof/storage"
	"go2o/core/domain/interface/ad"
	"go2o/core/domain/interface/valueobject"
	"go2o/core/dto"
	"go2o/core/service/dps"
	"go2o/x/echox"
	"net/http"
	"strconv"
	"strings"
	"sync"
)

const (
	//todo: ??? 设置为可配置
	maxSeconds int64 = 120
)

func init() {
	gob.Register(map[string]map[string]interface{}{})
	gob.Register(ad.ValueGallery{})
	gob.Register(ad.Ad{})
	gob.Register([]*valueobject.Goods{})
	gob.Register(valueobject.Goods{})
	gob.Register(ad.HyperLink{})
	gob.Register(ad.Image{})
}

type JsonC struct {
	gof.App
	mux *sync.RWMutex
}

func NewJsonC() *JsonC {
	return &JsonC{
		App: gof.CurrentApp,
		mux: new(sync.RWMutex),
	}
}

func getMd5(s string) string {
	return crypto.Md5([]byte(s))[8:16]
}

// 广告
func (j *JsonC) Ad(ctx *echox.Context) error {
	namesParams := strings.TrimSpace(ctx.Query("keys"))
	names := strings.Split(namesParams, "|")
	userId, _ := strconv.Atoi(ctx.Query("ad_user"))
	as := dps.AdService
	result := make(map[string]*ad.AdDto, len(names))
	key := fmt.Sprintf("go2o:rep:ad:%d:front:%s", userId, getMd5(namesParams))
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		for _, n := range names {
			//分别绑定广告
			dto := as.GetAdAndDataByKey(userId, n)
			if dto == nil {
				result[n] = nil
				continue
			}
			result[n] = dto
		}
		seconds := dps.BaseService.GetRegistry().CacheAdMaxAge
		sto.SetExpire(key, result, seconds)
		//log.Println("---- 更新广告缓存 ",err)
	}
	return ctx.JSON(http.StatusOK, result)
}

func (j *JsonC) getMultiParams(s string) (p string, size, begin int) {
	arr := strings.Split(s, "*")
	l := len(arr)
	if l == 1 {
		p = s
		size = 10 //返回默认10条
	} else {
		p = arr[0]
		size, _ = strconv.Atoi(arr[1])
		if l > 2 {
			begin, _ = strconv.Atoi(arr[2])
		}
	}
	return p, size, begin
}

func (j *JsonC) unmarshal(sto storage.Interface, key string, dst interface{}) error {
	jsStr, err := sto.GetString(key)
	if err == nil {
		err = json.Unmarshal([]byte(jsStr), &dst)
	}
	return err
}

// 商城/商铺分类JSON，shop_id为0，则返回商城的分类
// todo: ??? gob编码提示错误
func (j *JsonC) ShopCat(ctx *echox.Context) error {
	parentId, _ := strconv.Atoi(ctx.Form("parent_id"))
	shopId, _ := strconv.Atoi(ctx.Form("shop_id"))
	list := []dto.Category{}
	key := fmt.Sprintf("go2o:rep:cat:%d:json:%d", shopId, parentId)
	sto := ctx.App.Storage()
	if err := j.unmarshal(sto, key, &list); err != nil {
		//if err := sto.Get(key,*list);err != nil{
		if parentId == 0 {
			list = dps.SaleService.GetBigCategories(shopId)
		} else {
			list = dps.SaleService.GetChildCategories(shopId, parentId)
		}
		//sto.Set(key,list)
		var d []byte
		d, err = json.Marshal(list)
		sto.Set(key, string(d))
		//log.Println("---- 更新分类缓存 ", err)
	}
	return ctx.JSON(http.StatusOK, list)
}

func (j *JsonC) Get_shop(ctx *echox.Context) error {
	typeParams := strings.TrimSpace(ctx.Form("params"))
	types := strings.Split(typeParams, "|")
	result := make(map[string]interface{}, len(types))
	key := fmt.Sprint("go2o:rep:shop:front:glob_%s", typeParams)
	sto := ctx.App.Storage()
	//从缓存中读取
	if err := sto.Get(key, &result); err != nil {
		ss := dps.ShopService
		for _, t := range types {
			p, size, begin := j.getMultiParams(t)
			switch p {
			case "new-shop":
				_, result[p] = ss.PagedOnBusinessOnlineShops(
					begin, begin+size, "", "sp.create_time DESC")
			case "hot-shop":
				_, result[p] = ss.PagedOnBusinessOnlineShops(
					begin, begin+size, "", "")
			}
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}

// 商品
func (j *JsonC) Get_goods(ctx *echox.Context) error {
	shopId, _ := strconv.Atoi(ctx.Form("shop_id"))
	typeParams := strings.TrimSpace(ctx.Form("params"))
	types := strings.Split(typeParams, "|")
	result := make(map[string]interface{}, len(types))
	key := fmt.Sprint("go2o:rep:gs:fc3:%d_%s", shopId, typeParams)
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		ss := dps.SaleService
		for _, t := range types {
			p, size, begin := j.getMultiParams(t)
			switch p {
			case "new-goods":
				_, result[p] = ss.GetPagedOnShelvesGoods(shopId,
					-1, begin, begin+size, "gs_goods.id DESC")
			case "hot-sales":
				_, result[p] = ss.GetPagedOnShelvesGoods(shopId,
					-1, begin, begin+size, "gs_goods.sale_num DESC")
			}
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}

func (j *JsonC) Mch_goods(ctx *echox.Context) error {
	typeParams := strings.TrimSpace(ctx.Form("params"))
	types := strings.Split(typeParams, "|")
	mchId, _ := strconv.Atoi(ctx.Form("mch_id"))
	result := make(map[string]interface{}, len(types))

	key := fmt.Sprint("go2o:rep:sg:front:%d_%s", mchId, typeParams)
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		ss := dps.SaleService
		for _, t := range types {
			p, size, begin := j.getMultiParams(t)
			switch p {
			case "new-goods":
				_, result[p] = ss.GetShopPagedOnShelvesGoods(mchId,
					-1, begin, begin+size, "gs_goods.id DESC")
			case "hot-sales":
				_, result[p] = ss.GetShopPagedOnShelvesGoods(mchId,
					-1, begin, begin+size, "gs_goods.sale_num DESC")
			}
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}

// 获取销售标签获取商品
func (j *JsonC) SaleLabelGoods(ctx *echox.Context) error {
	codeParams := strings.TrimSpace(ctx.Form("params"))
	codes := strings.Split(codeParams, "|")
	mchId, _ := strconv.Atoi(ctx.Form("mch_id"))
	result := make(map[string]interface{}, len(codes))

	key := fmt.Sprint("go2o:rep:stg:front:%d--%s", mchId, getMd5(codeParams))
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		for _, param := range codes {
			code, size, begin := j.getMultiParams(param)
			list := dps.SaleService.GetValueGoodsBySaleLabel(
				mchId, code, "", begin, begin+size)
			result[code] = list
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}
<commit_msg>json_c<commit_after>/**
 * Copyright 2015 @ z3q.net.
 * name : json_c.go
 * author : jarryliu
 * date : 2016-04-25 23:09
 * description :
 * history :
 */
package shared

import (
	"encoding/gob"
	"encoding/json"
	"fmt"
	"github.com/jsix/gof"
	"github.com/jsix/gof/crypto"
	"github.com/jsix/gof/storage"
	"go2o/core/domain/interface/ad"
	"go2o/core/domain/interface/valueobject"
	"go2o/core/dto"
	"go2o/core/service/dps"
	"go2o/x/echox"
	"net/http"
	"strconv"
	"strings"
	"sync"
)

const (
	//todo: ??? 设置为可配置
	maxSeconds int64 = 120
)

func init() {
	gob.Register(map[string]map[string]interface{}{})
	gob.Register(ad.ValueGallery{})
	gob.Register(ad.Ad{})
	gob.Register([]*valueobject.Goods{})
	gob.Register(valueobject.Goods{})
	gob.Register(ad.HyperLink{})
	gob.Register(ad.Image{})
}

type JsonC struct {
	gof.App
	mux *sync.RWMutex
}

func NewJsonC() *JsonC {
	return &JsonC{
		App: gof.CurrentApp,
		mux: new(sync.RWMutex),
	}
}

func getMd5(s string) string {
	return crypto.Md5([]byte(s))[8:16]
}

// 广告
func (j *JsonC) Ad(ctx *echox.Context) error {
	namesParams := strings.TrimSpace(ctx.Query("keys"))
	names := strings.Split(namesParams, "|")
	userId, _ := strconv.Atoi(ctx.Query("ad_user"))
	as := dps.AdService
	result := make(map[string]*ad.AdDto, len(names))
	key := fmt.Sprintf("go2o:rep:ad:%d:front:%s", userId, getMd5(namesParams))
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		for _, n := range names {
			//分别绑定广告
			dto := as.GetAdAndDataByKey(userId, n)
			if dto == nil {
				result[n] = nil
				continue
			}
			result[n] = dto
		}
		seconds := dps.BaseService.GetRegistry().CacheAdMaxAge
		sto.SetExpire(key, result, seconds)
		//log.Println("---- 更新广告缓存 ",err)
	}
	return ctx.JSON(http.StatusOK, result)
}

func (j *JsonC) getMultiParams(s string) (p string, size, begin int) {
	arr := strings.Split(s, "*")
	l := len(arr)
	if l == 1 {
		p = s
		size = 10 //返回默认10条
	} else {
		p = arr[0]
		size, _ = strconv.Atoi(arr[1])
		if l > 2 {
			begin, _ = strconv.Atoi(arr[2])
		}
	}
	return p, size, begin
}

func (j *JsonC) unmarshal(sto storage.Interface, key string, dst interface{}) error {
	jsStr, err := sto.GetString(key)
	if err == nil {
		err = json.Unmarshal([]byte(jsStr), &dst)
	}
	return err
}

// 商城/商铺分类JSON，shop_id为0，则返回商城的分类
// todo: ??? gob编码提示错误
func (j *JsonC) ShopCat(ctx *echox.Context) error {
	parentId, _ := strconv.Atoi(ctx.Form("parent_id"))
	shopId, _ := strconv.Atoi(ctx.Form("shop_id"))
	list := []dto.Category{}
	key := fmt.Sprintf("go2o:rep:cat:%d:json:%d", shopId, parentId)
	sto := ctx.App.Storage()
	if err := j.unmarshal(sto, key, &list); err != nil {
		//if err := sto.Get(key,*list);err != nil{
		if parentId == 0 {
			list = dps.SaleService.GetBigCategories(shopId)
		} else {
			list = dps.SaleService.GetChildCategories(shopId, parentId)
		}
		//sto.Set(key,list)
		var d []byte
		d, err = json.Marshal(list)
		sto.Set(key, string(d))
		//log.Println("---- 更新分类缓存 ", err)
	}
	return ctx.JSON(http.StatusOK, list)
}

func (j *JsonC) Get_shop(ctx *echox.Context) error {
	typeParams := strings.TrimSpace(ctx.Form("params"))
	types := strings.Split(typeParams, "|")
	result := make(map[string]interface{}, len(types))
	key := fmt.Sprint("go2o:rep:shop:front:glob_%s", typeParams)
	sto := ctx.App.Storage()
	//从缓存中读取
	if err := sto.Get(key, &result); err != nil {
		ss := dps.ShopService
		for _, t := range types {
			p, size, begin := j.getMultiParams(t)
			switch p {
			case "new-shop":
				_, result[p] = ss.PagedOnBusinessOnlineShops(
					begin, begin+size, "", "sp.create_time DESC")
			case "hot-shop":
				_, result[p] = ss.PagedOnBusinessOnlineShops(
					begin, begin+size, "", "")
			}
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}

// 商品
func (j *JsonC) Get_goods(ctx *echox.Context) error {
	shopId, _ := strconv.Atoi(ctx.Form("shop_id"))
	typeParams := strings.TrimSpace(ctx.Form("params"))
	types := strings.Split(typeParams, "|")
	result := make(map[string]interface{}, len(types))
	key := fmt.Sprint("go2o:rep:gs:fc:%d_%s", shopId, typeParams)
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		ss := dps.SaleService
		for _, t := range types {
			p, size, begin := j.getMultiParams(t)
			switch p {
			case "new-goods":
				_, result[p] = ss.GetPagedOnShelvesGoods(shopId,
					-1, begin, begin+size, "gs_goods.id DESC")
			case "hot-sales":
				_, result[p] = ss.GetPagedOnShelvesGoods(shopId,
					-1, begin, begin+size, "gs_goods.sale_num DESC")
			}
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}

func (j *JsonC) Mch_goods(ctx *echox.Context) error {
	typeParams := strings.TrimSpace(ctx.Form("params"))
	types := strings.Split(typeParams, "|")
	mchId, _ := strconv.Atoi(ctx.Form("mch_id"))
	result := make(map[string]interface{}, len(types))
	key := fmt.Sprint("go2o:rep:sg:front:%d_%s", mchId, typeParams)
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		ss := dps.SaleService
		for _, t := range types {
			p, size, begin := j.getMultiParams(t)
			switch p {
			case "new-goods":
				_, result[p] = ss.GetShopPagedOnShelvesGoods(mchId,
					-1, begin, begin+size, "gs_goods.id DESC")
			case "hot-sales":
				_, result[p] = ss.GetShopPagedOnShelvesGoods(mchId,
					-1, begin, begin+size, "gs_goods.sale_num DESC")
			}
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}

// 获取销售标签获取商品
func (j *JsonC) SaleLabelGoods(ctx *echox.Context) error {
	codeParams := strings.TrimSpace(ctx.Form("params"))
	codes := strings.Split(codeParams, "|")
	mchId, _ := strconv.Atoi(ctx.Form("mch_id"))
	result := make(map[string]interface{}, len(codes))

	key := fmt.Sprint("go2o:rep:stg:front:%d--%s", mchId, getMd5(codeParams))
	sto := ctx.App.Storage()
	if err := sto.Get(key, &result); err != nil {
		//从缓存中读取
		for _, param := range codes {
			code, size, begin := j.getMultiParams(param)
			list := dps.SaleService.GetValueGoodsBySaleLabel(
				mchId, code, "", begin, begin+size)
			result[code] = list
		}
		sto.SetExpire(key, result, maxSeconds)
	}
	return ctx.Debug(ctx.JSON(http.StatusOK, result))
}
<|endoftext|>


<commit_before>/*
Package for reading and writing from the database. Perform all database
operations through this package.
*/
package database

import (
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
)

const (
	datastoreKind = "Tweet"
)

// The data access object that abstracts database interactions.
type Dao interface {
	WriteCelebrityTweet(tweet Tweet)
	GetCelebrityTweets(celebrtityName string) (tweets []Tweet)
	DeleteAllTweetsForCelebrity(celebrityName string)
}

// A DAO for interacting with App Engine's Datastore.
type DatastoreDao struct {
	Ctx context.Context // App Engine Context which can be obtained from an HTTP request.
}

// A tweet entity for storing data in the datastore.
type Tweet struct {
	CelebrityName string
	Id            int64
	Score         int32
}

// Saves the celebrityName, tweetContents pair to the datastore. Note that duplicates aren't
// caught here because of writing asynchronicity.
func (datastoreDao DatastoreDao) WriteCelebrityTweet(tweet Tweet) {
	key := datastore.NewIncompleteKey(datastoreDao.Ctx, datastoreKind, nil)
	if _, err := datastore.Put(datastoreDao.Ctx, key, &tweet); err != nil {
		fmt.Printf("Error writing to database: %v\n", err)
		return
	}
}

// Retrieves all the celebrity tweets related to a celebrity sorted with highest scores first.
// Duplicate tweets will be filtered out.
func (datastoreDao DatastoreDao) GetCelebrityTweets(celebrtityName string) (tweets []Tweet) {
	q := datastore.NewQuery(datastoreKind).
		Filter("CelebrityName = ", celebrtityName).
		Order("-Score")
	var results []Tweet
	if _, err := q.GetAll(datastoreDao.Ctx, &results); err != nil {
		fmt.Printf("Error reading the database: %v\n", err)
		return
	}
	tweetSet := make(map[int64]bool)
	for _, tweetResult := range results {
		if !tweetSet[tweetResult.Id] {
			tweets = append(tweets, tweetResult)
			tweetSet[tweetResult.Id] = true
		}
	}
	return
}

// Deletes all tweets for a provided celebirty name.
func (datastoreDao DatastoreDao) DeleteAllTweetsForCelebrity(celebrtityName string) {
	q := datastore.NewQuery(datastoreKind).
		Filter("CelebrityName = ", celebrtityName).
		KeysOnly()
	keys, err := q.GetAll(datastoreDao.Ctx, nil)
	if err != nil {
		fmt.Printf("Error reading the database: %v\n", err)
		return
	}
	datastore.DeleteMulti(datastoreDao.Ctx, keys)
}
<commit_msg>Fix celebrtity type<commit_after>/*
Package for reading and writing from the database. Perform all database
operations through this package.
*/
package database

import (
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
)

const (
	datastoreKind = "Tweet"
)

// The data access object that abstracts database interactions.
type Dao interface {
	WriteCelebrityTweet(tweet Tweet)
	GetCelebrityTweets(celebrityName string) (tweets []Tweet)
	DeleteAllTweetsForCelebrity(celebrityName string)
}

// A DAO for interacting with App Engine's Datastore.
type DatastoreDao struct {
	Ctx context.Context // App Engine Context which can be obtained from an HTTP request.
}

// A tweet entity for storing data in the datastore.
type Tweet struct {
	CelebrityName string
	Id            int64
	Score         int32
}

// Saves the celebrityName, tweetContents pair to the datastore. Note that duplicates aren't
// caught here because of writing asynchronicity.
func (datastoreDao DatastoreDao) WriteCelebrityTweet(tweet Tweet) {
	key := datastore.NewIncompleteKey(datastoreDao.Ctx, datastoreKind, nil)
	if _, err := datastore.Put(datastoreDao.Ctx, key, &tweet); err != nil {
		fmt.Printf("Error writing to database: %v\n", err)
		return
	}
}

// Retrieves all the celebrity tweets related to a celebrity sorted with highest scores first.
// Duplicate tweets will be filtered out.
func (datastoreDao DatastoreDao) GetCelebrityTweets(celebrityName string) (tweets []Tweet) {
	q := datastore.NewQuery(datastoreKind).
		Filter("CelebrityName = ", celebrityName).
		Order("-Score")
	var results []Tweet
	if _, err := q.GetAll(datastoreDao.Ctx, &results); err != nil {
		fmt.Printf("Error reading the database: %v\n", err)
		return
	}
	tweetSet := make(map[int64]bool)
	for _, tweetResult := range results {
		if !tweetSet[tweetResult.Id] {
			tweets = append(tweets, tweetResult)
			tweetSet[tweetResult.Id] = true
		}
	}
	return
}

// Deletes all tweets for a provided celebirty name.
func (datastoreDao DatastoreDao) DeleteAllTweetsForCelebrity(celebrityName string) {
	q := datastore.NewQuery(datastoreKind).
		Filter("CelebrityName = ", celebrityName).
		KeysOnly()
	keys, err := q.GetAll(datastoreDao.Ctx, nil)
	if err != nil {
		fmt.Printf("Error reading the database: %v\n", err)
		return
	}
	datastore.DeleteMulti(datastoreDao.Ctx, keys)
}
<|endoftext|>


<commit_before>/****************************************************************************
 * This file is part of Builder.
 *
 * Copyright (C) 2015 Pier Luigi Fiorini
 *
 * Author(s):
 *    Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
 *
 * $BEGIN_LICENSE:AGPL3+$
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $END_LICENSE$
 ***************************************************************************/

package database

import (
	"bytes"
	"encoding/json"
	"github.com/boltdb/bolt"
	"github.com/hawaii-desktop/builder"
	"strconv"
	"time"
)

type Job struct {
	Id           uint64            `json:"id"`
	Target       string            `json:"target"`
	Architecture string            `json:"arch"`
	Started      time.Time         `json:"started"`
	Finished     time.Time         `json:"finished"`
	Status       builder.JobStatus `json:"status"`
}

// Return a stored job.
func (db *Database) GetJob(id uint64) *Job {
	var job *Job = nil
	db.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte("job"))
		if bucket == nil {
			return nil
		}

		sid := strconv.FormatUint(id, 10)

		c := bucket.Cursor()
		for k, v := c.Seek([]byte(sid)); bytes.Equal(k, []byte(sid)); k, v = c.Next() {
			json.Unmarshal(v, &job)
			return nil
		}
		return nil
	})
	return job
}

// Return a list of jobs that match a certain criteria.
func (db *Database) FilterJobs(filter func(job *Job) bool) []*Job {
	var list []*Job
	db.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte("job"))
		if bucket == nil {
			return nil
		}

		bucket.ForEach(func(k, v []byte) error {
			var job *Job
			err := json.Unmarshal(v, &job)
			if err != nil {
				return err
			}

			if filter(job) {
				list = append(list, job)
			}
			return nil
		})

		return nil
	})
	return list
}

// Store a job.
func (db *Database) SaveJob(job *Job) error {
	return db.db.Update(func(tx *bolt.Tx) error {
		// Find bucket and return an error if it doesn't exist
		bucket, err := tx.CreateBucketIfNotExists([]byte("job"))
		if err != nil {
			return err
		}

		// Encode
		encoded, err := json.Marshal(job)
		if err != nil {
			return err
		}

		// Save
		sid := strconv.FormatUint(job.Id, 10)
		err = bucket.Put([]byte(sid), encoded)
		if err != nil {
			return err
		}

		return nil
	})
}
<commit_msg>Add database method to iterate through all jobs<commit_after>/****************************************************************************
 * This file is part of Builder.
 *
 * Copyright (C) 2015 Pier Luigi Fiorini
 *
 * Author(s):
 *    Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
 *
 * $BEGIN_LICENSE:AGPL3+$
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $END_LICENSE$
 ***************************************************************************/

package database

import (
	"bytes"
	"encoding/json"
	"github.com/boltdb/bolt"
	"github.com/hawaii-desktop/builder"
	"strconv"
	"time"
)

type Job struct {
	Id           uint64            `json:"id"`
	Target       string            `json:"target"`
	Architecture string            `json:"arch"`
	Started      time.Time         `json:"started"`
	Finished     time.Time         `json:"finished"`
	Status       builder.JobStatus `json:"status"`
}

// Return a stored job.
func (db *Database) GetJob(id uint64) *Job {
	var job *Job = nil
	db.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte("job"))
		if bucket == nil {
			return nil
		}

		sid := strconv.FormatUint(id, 10)

		c := bucket.Cursor()
		for k, v := c.Seek([]byte(sid)); bytes.Equal(k, []byte(sid)); k, v = c.Next() {
			json.Unmarshal(v, &job)
			return nil
		}
		return nil
	})
	return job
}

// Return a list of jobs that match a certain criteria.
func (db *Database) FilterJobs(filter func(job *Job) bool) []*Job {
	var list []*Job
	db.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte("job"))
		if bucket == nil {
			return nil
		}

		bucket.ForEach(func(k, v []byte) error {
			var job *Job
			err := json.Unmarshal(v, &job)
			if err != nil {
				return err
			}

			if filter(job) {
				list = append(list, job)
			}
			return nil
		})

		return nil
	})
	return list
}

// Iterate the jobs list.
func (db *Database) ForEachJob(f func(job *Job)) {
	db.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte("job"))
		if bucket == nil {
			return nil
		}

		bucket.ForEach(func(k, v []byte) error {
			var job *Job
			err := json.Unmarshal(v, &job)
			if err != nil {
				return err
			}

			f(job)

			return nil
		})

		return nil
	})
}

// Store a job.
func (db *Database) SaveJob(job *Job) error {
	return db.db.Update(func(tx *bolt.Tx) error {
		// Find bucket and return an error if it doesn't exist
		bucket, err := tx.CreateBucketIfNotExists([]byte("job"))
		if err != nil {
			return err
		}

		// Encode
		encoded, err := json.Marshal(job)
		if err != nil {
			return err
		}

		// Save
		sid := strconv.FormatUint(job.Id, 10)
		err = bucket.Put([]byte(sid), encoded)
		if err != nil {
			return err
		}

		return nil
	})
}
<|endoftext|>


<commit_before>package gorums

import "fmt"

// ConfigOption is a marker interface for options to NewConfiguration.
type ConfigOption interface{}

// NodeListOption must be implemented by node providers.
type NodeListOption interface {
	ConfigOption
	newConfig(*Manager) (Configuration, error)
}

type nodeIDMap struct {
	idMap map[string]uint32
}

func (o nodeIDMap) newConfig(mgr *Manager) (nodes Configuration, err error) {
	if len(o.idMap) == 0 {
		return nil, ConfigCreationError(fmt.Errorf("node-to-ID map required: WithNodeMap"))
	}
	nodes = make(Configuration, 0)
	for naddr, id := range o.idMap {
		node, found := mgr.Node(id)
		if !found {
			node, err = NewNodeWithID(naddr, id)
			if err != nil {
				return nil, ConfigCreationError(err)
			}
			err = mgr.AddNode(node)
			if err != nil {
				return nil, ConfigCreationError(err)
			}
		}
		nodes = append(nodes, node)
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, nil
}

// WithNodeMap returns a NodeListOption containing the provided
// mapping from node addresses to application-specific IDs.
func WithNodeMap(idMap map[string]uint32) NodeListOption {
	return &nodeIDMap{idMap: idMap}
}

type nodeList struct {
	addrsList []string
}

func (o nodeList) newConfig(mgr *Manager) (nodes Configuration, err error) {
	if len(o.addrsList) == 0 {
		return nil, ConfigCreationError(fmt.Errorf("node addresses required: WithNodeList"))
	}
	nodes = make(Configuration, 0)
	for _, naddr := range o.addrsList {
		node, err := NewNode(naddr)
		if err != nil {
			return nil, ConfigCreationError(err)
		}
		if n, found := mgr.Node(node.ID()); !found {
			err = mgr.AddNode(node)
			if err != nil {
				return nil, ConfigCreationError(err)
			}
		} else {
			node = n
		}
		nodes = append(nodes, node)
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, nil
}

// WithNodeList returns a NodeListOption containing the provided list of node addresses.
// With this option, node IDs are generated by the Manager.
func WithNodeList(addrsList []string) NodeListOption {
	return &nodeList{addrsList: addrsList}
}

type nodeIDs struct {
	nodeIDs []uint32
}

func (o nodeIDs) newConfig(mgr *Manager) (nodes Configuration, err error) {
	if len(o.nodeIDs) == 0 {
		return nil, ConfigCreationError(fmt.Errorf("node IDs required: WithNodeIDs"))
	}
	nodes = make(Configuration, 0)
	for _, id := range o.nodeIDs {
		node, found := mgr.Node(id)
		if !found {
			// Node IDs must have been registered previously
			return nil, ConfigCreationError(fmt.Errorf("node ID %d not found", id))
		}
		nodes = append(nodes, node)
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, nil
}

// WithNodeIDs returns a NodeListOption containing a list of node IDs.
// This assumes that the provided node IDs have already been registered with the manager.
func WithNodeIDs(ids []uint32) NodeListOption {
	return &nodeIDs{nodeIDs: ids}
}

type addNodes struct {
	old Configuration
	new NodeListOption
}

func (o addNodes) newConfig(mgr *Manager) (nodes Configuration, err error) {
	newNodes, err := o.new.newConfig(mgr)
	if err != nil {
		return nil, err
	}
	ac := &addConfig{old: o.old, add: newNodes}
	return ac.newConfig(mgr)
}

// Add returns a NodeListOption that can be used to create a new configuration combining c
// and the nodes provided via the NodeListOption new.
func (c Configuration) AddNodes(new NodeListOption) NodeListOption {
	return &addNodes{old: c, new: new}
}

type addConfig struct {
	old Configuration
	add Configuration
}

func (o addConfig) newConfig(mgr *Manager) (nodes Configuration, err error) {
	nodes = make(Configuration, 0)
	m := make(map[uint32]bool)
	for _, n := range append(o.old, o.add...) {
		if !m[n.id] {
			m[n.id] = true
			nodes = append(nodes, n)
		}
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, err
}

// Add returns a NodeListOption that can be used to create a new configuration combining c and add.
func (c Configuration) Add(add Configuration) NodeListOption {
	return &addConfig{old: c, add: add}
}

// RemoveNodes returns a NodeListOption that can be used to create a new configuration
// from configuration c without the given node IDs.
func (c Configuration) RemoveNodes(ids ...uint32) NodeListOption {
	rmIDs := make(map[uint32]bool)
	for _, id := range ids {
		rmIDs[id] = true
	}
	keepIDs := make([]uint32, 0)
	for _, cNode := range c {
		if !rmIDs[cNode.id] {
			keepIDs = append(keepIDs, cNode.id)
		}
	}
	return &nodeIDs{nodeIDs: keepIDs}
}

// Remove returns a NodeListOption that can be used to create a new configuration
// from configuration c without the nodes in configuration rm.
func (c Configuration) Remove(rm Configuration) NodeListOption {
	rmIDs := make(map[uint32]bool)
	for _, rmNode := range rm {
		rmIDs[rmNode.id] = true
	}
	keepIDs := make([]uint32, 0)
	for _, cNode := range c {
		if !rmIDs[cNode.id] {
			keepIDs = append(keepIDs, cNode.id)
		}
	}
	return &nodeIDs{nodeIDs: keepIDs}
}
<commit_msg>Added expected capacity to slice make operations<commit_after>package gorums

import "fmt"

// ConfigOption is a marker interface for options to NewConfiguration.
type ConfigOption interface{}

// NodeListOption must be implemented by node providers.
type NodeListOption interface {
	ConfigOption
	newConfig(*Manager) (Configuration, error)
}

type nodeIDMap struct {
	idMap map[string]uint32
}

func (o nodeIDMap) newConfig(mgr *Manager) (nodes Configuration, err error) {
	if len(o.idMap) == 0 {
		return nil, ConfigCreationError(fmt.Errorf("node-to-ID map required: WithNodeMap"))
	}
	nodes = make(Configuration, 0, len(o.idMap))
	for naddr, id := range o.idMap {
		node, found := mgr.Node(id)
		if !found {
			node, err = NewNodeWithID(naddr, id)
			if err != nil {
				return nil, ConfigCreationError(err)
			}
			err = mgr.AddNode(node)
			if err != nil {
				return nil, ConfigCreationError(err)
			}
		}
		nodes = append(nodes, node)
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, nil
}

// WithNodeMap returns a NodeListOption containing the provided
// mapping from node addresses to application-specific IDs.
func WithNodeMap(idMap map[string]uint32) NodeListOption {
	return &nodeIDMap{idMap: idMap}
}

type nodeList struct {
	addrsList []string
}

func (o nodeList) newConfig(mgr *Manager) (nodes Configuration, err error) {
	if len(o.addrsList) == 0 {
		return nil, ConfigCreationError(fmt.Errorf("node addresses required: WithNodeList"))
	}
	nodes = make(Configuration, 0, len(o.addrsList))
	for _, naddr := range o.addrsList {
		node, err := NewNode(naddr)
		if err != nil {
			return nil, ConfigCreationError(err)
		}
		if n, found := mgr.Node(node.ID()); !found {
			err = mgr.AddNode(node)
			if err != nil {
				return nil, ConfigCreationError(err)
			}
		} else {
			node = n
		}
		nodes = append(nodes, node)
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, nil
}

// WithNodeList returns a NodeListOption containing the provided list of node addresses.
// With this option, node IDs are generated by the Manager.
func WithNodeList(addrsList []string) NodeListOption {
	return &nodeList{addrsList: addrsList}
}

type nodeIDs struct {
	nodeIDs []uint32
}

func (o nodeIDs) newConfig(mgr *Manager) (nodes Configuration, err error) {
	if len(o.nodeIDs) == 0 {
		return nil, ConfigCreationError(fmt.Errorf("node IDs required: WithNodeIDs"))
	}
	nodes = make(Configuration, 0, len(o.nodeIDs))
	for _, id := range o.nodeIDs {
		node, found := mgr.Node(id)
		if !found {
			// Node IDs must have been registered previously
			return nil, ConfigCreationError(fmt.Errorf("node ID %d not found", id))
		}
		nodes = append(nodes, node)
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, nil
}

// WithNodeIDs returns a NodeListOption containing a list of node IDs.
// This assumes that the provided node IDs have already been registered with the manager.
func WithNodeIDs(ids []uint32) NodeListOption {
	return &nodeIDs{nodeIDs: ids}
}

type addNodes struct {
	old Configuration
	new NodeListOption
}

func (o addNodes) newConfig(mgr *Manager) (nodes Configuration, err error) {
	newNodes, err := o.new.newConfig(mgr)
	if err != nil {
		return nil, err
	}
	ac := &addConfig{old: o.old, add: newNodes}
	return ac.newConfig(mgr)
}

// Add returns a NodeListOption that can be used to create a new configuration combining c
// and the nodes provided via the NodeListOption new.
func (c Configuration) AddNodes(new NodeListOption) NodeListOption {
	return &addNodes{old: c, new: new}
}

type addConfig struct {
	old Configuration
	add Configuration
}

func (o addConfig) newConfig(mgr *Manager) (nodes Configuration, err error) {
	nodes = make(Configuration, 0, len(o.old)+len(o.add))
	m := make(map[uint32]bool)
	for _, n := range append(o.old, o.add...) {
		if !m[n.id] {
			m[n.id] = true
			nodes = append(nodes, n)
		}
	}
	// Sort nodes to ensure deterministic iteration.
	OrderedBy(ID).Sort(mgr.nodes)
	OrderedBy(ID).Sort(nodes)
	return nodes, err
}

// Add returns a NodeListOption that can be used to create a new configuration combining c and add.
func (c Configuration) Add(add Configuration) NodeListOption {
	return &addConfig{old: c, add: add}
}

// RemoveNodes returns a NodeListOption that can be used to create a new configuration
// from configuration c without the given node IDs.
func (c Configuration) RemoveNodes(ids ...uint32) NodeListOption {
	rmIDs := make(map[uint32]bool)
	for _, id := range ids {
		rmIDs[id] = true
	}
	keepIDs := make([]uint32, 0, len(c))
	for _, cNode := range c {
		if !rmIDs[cNode.id] {
			keepIDs = append(keepIDs, cNode.id)
		}
	}
	return &nodeIDs{nodeIDs: keepIDs}
}

// Remove returns a NodeListOption that can be used to create a new configuration
// from configuration c without the nodes in configuration rm.
func (c Configuration) Remove(rm Configuration) NodeListOption {
	rmIDs := make(map[uint32]bool)
	for _, rmNode := range rm {
		rmIDs[rmNode.id] = true
	}
	keepIDs := make([]uint32, 0, len(c))
	for _, cNode := range c {
		if !rmIDs[cNode.id] {
			keepIDs = append(keepIDs, cNode.id)
		}
	}
	return &nodeIDs{nodeIDs: keepIDs}
}
<|endoftext|>


<commit_before>package main

import "testing"

func Test_loadAllConfig_1(t *testing.T) {
	_, err := loadAllConfig("notexist", "/notexist")
	if err != nil {
                t.Errorf("Got error %v", err)
        }
}

func Test_Dump_1(t *testing.T) {
	exp := "ImageName busybox MountHomeTo %h ContainerUsername %u Shell /bin/ash DockerSocket /var/run/docker.sock"
	str := defaultConfig.Dump()
	if str != exp {
		t.Errorf("Got '%s' expected '%s'", str, exp)
	}

}

func Test_DefaultConfig_1(t *testing.T) {
	if defaultConfig.ImageName == "busybox" {
		t.Log("default ImageName passed.")
	} else {
		t.Errorf("default ImageName failed: expected busybox got %s", defaultConfig.ImageName)
	}
}

func Test_SimpleConfig_1(t *testing.T) {
	c, err := loadConfigFromString([]byte(``), "fred")
	if err != nil {
		t.Error(err)
	}
	c, err = loadConfigFromString([]byte(`[dockersh]
imagename = testimage`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.ImageName == "testimage" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
}

func Test_UserConfig_1(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
shell = someshell

[user "fred"]
imagename = fredsimage
containerusername = bill`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.Shell == "someshell" {
		t.Log("set Shell in dockersh config passed.")
	} else {
		t.Errorf("Expected Shell dockersg got %s", c.Shell)
	}
	if c.ContainerUsername == "bill" {
		t.Log("set ContainerUserName in user config passed.")
	} else {
		t.Errorf("Expected ContainerUserName bill got %s", c.ContainerUsername)
	}
	if c.ImageName == "fredsimage" {
		t.Log("set ImageName in user config passed.")
	} else {
		t.Errorf("Expected ImageName fredsimage got %s", c.ImageName)
	}
}

func Test_IniConfig_2(t *testing.T) {
	c := Configuration{ContainerUsername: "default_contun", ImageName: "default", EnableUserConfig: true, EnableUserImageName: true}
	n, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
containerusername = shouldbeblacklisted`), "fred")
	c = mergeConfigs(c, n, true)
	if err != nil {
		t.Error(err)
	}
	if c.ImageName == "testimage" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
	if c.ContainerUsername == "default_contun" {
		t.Log("blacklising worked, value not changed")
	} else {
		t.Error("blacklisting failed")
	}
}

func Test_Config_3(t *testing.T) {
	c := Configuration{ContainerUsername: "default_contun", Shell: "default_shell"}
	c, err := loadConfigFromString([]byte(`[dockersh]
shell = global_default
containerusername = global_default
mounthometo = somewhere
enableusershell
`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.Shell != "global_default" {
		t.Error("Set shell to global_default failed")
	}
	if c.ContainerUsername != "global_default" {
		t.Error("Set un to global default failed")
	}
	if c.MountHomeTo != "somewhere" {
		t.Error("Set mounthome to global default failed")
	}
	newc, err := loadConfigFromString([]byte(`[dockersh]
shell = user_value
containerusername = user_value
mounthometo = somewhere_else`), "fred")
	if err != nil {
		t.Error(err)
	}
	c = mergeConfigs(c, newc, true)
	if c.Shell != "user_value" {
		t.Error("Local defaults not applying over global defaults")
	} else {
		t.Log("c.shell not overridden")
	}
	if c.ContainerUsername != "global_default" {
		t.Error("Blacklist of container_username in global config failed")
	}
	if c.MountHomeTo != "somewhere" {
		t.Error("Blacklist mounthome in global config failed")
	}
}

func Test_IniConfig_4(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
containerusername = default_contun
imagename = default
enableuserconfig
enableuserimagename`), "fred")
	newc, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
containerusername = shouldbeblacklisted`), "fred")
	if err != nil {
		t.Error(err)
	}
	c = mergeConfigs(c, newc, true)
	if c.ImageName == "testimage" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
	if c.ContainerUsername != "default_contun" {
		t.Error("blacklising disabled, value changed")
	} else {
		t.Log("blacklisting enabled, value has not changed")
	}
}

func Test_IniConfig_5(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
containerusername = default_contun
imagename = default
enableuserconfig
`), "fred")
	newc, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
containerusername = shouldbeblacklisted`), "fred")
	if err != nil {
		t.Error(err)
	}
	c = mergeConfigs(c, newc, true)
	if c.ImageName == "default" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName default got %s", c.ImageName)
	}
	if c.ContainerUsername != "default_contun" {
		t.Error("blacklising disabled, value changed")
	} else {
		t.Log("blacklisting enabled, value has not changed")
	}
}

func Test_IniConfig_6(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
imagename = default
enableuserimagename

[user "fred"]
imagename = testimage
`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.ImageName == "testimage" {
		t.Log("set ImageName in user section when blacklisted in [dockersh] passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
}
<commit_msg>Fix test in travis<commit_after>package main

import (
	"testing"
	"os"
)

func Test_loadAllConfig_1(t *testing.T) {
	if _, err := os.Stat("/etc/dockersh"); os.IsNotExist(err) {
    		t.Log("No /etc/dockersh, skipping test")
    		return
	}
	_, err := loadAllConfig("notexist", "/notexist")
	if err != nil {
                t.Errorf("Got error %v", err)
        }
}

func Test_Dump_1(t *testing.T) {
	exp := "ImageName busybox MountHomeTo %h ContainerUsername %u Shell /bin/ash DockerSocket /var/run/docker.sock"
	str := defaultConfig.Dump()
	if str != exp {
		t.Errorf("Got '%s' expected '%s'", str, exp)
	}

}

func Test_DefaultConfig_1(t *testing.T) {
	if defaultConfig.ImageName == "busybox" {
		t.Log("default ImageName passed.")
	} else {
		t.Errorf("default ImageName failed: expected busybox got %s", defaultConfig.ImageName)
	}
}

func Test_SimpleConfig_1(t *testing.T) {
	c, err := loadConfigFromString([]byte(``), "fred")
	if err != nil {
		t.Error(err)
	}
	c, err = loadConfigFromString([]byte(`[dockersh]
imagename = testimage`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.ImageName == "testimage" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
}

func Test_UserConfig_1(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
shell = someshell

[user "fred"]
imagename = fredsimage
containerusername = bill`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.Shell == "someshell" {
		t.Log("set Shell in dockersh config passed.")
	} else {
		t.Errorf("Expected Shell dockersg got %s", c.Shell)
	}
	if c.ContainerUsername == "bill" {
		t.Log("set ContainerUserName in user config passed.")
	} else {
		t.Errorf("Expected ContainerUserName bill got %s", c.ContainerUsername)
	}
	if c.ImageName == "fredsimage" {
		t.Log("set ImageName in user config passed.")
	} else {
		t.Errorf("Expected ImageName fredsimage got %s", c.ImageName)
	}
}

func Test_IniConfig_2(t *testing.T) {
	c := Configuration{ContainerUsername: "default_contun", ImageName: "default", EnableUserConfig: true, EnableUserImageName: true}
	n, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
containerusername = shouldbeblacklisted`), "fred")
	c = mergeConfigs(c, n, true)
	if err != nil {
		t.Error(err)
	}
	if c.ImageName == "testimage" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
	if c.ContainerUsername == "default_contun" {
		t.Log("blacklising worked, value not changed")
	} else {
		t.Error("blacklisting failed")
	}
}

func Test_Config_3(t *testing.T) {
	c := Configuration{ContainerUsername: "default_contun", Shell: "default_shell"}
	c, err := loadConfigFromString([]byte(`[dockersh]
shell = global_default
containerusername = global_default
mounthometo = somewhere
enableusershell
`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.Shell != "global_default" {
		t.Error("Set shell to global_default failed")
	}
	if c.ContainerUsername != "global_default" {
		t.Error("Set un to global default failed")
	}
	if c.MountHomeTo != "somewhere" {
		t.Error("Set mounthome to global default failed")
	}
	newc, err := loadConfigFromString([]byte(`[dockersh]
shell = user_value
containerusername = user_value
mounthometo = somewhere_else`), "fred")
	if err != nil {
		t.Error(err)
	}
	c = mergeConfigs(c, newc, true)
	if c.Shell != "user_value" {
		t.Error("Local defaults not applying over global defaults")
	} else {
		t.Log("c.shell not overridden")
	}
	if c.ContainerUsername != "global_default" {
		t.Error("Blacklist of container_username in global config failed")
	}
	if c.MountHomeTo != "somewhere" {
		t.Error("Blacklist mounthome in global config failed")
	}
}

func Test_IniConfig_4(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
containerusername = default_contun
imagename = default
enableuserconfig
enableuserimagename`), "fred")
	newc, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
containerusername = shouldbeblacklisted`), "fred")
	if err != nil {
		t.Error(err)
	}
	c = mergeConfigs(c, newc, true)
	if c.ImageName == "testimage" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
	if c.ContainerUsername != "default_contun" {
		t.Error("blacklising disabled, value changed")
	} else {
		t.Log("blacklisting enabled, value has not changed")
	}
}

func Test_IniConfig_5(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
containerusername = default_contun
imagename = default
enableuserconfig
`), "fred")
	newc, err := loadConfigFromString([]byte(`[dockersh]
imagename = testimage
containerusername = shouldbeblacklisted`), "fred")
	if err != nil {
		t.Error(err)
	}
	c = mergeConfigs(c, newc, true)
	if c.ImageName == "default" {
		t.Log("set ImageName passed.")
	} else {
		t.Errorf("Expected ImageName default got %s", c.ImageName)
	}
	if c.ContainerUsername != "default_contun" {
		t.Error("blacklising disabled, value changed")
	} else {
		t.Log("blacklisting enabled, value has not changed")
	}
}

func Test_IniConfig_6(t *testing.T) {
	c, err := loadConfigFromString([]byte(`[dockersh]
imagename = default
enableuserimagename

[user "fred"]
imagename = testimage
`), "fred")
	if err != nil {
		t.Error(err)
	}
	if c.ImageName == "testimage" {
		t.Log("set ImageName in user section when blacklisted in [dockersh] passed.")
	} else {
		t.Errorf("Expected ImageName testimage got %s", c.ImageName)
	}
}
<|endoftext|>


<commit_before>package config_test

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"testing"

	"github.com/fly/config"
)

// In this example our organization is named "podhub", and our project
// namespace is "canary".
//
// In this example we have a file located at /Users/jchen/.config/podhub/canary/config.yaml,
// with the following contents:
//  example:
//    - "a"
//    - "b"
//    - "c"
func ExampleNamespace() {
	type Config struct {
		Example []string `yaml:"example"`
	}

	var err error
	var cfg Config
	var path string
	var cfgNS = config.Namespace{
		Organization: "podhub",
		System:       "canary",
	}

	path, _ = cfgNS.Path()
	fmt.Println("Path to config " + path)

	err = cfgNS.Load(&cfg)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println("Contents of cfg " + fmt.Sprint(cfg))
}

func TestExpandUser(t *testing.T) {
	var homeDir = os.Getenv("HOME")
	var correctPath = homeDir + "/.config/fly/config/testconfig.yaml"
	var err error
	var path string
	path, err = config.ExpandUser("~/.config/fly/config/testconfig.yaml")

	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	// docs say not to trust /home/travis to be homedir. We'll need to
	// revisit this later.
	if path != correctPath {
		t.Error("Expected ", correctPath, ", got ", path)
	}
}

func TestLoad(t *testing.T) {
	const correctDir = "/etc/fly/config/"
	const correctPath = correctDir + "testconfig.yaml"
	type configExample struct {
		Location string `yaml:"location"`
		Burritos bool   `yaml:"burritos"`
	}

	var correctCfgText = `location: Señor Sisig
burritos: true`
	var correctCfg = configExample{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var err error
	var cfg configExample
	var homeDir = os.Getenv("HOME")
	var dirMode os.FileMode = 0755
	var fileMode os.FileMode = 0644

	// Setup
	os.RemoveAll(homeDir + "/.config/fly/config/testconfig.yaml")
	os.MkdirAll(correctDir, dirMode)
	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ", got an error: ", err)
	}

	// Test
	err = config.Load(correctPath, &cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestUserBase(t *testing.T) {
	const correctUserBase = "~/.config/"
	var userBase string
	userBase = config.UserBase

	if userBase != correctUserBase {
		t.Error("Expecting ", correctUserBase, ", got ", userBase)
	}
}

func TestSystemBase(t *testing.T) {
	const correctSystemBase = "/etc/"
	var systemBase string
	systemBase = config.SystemBase

	if systemBase != correctSystemBase {
		t.Error("Expecting ", correctSystemBase, ", got ", systemBase)
	}
}

func TestNamespacePath(t *testing.T) {
	const correctDir = "/etc/fly/config/"
	const correctPath = correctDir + "testconfig.yaml"
	var cfgNS = config.Namespace{
		Organization: "fly",
		System:       "config",
	}
	var err error
	var path string
	var homeDir = os.Getenv("HOME")
	var dirMode os.FileMode = 0755

	// Setup
	os.RemoveAll(homeDir + "/.config/fly/config/testconfig.yaml")
	os.MkdirAll(correctDir, dirMode)
	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	// Test
	path, err = cfgNS.Path()
	if err != nil {
		t.Error("Got an error: ", err, " expecting nil")
	}
	if path != correctPath {
		t.Error("Expecting ", correctPath, ", got ", path)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestNamespaceLoad(t *testing.T) {
	const correctDir = "/etc/fly/config/"
	const correctPath = correctDir + "testconfig.yaml"
	type configExample struct {
		Location string
		Burritos bool
	}

	var correctCfgText = `location: Señor Sisig
burritos: true`
	var correctCfg = configExample{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var cfgNS = config.Namespace{
		Organization: "fly",
		System:       "config",
	}
	var err error
	var cfg configExample
	var homeDir = os.Getenv("HOME")
	var dirMode os.FileMode = 0755
	var fileMode os.FileMode = 0644

	// Setup
	os.RemoveAll(homeDir + "/.config/fly/config/testconfig.yaml")
	os.MkdirAll(correctDir, dirMode)
	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ", got an error: ", err)
	}

	// Test
	err = cfgNS.Load(&cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}
<commit_msg>fix path to test config<commit_after>package config_test

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"testing"

	"github.com/fly/config"
)

// In this example our organization is named "podhub", and our project
// namespace is "canary".
//
// In this example we have a file located at /Users/jchen/.config/podhub/canary/config.yaml,
// with the following contents:
//  example:
//    - "a"
//    - "b"
//    - "c"
func ExampleNamespace() {
	type Config struct {
		Example []string `yaml:"example"`
	}

	var err error
	var cfg Config
	var path string
	var cfgNS = config.Namespace{
		Organization: "podhub",
		System:       "canary",
	}

	path, _ = cfgNS.Path()
	fmt.Println("Path to config " + path)

	err = cfgNS.Load(&cfg)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println("Contents of cfg " + fmt.Sprint(cfg))
}

func TestExpandUser(t *testing.T) {
	var homeDir = os.Getenv("HOME")
	var correctPath = homeDir + "/.config/fly/config/config.yaml"
	var err error
	var path string
	path, err = config.ExpandUser("~/.config/fly/config/config.yaml")

	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	// docs say not to trust /home/travis to be homedir. We'll need to
	// revisit this later.
	if path != correctPath {
		t.Error("Expected ", correctPath, ", got ", path)
	}
}

func TestLoad(t *testing.T) {
	const correctDir = "/etc/fly/config/"
	const correctPath = correctDir + "config.yaml"
	type configExample struct {
		Location string `yaml:"location"`
		Burritos bool   `yaml:"burritos"`
	}

	var correctCfgText = `location: Señor Sisig
burritos: true`
	var correctCfg = configExample{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var err error
	var cfg configExample
	var homeDir = os.Getenv("HOME")
	var dirMode os.FileMode = 0755
	var fileMode os.FileMode = 0644

	// Setup
	os.RemoveAll(homeDir + "/.config/fly/config/config.yaml")
	os.MkdirAll(correctDir, dirMode)
	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ", got an error: ", err)
	}

	// Test
	err = config.Load(correctPath, &cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestUserBase(t *testing.T) {
	const correctUserBase = "~/.config/"
	var userBase string
	userBase = config.UserBase

	if userBase != correctUserBase {
		t.Error("Expecting ", correctUserBase, ", got ", userBase)
	}
}

func TestSystemBase(t *testing.T) {
	const correctSystemBase = "/etc/"
	var systemBase string
	systemBase = config.SystemBase

	if systemBase != correctSystemBase {
		t.Error("Expecting ", correctSystemBase, ", got ", systemBase)
	}
}

func TestNamespacePath(t *testing.T) {
	const correctDir = "/etc/fly/config/"
	const correctPath = correctDir + "config.yaml"
	var cfgNS = config.Namespace{
		Organization: "fly",
		System:       "config",
	}
	var err error
	var path string
	var homeDir = os.Getenv("HOME")
	var dirMode os.FileMode = 0755

	// Setup
	os.RemoveAll(homeDir + "/.config/fly/config/config.yaml")
	os.MkdirAll(correctDir, dirMode)
	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	// Test
	path, err = cfgNS.Path()
	if err != nil {
		t.Error("Got an error: ", err, " expecting nil")
	}
	if path != correctPath {
		t.Error("Expecting ", correctPath, ", got ", path)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestNamespaceLoad(t *testing.T) {
	const correctDir = "/etc/fly/config/"
	const correctPath = correctDir + "config.yaml"
	type configExample struct {
		Location string
		Burritos bool
	}

	var correctCfgText = `location: Señor Sisig
burritos: true`
	var correctCfg = configExample{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var cfgNS = config.Namespace{
		Organization: "fly",
		System:       "config",
	}
	var err error
	var cfg configExample
	var homeDir = os.Getenv("HOME")
	var dirMode os.FileMode = 0755
	var fileMode os.FileMode = 0644

	// Setup
	os.RemoveAll(homeDir + "/.config/fly/config/config.yaml")
	os.MkdirAll(correctDir, dirMode)
	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ", got an error: ", err)
	}

	// Test
	err = cfgNS.Load(&cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/gorest"
	"database/sql"
	"encoding/json"
	"fmt"
	_ "github.com/lib/pq"
	"log"
	"net/http"
	"os"
)

var g_conf Config

func main() {
	g_conf = ReadConfig()
	gorest.RegisterService(new(StatsService))
	http.Handle("/", gorest.Handle())
	http.ListenAndServe(fmt.Sprintf(":%v", g_conf.HttpPort), nil)
}

//************************Define Service***************************

type StatsService struct {
	//Service level config
	gorest.RestService `root:"/" consumes:"application/json" produces:"application/json"`

	//End-Point level configs: Field names must be the same as the corresponding method names,
	// but not-exported (starts with lowercase)

	getUser gorest.EndPoint `method:"GET" path:"/users/{id:int64}" output:"User"`
	putUser gorest.EndPoint `method:"PUT" path:"/users/{id:int64}" postdata:"User"`
}

type User struct {
	SteamId     int64
	DisplayName string
}

type Config struct {
	DbName     string
	DbUser     string
	DbPassword string
	HttpPort   int
}

//Handler Methods: Method names must be the same as in config, but exported (starts with uppercase)

func (serv StatsService) GetUser(id int64) User {
	db := OpenDatabase()
	defer db.Close()

	var steamid int64
	var username string

	err := db.QueryRow("SELECT steamid, displayName FROM users WHERE steamid = $1", id).Scan(&steamid, &username)

	switch {
	case err == sql.ErrNoRows:
		serv.ResponseBuilder().SetResponseCode(404).Overide(true)
	case err != nil:
		log.Fatal(err)
	}

	return User{SteamId: steamid, DisplayName: username}
}

func (serv StatsService) PutUser(user User, id int64) {
	db := OpenDatabase()
	defer db.Close()

	_, err := db.Exec("INSERT INTO users (steamid, displayname) VALUES ($1, $2)", user.SteamId, user.DisplayName)

	if err != nil {
		log.Print(err)
		serv.ResponseBuilder().SetResponseCode(500).Overide(true)
		return
	}

	serv.ResponseBuilder().SetResponseCode(201).Overide(true)
}

func OpenDatabase() (db *sql.DB) {
	var err error
	db, err = sql.Open("postgres", fmt.Sprintf("user=%v password=%v dbname=%v sslmode=disable", g_conf.DbUser, g_conf.DbPassword, g_conf.DbName))

	if err != nil {
		log.Fatal(err)
	}

	return
}

func ReadConfig() (config Config) {
	file, err := os.Open("conf.json")
	defer file.Close()

	if err != nil {
		log.Fatal(err)
	}

	decoder := json.NewDecoder(file)
	config = Config{}
	err = decoder.Decode(&config)

	if err != nil {
		log.Fatal(err)
	}

	return config
}
<commit_msg>Make sure id in path and request body match.<commit_after>package main

import (
	"code.google.com/p/gorest"
	"database/sql"
	"encoding/json"
	"fmt"
	_ "github.com/lib/pq"
	"log"
	"net/http"
	"os"
)

var g_conf Config

func main() {
	g_conf = ReadConfig()
	gorest.RegisterService(new(StatsService))
	http.Handle("/", gorest.Handle())
	http.ListenAndServe(fmt.Sprintf(":%v", g_conf.HttpPort), nil)
}

//************************Define Service***************************

type StatsService struct {
	//Service level config
	gorest.RestService `root:"/" consumes:"application/json" produces:"application/json"`

	//End-Point level configs: Field names must be the same as the corresponding method names,
	// but not-exported (starts with lowercase)

	getUser gorest.EndPoint `method:"GET" path:"/users/{id:int64}" output:"User"`
	putUser gorest.EndPoint `method:"PUT" path:"/users/{id:int64}" postdata:"User"`
}

type User struct {
	SteamId     int64
	DisplayName string
}

type Config struct {
	DbName     string
	DbUser     string
	DbPassword string
	HttpPort   int
}

//Handler Methods: Method names must be the same as in config, but exported (starts with uppercase)

func (serv StatsService) GetUser(id int64) User {
	db := OpenDatabase()
	defer db.Close()

	var steamid int64
	var username string

	err := db.QueryRow("SELECT steamid, displayName FROM users WHERE steamid = $1", id).Scan(&steamid, &username)

	switch {
	case err == sql.ErrNoRows:
		serv.ResponseBuilder().SetResponseCode(404).Overide(true)
	case err != nil:
		log.Fatal(err)
	}

	return User{SteamId: steamid, DisplayName: username}
}

func (serv StatsService) PutUser(user User, id int64) {

	if user.SteamId != id {
		serv.ResponseBuilder().SetResponseCode(400).Overide(true)
		return
	}

	db := OpenDatabase()
	defer db.Close()

	_, err := db.Exec("INSERT INTO users (steamid, displayname) VALUES ($1, $2)", user.SteamId, user.DisplayName)

	if err != nil {
		log.Print(err)
		serv.ResponseBuilder().SetResponseCode(500).Overide(true)
		return
	}

	serv.ResponseBuilder().SetResponseCode(201).Overide(true)
}

func OpenDatabase() (db *sql.DB) {
	var err error
	db, err = sql.Open("postgres", fmt.Sprintf("user=%v password=%v dbname=%v sslmode=disable", g_conf.DbUser, g_conf.DbPassword, g_conf.DbName))

	if err != nil {
		log.Fatal(err)
	}

	return
}

func ReadConfig() (config Config) {
	file, err := os.Open("conf.json")
	defer file.Close()

	if err != nil {
		log.Fatal(err)
	}

	decoder := json.NewDecoder(file)
	config = Config{}
	err = decoder.Decode(&config)

	if err != nil {
		log.Fatal(err)
	}

	return config
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2018-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package connmgr

import "github.com/decred/slog"

// log is a logger that is initialized with no output filters.  This
// means the package will not perform any logging by default until the caller
// requests it.
// The default amount of logging is none.
var log = slog.Disabled

// DisableLog disables all library log output.  Logging output is disabled
// by default until UseLogger is called.
//
// Deprecated: Use UseLogger(slog.Disabled) instead.
func DisableLog() {
	log = slog.Disabled
}

// UseLogger uses a specified Logger to output package logging info.
// This should be used in preference to SetLogWriter if the caller is also
// using slog.
func UseLogger(logger slog.Logger) {
	log = logger
}
<commit_msg>connmgr: Remove deprecated DisableLog func.<commit_after>// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2018-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package connmgr

import "github.com/decred/slog"

// log is a logger that is initialized with no output filters.  This
// means the package will not perform any logging by default until the caller
// requests it.
// The default amount of logging is none.
var log = slog.Disabled

// UseLogger uses a specified Logger to output package logging info.
// This should be used in preference to SetLogWriter if the caller is also
// using slog.
func UseLogger(logger slog.Logger) {
	log = logger
}
<|endoftext|>


<commit_before>// Package deck52 implements the standard 52 card deck for use with github.com/frenata/deck
package deck52

import (
	"fmt"
	"strconv"
)

type suit string
type rank int

const ( // suits
	Hearts   suit = "Hearts"
	Diamonds      = "Diamonds"
	Spades        = "Spades"
	Clubs         = "Clubs"
)

const (
	_        = iota
	Ace rank = iota
	Two
	Three
	Four
	Five
	Six
	Seven
	Eight
	Nine
	Ten
	Jack
	Queen
	King
)

// a card for a standard 52-card deck
type Card struct {
	suit
	rank
	name  string
	short string
}

// create a new card, since this is the standard deck, this has no need to be exported
// standard deck will be created in init()
func newCard(r rank, s suit) Card {
	c := Card{suit: s, rank: r}
	c.name = fmt.Sprintf("%s of %s", longRank(r), s)
	c.short = fmt.Sprintf("%s%s", shortRank(r), string(s[0]))

	return c
}

// String returns the short name of a card. Ex: "KC" for "King of Clubs"
func (c Card) String() string {
	return c.short
}

// Name returns the long name of a card. Ex: "King of Clubs"
func (c Card) Name() string {
	return c.name
}

// convert rank to short value
func shortRank(r rank) string {
	switch r {
	case Jack:
		return "J"
	case Queen:
		return "Q"
	case King:
		return "K"
	case Ace:
		return "A"
	default:
		return strconv.Itoa(int(r))
	}
}

// convert rank to full string for Name()
func longRank(r rank) string {
	switch r {
	case Ace:
		return "Ace"
	case Two:
		return "Two"
	case Three:
		return "Three"
	case Four:
		return "Four"
	case Five:
		return "Five"
	case Six:
		return "Six"
	case Seven:
		return "Seven"
	case Eight:
		return "Eight"
	case Nine:
		return "Nine"
	case Ten:
		return "Ten"
	case Jack:
		return "Jack"
	case Queen:
		return "Queen"
	case King:
		return "King"
	default:
		return ""
	}
}
<commit_msg>exported Rank and Suit types<commit_after>// Package deck52 implements the standard 52 card deck for use with github.com/frenata/deck
package deck52

import (
	"fmt"
	"strconv"
)

type Suit string
type Rank int

const ( // Suits
	Hearts   Suit = "Hearts"
	Diamonds      = "Diamonds"
	Spades        = "Spades"
	Clubs         = "Clubs"
)

const (
	_        = iota
	Ace Rank = iota
	Two
	Three
	Four
	Five
	Six
	Seven
	Eight
	Nine
	Ten
	Jack
	Queen
	King
)

// a card for a standard 52-card deck
type Card struct {
	suit  Suit
	rank  Rank
	name  string
	short string
}

// create a new card, since this is the standard deck, this has no need to be exported
// standard deck will be created in init()
func newCard(r Rank, s Suit) Card {
	c := Card{suit: s, rank: r}
	c.name = fmt.Sprintf("%s of %s", longRank(r), s)
	c.short = fmt.Sprintf("%s%s", shortRank(r), string(s[0]))

	return c
}

func (c Card) Suit() Suit {
	return c.suit
}

// String returns the short name of a card. Ex: "KC" for "King of Clubs"
func (c Card) String() string {
	return c.short
}

// Name returns the long name of a card. Ex: "King of Clubs"
func (c Card) Name() string {
	return c.name
}

// convert Rank to short value
func shortRank(r Rank) string {
	switch r {
	case Jack:
		return "J"
	case Queen:
		return "Q"
	case King:
		return "K"
	case Ace:
		return "A"
	default:
		return strconv.Itoa(int(r))
	}
}

// convert Rank to full string for Name()
func longRank(r Rank) string {
	switch r {
	case Ace:
		return "Ace"
	case Two:
		return "Two"
	case Three:
		return "Three"
	case Four:
		return "Four"
	case Five:
		return "Five"
	case Six:
		return "Six"
	case Seven:
		return "Seven"
	case Eight:
		return "Eight"
	case Nine:
		return "Nine"
	case Ten:
		return "Ten"
	case Jack:
		return "Jack"
	case Queen:
		return "Queen"
	case King:
		return "King"
	default:
		return ""
	}
}
<|endoftext|>