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

package main

import (
  "flag"
  "log"
  "net/http"

  "github.com/gorilla/mux"
)

var (
  addr      = flag.String("address", ":8080", "Address to bind to.")
  staticDir = flag.String("static_dir", "client", "Root directory for static files.")
  muxer     = mux.NewRouter()
)

func quitQuitQuitHandler(w http.ResponseWriter, r *http.Request) {
  log.Fatalf("%v requested we quit.", r.RemoteAddr)
}

func main() {
  flag.Parse()
  muxer.HandleFunc("/quitquitquit", quitQuitQuitHandler)
  muxer.Handle("/", http.FileServer(http.Dir(*staticDir)))
  http.Handle("/", muxer)
  log.Printf("Server now listening on %v", *addr)
  log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>Fix routing problem -- go server will now serve all the files in the static directory, and fall back to index.html if it would have served a 404 to make AngularJS routing work.<commit_after>// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
  "flag"
  "log"
  "net/http"

  "github.com/gorilla/mux"
)

var (
  addr      = flag.String("address", ":8080", "Address to bind to.")
  staticDir = flag.String("static_dir", "client", "Root directory for static files.")
  muxer     = mux.NewRouter()
)

type DefaultIndex struct {
  dir http.Dir
}

func (d DefaultIndex) Open(name string) (http.File, error) {
  log.Printf("Request: %v", name)
  f, err := d.dir.Open(name)
  if err != nil {
    f, err = d.dir.Open("/index.html")
  }
  return f, err
}

func quitQuitQuitHandler(w http.ResponseWriter, r *http.Request) {
  log.Fatalf("%v requested we quit.", r.RemoteAddr)
}

func main() {
  flag.Parse()
  muxer.HandleFunc("/quitquitquit", quitQuitQuitHandler)
  muxer.Handle("/{path:.*}", http.FileServer(DefaultIndex{dir: http.Dir(*staticDir)}))
  http.Handle("/", muxer)
  log.Printf("Server now listening on %v", *addr)
  log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package dockerclient

import (
	"fmt"
	"net"
	"net/url"
	"os"
	"path"
	"regexp"
	"sort"

	"github.com/fsouza/go-dockerclient"
	"github.com/rafecolton/go-dockerclient-sort"
)

var client *dockerClient

type dockerClient docker.Client

// DockerClient wraps docker.Client, adding a few handy functions
type DockerClient interface {
	// Client returns the underlying *docker.Client
	Client() *docker.Client

	// LatestImageIDByName uses the provided docker client to get the id
	// of the most-recently-created image with a name matching `name`
	LatestImageIDByName(name string) (string, error)

	// LatestImageIDByTag uses the provided docker client to get the id
	// of the most-recently-created image with a name matching `:<tag>$`
	LatestImageIDByTag(tag string) (string, error)
}

// NewDockerClient returns the dockerclient used by the artifactory package
func NewDockerClient() (DockerClient, error) {
	if client != nil {
		return client, nil
	}

	endpoint, err := getEndpoint()
	if err != nil {
		return nil, err
	}
	certPath := os.Getenv("DOCKER_CERT_PATH")
	tlsVerify := os.Getenv("DOCKER_TLS_VERIFY") != ""

	var dclient *docker.Client
	if endpoint.Scheme == "https" {
		cert := path.Join(certPath, "cert.pem")
		key := path.Join(certPath, "key.pem")
		ca := ""
		if tlsVerify {
			ca = path.Join(certPath, "ca.pem")
		}

		dclient, err = docker.NewTLSClient(endpoint.String(), cert, key, ca)
		if err != nil {
			return nil, err
		}
	} else {
		dclient, err = docker.NewClient(endpoint.String())
		if err != nil {
			return nil, err
		}
	}
	client = (*dockerClient)(dclient)
	return client, nil
}

func getEndpoint() (*url.URL, error) {
	endpoint := os.Getenv("DOCKER_HOST")
	if endpoint == "" {
		endpoint = "unix:///var/run/docker.sock"
	}

	u, err := url.Parse(endpoint)
	if err != nil {
		return nil, fmt.Errorf("couldn't parse endpoint %s as URL", endpoint)
	}
	if u.Scheme == "tcp" {
		_, port, err := net.SplitHostPort(u.Host)
		if err != nil {
			return nil, fmt.Errorf("error parsing %s for port", u.Host)
		}

		// Only reliable way to determine if we should be using HTTPS appears to be via port
		if os.Getenv("DOCKER_HOST_SCHEME") != "" {
			u.Scheme = os.Getenv("DOCKER_HOST_SCHEME")
		} else if port == "2376" {
			u.Scheme = "https"
		} else {
			u.Scheme = "http"
		}
	}
	return u, nil
}

func (client *dockerClient) LatestImageIDByName(name string) (string, error) {
	return client.latestImageByRegex("^" + name + "$")
}

func (client *dockerClient) LatestImageIDByTag(tag string) (string, error) {
	return client.latestImageByRegex(":" + tag + "$")
}

func (client *dockerClient) latestImageByRegex(regex string) (string, error) {
	images, err := (*docker.Client)(client).ListImages(false)
	if err != nil {
		return "", err
	}
	sort.Sort(dockersort.ByCreatedDescending(images))
	for _, image := range images {
		for _, tag := range image.RepoTags {
			matched, err := regexp.MatchString(regex, tag)
			if err != nil {
				return "", nil
			}
			if matched {
				return image.ID, nil
			}
		}
	}
	return "", fmt.Errorf("unable to find image matching %q", regex)
}

// Client returns the underlying *docker.Client for calling all of its functions
func (client *dockerClient) Client() *docker.Client {
	return (*docker.Client)(client)
}
<commit_msg>Exporting LatestImageByRegex func<commit_after>package dockerclient

import (
	"fmt"
	"net"
	"net/url"
	"os"
	"path"
	"regexp"
	"sort"

	"github.com/fsouza/go-dockerclient"
	"github.com/rafecolton/go-dockerclient-sort"
)

var client *dockerClient

type dockerClient docker.Client

// DockerClient wraps docker.Client, adding a few handy functions
type DockerClient interface {
	// Client returns the underlying *docker.Client
	Client() *docker.Client

	// LatestImageIDByName uses the provided docker client to get the id
	// of the most-recently-created image with a name matching `name`
	LatestImageIDByName(name string) (string, error)

	// LatestImageIDByTag uses the provided docker client to get the id
	// of the most-recently-created image with a name matching `:<tag>$`
	LatestImageIDByTag(tag string) (string, error)

	// LatestImageByRegex returns the docker api image object if that object is
	// tagged with at least one tag that matches "regex"
	LatestImageByRegex(regex string) (*docker.APIImages, error)
}

// NewDockerClient returns the dockerclient used by the artifactory package
func NewDockerClient() (DockerClient, error) {
	if client != nil {
		return client, nil
	}

	endpoint, err := getEndpoint()
	if err != nil {
		return nil, err
	}
	certPath := os.Getenv("DOCKER_CERT_PATH")
	tlsVerify := os.Getenv("DOCKER_TLS_VERIFY") != ""

	var dclient *docker.Client
	if endpoint.Scheme == "https" {
		cert := path.Join(certPath, "cert.pem")
		key := path.Join(certPath, "key.pem")
		ca := ""
		if tlsVerify {
			ca = path.Join(certPath, "ca.pem")
		}

		dclient, err = docker.NewTLSClient(endpoint.String(), cert, key, ca)
		if err != nil {
			return nil, err
		}
	} else {
		dclient, err = docker.NewClient(endpoint.String())
		if err != nil {
			return nil, err
		}
	}
	client = (*dockerClient)(dclient)
	return client, nil
}

func getEndpoint() (*url.URL, error) {
	endpoint := os.Getenv("DOCKER_HOST")
	if endpoint == "" {
		endpoint = "unix:///var/run/docker.sock"
	}

	u, err := url.Parse(endpoint)
	if err != nil {
		return nil, fmt.Errorf("couldn't parse endpoint %s as URL", endpoint)
	}
	if u.Scheme == "tcp" {
		_, port, err := net.SplitHostPort(u.Host)
		if err != nil {
			return nil, fmt.Errorf("error parsing %s for port", u.Host)
		}

		// Only reliable way to determine if we should be using HTTPS appears to be via port
		if os.Getenv("DOCKER_HOST_SCHEME") != "" {
			u.Scheme = os.Getenv("DOCKER_HOST_SCHEME")
		} else if port == "2376" {
			u.Scheme = "https"
		} else {
			u.Scheme = "http"
		}
	}
	return u, nil
}

func (client *dockerClient) LatestImageIDByName(name string) (string, error) {
	image, err := client.LatestImageByRegex("^" + name + "$")
	if err != nil {
		return "", err
	}
	return image.ID, nil
}

func (client *dockerClient) LatestImageIDByTag(tag string) (string, error) {
	image, err := client.LatestImageByRegex(":" + tag + "$")
	if err != nil {
		return "", err
	}
	return image.ID, nil
}

func (client *dockerClient) LatestImageByRegex(regex string) (*docker.APIImages, error) {
	images, err := (*docker.Client)(client).ListImages(false)
	if err != nil {
		return nil, err
	}
	sort.Sort(dockersort.ByCreatedDescending(images))
	for _, image := range images {
		for _, tag := range image.RepoTags {
			matched, err := regexp.MatchString(regex, tag)
			if err != nil {
				return nil, err
			}
			if matched {
				return &image, nil
			}
		}
	}
	return nil, fmt.Errorf("unable to find image matching %q", regex)
}

// Client returns the underlying *docker.Client for calling all of its functions
func (client *dockerClient) Client() *docker.Client {
	return (*docker.Client)(client)
}
<|endoftext|>


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

package inode_test

import (
	"os"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/fs/inode"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcsfake"
	. "github.com/jacobsa/ogletest"
)

func TestDir(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const inodeID = 17
const inodeName = "foo/bar/"
const typeCacheTTL = time.Second

type DirTest struct {
	ctx    context.Context
	bucket gcs.Bucket
	clock  timeutil.SimulatedClock

	in *inode.DirInode
}

var _ SetUpInterface = &DirTest{}
var _ TearDownInterface = &DirTest{}

func init() { RegisterTestSuite(&DirTest{}) }

func (t *DirTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))
	t.bucket = gcsfake.NewFakeBucket(&t.clock, "some_bucket")

	// Create the inode. No implicit dirs by default.
	t.resetInode(false)
}

func (t *DirTest) TearDown() {
	t.in.Unlock()
}

func (t *DirTest) resetInode(implicitDirs bool) {
	if t.in != nil {
		t.in.Unlock()
	}

	t.in = inode.NewDirInode(
		inodeID,
		inodeName,
		implicitDirs,
		typeCacheTTL,
		t.bucket,
		&t.clock)

	t.in.Lock()
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DirTest) ID() {
	ExpectEq(inodeID, t.in.ID())
}

func (t *DirTest) Name() {
	ExpectEq(inodeName, t.in.Name())
}

func (t *DirTest) LookupCount() {
	// Increment thrice. The count should now be three.
	t.in.IncrementLookupCount()
	t.in.IncrementLookupCount()
	t.in.IncrementLookupCount()

	// Decrementing twice shouldn't cause destruction. But one more should.
	AssertFalse(t.in.DecrementLookupCount(2))
	ExpectTrue(t.in.DecrementLookupCount(1))
}

func (t *DirTest) Attributes() {
	attrs, err := t.in.Attributes(t.ctx)
	AssertEq(nil, err)
	ExpectEq(os.FileMode(0700)|os.ModeDir, attrs.Mode)
}

func (t *DirTest) LookUpChild_NonExistent() {
	o, err := t.in.LookUpChild(t.ctx, "qux")

	AssertEq(nil, err)
	ExpectEq(nil, o)
}

func (t *DirTest) LookUpChild_FileOnly() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_DirOnly() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDir() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_Empty() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsDisabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsEnabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_LotsOfEntries() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_Exists() {
	AssertTrue(false, "TODO")
}

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

package inode_test

import (
	"os"
	"path"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/fs/inode"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcsfake"
	"github.com/jacobsa/gcloud/gcs/gcsutil"
	. "github.com/jacobsa/ogletest"
)

func TestDir(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const inodeID = 17
const inodeName = "foo/bar/"
const typeCacheTTL = time.Second

type DirTest struct {
	ctx    context.Context
	bucket gcs.Bucket
	clock  timeutil.SimulatedClock

	in *inode.DirInode
}

var _ SetUpInterface = &DirTest{}
var _ TearDownInterface = &DirTest{}

func init() { RegisterTestSuite(&DirTest{}) }

func (t *DirTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))
	t.bucket = gcsfake.NewFakeBucket(&t.clock, "some_bucket")

	// Create the inode. No implicit dirs by default.
	t.resetInode(false)
}

func (t *DirTest) TearDown() {
	t.in.Unlock()
}

func (t *DirTest) resetInode(implicitDirs bool) {
	if t.in != nil {
		t.in.Unlock()
	}

	t.in = inode.NewDirInode(
		inodeID,
		inodeName,
		implicitDirs,
		typeCacheTTL,
		t.bucket,
		&t.clock)

	t.in.Lock()
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DirTest) ID() {
	ExpectEq(inodeID, t.in.ID())
}

func (t *DirTest) Name() {
	ExpectEq(inodeName, t.in.Name())
}

func (t *DirTest) LookupCount() {
	// Increment thrice. The count should now be three.
	t.in.IncrementLookupCount()
	t.in.IncrementLookupCount()
	t.in.IncrementLookupCount()

	// Decrementing twice shouldn't cause destruction. But one more should.
	AssertFalse(t.in.DecrementLookupCount(2))
	ExpectTrue(t.in.DecrementLookupCount(1))
}

func (t *DirTest) Attributes() {
	attrs, err := t.in.Attributes(t.ctx)
	AssertEq(nil, err)
	ExpectEq(os.FileMode(0700)|os.ModeDir, attrs.Mode)
}

func (t *DirTest) LookUpChild_NonExistent() {
	o, err := t.in.LookUpChild(t.ctx, "qux")

	AssertEq(nil, err)
	ExpectEq(nil, o)
}

func (t *DirTest) LookUpChild_FileOnly() {
	const name = "qux"
	fullName := path.Join(inodeName, name)

	var o *gcs.Object
	var err error

	// Create a backing object.
	createObj, err := gcsutil.CreateObject(t.ctx, t.bucket, fullName, "taco")
	AssertEq(nil, err)

	// Look up with the proper name.
	o, err = t.in.LookUpChild(t.ctx, name)
	AssertEq(nil, err)
	AssertNe(nil, o)

	ExpectEq(fullName, o.Name)
	ExpectEq(createObj.Generation, o.Generation)
	ExpectEq(createObj.Size, o.Size)

	// A conflict marker name shouldn't work.
	o, err = t.in.LookUpChild(t.ctx, name+inode.ConflictingFileNameSuffix)
	AssertEq(nil, err)
	ExpectEq(nil, o)
}

func (t *DirTest) LookUpChild_DirOnly() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDir() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_Empty() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsDisabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsEnabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_LotsOfEntries() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_TypeCaching() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


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

package rocserv

import (
	"fmt"
	"time"
	"encoding/json"
	"strconv"
	"sort"
	"crypto/sha1"
	"crypto/md5"

	// now use 73a8ef737e8ea002281a28b4cb92a1de121ad4c6
    "github.com/coreos/go-etcd/etcd"

	"github.com/sdming/gosnow"

	"github.com/shawnfeng/sutil"
	"github.com/shawnfeng/sutil/slog"

	"github.com/shawnfeng/roc/util/dbrouter"
)

// id生成器
// 服务注册

type ServInfo struct {
	Type string         `json:"type"`
	Addr string         `json:"addr"`
	//Processor string    `json:"processor"`
}

func (m *ServInfo) String() string {
	return fmt.Sprintf("type:%s addr:%s", m.Type, m.Addr)
}

// ServBase Interface
type ServBase interface {
	// key is processor to ServInfo
	RegisterService(servs map[string]*ServInfo) error
	Servid() int
	// 服务副本名称, servename + servid
	Copyname() string

	// 获取服务的配置
	ServConfig(cfg interface{}) error
	// 任意路径的配置信息
	//ArbiConfig(location string) (string, error)

	// id生成逻辑
	GenSnowFlakeId() (int64, error)
	GenUuid() string
	GenUuidSha1() string
	GenUuidMd5() string

	// db router
	Dbrouter() *dbrouter.Router
}

//====================
// id生成逻辑
type IdGenerator struct {
	snow *gosnow.SnowFlake
}

func (m *IdGenerator) GenSnowFlakeId() (int64, error) {
	id, err := m.snow.Next()
	return int64(id), err
}

func (m *IdGenerator) GenUuid() string {
	return sutil.GetUUID()
}

func (m *IdGenerator) GenUuidSha1() string {
	h := sha1.Sum([]byte(m.GenUuid()))
	return fmt.Sprintf("%x", h)
}

func (m *IdGenerator) GenUuidMd5() string {
	h := md5.Sum([]byte(m.GenUuid()))
	return fmt.Sprintf("%x", h)
}

//====================================
func getValue(client *etcd.Client, path string) ([]byte, error) {
    r, err := client.Get(path, false, false)
	if err != nil {
		return nil, err
	}

	if r.Node == nil || r.Node.Dir {
		return nil, fmt.Errorf("etcd node value err location:%s", path)
	}

	return []byte(r.Node.Value), nil

}

func genSid(client *etcd.Client, path, skey string) (int, error) {
	fun := "genSid -->"
    r, err := client.Get(path, false, false)
	if err != nil {
		return -1, err
	}

	js, _ := json.Marshal(r)

	slog.Infof("%s", js)

	if r.Node == nil || !r.Node.Dir {
		return -1, fmt.Errorf("node error location:%s", path)
	}

	slog.Infof("%s serv:%s len:%d", fun, r.Node.Key, r.Node.Nodes.Len())

	// 获取已有的servid，按从小到大排列
	ids := make([]int, 0)
	for _, n := range r.Node.Nodes {
		sid := n.Key[len(r.Node.Key)+1:]
		id, err := strconv.Atoi(sid)
		if err != nil || id < 0 {
			slog.Errorf("%s sid error key:%s", fun, n.Key)
		} else {
			ids = append(ids, id)
			if n.Value == skey {
				// 如果已经存在的sid使用的skey和设置一致，则使用之前的sid
				return id, nil
			}
		}
	}

	sort.Ints(ids)
	sid := 0
	for _, id := range ids {
		// 取不重复的最小的id
		if sid == id {
			sid++
		} else {
			break
		}
	}

	nserv := fmt.Sprintf("%s/%d", r.Node.Key, sid)
	r, err = client.Create(nserv, skey, 0)
	if err != nil {
		return -1, err
	}

	jr, _ := json.Marshal(r)
	slog.Infof("%s newserv:%s rep:%s", fun, nserv, jr)

	return sid, nil

}

func retryGenSid(client *etcd.Client, path, skey string, try int) (int, error) {
	fun := "retryGenSid -->"
	for i := 0; i < try; i++ {
		// 重试3次
		sid, err := genSid(client, path, skey)
		if err != nil {
			slog.Errorf("%s gensid try:%d path:%s err:%s", fun, i, path, err)
		} else {
			return sid, nil
		}
	}

	return -1, fmt.Errorf("gensid error try:%d", try)
}

func initSnowflake(servid int) (*gosnow.SnowFlake, error) {
	if servid < 0 {
		return nil, fmt.Errorf("init snowflake use nagtive servid")
	}
	gosnow.Since = time.Date(2014, 11, 1, 0, 0, 0, 0, time.UTC).UnixNano() / 1000000
	v, err := gosnow.NewSnowFlake(uint32(servid))
	if err != nil {
		return nil, err
	}

	return v, nil
}

<commit_msg>增加获取snowflakeid 时间戳接口<commit_after>// Copyright 2014 The roc Author. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rocserv

import (
	"fmt"
	"time"
	"encoding/json"
	"strconv"
	"sort"
	"crypto/sha1"
	"crypto/md5"

	// now use 73a8ef737e8ea002281a28b4cb92a1de121ad4c6
    "github.com/coreos/go-etcd/etcd"

	"github.com/sdming/gosnow"

	"github.com/shawnfeng/sutil"
	"github.com/shawnfeng/sutil/slog"

	"github.com/shawnfeng/roc/util/dbrouter"
)

// id生成器
// 服务注册

type ServInfo struct {
	Type string         `json:"type"`
	Addr string         `json:"addr"`
	//Processor string    `json:"processor"`
}

func (m *ServInfo) String() string {
	return fmt.Sprintf("type:%s addr:%s", m.Type, m.Addr)
}

// ServBase Interface
type ServBase interface {
	// key is processor to ServInfo
	RegisterService(servs map[string]*ServInfo) error
	Servid() int
	// 服务副本名称, servename + servid
	Copyname() string

	// 获取服务的配置
	ServConfig(cfg interface{}) error
	// 任意路径的配置信息
	//ArbiConfig(location string) (string, error)

	// id生成逻辑
	GenSnowFlakeId() (int64, error)
	// 获取snowflakeid生成时间戳，单位ms
	GetSnowFlakeIdStamp(sid int64) int64
	GenUuid() string
	GenUuidSha1() string
	GenUuidMd5() string

	// db router
	Dbrouter() *dbrouter.Router
}

//====================
// id生成逻辑
type IdGenerator struct {
	snow *gosnow.SnowFlake
}

func (m *IdGenerator) GenSnowFlakeId() (int64, error) {
	id, err := m.snow.Next()
	return int64(id), err
}

func (m *IdGenerator) GetSnowFlakeIdStamp(sid int64) int64 {
	return gosnow.Since+sid>>22
}

func (m *IdGenerator) GenUuid() string {
	return sutil.GetUUID()
}

func (m *IdGenerator) GenUuidSha1() string {
	h := sha1.Sum([]byte(m.GenUuid()))
	return fmt.Sprintf("%x", h)
}

func (m *IdGenerator) GenUuidMd5() string {
	h := md5.Sum([]byte(m.GenUuid()))
	return fmt.Sprintf("%x", h)
}

//====================================
func getValue(client *etcd.Client, path string) ([]byte, error) {
    r, err := client.Get(path, false, false)
	if err != nil {
		return nil, err
	}

	if r.Node == nil || r.Node.Dir {
		return nil, fmt.Errorf("etcd node value err location:%s", path)
	}

	return []byte(r.Node.Value), nil

}

func genSid(client *etcd.Client, path, skey string) (int, error) {
	fun := "genSid -->"
    r, err := client.Get(path, false, false)
	if err != nil {
		return -1, err
	}

	js, _ := json.Marshal(r)

	slog.Infof("%s", js)

	if r.Node == nil || !r.Node.Dir {
		return -1, fmt.Errorf("node error location:%s", path)
	}

	slog.Infof("%s serv:%s len:%d", fun, r.Node.Key, r.Node.Nodes.Len())

	// 获取已有的servid，按从小到大排列
	ids := make([]int, 0)
	for _, n := range r.Node.Nodes {
		sid := n.Key[len(r.Node.Key)+1:]
		id, err := strconv.Atoi(sid)
		if err != nil || id < 0 {
			slog.Errorf("%s sid error key:%s", fun, n.Key)
		} else {
			ids = append(ids, id)
			if n.Value == skey {
				// 如果已经存在的sid使用的skey和设置一致，则使用之前的sid
				return id, nil
			}
		}
	}

	sort.Ints(ids)
	sid := 0
	for _, id := range ids {
		// 取不重复的最小的id
		if sid == id {
			sid++
		} else {
			break
		}
	}

	nserv := fmt.Sprintf("%s/%d", r.Node.Key, sid)
	r, err = client.Create(nserv, skey, 0)
	if err != nil {
		return -1, err
	}

	jr, _ := json.Marshal(r)
	slog.Infof("%s newserv:%s rep:%s", fun, nserv, jr)

	return sid, nil

}

func retryGenSid(client *etcd.Client, path, skey string, try int) (int, error) {
	fun := "retryGenSid -->"
	for i := 0; i < try; i++ {
		// 重试3次
		sid, err := genSid(client, path, skey)
		if err != nil {
			slog.Errorf("%s gensid try:%d path:%s err:%s", fun, i, path, err)
		} else {
			return sid, nil
		}
	}

	return -1, fmt.Errorf("gensid error try:%d", try)
}

func initSnowflake(servid int) (*gosnow.SnowFlake, error) {
	if servid < 0 {
		return nil, fmt.Errorf("init snowflake use nagtive servid")
	}
	gosnow.Since = time.Date(2014, 11, 1, 0, 0, 0, 0, time.UTC).UnixNano() / 1000000
	v, err := gosnow.NewSnowFlake(uint32(servid))
	if err != nil {
		return nil, err
	}

	return v, nil
}

<|endoftext|>


<commit_before>package wutil

import (
	"context"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"

	"github.com/dchest/blake2b"
	"github.com/leeola/fixity"
	"github.com/leeola/fixity/blobstore"
	"github.com/leeola/fixity/chunk"
)

const partSize = 3 // low for testing

func WriteData(ctx context.Context, w blobstore.Writer,
	chunkRefs []fixity.Ref, totalSize int64, contentHash string) ([]fixity.Ref, error) {

	chunkRefLen := len(chunkRefs)
	partCount := chunkRefLen / partSize

	var lastPart *fixity.Ref

	// write all of the parts first, including the partial final part..
	// ie, the part that has less than the max chunks.
	for i := partCount; i > 0; i-- {
		startBound := partSize * i
		endBound := startBound + partSize
		if i == partCount {
			endBound = startBound + chunkRefLen%partSize
		}

		part := fixity.Parts{
			Schema: fixity.Schema{
				SchemaType: fixity.BlobTypeParts,
			},
			Parts:     chunkRefs[startBound:endBound],
			MoreParts: lastPart,
		}

		ref, err := MarshalAndWrite(ctx, w, part)
		if err != nil {
			return nil, fmt.Errorf("marshalandwrite part %d: %v", i, err)
		}
		chunkRefs = append(chunkRefs, ref)
	}

	endBound := partSize
	if chunkRefLen < partSize {
		endBound = chunkRefLen
	}

	// now we've written all the parts except for the most important
	// one, the content which has a part embedded.
	data := fixity.Data{
		Parts: fixity.Parts{
			Schema: fixity.Schema{
				SchemaType: fixity.BlobTypeData,
			},
			Parts:     chunkRefs[0:endBound],
			MoreParts: lastPart,
		},
		Size: totalSize,
	}

	ref, err := MarshalAndWrite(ctx, w, data)
	if err != nil {
		return nil, fmt.Errorf("marshalandwrite content: %v", err)
	}

	return append(chunkRefs, ref), nil
}

func WriteChunks(ctx context.Context, w blobstore.Writer, r chunk.Chunker) (
	refs []fixity.Ref, totalSize int64, contentHash string, err error) {

	hasher := blake2b.New256()

	var hashes []fixity.Ref
	for {
		c, err := r.Chunk(ctx)
		if err != nil && err != io.EOF {
			return nil, 0, "", fmt.Errorf("chunk: %v", err)
		}

		totalSize += c.Size

		if err == io.EOF {
			break
		}

		if _, err := hasher.Write(c.Bytes); err != nil {
			return nil, 0, "", fmt.Errorf("hasher write: %v", err)
		}

		h, err := w.Write(ctx, c.Bytes)
		if err != nil {
			return nil, 0, "", fmt.Errorf("blob write: %v", err)
		}

		hashes = append(hashes, h)
	}

	hash := hex.EncodeToString(hasher.Sum(nil)[:])
	return hashes, totalSize, hash, nil
}

func MarshalAndWrite(ctx context.Context, w blobstore.Writer, v interface{}) (fixity.Ref, error) {
	b, err := json.Marshal(v)
	if err != nil {
		return "", fmt.Errorf("marshal: %v", err)
	}

	ref, err := w.Write(ctx, b)
	if err != nil {
		return "", fmt.Errorf("blob write: %v", err)
	}

	return ref, nil
}

func WriteValues(ctx context.Context, w blobstore.Writer, v fixity.Values) (fixity.Ref, error) {
	return MarshalAndWrite(ctx, w, fixity.ValuesMap{
		Schema: fixity.Schema{
			SchemaType: fixity.BlobTypeValues,
		},
		Values: v,
	})
}
<commit_msg>fix: do not make empty parts<commit_after>package wutil

import (
	"context"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"

	"github.com/dchest/blake2b"
	"github.com/leeola/fixity"
	"github.com/leeola/fixity/blobstore"
	"github.com/leeola/fixity/chunk"
)

const partSize = 2 // low for testing

func WriteData(ctx context.Context, w blobstore.Writer,
	chunkRefs []fixity.Ref, totalSize int64, contentHash string) ([]fixity.Ref, error) {

	chunkRefLen := len(chunkRefs)

	// -1 ensures that the morePartCount doesn't increase at an equal divide,
	// like 2 items for a pagesize of 2, would only need 1 page, yet morePartCount
	// would indicate that there's a morePart page as well.
	//
	//
	// I feel like that made no sense.
	morePartCount := (chunkRefLen - 1) / partSize

	var lastPart *fixity.Ref

	// write all of the parts first, including the partial final part..
	// ie, the part that has less than the max chunks.
	for i := morePartCount; i > 0; i-- {
		startBound := partSize * i
		endBound := startBound + partSize
		if i == morePartCount {
			endBound = startBound + chunkRefLen%partSize
		}

		part := fixity.Parts{
			Schema: fixity.Schema{
				SchemaType: fixity.BlobTypeParts,
			},
			Parts:     chunkRefs[startBound:endBound],
			MoreParts: lastPart,
		}

		ref, err := MarshalAndWrite(ctx, w, part)
		if err != nil {
			return nil, fmt.Errorf("marshalandwrite part %d: %v", i, err)
		}
		chunkRefs = append(chunkRefs, ref)
	}

	endBound := partSize
	if chunkRefLen < partSize {
		endBound = chunkRefLen
	}

	// now we've written all the parts except for the most important
	// one, the content which has a part embedded.
	data := fixity.Data{
		Parts: fixity.Parts{
			Schema: fixity.Schema{
				SchemaType: fixity.BlobTypeData,
			},
			Parts:     chunkRefs[0:endBound],
			MoreParts: lastPart,
		},
		Size: totalSize,
	}

	ref, err := MarshalAndWrite(ctx, w, data)
	if err != nil {
		return nil, fmt.Errorf("marshalandwrite content: %v", err)
	}

	return append(chunkRefs, ref), nil
}

func WriteChunks(ctx context.Context, w blobstore.Writer, r chunk.Chunker) (
	refs []fixity.Ref, totalSize int64, contentHash string, err error) {

	hasher := blake2b.New256()

	var hashes []fixity.Ref
	for {
		c, err := r.Chunk(ctx)
		if err != nil && err != io.EOF {
			return nil, 0, "", fmt.Errorf("chunk: %v", err)
		}

		totalSize += c.Size

		if err == io.EOF {
			break
		}

		if _, err := hasher.Write(c.Bytes); err != nil {
			return nil, 0, "", fmt.Errorf("hasher write: %v", err)
		}

		h, err := w.Write(ctx, c.Bytes)
		if err != nil {
			return nil, 0, "", fmt.Errorf("blob write: %v", err)
		}

		hashes = append(hashes, h)
	}

	hash := hex.EncodeToString(hasher.Sum(nil)[:])
	return hashes, totalSize, hash, nil
}

func MarshalAndWrite(ctx context.Context, w blobstore.Writer, v interface{}) (fixity.Ref, error) {
	b, err := json.Marshal(v)
	if err != nil {
		return "", fmt.Errorf("marshal: %v", err)
	}

	ref, err := w.Write(ctx, b)
	if err != nil {
		return "", fmt.Errorf("blob write: %v", err)
	}

	return ref, nil
}

func WriteValues(ctx context.Context, w blobstore.Writer, v fixity.Values) (fixity.Ref, error) {
	return MarshalAndWrite(ctx, w, fixity.ValuesMap{
		Schema: fixity.Schema{
			SchemaType: fixity.BlobTypeValues,
		},
		Values: v,
	})
}
<|endoftext|>


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

package cpuload

import (
	"fmt"

	"github.com/golang/glog"
	"github.com/google/cadvisor/info"
	"github.com/google/cadvisor/utils/cpuload/netlink"
	"github.com/google/cadvisor/utils/cpuload/scheddebug"
)

type CpuLoadReader interface {
	// Start the reader.
	Start() error

	// Stop the reader and clean up internal state.
	Stop()

	// Retrieve Cpu load for a given group.
	// name is the full hierarchical name of the container.
	// Path is an absolute filesystem path for a container under CPU cgroup hierarchy.
	GetCpuLoad(name string, path string) (info.LoadStats, error)
}

func New() (CpuLoadReader, error) {
	// First try to create a netlink based load reader.
	reader, err := netlink.New()
	if err == nil {
		glog.Info("Using a netlink-based load reader")
		return reader, nil
	}
	glog.V(1).Infof("failed to create a netlink-based cpu load read: %v", err)
	// Netlink based load reader doesn't work inside namespaces. Fall back to using scheddebug.
	schedReader, schedErr := scheddebug.New()
	if schedErr != nil {
		return nil, fmt.Errorf("failed to create any cpu load reader - netlink based (%v), scheddebug based (%v)", err, schedErr)
	}
	glog.Info("Using a sched debug based load reader")
	return schedReader, nil
}
<commit_msg>Prefer scheddebug over netlink for cpu load.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cpuload

import (
	"fmt"

	"github.com/golang/glog"
	"github.com/google/cadvisor/info"
	"github.com/google/cadvisor/utils/cpuload/netlink"
	"github.com/google/cadvisor/utils/cpuload/scheddebug"
)

type CpuLoadReader interface {
	// Start the reader.
	Start() error

	// Stop the reader and clean up internal state.
	Stop()

	// Retrieve Cpu load for a given group.
	// name is the full hierarchical name of the container.
	// Path is an absolute filesystem path for a container under CPU cgroup hierarchy.
	GetCpuLoad(name string, path string) (info.LoadStats, error)
}

func New() (CpuLoadReader, error) {
	// First try to create a scheddebug based load reader.
	schedReader, schedErr := scheddebug.New()
	if schedErr == nil {
		glog.Info("Using a sched debug based load reader")
		return schedReader, nil
	}
	glog.V(1).Infof("failed to create a scheddebug-based cpu load reader: %v", schedErr)
	// netlink gives us more data than scheddebug, but it doesn't work inside network namespaces. It also needs to be hierarchical.
	reader, err := netlink.New()
	if err != nil {
		return nil, fmt.Errorf("failed to create any cpu load reader - netlink based (%v), scheddebug based (%v)", err, schedErr)
	}
	glog.Info("Using a netlink-based load reader")
	return reader, nil
}
<|endoftext|>


<commit_before>package log

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"sort"
	"strconv"
	"strings"
	"time"

	"gopkg.in/yaml.v3"
)

//------------------------------------------------------------------------------

// Logger level constants
const (
	LogOff   int = 0
	LogFatal int = 1
	LogError int = 2
	LogWarn  int = 3
	LogInfo  int = 4
	LogDebug int = 5
	LogTrace int = 6
	LogAll   int = 7
)

// intToLogLevel converts an integer into a human readable log level.
func intToLogLevel(i int) string {
	switch i {
	case LogOff:
		return "OFF"
	case LogFatal:
		return "FATAL"
	case LogError:
		return "ERROR"
	case LogWarn:
		return "WARN"
	case LogInfo:
		return "INFO"
	case LogDebug:
		return "DEBUG"
	case LogTrace:
		return "TRACE"
	case LogAll:
		return "ALL"
	}
	return "ALL"
}

// logLevelToInt converts a human readable log level into an integer value.
func logLevelToInt(level string) int {
	levelUpper := strings.ToUpper(level)
	switch levelUpper {
	case "OFF":
		return LogOff
	case "FATAL":
		return LogFatal
	case "ERROR":
		return LogError
	case "WARN":
		return LogWarn
	case "INFO":
		return LogInfo
	case "DEBUG":
		return LogDebug
	case "TRACE":
		return LogTrace
	case "ALL":
		return LogAll
	}
	return -1
}

//------------------------------------------------------------------------------

// Config holds configuration options for a logger object.
type Config struct {
	Prefix       string            `json:"prefix" yaml:"prefix"`
	LogLevel     string            `json:"level" yaml:"level"`
	Format       string            `json:"format" yaml:"format"`
	AddTimeStamp bool              `json:"add_timestamp" yaml:"add_timestamp"`
	JSONFormat   bool              `json:"json_format" yaml:"json_format"`
	StaticFields map[string]string `json:"static_fields" yaml:"static_fields"`
}

// NewConfig returns a config struct with the default values for each field.
func NewConfig() Config {
	return Config{
		Prefix:       "benthos",
		LogLevel:     "INFO",
		Format:       "json",
		AddTimeStamp: true,
		JSONFormat:   true,
		StaticFields: map[string]string{
			"@service": "benthos",
		},
	}
}

// Sanitised returns a sanitised version of the config, meaning sections that
// aren't relevant to behaviour are removed. Also optionally removes deprecated
// fields.
func (conf Config) Sanitised(removeDeprecated bool) (interface{}, error) {
	cBytes, err := yaml.Marshal(conf)
	if err != nil {
		return nil, err
	}

	hashMap := map[string]interface{}{}
	if err = yaml.Unmarshal(cBytes, &hashMap); err != nil {
		return nil, err
	}

	if conf.JSONFormat {
		delete(hashMap, "json_format")
	}

	return hashMap, nil
}

//------------------------------------------------------------------------------

// UnmarshalJSON ensures that when parsing configs that are in a slice the
// default values are still applied.
func (conf *Config) UnmarshalJSON(bytes []byte) error {
	type confAlias Config
	aliased := confAlias(NewConfig())

	defaultFields := aliased.StaticFields
	aliased.StaticFields = nil
	if err := json.Unmarshal(bytes, &aliased); err != nil {
		return err
	}

	if aliased.StaticFields == nil {
		aliased.StaticFields = defaultFields
	}

	*conf = Config(aliased)
	return nil
}

// UnmarshalYAML ensures that when parsing configs that are in a slice the
// default values are still applied.
func (conf *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type confAlias Config
	aliased := confAlias(NewConfig())

	defaultFields := aliased.StaticFields
	aliased.StaticFields = nil

	if err := unmarshal(&aliased); err != nil {
		return err
	}

	if aliased.StaticFields == nil {
		aliased.StaticFields = defaultFields
	}

	*conf = Config(aliased)
	return nil
}

//------------------------------------------------------------------------------

// Logger is an object with support for levelled logging and modular components.
type Logger struct {
	stream    io.Writer
	config    Config
	level     int
	formatter logFormatter
}

// New creates and returns a new logger object.
// TODO: V4 replace this with NewV2
func New(stream io.Writer, config Config) Modular {
	if !config.JSONFormat {
		config.Format = "deprecated"
	}

	logger := Logger{
		stream: stream,
		config: config,
		level:  logLevelToInt(config.LogLevel),
	}

	logger.formatter, _ = getFormatter(config)
	if logger.formatter == nil {
		logger.formatter = deprecatedFormatter(config)
	}
	return &logger
}

// NewV2 returns a new logger from a config, or returns an error if the config
// is invalid.
func NewV2(stream io.Writer, config Config) (Modular, error) {
	if !config.JSONFormat {
		config.Format = "deprecated"
	}

	logger := Logger{
		stream: stream,
		config: config,
		level:  logLevelToInt(config.LogLevel),
	}

	var err error
	if logger.formatter, err = getFormatter(config); err != nil {
		return nil, err
	}
	return &logger, nil
}

//------------------------------------------------------------------------------

// Noop creates and returns a new logger object that writes nothing.
func Noop() Modular {
	return &Logger{
		stream:    ioutil.Discard,
		config:    NewConfig(),
		level:     LogOff,
		formatter: deprecatedFormatter(NewConfig()),
	}
}

// NewModule creates a new logger object from the previous, using the same
// configuration, but adds an extra prefix to represent a submodule.
func (l *Logger) NewModule(prefix string) Modular {
	config := l.config
	config.Prefix = fmt.Sprintf("%v%v", config.Prefix, prefix)

	formatter, _ := getFormatter(config)
	if formatter == nil {
		formatter = deprecatedFormatter(config)
	}

	return &Logger{
		stream:    l.stream,
		config:    config,
		level:     l.level,
		formatter: formatter,
	}
}

// WithFields returns a logger with new fields added to the JSON formatted
// output.
func (l *Logger) WithFields(fields map[string]string) Modular {
	newConfig := l.config
	newConfig.StaticFields = fields
	for k, v := range l.config.StaticFields {
		if _, exists := fields[k]; !exists {
			newConfig.StaticFields[k] = v
		}
	}

	formatter, _ := getFormatter(newConfig)
	if formatter == nil {
		formatter = deprecatedFormatter(newConfig)
	}

	return &Logger{
		stream:    l.stream,
		config:    newConfig,
		level:     l.level,
		formatter: formatter,
	}
}

// WithFields attempts to cast the Modular implementation into an interface that
// implements WithFields, and if successful returns the result.
func WithFields(l Modular, fields map[string]string) Modular {
	return l.WithFields(fields)
}

//------------------------------------------------------------------------------

type logFormatter func(w io.Writer, message string, level string, other ...interface{})

func jsonFormatter(conf Config) logFormatter {
	var staticFieldsRawJSON string
	if len(conf.StaticFields) > 0 {
		jBytes, _ := json.Marshal(conf.StaticFields)
		if len(jBytes) > 2 {
			staticFieldsRawJSON = string(jBytes[1:len(jBytes)-1]) + ","
		}
	}

	return func(w io.Writer, message string, level string, other ...interface{}) {
		message = strings.TrimSuffix(message, "\n")
		timestampStr := ""
		if conf.AddTimeStamp {
			timestampStr = fmt.Sprintf("\"@timestamp\":\"%v\",", time.Now().Format(time.RFC3339))
		}
		fmt.Fprintf(
			w,
			"{%v%v\"level\":\"%v\",\"component\":\"%v\",\"message\":%v}\n",
			timestampStr, staticFieldsRawJSON, level, conf.Prefix,
			strconv.QuoteToASCII(fmt.Sprintf(message, other...)),
		)
	}
}

func logfmtFormatter(conf Config) logFormatter {
	var staticFieldsRaw string
	if len(conf.StaticFields) > 0 {
		keys := make([]string, 0, len(conf.StaticFields))
		for k := range conf.StaticFields {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		var buf bytes.Buffer
		for _, k := range keys {
			buf.WriteString(fmt.Sprintf("%v=%v ", k, conf.StaticFields[k]))
		}
		staticFieldsRaw = buf.String()
	}

	return func(w io.Writer, message string, level string, other ...interface{}) {
		message = strings.TrimSuffix(message, "\n")
		timestampStr := ""
		if conf.AddTimeStamp {
			timestampStr = fmt.Sprintf("timestamp=\"%v\" ", time.Now().Format(time.RFC3339))
		}
		fmt.Fprintf(
			w,
			"%v%vlevel=%v component=%v msg=%v\n",
			timestampStr, staticFieldsRaw, level, conf.Prefix,
			strconv.QuoteToASCII(fmt.Sprintf(message, other...)),
		)
	}
}

func deprecatedFormatter(conf Config) logFormatter {
	return func(w io.Writer, message string, level string, other ...interface{}) {
		if !strings.HasSuffix(message, "\n") {
			message = message + "\n"
		}
		timestampStr := ""
		if conf.AddTimeStamp {
			timestampStr = fmt.Sprintf("%v | ", time.Now().Format(time.RFC3339))
		}
		fmt.Fprintf(w, fmt.Sprintf(
			"%v%v | %v | %v",
			timestampStr, level, conf.Prefix, message,
		), other...)
	}
}

func getFormatter(conf Config) (logFormatter, error) {
	switch conf.Format {
	case "json":
		return jsonFormatter(conf), nil
	case "logfmt":
		return logfmtFormatter(conf), nil
	case "deprecated", "classic":
		return deprecatedFormatter(conf), nil
	}
	return nil, fmt.Errorf("log format '%v' not recognized", conf.Format)
}

// write prints a log message with any configured extras prepended.
func (l *Logger) write(message string, level string, other ...interface{}) {
	l.formatter(l.stream, message, level, other...)
}

//------------------------------------------------------------------------------

// Fatalf prints a fatal message to the console. Does NOT cause panic.
func (l *Logger) Fatalf(format string, v ...interface{}) {
	if LogFatal <= l.level {
		l.write(format, "FATAL", v...)
	}
}

// Errorf prints an error message to the console.
func (l *Logger) Errorf(format string, v ...interface{}) {
	if LogError <= l.level {
		l.write(format, "ERROR", v...)
	}
}

// Warnf prints a warning message to the console.
func (l *Logger) Warnf(format string, v ...interface{}) {
	if LogWarn <= l.level {
		l.write(format, "WARN", v...)
	}
}

// Infof prints an information message to the console.
func (l *Logger) Infof(format string, v ...interface{}) {
	if LogInfo <= l.level {
		l.write(format, "INFO", v...)
	}
}

// Debugf prints a debug message to the console.
func (l *Logger) Debugf(format string, v ...interface{}) {
	if LogDebug <= l.level {
		l.write(format, "DEBUG", v...)
	}
}

// Tracef prints a trace message to the console.
func (l *Logger) Tracef(format string, v ...interface{}) {
	if LogTrace <= l.level {
		l.write(format, "TRACE", v...)
	}
}

//------------------------------------------------------------------------------

// Fatalln prints a fatal message to the console. Does NOT cause panic.
func (l *Logger) Fatalln(message string) {
	if LogFatal <= l.level {
		l.write(message, "FATAL")
	}
}

// Errorln prints an error message to the console.
func (l *Logger) Errorln(message string) {
	if LogError <= l.level {
		l.write(message, "ERROR")
	}
}

// Warnln prints a warning message to the console.
func (l *Logger) Warnln(message string) {
	if LogWarn <= l.level {
		l.write(message, "WARN")
	}
}

// Infoln prints an information message to the console.
func (l *Logger) Infoln(message string) {
	if LogInfo <= l.level {
		l.write(message, "INFO")
	}
}

// Debugln prints a debug message to the console.
func (l *Logger) Debugln(message string) {
	if LogDebug <= l.level {
		l.write(message, "DEBUG")
	}
}

// Traceln prints a trace message to the console.
func (l *Logger) Traceln(message string) {
	if LogTrace <= l.level {
		l.write(message, "TRACE")
	}
}

//------------------------------------------------------------------------------
<commit_msg>Only remove json_format when removing deprecated fields<commit_after>package log

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"sort"
	"strconv"
	"strings"
	"time"

	"gopkg.in/yaml.v3"
)

//------------------------------------------------------------------------------

// Logger level constants
const (
	LogOff   int = 0
	LogFatal int = 1
	LogError int = 2
	LogWarn  int = 3
	LogInfo  int = 4
	LogDebug int = 5
	LogTrace int = 6
	LogAll   int = 7
)

// intToLogLevel converts an integer into a human readable log level.
func intToLogLevel(i int) string {
	switch i {
	case LogOff:
		return "OFF"
	case LogFatal:
		return "FATAL"
	case LogError:
		return "ERROR"
	case LogWarn:
		return "WARN"
	case LogInfo:
		return "INFO"
	case LogDebug:
		return "DEBUG"
	case LogTrace:
		return "TRACE"
	case LogAll:
		return "ALL"
	}
	return "ALL"
}

// logLevelToInt converts a human readable log level into an integer value.
func logLevelToInt(level string) int {
	levelUpper := strings.ToUpper(level)
	switch levelUpper {
	case "OFF":
		return LogOff
	case "FATAL":
		return LogFatal
	case "ERROR":
		return LogError
	case "WARN":
		return LogWarn
	case "INFO":
		return LogInfo
	case "DEBUG":
		return LogDebug
	case "TRACE":
		return LogTrace
	case "ALL":
		return LogAll
	}
	return -1
}

//------------------------------------------------------------------------------

// Config holds configuration options for a logger object.
type Config struct {
	Prefix       string            `json:"prefix" yaml:"prefix"`
	LogLevel     string            `json:"level" yaml:"level"`
	Format       string            `json:"format" yaml:"format"`
	AddTimeStamp bool              `json:"add_timestamp" yaml:"add_timestamp"`
	JSONFormat   bool              `json:"json_format" yaml:"json_format"`
	StaticFields map[string]string `json:"static_fields" yaml:"static_fields"`
}

// NewConfig returns a config struct with the default values for each field.
func NewConfig() Config {
	return Config{
		Prefix:       "benthos",
		LogLevel:     "INFO",
		Format:       "json",
		AddTimeStamp: true,
		JSONFormat:   true,
		StaticFields: map[string]string{
			"@service": "benthos",
		},
	}
}

// Sanitised returns a sanitised version of the config, meaning sections that
// aren't relevant to behaviour are removed. Also optionally removes deprecated
// fields.
func (conf Config) Sanitised(removeDeprecated bool) (interface{}, error) {
	cBytes, err := yaml.Marshal(conf)
	if err != nil {
		return nil, err
	}

	hashMap := map[string]interface{}{}
	if err = yaml.Unmarshal(cBytes, &hashMap); err != nil {
		return nil, err
	}

	if removeDeprecated && conf.JSONFormat {
		delete(hashMap, "json_format")
	}

	return hashMap, nil
}

//------------------------------------------------------------------------------

// UnmarshalJSON ensures that when parsing configs that are in a slice the
// default values are still applied.
func (conf *Config) UnmarshalJSON(bytes []byte) error {
	type confAlias Config
	aliased := confAlias(NewConfig())

	defaultFields := aliased.StaticFields
	aliased.StaticFields = nil
	if err := json.Unmarshal(bytes, &aliased); err != nil {
		return err
	}

	if aliased.StaticFields == nil {
		aliased.StaticFields = defaultFields
	}

	*conf = Config(aliased)
	return nil
}

// UnmarshalYAML ensures that when parsing configs that are in a slice the
// default values are still applied.
func (conf *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type confAlias Config
	aliased := confAlias(NewConfig())

	defaultFields := aliased.StaticFields
	aliased.StaticFields = nil

	if err := unmarshal(&aliased); err != nil {
		return err
	}

	if aliased.StaticFields == nil {
		aliased.StaticFields = defaultFields
	}

	*conf = Config(aliased)
	return nil
}

//------------------------------------------------------------------------------

// Logger is an object with support for levelled logging and modular components.
type Logger struct {
	stream    io.Writer
	config    Config
	level     int
	formatter logFormatter
}

// New creates and returns a new logger object.
// TODO: V4 replace this with NewV2
func New(stream io.Writer, config Config) Modular {
	if !config.JSONFormat {
		config.Format = "deprecated"
	}

	logger := Logger{
		stream: stream,
		config: config,
		level:  logLevelToInt(config.LogLevel),
	}

	logger.formatter, _ = getFormatter(config)
	if logger.formatter == nil {
		logger.formatter = deprecatedFormatter(config)
	}
	return &logger
}

// NewV2 returns a new logger from a config, or returns an error if the config
// is invalid.
func NewV2(stream io.Writer, config Config) (Modular, error) {
	if !config.JSONFormat {
		config.Format = "deprecated"
	}

	logger := Logger{
		stream: stream,
		config: config,
		level:  logLevelToInt(config.LogLevel),
	}

	var err error
	if logger.formatter, err = getFormatter(config); err != nil {
		return nil, err
	}
	return &logger, nil
}

//------------------------------------------------------------------------------

// Noop creates and returns a new logger object that writes nothing.
func Noop() Modular {
	return &Logger{
		stream:    ioutil.Discard,
		config:    NewConfig(),
		level:     LogOff,
		formatter: deprecatedFormatter(NewConfig()),
	}
}

// NewModule creates a new logger object from the previous, using the same
// configuration, but adds an extra prefix to represent a submodule.
func (l *Logger) NewModule(prefix string) Modular {
	config := l.config
	config.Prefix = fmt.Sprintf("%v%v", config.Prefix, prefix)

	formatter, _ := getFormatter(config)
	if formatter == nil {
		formatter = deprecatedFormatter(config)
	}

	return &Logger{
		stream:    l.stream,
		config:    config,
		level:     l.level,
		formatter: formatter,
	}
}

// WithFields returns a logger with new fields added to the JSON formatted
// output.
func (l *Logger) WithFields(fields map[string]string) Modular {
	newConfig := l.config
	newConfig.StaticFields = fields
	for k, v := range l.config.StaticFields {
		if _, exists := fields[k]; !exists {
			newConfig.StaticFields[k] = v
		}
	}

	formatter, _ := getFormatter(newConfig)
	if formatter == nil {
		formatter = deprecatedFormatter(newConfig)
	}

	return &Logger{
		stream:    l.stream,
		config:    newConfig,
		level:     l.level,
		formatter: formatter,
	}
}

// WithFields attempts to cast the Modular implementation into an interface that
// implements WithFields, and if successful returns the result.
func WithFields(l Modular, fields map[string]string) Modular {
	return l.WithFields(fields)
}

//------------------------------------------------------------------------------

type logFormatter func(w io.Writer, message string, level string, other ...interface{})

func jsonFormatter(conf Config) logFormatter {
	var staticFieldsRawJSON string
	if len(conf.StaticFields) > 0 {
		jBytes, _ := json.Marshal(conf.StaticFields)
		if len(jBytes) > 2 {
			staticFieldsRawJSON = string(jBytes[1:len(jBytes)-1]) + ","
		}
	}

	return func(w io.Writer, message string, level string, other ...interface{}) {
		message = strings.TrimSuffix(message, "\n")
		timestampStr := ""
		if conf.AddTimeStamp {
			timestampStr = fmt.Sprintf("\"@timestamp\":\"%v\",", time.Now().Format(time.RFC3339))
		}
		fmt.Fprintf(
			w,
			"{%v%v\"level\":\"%v\",\"component\":\"%v\",\"message\":%v}\n",
			timestampStr, staticFieldsRawJSON, level, conf.Prefix,
			strconv.QuoteToASCII(fmt.Sprintf(message, other...)),
		)
	}
}

func logfmtFormatter(conf Config) logFormatter {
	var staticFieldsRaw string
	if len(conf.StaticFields) > 0 {
		keys := make([]string, 0, len(conf.StaticFields))
		for k := range conf.StaticFields {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		var buf bytes.Buffer
		for _, k := range keys {
			buf.WriteString(fmt.Sprintf("%v=%v ", k, conf.StaticFields[k]))
		}
		staticFieldsRaw = buf.String()
	}

	return func(w io.Writer, message string, level string, other ...interface{}) {
		message = strings.TrimSuffix(message, "\n")
		timestampStr := ""
		if conf.AddTimeStamp {
			timestampStr = fmt.Sprintf("timestamp=\"%v\" ", time.Now().Format(time.RFC3339))
		}
		fmt.Fprintf(
			w,
			"%v%vlevel=%v component=%v msg=%v\n",
			timestampStr, staticFieldsRaw, level, conf.Prefix,
			strconv.QuoteToASCII(fmt.Sprintf(message, other...)),
		)
	}
}

func deprecatedFormatter(conf Config) logFormatter {
	return func(w io.Writer, message string, level string, other ...interface{}) {
		if !strings.HasSuffix(message, "\n") {
			message = message + "\n"
		}
		timestampStr := ""
		if conf.AddTimeStamp {
			timestampStr = fmt.Sprintf("%v | ", time.Now().Format(time.RFC3339))
		}
		fmt.Fprintf(w, fmt.Sprintf(
			"%v%v | %v | %v",
			timestampStr, level, conf.Prefix, message,
		), other...)
	}
}

func getFormatter(conf Config) (logFormatter, error) {
	switch conf.Format {
	case "json":
		return jsonFormatter(conf), nil
	case "logfmt":
		return logfmtFormatter(conf), nil
	case "deprecated", "classic":
		return deprecatedFormatter(conf), nil
	}
	return nil, fmt.Errorf("log format '%v' not recognized", conf.Format)
}

// write prints a log message with any configured extras prepended.
func (l *Logger) write(message string, level string, other ...interface{}) {
	l.formatter(l.stream, message, level, other...)
}

//------------------------------------------------------------------------------

// Fatalf prints a fatal message to the console. Does NOT cause panic.
func (l *Logger) Fatalf(format string, v ...interface{}) {
	if LogFatal <= l.level {
		l.write(format, "FATAL", v...)
	}
}

// Errorf prints an error message to the console.
func (l *Logger) Errorf(format string, v ...interface{}) {
	if LogError <= l.level {
		l.write(format, "ERROR", v...)
	}
}

// Warnf prints a warning message to the console.
func (l *Logger) Warnf(format string, v ...interface{}) {
	if LogWarn <= l.level {
		l.write(format, "WARN", v...)
	}
}

// Infof prints an information message to the console.
func (l *Logger) Infof(format string, v ...interface{}) {
	if LogInfo <= l.level {
		l.write(format, "INFO", v...)
	}
}

// Debugf prints a debug message to the console.
func (l *Logger) Debugf(format string, v ...interface{}) {
	if LogDebug <= l.level {
		l.write(format, "DEBUG", v...)
	}
}

// Tracef prints a trace message to the console.
func (l *Logger) Tracef(format string, v ...interface{}) {
	if LogTrace <= l.level {
		l.write(format, "TRACE", v...)
	}
}

//------------------------------------------------------------------------------

// Fatalln prints a fatal message to the console. Does NOT cause panic.
func (l *Logger) Fatalln(message string) {
	if LogFatal <= l.level {
		l.write(message, "FATAL")
	}
}

// Errorln prints an error message to the console.
func (l *Logger) Errorln(message string) {
	if LogError <= l.level {
		l.write(message, "ERROR")
	}
}

// Warnln prints a warning message to the console.
func (l *Logger) Warnln(message string) {
	if LogWarn <= l.level {
		l.write(message, "WARN")
	}
}

// Infoln prints an information message to the console.
func (l *Logger) Infoln(message string) {
	if LogInfo <= l.level {
		l.write(message, "INFO")
	}
}

// Debugln prints a debug message to the console.
func (l *Logger) Debugln(message string) {
	if LogDebug <= l.level {
		l.write(message, "DEBUG")
	}
}

// Traceln prints a trace message to the console.
func (l *Logger) Traceln(message string) {
	if LogTrace <= l.level {
		l.write(message, "TRACE")
	}
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package main

import "io/ioutil"

func mustTempDir(prefix string) string {
	outdir, err := ioutil.TempDir("", "TestExtractCommand")
	if err != nil {
		panic(err)
	}
	return outdir
}
<commit_msg>use prefix arg<commit_after>package main

import "io/ioutil"

func mustTempDir(prefix string) string {
	outdir, err := ioutil.TempDir("", prefix)
	if err != nil {
		panic(err)
	}
	return outdir
}
<|endoftext|>


<commit_before>package main

import (
	"jiacrontab/libs/mailer"
	"jiacrontab/libs/rpc"
	db "jiacrontab/model"
	"jiacrontab/server/conf"
	"jiacrontab/server/handle"
	"jiacrontab/server/model"
	"log"
	_ "net/http/pprof"

	"github.com/kataras/iris/middleware/logger"
	"github.com/kataras/iris/middleware/recover"

	"jiacrontab/libs"

	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/kataras/iris"
)

const (
	DefaultLayout = "layouts/layout.html"
)

func main() {

	log.SetFlags(log.LstdFlags | log.Lshortfile)
	db.CreateDB("sqlite3", "data/jiacrontab_server.db")
	db.DB().CreateTable(&db.Client{})
	db.DB().AutoMigrate(&db.Client{})

	// mail
	mailer.InitMailer(&mailer.Mailer{
		QueueLength:    conf.MailService.QueueLength,
		SubjectPrefix:  conf.MailService.SubjectPrefix,
		From:           conf.MailService.From,
		Host:           conf.MailService.Host,
		User:           conf.MailService.User,
		Passwd:         conf.MailService.Passwd,
		FromEmail:      conf.MailService.FromEmail,
		DisableHelo:    conf.MailService.DisableHelo,
		HeloHostname:   conf.MailService.HeloHostname,
		SkipVerify:     conf.MailService.SkipVerify,
		UseCertificate: conf.MailService.UseCertificate,
		CertFile:       conf.MailService.CertFile,
		KeyFile:        conf.MailService.KeyFile,
		UsePlainText:   conf.MailService.UsePlainText,
	})

	model.InitStore(conf.AppService.DataFile)

	app := iris.New()
	if conf.AppService.Debug {
		app.Logger().SetLevel("debug")
		app.Use(logger.New())
	}

	app.Use(recover.New())
	html := iris.HTML(conf.AppService.TplDir, conf.AppService.TplExt)
	html.AddFunc("date", libs.Date)
	html.AddFunc("formatMs", libs.Int2floatstr)
	html.Layout("layouts/layout.html")
	html.Reload(true)
	app.RegisterView(html)
	router(app)
	go rpc.ListenAndServe(conf.AppService.RpcListenAddr, &handle.Logic{})
	app.Run(iris.Addr(conf.AppService.HttpListenAddr))
}
<commit_msg>update<commit_after>package main

import (
	"jiacrontab/libs/mailer"
	"jiacrontab/libs/rpc"
	db "jiacrontab/model"
	"jiacrontab/server/conf"
	"jiacrontab/server/handle"
	"jiacrontab/server/model"
	"log"
	_ "net/http/pprof"

	"github.com/kataras/iris/middleware/logger"
	"github.com/kataras/iris/middleware/recover"

	"jiacrontab/libs"

	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/kataras/iris"
)

const (
	DefaultLayout = "layouts/layout.html"
)

func main() {

	log.SetFlags(log.LstdFlags | log.Lshortfile)

	db.CreateDB("sqlite3", "data/jiacrontab_server.db")
	db.DB().CreateTable(&db.Client{})
	db.DB().AutoMigrate(&db.Client{})

	// mail
	mailer.InitMailer(&mailer.Mailer{
		QueueLength:    conf.MailService.QueueLength,
		SubjectPrefix:  conf.MailService.SubjectPrefix,
		From:           conf.MailService.From,
		Host:           conf.MailService.Host,
		User:           conf.MailService.User,
		Passwd:         conf.MailService.Passwd,
		FromEmail:      conf.MailService.FromEmail,
		DisableHelo:    conf.MailService.DisableHelo,
		HeloHostname:   conf.MailService.HeloHostname,
		SkipVerify:     conf.MailService.SkipVerify,
		UseCertificate: conf.MailService.UseCertificate,
		CertFile:       conf.MailService.CertFile,
		KeyFile:        conf.MailService.KeyFile,
		UsePlainText:   conf.MailService.UsePlainText,
	})

	model.InitStore(conf.AppService.DataFile)

	app := iris.New()
	if conf.AppService.Debug {
		app.Logger().SetLevel("debug")
		app.Use(logger.New())
	}

	app.Use(recover.New())
	html := iris.HTML(conf.AppService.TplDir, conf.AppService.TplExt)
	html.AddFunc("date", libs.Date)
	html.AddFunc("formatMs", libs.Int2floatstr)
	html.Layout("layouts/layout.html")
	html.Reload(true)
	app.RegisterView(html)
	router(app)
	go rpc.ListenAndServe(conf.AppService.RpcListenAddr, &handle.Logic{})
	app.Run(iris.Addr(conf.AppService.HttpListenAddr))
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/ActiveState/log"
	"github.com/apcera/nats"
	"time"
)

// NewNatsClient connects to the NATS server of the Stackato cluster
func NewNatsClient() *nats.EncodedConn {
	natsUri := GetClusterConfig().GetNatsUri()
	// TODO: hardcoding nats uri until we read the actual config.
	natsUri = "nats://127.0.0.1:4222/"
	log.Infof("Connecting to NATS %s\n", natsUri)
	nc, err := nats.Connect(natsUri)
	if err != nil {
		log.Fatal(err)
	}
	log.Infof("Connected to NATS %s\n", natsUri)
	client, err := nats.NewEncodedConn(nc, "json")
	if err != nil {
		log.Fatal(err)
	}

	// Diagnosing Bug #97856 by periodically checking if we are still
	// connected to NATS.
	go func() {
		log.Info("Periodically checking NATS connectivity")
		for _ = range time.Tick(1 * time.Minute) {
			if nc.IsClosed() {
				log.Fatal("Connection to NATS has been closed (in the last minute)")
			}
		}
	}()

	return client
}
<commit_msg>allow retrying when connecting to NATS<commit_after>package server

import (
	"github.com/ActiveState/log"
	"github.com/apcera/nats"
	"time"
)

// NewNatsClient connects to the NATS server of the Stackato cluster
func NewNatsClient(retries int) *nats.EncodedConn {
	natsUri := GetClusterConfig().GetNatsUri()
	// TODO: hardcoding nats uri until we read the actual config.
	natsUri = "nats://127.0.0.1:4222/"
	log.Infof("Connecting to NATS %s\n", natsUri)

	var nc *nats.Conn
	var err error

	for attempt := 0; attempt < retries; attempt++ {
		nc, err = nats.Connect(natsUri)
		if err != nil {
			if (attempt + 1) == retries {
				log.Fatal(err)
			}
			log.Warnf("NATS connection error (%v); retrying after 1 second..",
				err)
			time.Sleep(time.Second)
		}
	}

	log.Infof("Connected to NATS %s\n", natsUri)
	client, err := nats.NewEncodedConn(nc, "json")
	if err != nil {
		log.Fatal(err)
	}

	// Diagnosing Bug #97856 by periodically checking if we are still
	// connected to NATS.
	go func() {
		log.Info("Periodically checking NATS connectivity")
		for _ = range time.Tick(1 * time.Minute) {
			if nc.IsClosed() {
				log.Fatal("Connection to NATS has been closed (in the last minute)")
			}
		}
	}()

	return client
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package storage

import (
	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/storage"
)

// InterpretListError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretListError(err error, qualifiedResource unversioned.GroupResource) error {
	switch {
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, "")
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "list", 2) // TODO: make configurable or handled at a higher level
	default:
		return err
	}
}

// InterpretGetError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretGetError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, name)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "get", 2) // TODO: make configurable or handled at a higher level
	default:
		return err
	}
}

// InterpretCreateError converts a generic error on a create
// operation into the appropriate API error.
func InterpretCreateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsNodeExist(err):
		return errors.NewAlreadyExists(qualifiedResource, name)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "create", 2) // TODO: make configurable or handled at a higher level
	default:
		return err
	}
}

// InterpretUpdateError converts a generic error on a update
// operation into the appropriate API error.
func InterpretUpdateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsTestFailed(err), storage.IsNodeExist(err):
		return errors.NewConflict(qualifiedResource, name, err)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "update", 2) // TODO: make configurable or handled at a higher level
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, name)
	case storage.IsInternalError(err):
		return errors.NewInternalError(err)
	default:
		return err
	}
}

// InterpretDeleteError converts a generic error on a delete
// operation into the appropriate API error.
func InterpretDeleteError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, name)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "delete", 2) // TODO: make configurable or handled at a higher level
	case storage.IsTestFailed(err), storage.IsNodeExist(err):
		return errors.NewConflict(qualifiedResource, name, err)
	case storage.IsInternalError(err):
		return errors.NewInternalError(err)
	default:
		return err
	}
}

// InterpretWatchError converts a generic error on a watch
// operation into the appropriate API error.
func InterpretWatchError(err error, resource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsInvalidError(err):
		invalidError, _ := err.(storage.InvalidError)
		return errors.NewInvalid(unversioned.GroupKind{Group: resource.Group, Kind: resource.Resource}, name, invalidError.Errs)
	default:
		return err
	}
}
<commit_msg>storage error: precondition failure should return invalid object error<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package storage

import (
	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/storage"
)

// InterpretListError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretListError(err error, qualifiedResource unversioned.GroupResource) error {
	switch {
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, "")
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "list", 2) // TODO: make configurable or handled at a higher level
	default:
		return err
	}
}

// InterpretGetError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretGetError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, name)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "get", 2) // TODO: make configurable or handled at a higher level
	default:
		return err
	}
}

// InterpretCreateError converts a generic error on a create
// operation into the appropriate API error.
func InterpretCreateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsNodeExist(err):
		return errors.NewAlreadyExists(qualifiedResource, name)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "create", 2) // TODO: make configurable or handled at a higher level
	default:
		return err
	}
}

// InterpretUpdateError converts a generic error on a update
// operation into the appropriate API error.
func InterpretUpdateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsTestFailed(err), storage.IsNodeExist(err), storage.IsInvalidObj(err):
		return errors.NewConflict(qualifiedResource, name, err)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "update", 2) // TODO: make configurable or handled at a higher level
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, name)
	case storage.IsInternalError(err):
		return errors.NewInternalError(err)
	default:
		return err
	}
}

// InterpretDeleteError converts a generic error on a delete
// operation into the appropriate API error.
func InterpretDeleteError(err error, qualifiedResource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsNotFound(err):
		return errors.NewNotFound(qualifiedResource, name)
	case storage.IsUnreachable(err):
		return errors.NewServerTimeout(qualifiedResource, "delete", 2) // TODO: make configurable or handled at a higher level
	case storage.IsTestFailed(err), storage.IsNodeExist(err), storage.IsInvalidObj(err):
		return errors.NewConflict(qualifiedResource, name, err)
	case storage.IsInternalError(err):
		return errors.NewInternalError(err)
	default:
		return err
	}
}

// InterpretWatchError converts a generic error on a watch
// operation into the appropriate API error.
func InterpretWatchError(err error, resource unversioned.GroupResource, name string) error {
	switch {
	case storage.IsInvalidError(err):
		invalidError, _ := err.(storage.InvalidError)
		return errors.NewInvalid(unversioned.GroupKind{Group: resource.Group, Kind: resource.Resource}, name, invalidError.Errs)
	default:
		return err
	}
}
<|endoftext|>


<commit_before>package kic

import (
	"fmt"
	"strings"
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	typed_core "k8s.io/client-go/kubernetes/typed/core/v1"

	"k8s.io/minikube/pkg/minikube/tunnel"
)

// Tunnel ...
type Tunnel struct {
	sshPort              string
	sshKey               string
	v1Core               typed_core.CoreV1Interface
	LoadBalancerEmulator tunnel.LoadBalancerEmulator
}

// NewTunnel ...
func NewTunnel(sshPort, sshKey string, v1Core typed_core.CoreV1Interface) *Tunnel {
	return &Tunnel{
		sshPort:              sshPort,
		sshKey:               sshKey,
		v1Core:               v1Core,
		LoadBalancerEmulator: tunnel.NewLoadBalancerEmulator(v1Core),
	}
}

// Start ...
func (t *Tunnel) Start() error {
	sshTunnels := make(map[string]*sshTunnel)

	for {
		services, err := t.v1Core.Services("").List(metav1.ListOptions{})
		if err != nil {
			return err
		}

		for _, sshTunnel := range sshTunnels {
			sshTunnel.sigkill = true
		}

		for _, s := range services.Items {
			if s.Spec.Type == v1.ServiceTypeLoadBalancer {
				name := sshTunnelName(s)
				existingSSHTunnel, ok := sshTunnels[name]

				if ok {
					existingSSHTunnel.sigkill = false
					continue
				}

				newSSHTunnel := createSSHTunnel(name, t.sshPort, t.sshKey, s)
				sshTunnels[newSSHTunnel.name] = newSSHTunnel
				_, err := t.LoadBalancerEmulator.PatchServicesIP("127.0.0.1")
				if err != nil {
					fmt.Println(err)
				}
			}
		}

		for _, sshTunnel := range sshTunnels {
			if sshTunnel.sigkill {
				sshTunnel.stop()
				delete(sshTunnels, sshTunnel.name)
			}
		}

		// TODO: which time to use?
		time.Sleep(1 * time.Second)
	}
}

// sshTunnelName creaets a uniq name for the tunnel, using its name/clusterIP/ports.
// This allows a new process to be created if an existing service was changed,
// the new process will support the IP/Ports change ocurred.
func sshTunnelName(service v1.Service) string {
	n := []string{
		service.Name,
		"-",
		service.Spec.ClusterIP,
	}

	for _, port := range service.Spec.Ports {
		n = append(n, fmt.Sprintf("-%d", port.Port))
	}

	return strings.Join(n, "")
}
<commit_msg>Add cleanup to kic tunnel<commit_after>package kic

import (
	"context"
	"fmt"
	"strings"
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	typed_core "k8s.io/client-go/kubernetes/typed/core/v1"

	"k8s.io/minikube/pkg/minikube/tunnel"
)

// Tunnel ...
type Tunnel struct {
	ctx                  context.Context
	sshPort              string
	sshKey               string
	v1Core               typed_core.CoreV1Interface
	LoadBalancerEmulator tunnel.LoadBalancerEmulator
}

// NewTunnel ...
func NewTunnel(ctx context.Context, sshPort, sshKey string, v1Core typed_core.CoreV1Interface) *Tunnel {
	return &Tunnel{
		ctx:                  ctx,
		sshPort:              sshPort,
		sshKey:               sshKey,
		v1Core:               v1Core,
		LoadBalancerEmulator: tunnel.NewLoadBalancerEmulator(v1Core),
	}
}

// Start ...
func (t *Tunnel) Start() error {
	sshTunnels := make(map[string]*sshTunnel)

	for {
		select {
		case <-t.ctx.Done():
			_, err := t.LoadBalancerEmulator.Cleanup()
			if err != nil {
				fmt.Println(err)
			}
			return nil
		default:
		}

		services, err := t.v1Core.Services("").List(metav1.ListOptions{})
		if err != nil {
			return err
		}

		for _, sshTunnel := range sshTunnels {
			sshTunnel.sigkill = true
		}

		for _, s := range services.Items {
			if s.Spec.Type == v1.ServiceTypeLoadBalancer {
				name := sshTunnelName(s)
				existingSSHTunnel, ok := sshTunnels[name]

				if ok {
					existingSSHTunnel.sigkill = false
					continue
				}

				newSSHTunnel := createSSHTunnel(name, t.sshPort, t.sshKey, s)
				sshTunnels[newSSHTunnel.name] = newSSHTunnel

				// PatchServicesIP maybe can receive the svc here, instead of listing inside again
				_, err := t.LoadBalancerEmulator.PatchServicesIP("127.0.0.1")
				if err != nil {
					fmt.Println(err)
				}
			}
		}

		for _, sshTunnel := range sshTunnels {
			if sshTunnel.sigkill {
				sshTunnel.stop()
				delete(sshTunnels, sshTunnel.name)
			}
		}

		// TODO: which time to use?
		time.Sleep(1 * time.Second)
	}
}

// sshTunnelName creaets a uniq name for the tunnel, using its name/clusterIP/ports.
// This allows a new process to be created if an existing service was changed,
// the new process will support the IP/Ports change ocurred.
func sshTunnelName(service v1.Service) string {
	n := []string{
		service.Name,
		"-",
		service.Spec.ClusterIP,
	}

	for _, port := range service.Spec.Ports {
		n = append(n, fmt.Sprintf("-%d", port.Port))
	}

	return strings.Join(n, "")
}
<|endoftext|>


<commit_before>package nndb

import (
	"fmt"
	"strings"
	"testing"
)

var nutrientInput = `~01001~^~203~^0.85^16^0.074^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~204~^81.11^580^0.065^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~205~^0.06^0^^~4~^~NC~^~~^~~^^^^^^^~~^11/1976^
~01001~^~207~^2.11^35^0.054^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~208~^717^0^^~4~^~NC~^~~^~~^^^^^^^~~^08/2010^
~01001~^~221~^0.0^0^^~7~^~~^~~^~~^^^^^^^~~^04/1985^
~01001~^~255~^15.87^522^0.061^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~262~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^02/2001^
~01001~^~263~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^02/2001^
~01001~^~268~^2999^0^^~4~^~NC~^~~^~~^^^^^^^~~^09/2015^
~01001~^~269~^0.06^0^^~4~^~NR~^~~^~~^^^^^^^~~^11/2002^
~01001~^~291~^0.0^0^^~4~^~~^~~^~~^^^^^^^~~^^
~01001~^~301~^24^17^0.789^~1~^~A~^~~^~~^7^19^30^4^22.021^26.496^~2, 3~^11/2002^
~01002~^~208~^555^0^^~4~^~NC~^~~^~~^^^^^^^~~^08/2010^
~01116~^~203~^3.47^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~204~^3.25^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~205~^4.66^0^^~4~^~NC~^~~^~~^^^^^^^~~^11/1976^
~01116~^~207~^0.72^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~208~^61^0^^~4~^~NC~^~~^~~^^^^^^^~~^02/2009^
~01116~^~221~^0.0^0^^~7~^~~^~~^~~^^^^^^^~~^04/1985^
~01116~^~255~^87.90^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~262~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^01/2003^
~01116~^~263~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^01/2003^
~01116~^~268~^257^0^^~4~^~NC~^~~^~~^^^^^^^~~^02/2009^
~01116~^~269~^4.66^0^^~4~^~NR~^~~^~~^^^^^^^~~^01/2003^
~01116~^~291~^0.0^0^^~4~^~~^~~^~~^^^^^^^~~^11/1976^`
var foodInput = "~01116~^~0100~^~Yogurt, plain, whole milk, 8 grams protein per 8 ounce~^~YOGURT,PLN,WHL MILK,8 GRAMS PROT PER 8 OZ~^~~^~~^~Y~^~~^0^~~^6.38^4.27^8.79^3.87"
var foodGroupInput = "~0100~^~Dairy and Egg Products~\n~0200~^~Spices and Herbs~\n"
var weightInput = `~01001~^1^1^~pat (1" sq, 1/3" high)~^5.0^^
~01001~^2^1^~tbsp~^14.2^^
~01001~^3^1^~cup~^227^^
~01001~^4^1^~stick~^113^^
~01002~^1^1^~pat (1" sq, 1/3" high)~^3.8^^
~01002~^2^1^~tbsp~^9.4^^
~01002~^3^1^~cup~^151^^
~01002~^4^1^~stick~^76^^
~01116~^1^4^~oz~^113^^
~01116~^2^1^~cup (not packed)~^226^^`

func TestParseNutrientDescription(t *testing.T) {

	parser, error := NewParser(strings.NewReader(""), strings.NewReader(""), strings.NewReader(nutrientInput), strings.NewReader(""))
	isValidParser(parser, error, t)

	nutrients, error := parser.parseNutrients()
	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if nutrients == nil {
		t.Error(`parse returned nil`)
	}
	if len(nutrients) != 3 {
		t.Errorf(`incorrect number of results %v`, len(nutrients))
	}

	nutrientsShouldMatch(nutrients[1001], Nutrients{Calories: 717, Fiber: 0, Fat: 81.11, Protein: 0.85, Sugar: 0.06}, t)
	nutrientsShouldMatch(nutrients[1002], Nutrients{Calories: 555}, t)
}

func nutrientsShouldMatch(actual Nutrients, expected Nutrients, t *testing.T) {
	if actual.Calories != expected.Calories {
		t.Errorf(`incorrect amount of calories %v when expected %v`, actual.Calories, expected.Calories)
	}
	if actual.Fiber != expected.Fiber {
		t.Errorf(`incorrect amount of fiber %v when expected %v`, actual.Fiber, expected.Fiber)
	}
	if actual.Fat != expected.Fat {
		t.Errorf(`incorrect amount of fat %v when expected %v`, actual.Fat, expected.Fat)
	}
	if actual.Protein != expected.Protein {
		t.Errorf(`incorrect amount of protein %v when expected %v`, actual.Protein, expected.Protein)
	}
	if actual.Sugar != expected.Sugar {
		t.Errorf(`incorrect amount of sugar %v when expected %v`, actual.Sugar, expected.Sugar)
	}
}

func isValidParser(parser Parser, e error, t *testing.T) {
	if e != nil {
		t.Errorf(`newReaderParser returned an error %v`, e)
	}
	if parser == nil {
		t.Error(`newReaderParser returned nil parser`)
	}
}

func TestParse(t *testing.T) {
	parser, error := NewParser(strings.NewReader(foodInput), strings.NewReader(foodGroupInput), strings.NewReader(nutrientInput), strings.NewReader(weightInput))
	isValidParser(parser, error, t)

	food, error := parser.Parse()

	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if food == nil {
		t.Error(`parse returned nil`)
	}
	if food[0].ID != 1116 {
		t.Error(`incorect value for foodGroups[0].ndbNo`)
	}
	if food[0].FoodGroup.ID != 100 {
		t.Error(`incorect food group`)
	}
	if food[0].Nutrients.Calories == 0 {
		t.Error(`Nutrients should be present`)
	}
	if food[0].Name != "Yogurt, plain, whole milk, 8 grams protein per 8 ounce" {
		t.Error(`Incorrect value for name`)
	}
	if len(food[0].Measurements) != 2 {
		t.Error(`Incorrect number of measurements`)
	}

	fmt.Println(food[0])
}

func TestParseFoodGroup(t *testing.T) {
	parser, error := NewParser(strings.NewReader(""), strings.NewReader(foodGroupInput), strings.NewReader(""), strings.NewReader(""))
	isValidParser(parser, error, t)

	groups, error := parser.parseFoodGroups()

	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if groups == nil {
		t.Error(`parse returned nil`)
	}

	if groups[100].ID != 100 {
		t.Error(`incorect value for foodGroups[100].code`)
	}
	if groups[100].Name != "Dairy and Egg Products" {
		t.Error(`incorect value for foodGroups[100].code`)
	}

	if groups[200].ID != 200 {
		t.Error(`incorect value for foodGroups[200].code`)
	}
	if groups[200].Name != "Spices and Herbs" {
		t.Error(`incorect value for foodGroups[200].code`)
	}
}

func TestParseWeight(t *testing.T) {
	parser, error := NewParser(strings.NewReader(""), strings.NewReader(foodGroupInput), strings.NewReader(""), strings.NewReader(weightInput))
	isValidParser(parser, error, t)

	weights, error := parser.parseWeights()

	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if weights == nil {
		t.Errorf(`weights returned nil`)
	}

	if len(weights[1001]) != 4 {
		t.Error(`incorrect number of measurements for weights[1001]`)
	}

	if weights[1001][1].Amount != 1 || weights[1001][1].Unit != "tbsp" || weights[1001][1].Weight != 14.2 {
		t.Errorf("Measurement does not match expected.  1 tbsp : 14.2 expected, saw %v", weights[1001][1])
	}
}

func TestParseWrongFileFormat(t *testing.T) {
	input := "blahblah"
	parser, _ := NewParser(strings.NewReader(input), strings.NewReader(input), strings.NewReader(input), strings.NewReader(input))

	_, error := parser.parseFoodGroups()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}

	_, error = parser.parseNutrients()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}

	_, error = parser.parseWeights()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}

	_, error = parser.Parse()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}
}

func TestParseEmptyDataOK(t *testing.T) {
	input := ""
	parser, _ := NewParser(strings.NewReader(input), strings.NewReader(input), strings.NewReader(input), strings.NewReader(input))

	_, error := parser.parseFoodGroups()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

	_, error = parser.parseNutrients()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

	_, error = parser.parseWeights()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

	_, error = parser.Parse()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

}
<commit_msg>Removing extraneous print.<commit_after>package nndb

import (
	"strings"
	"testing"
)

var nutrientInput = `~01001~^~203~^0.85^16^0.074^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~204~^81.11^580^0.065^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~205~^0.06^0^^~4~^~NC~^~~^~~^^^^^^^~~^11/1976^
~01001~^~207~^2.11^35^0.054^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~208~^717^0^^~4~^~NC~^~~^~~^^^^^^^~~^08/2010^
~01001~^~221~^0.0^0^^~7~^~~^~~^~~^^^^^^^~~^04/1985^
~01001~^~255~^15.87^522^0.061^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01001~^~262~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^02/2001^
~01001~^~263~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^02/2001^
~01001~^~268~^2999^0^^~4~^~NC~^~~^~~^^^^^^^~~^09/2015^
~01001~^~269~^0.06^0^^~4~^~NR~^~~^~~^^^^^^^~~^11/2002^
~01001~^~291~^0.0^0^^~4~^~~^~~^~~^^^^^^^~~^^
~01001~^~301~^24^17^0.789^~1~^~A~^~~^~~^7^19^30^4^22.021^26.496^~2, 3~^11/2002^
~01002~^~208~^555^0^^~4~^~NC~^~~^~~^^^^^^^~~^08/2010^
~01116~^~203~^3.47^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~204~^3.25^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~205~^4.66^0^^~4~^~NC~^~~^~~^^^^^^^~~^11/1976^
~01116~^~207~^0.72^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~208~^61^0^^~4~^~NC~^~~^~~^^^^^^^~~^02/2009^
~01116~^~221~^0.0^0^^~7~^~~^~~^~~^^^^^^^~~^04/1985^
~01116~^~255~^87.90^0^^~1~^~~^~~^~~^^^^^^^~~^11/1976^
~01116~^~262~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^01/2003^
~01116~^~263~^0^0^^~7~^~Z~^~~^~~^^^^^^^~~^01/2003^
~01116~^~268~^257^0^^~4~^~NC~^~~^~~^^^^^^^~~^02/2009^
~01116~^~269~^4.66^0^^~4~^~NR~^~~^~~^^^^^^^~~^01/2003^
~01116~^~291~^0.0^0^^~4~^~~^~~^~~^^^^^^^~~^11/1976^`
var foodInput = "~01116~^~0100~^~Yogurt, plain, whole milk, 8 grams protein per 8 ounce~^~YOGURT,PLN,WHL MILK,8 GRAMS PROT PER 8 OZ~^~~^~~^~Y~^~~^0^~~^6.38^4.27^8.79^3.87"
var foodGroupInput = "~0100~^~Dairy and Egg Products~\n~0200~^~Spices and Herbs~\n"
var weightInput = `~01001~^1^1^~pat (1" sq, 1/3" high)~^5.0^^
~01001~^2^1^~tbsp~^14.2^^
~01001~^3^1^~cup~^227^^
~01001~^4^1^~stick~^113^^
~01002~^1^1^~pat (1" sq, 1/3" high)~^3.8^^
~01002~^2^1^~tbsp~^9.4^^
~01002~^3^1^~cup~^151^^
~01002~^4^1^~stick~^76^^
~01116~^1^4^~oz~^113^^
~01116~^2^1^~cup (not packed)~^226^^`

func TestParseNutrientDescription(t *testing.T) {

	parser, error := NewParser(strings.NewReader(""), strings.NewReader(""), strings.NewReader(nutrientInput), strings.NewReader(""))
	isValidParser(parser, error, t)

	nutrients, error := parser.parseNutrients()
	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if nutrients == nil {
		t.Error(`parse returned nil`)
	}
	if len(nutrients) != 3 {
		t.Errorf(`incorrect number of results %v`, len(nutrients))
	}

	nutrientsShouldMatch(nutrients[1001], Nutrients{Calories: 717, Fiber: 0, Fat: 81.11, Protein: 0.85, Sugar: 0.06}, t)
	nutrientsShouldMatch(nutrients[1002], Nutrients{Calories: 555}, t)
}

func nutrientsShouldMatch(actual Nutrients, expected Nutrients, t *testing.T) {
	if actual.Calories != expected.Calories {
		t.Errorf(`incorrect amount of calories %v when expected %v`, actual.Calories, expected.Calories)
	}
	if actual.Fiber != expected.Fiber {
		t.Errorf(`incorrect amount of fiber %v when expected %v`, actual.Fiber, expected.Fiber)
	}
	if actual.Fat != expected.Fat {
		t.Errorf(`incorrect amount of fat %v when expected %v`, actual.Fat, expected.Fat)
	}
	if actual.Protein != expected.Protein {
		t.Errorf(`incorrect amount of protein %v when expected %v`, actual.Protein, expected.Protein)
	}
	if actual.Sugar != expected.Sugar {
		t.Errorf(`incorrect amount of sugar %v when expected %v`, actual.Sugar, expected.Sugar)
	}
}

func isValidParser(parser Parser, e error, t *testing.T) {
	if e != nil {
		t.Errorf(`newReaderParser returned an error %v`, e)
	}
	if parser == nil {
		t.Error(`newReaderParser returned nil parser`)
	}
}

func TestParse(t *testing.T) {
	parser, error := NewParser(strings.NewReader(foodInput), strings.NewReader(foodGroupInput), strings.NewReader(nutrientInput), strings.NewReader(weightInput))
	isValidParser(parser, error, t)

	food, error := parser.Parse()

	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if food == nil {
		t.Error(`parse returned nil`)
	}
	if food[0].ID != 1116 {
		t.Error(`incorect value for foodGroups[0].ndbNo`)
	}
	if food[0].FoodGroup.ID != 100 {
		t.Error(`incorect food group`)
	}
	if food[0].Nutrients.Calories == 0 {
		t.Error(`Nutrients should be present`)
	}
	if food[0].Name != "Yogurt, plain, whole milk, 8 grams protein per 8 ounce" {
		t.Error(`Incorrect value for name`)
	}
	if len(food[0].Measurements) != 2 {
		t.Error(`Incorrect number of measurements`)
	}
}

func TestParseFoodGroup(t *testing.T) {
	parser, error := NewParser(strings.NewReader(""), strings.NewReader(foodGroupInput), strings.NewReader(""), strings.NewReader(""))
	isValidParser(parser, error, t)

	groups, error := parser.parseFoodGroups()

	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if groups == nil {
		t.Error(`parse returned nil`)
	}

	if groups[100].ID != 100 {
		t.Error(`incorect value for foodGroups[100].code`)
	}
	if groups[100].Name != "Dairy and Egg Products" {
		t.Error(`incorect value for foodGroups[100].code`)
	}

	if groups[200].ID != 200 {
		t.Error(`incorect value for foodGroups[200].code`)
	}
	if groups[200].Name != "Spices and Herbs" {
		t.Error(`incorect value for foodGroups[200].code`)
	}
}

func TestParseWeight(t *testing.T) {
	parser, error := NewParser(strings.NewReader(""), strings.NewReader(foodGroupInput), strings.NewReader(""), strings.NewReader(weightInput))
	isValidParser(parser, error, t)

	weights, error := parser.parseWeights()

	if error != nil {
		t.Errorf(`Parse() returned an error %v`, error)
	}
	if weights == nil {
		t.Errorf(`weights returned nil`)
	}

	if len(weights[1001]) != 4 {
		t.Error(`incorrect number of measurements for weights[1001]`)
	}

	if weights[1001][1].Amount != 1 || weights[1001][1].Unit != "tbsp" || weights[1001][1].Weight != 14.2 {
		t.Errorf("Measurement does not match expected.  1 tbsp : 14.2 expected, saw %v", weights[1001][1])
	}
}

func TestParseWrongFileFormat(t *testing.T) {
	input := "blahblah"
	parser, _ := NewParser(strings.NewReader(input), strings.NewReader(input), strings.NewReader(input), strings.NewReader(input))

	_, error := parser.parseFoodGroups()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}

	_, error = parser.parseNutrients()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}

	_, error = parser.parseWeights()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}

	_, error = parser.Parse()
	if error == nil {
		t.Error(`invalid data should cause error`)
	}
}

func TestParseEmptyDataOK(t *testing.T) {
	input := ""
	parser, _ := NewParser(strings.NewReader(input), strings.NewReader(input), strings.NewReader(input), strings.NewReader(input))

	_, error := parser.parseFoodGroups()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

	_, error = parser.parseNutrients()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

	_, error = parser.parseWeights()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

	_, error = parser.Parse()
	if error != nil {
		t.Error(`empty data should not cause error`)
	}

}
<|endoftext|>