<commit_before>package filesys

import (
	"context"
	"os"
	"sort"
	"time"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/seaweedfs/fuse"
	"github.com/seaweedfs/fuse/fs"
)

const blockSize = 512

var _ = fs.Node(&File{})
var _ = fs.NodeOpener(&File{})
var _ = fs.NodeFsyncer(&File{})
var _ = fs.NodeSetattrer(&File{})
var _ = fs.NodeGetxattrer(&File{})
var _ = fs.NodeSetxattrer(&File{})
var _ = fs.NodeRemovexattrer(&File{})
var _ = fs.NodeListxattrer(&File{})
var _ = fs.NodeForgetter(&File{})

type File struct {
	Name           string
	dir            *Dir
	wfs            *WFS
	entry          *filer_pb.Entry
	entryViewCache []filer2.VisibleInterval
	isOpen         int
}

func (file *File) fullpath() filer2.FullPath {
	return filer2.NewFullPath(file.dir.Path, file.Name)
}

func (file *File) Attr(ctx context.Context, attr *fuse.Attr) error {

	glog.V(4).Infof("file Attr %s, open:%v, existing attr: %+v", file.fullpath(), file.isOpen, attr)

	if file.isOpen <=0 {
		if err := file.maybeLoadEntry(ctx); err != nil {
			return err
		}
	}

	attr.Inode = file.fullpath().AsInode()
	attr.Valid = time.Second
	attr.Mode = os.FileMode(file.entry.Attributes.FileMode)
	attr.Size = filer2.TotalSize(file.entry.Chunks)
	if file.isOpen > 0 {
		attr.Size = file.entry.Attributes.FileSize
	}
	attr.Crtime = time.Unix(file.entry.Attributes.Crtime, 0)
	attr.Mtime = time.Unix(file.entry.Attributes.Mtime, 0)
	attr.Gid = file.entry.Attributes.Gid
	attr.Uid = file.entry.Attributes.Uid
	attr.Blocks = attr.Size/blockSize + 1
	attr.BlockSize = uint32(file.wfs.option.ChunkSizeLimit)

	return nil

}

func (file *File) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error {

	// glog.V(4).Infof("file Getxattr %s", file.fullpath())

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	return getxattr(file.entry, req, resp)
}

func (file *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {

	glog.V(4).Infof("file %v open %+v", file.fullpath(), req)

	file.isOpen++

	handle := file.wfs.AcquireHandle(file, req.Uid, req.Gid)

	resp.Handle = fuse.HandleID(handle.handle)

	glog.V(3).Infof("%v file open handle id = %d", file.fullpath(), handle.handle)

	return handle, nil

}

func (file *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {

	glog.V(3).Infof("%v file setattr %+v, old:%+v", file.fullpath(), req, file.entry.Attributes)

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if req.Valid.Size() {

		glog.V(3).Infof("%v file setattr set size=%v", file.fullpath(), req.Size)
		if req.Size < filer2.TotalSize(file.entry.Chunks) {
			// fmt.Printf("truncate %v \n", fullPath)
			var chunks []*filer_pb.FileChunk
			for _, chunk := range file.entry.Chunks {
				if uint64(chunk.Offset)+chunk.Size > req.Size {
					chunk.Size = req.Size - uint64(chunk.Offset)
				}
				if chunk.Size > 0 {
					chunks = append(chunks, chunk)
				}
			}
			file.entry.Chunks = chunks
			file.entryViewCache = nil
		}
		file.entry.Attributes.FileSize = req.Size
	}
	if req.Valid.Mode() {
		file.entry.Attributes.FileMode = uint32(req.Mode)
	}

	if req.Valid.Uid() {
		file.entry.Attributes.Uid = req.Uid
	}

	if req.Valid.Gid() {
		file.entry.Attributes.Gid = req.Gid
	}

	if req.Valid.Crtime() {
		file.entry.Attributes.Crtime = req.Crtime.Unix()
	}

	if req.Valid.Mtime() {
		file.entry.Attributes.Mtime = req.Mtime.Unix()
	}

	if file.isOpen > 0 {
		return nil
	}

	file.wfs.cacheDelete(file.fullpath())

	return file.saveEntry(ctx)

}

func (file *File) Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error {

	glog.V(4).Infof("file Setxattr %s: %s", file.fullpath(), req.Name)

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if err := setxattr(file.entry, req); err != nil {
		return err
	}

	file.wfs.cacheDelete(file.fullpath())

	return file.saveEntry(ctx)

}

func (file *File) Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error {

	glog.V(4).Infof("file Removexattr %s: %s", file.fullpath(), req.Name)

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if err := removexattr(file.entry, req); err != nil {
		return err
	}

	file.wfs.cacheDelete(file.fullpath())

	return file.saveEntry(ctx)

}

func (file *File) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error {

	glog.V(4).Infof("file Listxattr %s", file.fullpath())

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if err := listxattr(file.entry, req, resp); err != nil {
		return err
	}

	return nil

}

func (file *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
	// fsync works at OS level
	// write the file chunks to the filerGrpcAddress
	glog.V(3).Infof("%s/%s fsync file %+v", file.dir.Path, file.Name, req)

	return nil
}

func (file *File) Forget() {
	glog.V(3).Infof("Forget file %s/%s", file.dir.Path, file.Name)

	file.wfs.forgetNode(filer2.NewFullPath(file.dir.Path, file.Name))

}

func (file *File) maybeLoadEntry(ctx context.Context) error {
	if file.entry == nil || file.isOpen <= 0{
		entry, err := file.wfs.maybeLoadEntry(ctx, file.dir.Path, file.Name)
		if err != nil {
			return err
		}
		if entry != nil {
			file.setEntry(entry)
		}
	}
	return nil
}

func (file *File) addChunks(chunks []*filer_pb.FileChunk) {

	sort.Slice(chunks, func(i, j int) bool {
		return chunks[i].Mtime < chunks[j].Mtime
	})

	var newVisibles []filer2.VisibleInterval
	for _, chunk := range chunks {
		newVisibles = filer2.MergeIntoVisibles(file.entryViewCache, newVisibles, chunk)
		t := file.entryViewCache[:0]
		file.entryViewCache = newVisibles
		newVisibles = t
	}

	glog.V(3).Infof("%s existing %d chunks adds %d more", file.fullpath(), len(file.entry.Chunks), len(chunks))

	file.entry.Chunks = append(file.entry.Chunks, chunks...)
}

func (file *File) setEntry(entry *filer_pb.Entry) {
	file.entry = entry
	file.entryViewCache = filer2.NonOverlappingVisibleIntervals(file.entry.Chunks)
}

func (file *File) saveEntry(ctx context.Context) error {
	return file.wfs.WithFilerClient(ctx, func(client filer_pb.SeaweedFilerClient) error {

		request := &filer_pb.UpdateEntryRequest{
			Directory: file.dir.Path,
			Entry:     file.entry,
		}

		glog.V(1).Infof("save file entry: %v", request)
		_, err := client.UpdateEntry(ctx, request)
		if err != nil {
			glog.V(0).Infof("UpdateEntry file %s/%s: %v", file.dir.Path, file.Name, err)
			return fuse.EIO
		}

		return nil
	})
}
<commit_msg>mount: avoid use uint64 for greater than zero test<commit_after>package filesys

import (
	"context"
	"os"
	"sort"
	"time"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/seaweedfs/fuse"
	"github.com/seaweedfs/fuse/fs"
)

const blockSize = 512

var _ = fs.Node(&File{})
var _ = fs.NodeOpener(&File{})
var _ = fs.NodeFsyncer(&File{})
var _ = fs.NodeSetattrer(&File{})
var _ = fs.NodeGetxattrer(&File{})
var _ = fs.NodeSetxattrer(&File{})
var _ = fs.NodeRemovexattrer(&File{})
var _ = fs.NodeListxattrer(&File{})
var _ = fs.NodeForgetter(&File{})

type File struct {
	Name           string
	dir            *Dir
	wfs            *WFS
	entry          *filer_pb.Entry
	entryViewCache []filer2.VisibleInterval
	isOpen         int
}

func (file *File) fullpath() filer2.FullPath {
	return filer2.NewFullPath(file.dir.Path, file.Name)
}

func (file *File) Attr(ctx context.Context, attr *fuse.Attr) error {

	glog.V(4).Infof("file Attr %s, open:%v, existing attr: %+v", file.fullpath(), file.isOpen, attr)

	if file.isOpen <= 0 {
		if err := file.maybeLoadEntry(ctx); err != nil {
			return err
		}
	}

	attr.Inode = file.fullpath().AsInode()
	attr.Valid = time.Second
	attr.Mode = os.FileMode(file.entry.Attributes.FileMode)
	attr.Size = filer2.TotalSize(file.entry.Chunks)
	if file.isOpen > 0 {
		attr.Size = file.entry.Attributes.FileSize
	}
	attr.Crtime = time.Unix(file.entry.Attributes.Crtime, 0)
	attr.Mtime = time.Unix(file.entry.Attributes.Mtime, 0)
	attr.Gid = file.entry.Attributes.Gid
	attr.Uid = file.entry.Attributes.Uid
	attr.Blocks = attr.Size/blockSize + 1
	attr.BlockSize = uint32(file.wfs.option.ChunkSizeLimit)

	return nil

}

func (file *File) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error {

	// glog.V(4).Infof("file Getxattr %s", file.fullpath())

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	return getxattr(file.entry, req, resp)
}

func (file *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {

	glog.V(4).Infof("file %v open %+v", file.fullpath(), req)

	file.isOpen++

	handle := file.wfs.AcquireHandle(file, req.Uid, req.Gid)

	resp.Handle = fuse.HandleID(handle.handle)

	glog.V(3).Infof("%v file open handle id = %d", file.fullpath(), handle.handle)

	return handle, nil

}

func (file *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {

	glog.V(3).Infof("%v file setattr %+v, old:%+v", file.fullpath(), req, file.entry.Attributes)

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if req.Valid.Size() {

		glog.V(3).Infof("%v file setattr set size=%v", file.fullpath(), req.Size)
		if req.Size < filer2.TotalSize(file.entry.Chunks) {
			// fmt.Printf("truncate %v \n", fullPath)
			var chunks []*filer_pb.FileChunk
			for _, chunk := range file.entry.Chunks {
				int64Size := int64(chunk.Size)
				if chunk.Offset+int64Size > int64(req.Size) {
					int64Size = int64(req.Size) - chunk.Offset
				}
				if int64Size > 0 {
					chunks = append(chunks, chunk)
				}
			}
			file.entry.Chunks = chunks
			file.entryViewCache = nil
		}
		file.entry.Attributes.FileSize = req.Size
	}
	if req.Valid.Mode() {
		file.entry.Attributes.FileMode = uint32(req.Mode)
	}

	if req.Valid.Uid() {
		file.entry.Attributes.Uid = req.Uid
	}

	if req.Valid.Gid() {
		file.entry.Attributes.Gid = req.Gid
	}

	if req.Valid.Crtime() {
		file.entry.Attributes.Crtime = req.Crtime.Unix()
	}

	if req.Valid.Mtime() {
		file.entry.Attributes.Mtime = req.Mtime.Unix()
	}

	if file.isOpen > 0 {
		return nil
	}

	file.wfs.cacheDelete(file.fullpath())

	return file.saveEntry(ctx)

}

func (file *File) Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error {

	glog.V(4).Infof("file Setxattr %s: %s", file.fullpath(), req.Name)

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if err := setxattr(file.entry, req); err != nil {
		return err
	}

	file.wfs.cacheDelete(file.fullpath())

	return file.saveEntry(ctx)

}

func (file *File) Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error {

	glog.V(4).Infof("file Removexattr %s: %s", file.fullpath(), req.Name)

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if err := removexattr(file.entry, req); err != nil {
		return err
	}

	file.wfs.cacheDelete(file.fullpath())

	return file.saveEntry(ctx)

}

func (file *File) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error {

	glog.V(4).Infof("file Listxattr %s", file.fullpath())

	if err := file.maybeLoadEntry(ctx); err != nil {
		return err
	}

	if err := listxattr(file.entry, req, resp); err != nil {
		return err
	}

	return nil

}

func (file *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
	// fsync works at OS level
	// write the file chunks to the filerGrpcAddress
	glog.V(3).Infof("%s/%s fsync file %+v", file.dir.Path, file.Name, req)

	return nil
}

func (file *File) Forget() {
	glog.V(3).Infof("Forget file %s/%s", file.dir.Path, file.Name)

	file.wfs.forgetNode(filer2.NewFullPath(file.dir.Path, file.Name))

}

func (file *File) maybeLoadEntry(ctx context.Context) error {
	if file.entry == nil || file.isOpen <= 0 {
		entry, err := file.wfs.maybeLoadEntry(ctx, file.dir.Path, file.Name)
		if err != nil {
			return err
		}
		if entry != nil {
			file.setEntry(entry)
		}
	}
	return nil
}

func (file *File) addChunks(chunks []*filer_pb.FileChunk) {

	sort.Slice(chunks, func(i, j int) bool {
		return chunks[i].Mtime < chunks[j].Mtime
	})

	var newVisibles []filer2.VisibleInterval
	for _, chunk := range chunks {
		newVisibles = filer2.MergeIntoVisibles(file.entryViewCache, newVisibles, chunk)
		t := file.entryViewCache[:0]
		file.entryViewCache = newVisibles
		newVisibles = t
	}

	glog.V(3).Infof("%s existing %d chunks adds %d more", file.fullpath(), len(file.entry.Chunks), len(chunks))

	file.entry.Chunks = append(file.entry.Chunks, chunks...)
}

func (file *File) setEntry(entry *filer_pb.Entry) {
	file.entry = entry
	file.entryViewCache = filer2.NonOverlappingVisibleIntervals(file.entry.Chunks)
}

func (file *File) saveEntry(ctx context.Context) error {
	return file.wfs.WithFilerClient(ctx, func(client filer_pb.SeaweedFilerClient) error {

		request := &filer_pb.UpdateEntryRequest{
			Directory: file.dir.Path,
			Entry:     file.entry,
		}

		glog.V(1).Infof("save file entry: %v", request)
		_, err := client.UpdateEntry(ctx, request)
		if err != nil {
			glog.V(0).Infof("UpdateEntry file %s/%s: %v", file.dir.Path, file.Name, err)
			return fuse.EIO
		}

		return nil
	})
}
<|endoftext|>


<commit_before>package gitea

import (
	"io"
	"net/http"

	"github.com/drone/drone/model"
)

const (
	hookEvent       = "X-Gogs-Event"
	hookPush        = "push"
	hookCreated     = "create"
	hookPullRequest = "pull_request"

	actionOpen = "opened"
	actionSync = "synchronize"

	stateOpen = "open"

	refBranch = "branch"
	refTag    = "tag"
)

// parseHook parses a Gitea hook from an http.Request request and returns
// Repo and Build detail. If a hook type is unsupported nil values are returned.
func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
	switch r.Header.Get(hookEvent) {
	case hookPush:
		return parsePushHook(r.Body)
	case hookCreated:
		return parseCreatedHook(r.Body)
	case hookPullRequest:
		return parsePullRequestHook(r.Body)
	}
	return nil, nil, nil
}

// parsePushHook parses a push hook and returns the Repo and Build details.
// If the commit type is unsupported nil values are returned.
func parsePushHook(payload io.Reader) (*model.Repo, *model.Build, error) {
	var (
		repo  *model.Repo
		build *model.Build
	)

	push, err := parsePush(payload)
	if err != nil {
		return nil, nil, err
	}

	// is this even needed?
	if push.RefType == refBranch {
		return nil, nil, nil
	}

	repo = repoFromPush(push)
	build = buildFromPush(push)
	return repo, build, err
}

// parseCreatedHook parses a push hook and returns the Repo and Build details.
// If the commit type is unsupported nil values are returned.
func parseCreatedHook(payload io.Reader) (*model.Repo, *model.Build, error) {
	var (
		repo  *model.Repo
		build *model.Build
	)

	push, err := parsePush(payload)
	if err != nil {
		return nil, nil, err
	}

	if push.RefType != refTag {
		return nil, nil, nil
	}

	repo = repoFromPush(push)
	build = buildFromTag(push)
	return repo, build, err
}

// parsePullRequestHook parses a pull_request hook and returns the Repo and Build details.
func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Build, error) {
	var (
		repo  *model.Repo
		build *model.Build
	)

	pr, err := parsePullRequest(payload)
	if err != nil {
		return nil, nil, err
	}

	// Don't trigger builds for non-code changes, or if PR is not open
	if pr.Action != actionOpen && pr.Action != actionSync {
		return nil, nil, nil
	}
	if pr.PullRequest.State != stateOpen {
		return nil, nil, nil
	}

	repo = repoFromPullRequest(pr)
	build = buildFromPullRequest(pr)
	return repo, build, err
}
<commit_msg>update hook event<commit_after>package gitea

import (
	"io"
	"net/http"

	"github.com/drone/drone/model"
)

const (
	hookEvent       = "X-Gitea-Event"
	hookPush        = "push"
	hookCreated     = "create"
	hookPullRequest = "pull_request"

	actionOpen = "opened"
	actionSync = "synchronize"

	stateOpen = "open"

	refBranch = "branch"
	refTag    = "tag"
)

// parseHook parses a Gitea hook from an http.Request request and returns
// Repo and Build detail. If a hook type is unsupported nil values are returned.
func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
	switch r.Header.Get(hookEvent) {
	case hookPush:
		return parsePushHook(r.Body)
	case hookCreated:
		return parseCreatedHook(r.Body)
	case hookPullRequest:
		return parsePullRequestHook(r.Body)
	}
	return nil, nil, nil
}

// parsePushHook parses a push hook and returns the Repo and Build details.
// If the commit type is unsupported nil values are returned.
func parsePushHook(payload io.Reader) (*model.Repo, *model.Build, error) {
	var (
		repo  *model.Repo
		build *model.Build
	)

	push, err := parsePush(payload)
	if err != nil {
		return nil, nil, err
	}

	// is this even needed?
	if push.RefType == refBranch {
		return nil, nil, nil
	}

	repo = repoFromPush(push)
	build = buildFromPush(push)
	return repo, build, err
}

// parseCreatedHook parses a push hook and returns the Repo and Build details.
// If the commit type is unsupported nil values are returned.
func parseCreatedHook(payload io.Reader) (*model.Repo, *model.Build, error) {
	var (
		repo  *model.Repo
		build *model.Build
	)

	push, err := parsePush(payload)
	if err != nil {
		return nil, nil, err
	}

	if push.RefType != refTag {
		return nil, nil, nil
	}

	repo = repoFromPush(push)
	build = buildFromTag(push)
	return repo, build, err
}

// parsePullRequestHook parses a pull_request hook and returns the Repo and Build details.
func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Build, error) {
	var (
		repo  *model.Repo
		build *model.Build
	)

	pr, err := parsePullRequest(payload)
	if err != nil {
		return nil, nil, err
	}

	// Don't trigger builds for non-code changes, or if PR is not open
	if pr.Action != actionOpen && pr.Action != actionSync {
		return nil, nil, nil
	}
	if pr.PullRequest.State != stateOpen {
		return nil, nil, nil
	}

	repo = repoFromPullRequest(pr)
	build = buildFromPullRequest(pr)
	return repo, build, err
}
<|endoftext|>


<commit_before>package testflight_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("A job with nested volume mounts", func() {
	BeforeEach(func() {
		setAndUnpausePipeline("fixtures/volume-mounting.yml")
	})

	It("procceds through the plan with input under output mounts", func() {
		watch := fly("trigger-job", "-j", inPipeline("input-under-output"), "-w")
		Expect(watch).To(gexec.Exit(0))
		Expect(watch).To(gbytes.Say("some-resource"))
	})

	It("procceds through the plan with input under input mounts", func() {
		sess := fly("trigger-job", "-j", inPipeline("input-under-input"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("helloworld"))
	})

	It("procceds through the plan having output being mapped to dot and input within", func() {
		sess := fly("trigger-job", "-j", inPipeline("output-with-dot-with-input-within"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("bar"))
	})

	It("procceds through the plan with output under input mounts", func() {
		sess := fly("trigger-job", "-j", inPipeline("output-under-input"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("hello"))
	})

	It("procceds through the plan with input same as output mounts", func() {
		sess := fly("trigger-job", "-j", inPipeline("input-same-output"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("hello"))
	})

	It("procceds through the plan with input and output having the same path but a different name", func() {
		sess := fly("trigger-job", "-j", inPipeline("input-output-same-path-diff-name"), "-w")
		Expect(sess).To(gexec.Exit(0))
	})
})
<commit_msg>Revert "Revert "tf: temporary pend failing testflight test""<commit_after>package testflight_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("A job with nested volume mounts", func() {
	BeforeEach(func() {
		setAndUnpausePipeline("fixtures/volume-mounting.yml")
	})

	It("procceds through the plan with input under output mounts", func() {
		watch := fly("trigger-job", "-j", inPipeline("input-under-output"), "-w")
		Expect(watch).To(gexec.Exit(0))
		Expect(watch).To(gbytes.Say("some-resource"))
	})

	It("procceds through the plan with input under input mounts", func() {
		sess := fly("trigger-job", "-j", inPipeline("input-under-input"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("helloworld"))
	})

	It("procceds through the plan having output being mapped to dot and input within", func() {
		sess := fly("trigger-job", "-j", inPipeline("output-with-dot-with-input-within"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("bar"))
	})

	It("procceds through the plan with output under input mounts", func() {
		sess := fly("trigger-job", "-j", inPipeline("output-under-input"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("hello"))
	})

	// Pending this test for now, @cirocosta will be looking into it
	XIt("procceds through the plan with input same as output mounts", func() {
		sess := fly("trigger-job", "-j", inPipeline("input-same-output"), "-w")
		Expect(sess).To(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("hello"))
	})

	It("procceds through the plan with input and output having the same path but a different name", func() {
		sess := fly("trigger-job", "-j", inPipeline("input-output-same-path-diff-name"), "-w")
		Expect(sess).To(gexec.Exit(0))
	})
})
<|endoftext|>


<commit_before>package report_test

import (
	"reflect"
	"testing"
	"time"

	"github.com/weaveworks/common/mtime"
	"github.com/weaveworks/common/test"
	"github.com/weaveworks/scope/report"
	s_reflect "github.com/weaveworks/scope/test/reflect"
)

func newu64(value uint64) *uint64 { return &value }

// Make sure we don't add a topology and miss it in the Topologies method.
func TestReportTopologies(t *testing.T) {
	var (
		reportType   = reflect.TypeOf(report.MakeReport())
		topologyType = reflect.TypeOf(report.MakeTopology())
	)

	var want, have int
	for i := 0; i < reportType.NumField(); i++ {
		if reportType.Field(i).Type == topologyType {
			want++
		}
	}

	r := report.MakeReport()
	r.WalkTopologies(func(_ *report.Topology) {
		have++
	})
	if want != have {
		t.Errorf("want %d, have %d", want, have)
	}
}

func TestReportTopology(t *testing.T) {
	r := report.MakeReport()
	if _, ok := r.Topology(report.Container); !ok {
		t.Errorf("Expected %s topology to be found", report.Container)
	}
	if _, ok := r.Topology("foo"); ok {
		t.Errorf("Expected %s topology not to be found", "foo")
	}
}

func TestNode(t *testing.T) {
	{
		node := report.MakeNodeWith("foo", map[string]string{
			"foo": "bar",
		})

		if v, _ := node.Latest.Lookup("foo"); v != "bar" {
			t.Errorf("want foo, have %s", v)
		}
	}
	{
		node := report.MakeNode("foo").WithCounters(
			map[string]int{"foo": 1},
		)
		if value, _ := node.Counters.Lookup("foo"); value != 1 {
			t.Errorf("want foo, have %d", value)
		}
	}
	{
		node := report.MakeNode("foo").WithAdjacent("foo")
		if node.Adjacency[0] != "foo" {
			t.Errorf("want foo, have %v", node.Adjacency)
		}
	}
}

func TestReportUpgrade(t *testing.T) {
	mtime.NowForce(time.Now())
	defer mtime.NowReset()
	parentsWithDeployment := report.MakeSets().Add(report.Deployment, report.MakeStringSet("id"))
	rsNode := report.MakeNode("bar").
		WithParents(parentsWithDeployment)
	namespaceName := "ns"
	namespaceID := report.MakeNamespaceNodeID(namespaceName)
	podNode := report.MakeNode("foo").
		WithLatests(map[string]string{report.KubernetesNamespace: namespaceName}).
		WithParents(report.MakeSets().Add(report.ReplicaSet, report.MakeStringSet("bar")))
	expectedPodNode := podNode.PruneParents().WithParents(parentsWithDeployment)
	rpt := report.MakeReport()
	rpt.ReplicaSet.AddNode(rsNode)
	rpt.Pod.AddNode(podNode)
	namespaceNode := report.MakeNode(namespaceID).
		WithLatests(map[string]string{report.KubernetesName: namespaceName})
	expected := report.MakeReport()
	expected.ReplicaSet.AddNode(rsNode)
	expected.Pod.AddNode(expectedPodNode)
	expected.Namespace.AddNode(namespaceNode)
	got := rpt.Upgrade()
	if !s_reflect.DeepEqual(expected, got) {
		t.Error(test.Diff(expected, got))
	}
}
<commit_msg>test: add TestReportUnMerge()<commit_after>package report_test

import (
	"reflect"
	"testing"
	"time"

	"github.com/weaveworks/common/mtime"
	"github.com/weaveworks/common/test"
	"github.com/weaveworks/scope/report"
	s_reflect "github.com/weaveworks/scope/test/reflect"
)

func newu64(value uint64) *uint64 { return &value }

// Make sure we don't add a topology and miss it in the Topologies method.
func TestReportTopologies(t *testing.T) {
	var (
		reportType   = reflect.TypeOf(report.MakeReport())
		topologyType = reflect.TypeOf(report.MakeTopology())
	)

	var want, have int
	for i := 0; i < reportType.NumField(); i++ {
		if reportType.Field(i).Type == topologyType {
			want++
		}
	}

	r := report.MakeReport()
	r.WalkTopologies(func(_ *report.Topology) {
		have++
	})
	if want != have {
		t.Errorf("want %d, have %d", want, have)
	}
}

func TestReportTopology(t *testing.T) {
	r := report.MakeReport()
	if _, ok := r.Topology(report.Container); !ok {
		t.Errorf("Expected %s topology to be found", report.Container)
	}
	if _, ok := r.Topology("foo"); ok {
		t.Errorf("Expected %s topology not to be found", "foo")
	}
}

func TestNode(t *testing.T) {
	{
		node := report.MakeNodeWith("foo", map[string]string{
			"foo": "bar",
		})

		if v, _ := node.Latest.Lookup("foo"); v != "bar" {
			t.Errorf("want foo, have %s", v)
		}
	}
	{
		node := report.MakeNode("foo").WithCounters(
			map[string]int{"foo": 1},
		)
		if value, _ := node.Counters.Lookup("foo"); value != 1 {
			t.Errorf("want foo, have %d", value)
		}
	}
	{
		node := report.MakeNode("foo").WithAdjacent("foo")
		if node.Adjacency[0] != "foo" {
			t.Errorf("want foo, have %v", node.Adjacency)
		}
	}
}

func TestReportUpgrade(t *testing.T) {
	mtime.NowForce(time.Now())
	defer mtime.NowReset()
	parentsWithDeployment := report.MakeSets().Add(report.Deployment, report.MakeStringSet("id"))
	rsNode := report.MakeNode("bar").
		WithParents(parentsWithDeployment)
	namespaceName := "ns"
	namespaceID := report.MakeNamespaceNodeID(namespaceName)
	podNode := report.MakeNode("foo").
		WithLatests(map[string]string{report.KubernetesNamespace: namespaceName}).
		WithParents(report.MakeSets().Add(report.ReplicaSet, report.MakeStringSet("bar")))
	expectedPodNode := podNode.PruneParents().WithParents(parentsWithDeployment)
	rpt := report.MakeReport()
	rpt.ReplicaSet.AddNode(rsNode)
	rpt.Pod.AddNode(podNode)
	namespaceNode := report.MakeNode(namespaceID).
		WithLatests(map[string]string{report.KubernetesName: namespaceName})
	expected := report.MakeReport()
	expected.ReplicaSet.AddNode(rsNode)
	expected.Pod.AddNode(expectedPodNode)
	expected.Namespace.AddNode(namespaceNode)
	got := rpt.Upgrade()
	if !s_reflect.DeepEqual(expected, got) {
		t.Error(test.Diff(expected, got))
	}
}

func TestReportUnMerge(t *testing.T) {
	n1 := report.MakeNodeWith("foo", map[string]string{"foo": "bar"})
	r1 := makeTestReport()
	r2 := r1.Copy()
	r2.Container.AddNode(n1)
	// r2 should be the same as r1 with just the foo-bar node added
	r2.UnsafeUnMerge(r1)
	// Now r2 should have everything removed except that one node, and its ID
	expected := report.Report{
		ID: r2.ID,
		Container: report.Topology{
			Nodes: report.Nodes{
				"foo": n1,
			},
		},
	}

	// Now test report with two nodes unmerged on report with one
	r1.Container.AddNode(n1)
	r2 = r1.Copy()
	n2 := report.MakeNodeWith("foo2", map[string]string{"ping": "pong"})
	r2.Container.AddNode(n2)
	// r2 should be the same as r1 with one extra node
	r2.UnsafeUnMerge(r1)
	expected = report.Report{
		ID: r2.ID,
		Container: report.Topology{
			Nodes: report.Nodes{
				"foo2": n2,
			},
		},
	}

	if !s_reflect.DeepEqual(expected, r2) {
		t.Error(test.Diff(expected, r2))
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.

package alto

import (
	"bytes"
	"encoding/json"
	"net"
	"os"
	"reflect"
	"testing"
)

func TestDecodeEncodeEndpointAddrGroup(t *testing.T) {
	f, err := os.Open("testdata/endpointaddrgroup.js")
	if err != nil {
		t.Fatalf("os.Open failed: %v", err)
	}
	eag := make(EndpointAddrGroup)
	if err := json.NewDecoder(f).Decode(&eag); err != nil {
		t.Fatalf("json.Decoder.Decode failed: %v", err)
	}
	var dst bytes.Buffer
	if err := json.NewEncoder(&dst).Encode(&eag); err != nil {
		t.Fatalf("json.Encoder.Encode failed: %v", err)
	}
}

var parseIPEndpointTests = []struct {
	net       string
	in        string
	ip        net.IP
	prefixLen int
}{
	{"ipv4", "172.16.254.191", net.ParseIP("172.16.254.191"), 32},
	{"ipv4", "172.16.254.192/32", net.ParseIP("172.16.254.192"), 32},
	{"ipv4", "ipv4:172.16.254.193", net.ParseIP("172.16.254.193"), 32},
	{"ipv4", "172.16.254.194/24", net.ParseIP("172.16.254.0"), 24},
	{"ipv4", "ipv4:172.16.254.195/24", net.ParseIP("172.16.254.0"), 24},
	{"ipv4", "ipv4:172.16.254.0/24", net.ParseIP("172.16.254.0"), 24},

	{"ipv6", "2001:abcd::191", net.ParseIP("2001:abcd::191"), 128},
	{"ipv6", "2001:abcd::192/128", net.ParseIP("2001:abcd::192"), 128},
	{"ipv6", "ipv6:2001:abcd::193/128", net.ParseIP("2001:abcd::193"), 128},
	{"ipv6", "2001:abcd::194/29", net.ParseIP("2001:abc8::"), 29},
	{"ipv6", "ipv6:2001:abcd::195/29", net.ParseIP("2001:abc8::"), 29},
	{"ipv6", "ipv6:2001:abcd::/29", net.ParseIP("2001:abc8::"), 29},
}

func TestParseIPEndpoint(t *testing.T) {
	for _, tt := range parseIPEndpointTests {
		ep, err := ParseEndpoint(tt.net, tt.in)
		if err != nil {
			t.Fatalf("ParseEndpoint(%q, %q) failed: %v", tt.net, tt.in, err)
		}
		switch ep := ep.(type) {
		case *IPEndpoint:
			if !ep.IP.Addr().Equal(tt.ip) || ep.IP.Len() != tt.prefixLen {
				t.Fatalf("got %v; expected %v/%v", ep, tt.ip, tt.prefixLen)
			}
		default:
			t.Fatal("got unknown endpoint %v", ep)
		}
	}
}

var parseMACEndpointTests = []struct {
	net string
	in  string
	out Endpoint
}{
	{"mac-48", "01:23:45:67:89:ab", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}},
	{"mac-48", "mac-48:01:23:45:67:89:ab", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}},

	{"mac-64", "01:23:45:67:89:ab:cd:ef", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}},
	{"mac-64", "mac-64:01:23:45:67:89:ab:cd:ef", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}},
}

func TestParseMACEndpoint(t *testing.T) {
	for _, tt := range parseMACEndpointTests {
		ep, err := ParseEndpoint(tt.net, tt.in)
		if err != nil {
			t.Fatalf("ParseEndpoint(%q, %q) failed: %v", tt.net, tt.in, err)
		}
		switch ep := ep.(type) {
		case MACEndpoint:
			if !reflect.DeepEqual(ep, tt.out) {
				t.Fatalf("got %v; expected %v", ep, tt.out)
			}
		default:
			t.Fatal("got unknown endpoint %v", ep)
		}
	}
}
<commit_msg>alto: fix some bugs found by go tool in test cases<commit_after>// Copyright 2013 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.

package alto

import (
	"bytes"
	"encoding/json"
	"net"
	"os"
	"reflect"
	"testing"
)

func TestDecodeEncodeEndpointAddrGroup(t *testing.T) {
	f, err := os.Open("testdata/endpointaddrgroup.js")
	if err != nil {
		t.Fatalf("os.Open failed: %v", err)
	}
	eag := make(EndpointAddrGroup)
	if err := json.NewDecoder(f).Decode(&eag); err != nil {
		t.Fatalf("json.Decoder.Decode failed: %v", err)
	}
	var dst bytes.Buffer
	if err := json.NewEncoder(&dst).Encode(&eag); err != nil {
		t.Fatalf("json.Encoder.Encode failed: %v", err)
	}
}

var parseIPEndpointTests = []struct {
	net       string
	in        string
	ip        net.IP
	prefixLen int
}{
	{"ipv4", "172.16.254.191", net.ParseIP("172.16.254.191"), 32},
	{"ipv4", "172.16.254.192/32", net.ParseIP("172.16.254.192"), 32},
	{"ipv4", "ipv4:172.16.254.193", net.ParseIP("172.16.254.193"), 32},
	{"ipv4", "172.16.254.194/24", net.ParseIP("172.16.254.0"), 24},
	{"ipv4", "ipv4:172.16.254.195/24", net.ParseIP("172.16.254.0"), 24},
	{"ipv4", "ipv4:172.16.254.0/24", net.ParseIP("172.16.254.0"), 24},

	{"ipv6", "2001:abcd::191", net.ParseIP("2001:abcd::191"), 128},
	{"ipv6", "2001:abcd::192/128", net.ParseIP("2001:abcd::192"), 128},
	{"ipv6", "ipv6:2001:abcd::193/128", net.ParseIP("2001:abcd::193"), 128},
	{"ipv6", "2001:abcd::194/29", net.ParseIP("2001:abc8::"), 29},
	{"ipv6", "ipv6:2001:abcd::195/29", net.ParseIP("2001:abc8::"), 29},
	{"ipv6", "ipv6:2001:abcd::/29", net.ParseIP("2001:abc8::"), 29},
}

func TestParseIPEndpoint(t *testing.T) {
	for _, tt := range parseIPEndpointTests {
		ep, err := ParseEndpoint(tt.net, tt.in)
		if err != nil {
			t.Fatalf("ParseEndpoint(%q, %q) failed: %v", tt.net, tt.in, err)
		}
		switch ep := ep.(type) {
		case *IPEndpoint:
			if !ep.IP.Addr().Equal(tt.ip) || ep.IP.Len() != tt.prefixLen {
				t.Fatalf("got %v; expected %v/%v", ep, tt.ip, tt.prefixLen)
			}
		default:
			t.Fatalf("got unknown endpoint %v", ep)
		}
	}
}

var parseMACEndpointTests = []struct {
	net string
	in  string
	out Endpoint
}{
	{"mac-48", "01:23:45:67:89:ab", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}},
	{"mac-48", "mac-48:01:23:45:67:89:ab", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}},

	{"mac-64", "01:23:45:67:89:ab:cd:ef", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}},
	{"mac-64", "mac-64:01:23:45:67:89:ab:cd:ef", MACEndpoint{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}},
}

func TestParseMACEndpoint(t *testing.T) {
	for _, tt := range parseMACEndpointTests {
		ep, err := ParseEndpoint(tt.net, tt.in)
		if err != nil {
			t.Fatalf("ParseEndpoint(%q, %q) failed: %v", tt.net, tt.in, err)
		}
		switch ep := ep.(type) {
		case MACEndpoint:
			if !reflect.DeepEqual(ep, tt.out) {
				t.Fatalf("got %v; expected %v", ep, tt.out)
			}
		default:
			t.Fatalf("got unknown endpoint %v", ep)
		}
	}
}
<|endoftext|>


<commit_before>// +build !v2

// Package provides a plugin based pipeline engine that decouples Input/Filter/Output plugins.
package engine

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/funkygao/gafka/telemetry"
	"github.com/funkygao/gafka/telemetry/influxdb"
	"github.com/funkygao/go-metrics"
	"github.com/funkygao/golib/observer"
	conf "github.com/funkygao/jsconf"
	log "github.com/funkygao/log4go"
	"github.com/gorilla/mux"
)

var (
	_ PluginHelper = &Engine{}
)

// Engine is the pipeline engine of the data bus system which manages the core loop.
type Engine struct {
	sync.RWMutex

	// Engine will load json config file
	*conf.Conf
	fn string

	// REST exporter
	httpListener net.Listener
	httpServer   *http.Server
	httpRouter   *mux.Router
	httpPaths    []string

	InputRunners  map[string]InputRunner
	inputWrappers map[string]*pluginWrapper

	FilterRunners  map[string]FilterRunner
	filterWrappers map[string]*pluginWrapper

	OutputRunners  map[string]OutputRunner
	outputWrappers map[string]*pluginWrapper

	top    *topology
	router *Router

	inputRecycleChan  chan *Packet
	filterRecycleChan chan *Packet

	hostname string
	pid      int
}

func New(globals *GlobalConfig) *Engine {
	if globals == nil {
		globals = DefaultGlobals()
	}
	Globals = func() *GlobalConfig {
		return globals
	}

	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	return &Engine{
		InputRunners:   make(map[string]InputRunner),
		inputWrappers:  make(map[string]*pluginWrapper),
		FilterRunners:  make(map[string]FilterRunner),
		filterWrappers: make(map[string]*pluginWrapper),
		OutputRunners:  make(map[string]OutputRunner),
		outputWrappers: make(map[string]*pluginWrapper),

		inputRecycleChan:  make(chan *Packet, globals.InputRecyclePoolSize),
		filterRecycleChan: make(chan *Packet, globals.FilterRecyclePoolSize),

		top:    newTopology(),
		router: newMessageRouter(),

		httpPaths: make([]string, 0, 6),

		pid:      os.Getpid(),
		hostname: hostname,
	}
}

func (e *Engine) stopInputRunner(name string) {
	e.Lock()
	e.InputRunners[name] = nil
	e.Unlock()
}

// ClonePacket is used for plugin Filter to generate new Packet.
// The generated Packet will use dedicated filter recycle chan.
func (e *Engine) ClonePacket(p *Packet) *Packet {
	pack := <-e.filterRecycleChan
	pack.Reset()
	p.copyTo(pack)
	return pack
}

func (e *Engine) LoadConfigFile(fn string) *Engine {
	if fn == "" {
		panic("config file is required")
	}
	if _, err := os.Stat(fn); err != nil {
		panic(err)
	}
	cf, err := conf.Load(fn)
	if err != nil {
		panic(err)
	}

	e.fn = fn
	e.Conf = cf
	Globals().Conf = cf

	// 'plugins' section
	for i := 0; i < len(e.List("plugins", nil)); i++ {
		section, err := e.Section(fmt.Sprintf("plugins[%d]", i))
		if err != nil {
			panic(err)
		}

		e.loadPluginSection(section)
	}

	// 'topology' section
	e.top.load(e.Conf)

	if c, err := influxdb.NewConfig(cf.String("influx_addr", ""),
		cf.String("influx_db", "dbus"), "", "",
		cf.Duration("influx_tick", time.Minute)); err == nil {
		telemetry.Default = influxdb.New(metrics.DefaultRegistry, c)
	} else {
		log.Warn("telemetry disabled for: %s", err)
	}

	return e
}

func (e *Engine) loadPluginSection(section *conf.Conf) {
	pluginCommons := new(pluginCommons)
	pluginCommons.loadConfig(section)
	if pluginCommons.disabled {
		log.Warn("%s disabled", pluginCommons.name)

		return
	}

	wrapper := &pluginWrapper{
		name:          pluginCommons.name,
		configCreator: func() *conf.Conf { return section },
	}
	var ok bool
	if wrapper.pluginCreator, ok = availablePlugins[pluginCommons.class]; !ok {
		panic("unknown plugin type: " + pluginCommons.class)
	}

	pluginType := pluginTypeRegex.FindStringSubmatch(pluginCommons.class)
	if len(pluginType) < 2 {
		panic("invalid plugin type: " + pluginCommons.class)
	}

	plugin := wrapper.Create()
	pluginCategory := pluginType[1]
	if pluginCategory == "Input" {
		e.InputRunners[wrapper.name] = newInputRunner(plugin.(Input), pluginCommons)
		e.inputWrappers[wrapper.name] = wrapper
		e.router.metrics.m[wrapper.name] = metrics.NewRegisteredMeter(wrapper.name, metrics.DefaultRegistry)
		return
	}

	foRunner := newFORunner(plugin, pluginCommons)
	matcher := newMatcher(section.StringList("match", nil), foRunner)
	foRunner.matcher = matcher

	switch pluginCategory {
	case "Filter":
		e.router.addFilterMatcher(matcher)
		e.FilterRunners[foRunner.Name()] = foRunner
		e.filterWrappers[foRunner.Name()] = wrapper
		e.router.metrics.m[wrapper.name] = metrics.NewRegisteredMeter(wrapper.name, metrics.DefaultRegistry)

	case "Output":
		e.router.addOutputMatcher(matcher)
		e.OutputRunners[foRunner.Name()] = foRunner
		e.outputWrappers[foRunner.Name()] = wrapper
		e.router.metrics.m[wrapper.name] = metrics.NewRegisteredMeter(wrapper.name, metrics.DefaultRegistry)

	default:
		panic("unknown plugin: " + pluginCategory)
	}
}

func (e *Engine) ServeForever() {
	var (
		outputsWg = new(sync.WaitGroup)
		filtersWg = new(sync.WaitGroup)
		inputsWg  = new(sync.WaitGroup)
		routerWg  = new(sync.WaitGroup)

		globals = Globals()
		err     error
	)

	// setup signal handler first to avoid race condition
	// if Input terminates very soon, global.Shutdown will
	// not be able to trap it
	globals.sigChan = make(chan os.Signal)
	signal.Notify(globals.sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGUSR1, syscall.SIGUSR2)

	e.launchHttpServ()

	if telemetry.Default != nil {
		log.Info("launching telemetry dumper...")

		go func() {
			if err := telemetry.Default.Start(); err != nil {
				log.Error("telemetry[%s]: %s", telemetry.Default.Name(), err)
			}
		}()
	}

	for _, outputRunner := range e.OutputRunners {
		log.Trace("launching Output[%s]...", outputRunner.Name())

		outputsWg.Add(1)
		if err = outputRunner.start(e, outputsWg); err != nil {
			panic(err)
		}
	}

	for _, filterRunner := range e.FilterRunners {
		log.Trace("launching Filter[%s]...", filterRunner.Name())

		filtersWg.Add(1)
		if err = filterRunner.start(e, filtersWg); err != nil {
			panic(err)
		}
	}

	log.Info("initializing Input Packet pool with size=%d", globals.InputRecyclePoolSize)
	for i := 0; i < globals.InputRecyclePoolSize; i++ {
		inputPack := newPacket(e.inputRecycleChan)
		e.inputRecycleChan <- inputPack
	}

	log.Info("initializing Filter Packet pool with size=%d", globals.FilterRecyclePoolSize)
	for i := 0; i < globals.FilterRecyclePoolSize; i++ {
		filterPack := newPacket(e.filterRecycleChan)
		e.filterRecycleChan <- filterPack
	}

	log.Info("launching Watchdog with ticker=%s", globals.WatchdogTick)
	go e.runWatchdog(globals.WatchdogTick)

	log.Info("launching Router...")
	routerWg.Add(1)
	go e.router.Start(routerWg)

	for _, inputRunner := range e.InputRunners {
		log.Trace("launching Input[%s]...", inputRunner.Name())

		inputsWg.Add(1)
		if err = inputRunner.start(e, inputsWg); err != nil {
			inputsWg.Done()
			panic(err)
		}
	}

	// hot reload
	cfChanged := make(chan *conf.Conf)
	go conf.Watch(e.Conf, time.Second, cfChanged)

	for !globals.Stopping {
		select {
		case <-cfChanged:
			log.Info("%s updated, reloading...", e.fn)
			// TODO

		case sig := <-globals.sigChan:
			log.Info("Got signal %s", strings.ToUpper(sig.String()))

			switch sig {
			case syscall.SIGHUP:
				log.Info("Reloading...")
				observer.Publish(RELOAD, nil)

			case syscall.SIGINT, syscall.SIGTERM:
				log.Info("shutdown...")
				globals.Stopping = true
				if telemetry.Default != nil {
					telemetry.Default.Stop()
				}

			case syscall.SIGUSR1:
				observer.Publish(SIGUSR1, nil)

			case syscall.SIGUSR2:
				observer.Publish(SIGUSR2, nil)
			}
		}
	}

	e.Lock()
	for _, inputRunner := range e.InputRunners {
		if inputRunner == nil {
			// the Input plugin already exit
			continue
		}

		log.Trace("Stop message sent to %s", inputRunner.Name())
		inputRunner.Input().Stop(inputRunner)
	}
	e.Unlock()
	inputsWg.Wait() // wait for all inputs done
	log.Info("all Inputs stopped")

	// ok, now we are sure no more inputs, but in route.inChan there
	// still may be filter injected packs and output not consumed packs
	// we must wait for all the packs to be consumed before shutdown

	for _, filterRunner := range e.FilterRunners {
		log.Trace("Stop message sent to %s", filterRunner.Name())
		e.router.removeFilterMatcher <- filterRunner.getMatcher()
	}
	filtersWg.Wait()
	if len(e.FilterRunners) > 0 {
		log.Info("all Filters stopped")
	}

	for _, outputRunner := range e.OutputRunners {
		log.Trace("Stop message sent to %s", outputRunner.Name())
		e.router.removeOutputMatcher <- outputRunner.getMatcher()
	}
	outputsWg.Wait()
	log.Info("all Outputs stopped")

	close(e.router.hub)
	routerWg.Wait()
	log.Info("Router stopped")

	e.stopHttpServ()

	log.Info("shutdown complete")
}
<commit_msg>tweak of log message<commit_after>// +build !v2

// Package provides a plugin based pipeline engine that decouples Input/Filter/Output plugins.
package engine

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/funkygao/gafka/telemetry"
	"github.com/funkygao/gafka/telemetry/influxdb"
	"github.com/funkygao/go-metrics"
	"github.com/funkygao/golib/observer"
	conf "github.com/funkygao/jsconf"
	log "github.com/funkygao/log4go"
	"github.com/gorilla/mux"
)

var (
	_ PluginHelper = &Engine{}
)

// Engine is the pipeline engine of the data bus system which manages the core loop.
type Engine struct {
	sync.RWMutex

	// Engine will load json config file
	*conf.Conf
	fn string

	// REST exporter
	httpListener net.Listener
	httpServer   *http.Server
	httpRouter   *mux.Router
	httpPaths    []string

	InputRunners  map[string]InputRunner
	inputWrappers map[string]*pluginWrapper

	FilterRunners  map[string]FilterRunner
	filterWrappers map[string]*pluginWrapper

	OutputRunners  map[string]OutputRunner
	outputWrappers map[string]*pluginWrapper

	top    *topology
	router *Router

	inputRecycleChan  chan *Packet
	filterRecycleChan chan *Packet

	hostname string
	pid      int
}

func New(globals *GlobalConfig) *Engine {
	if globals == nil {
		globals = DefaultGlobals()
	}
	Globals = func() *GlobalConfig {
		return globals
	}

	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	return &Engine{
		InputRunners:   make(map[string]InputRunner),
		inputWrappers:  make(map[string]*pluginWrapper),
		FilterRunners:  make(map[string]FilterRunner),
		filterWrappers: make(map[string]*pluginWrapper),
		OutputRunners:  make(map[string]OutputRunner),
		outputWrappers: make(map[string]*pluginWrapper),

		inputRecycleChan:  make(chan *Packet, globals.InputRecyclePoolSize),
		filterRecycleChan: make(chan *Packet, globals.FilterRecyclePoolSize),

		top:    newTopology(),
		router: newMessageRouter(),

		httpPaths: make([]string, 0, 6),

		pid:      os.Getpid(),
		hostname: hostname,
	}
}

func (e *Engine) stopInputRunner(name string) {
	e.Lock()
	e.InputRunners[name] = nil
	e.Unlock()
}

// ClonePacket is used for plugin Filter to generate new Packet.
// The generated Packet will use dedicated filter recycle chan.
func (e *Engine) ClonePacket(p *Packet) *Packet {
	pack := <-e.filterRecycleChan
	pack.Reset()
	p.copyTo(pack)
	return pack
}

func (e *Engine) LoadConfigFile(fn string) *Engine {
	if fn == "" {
		panic("config file is required")
	}
	if _, err := os.Stat(fn); err != nil {
		panic(err)
	}
	cf, err := conf.Load(fn)
	if err != nil {
		panic(err)
	}

	e.fn = fn
	e.Conf = cf
	Globals().Conf = cf

	// 'plugins' section
	for i := 0; i < len(e.List("plugins", nil)); i++ {
		section, err := e.Section(fmt.Sprintf("plugins[%d]", i))
		if err != nil {
			panic(err)
		}

		e.loadPluginSection(section)
	}

	// 'topology' section
	e.top.load(e.Conf)

	if c, err := influxdb.NewConfig(cf.String("influx_addr", ""),
		cf.String("influx_db", "dbus"), "", "",
		cf.Duration("influx_tick", time.Minute)); err == nil {
		telemetry.Default = influxdb.New(metrics.DefaultRegistry, c)
	} else {
		log.Warn("telemetry disabled for: %s", err)
	}

	return e
}

func (e *Engine) loadPluginSection(section *conf.Conf) {
	pluginCommons := new(pluginCommons)
	pluginCommons.loadConfig(section)
	if pluginCommons.disabled {
		log.Warn("%s disabled", pluginCommons.name)

		return
	}

	wrapper := &pluginWrapper{
		name:          pluginCommons.name,
		configCreator: func() *conf.Conf { return section },
	}
	var ok bool
	if wrapper.pluginCreator, ok = availablePlugins[pluginCommons.class]; !ok {
		panic("unknown plugin type: " + pluginCommons.class)
	}

	pluginType := pluginTypeRegex.FindStringSubmatch(pluginCommons.class)
	if len(pluginType) < 2 {
		panic("invalid plugin type: " + pluginCommons.class)
	}

	plugin := wrapper.Create()
	pluginCategory := pluginType[1]
	if pluginCategory == "Input" {
		e.InputRunners[wrapper.name] = newInputRunner(plugin.(Input), pluginCommons)
		e.inputWrappers[wrapper.name] = wrapper
		e.router.metrics.m[wrapper.name] = metrics.NewRegisteredMeter(wrapper.name, metrics.DefaultRegistry)
		return
	}

	foRunner := newFORunner(plugin, pluginCommons)
	matcher := newMatcher(section.StringList("match", nil), foRunner)
	foRunner.matcher = matcher

	switch pluginCategory {
	case "Filter":
		e.router.addFilterMatcher(matcher)
		e.FilterRunners[foRunner.Name()] = foRunner
		e.filterWrappers[foRunner.Name()] = wrapper
		e.router.metrics.m[wrapper.name] = metrics.NewRegisteredMeter(wrapper.name, metrics.DefaultRegistry)

	case "Output":
		e.router.addOutputMatcher(matcher)
		e.OutputRunners[foRunner.Name()] = foRunner
		e.outputWrappers[foRunner.Name()] = wrapper
		e.router.metrics.m[wrapper.name] = metrics.NewRegisteredMeter(wrapper.name, metrics.DefaultRegistry)

	default:
		panic("unknown plugin: " + pluginCategory)
	}
}

func (e *Engine) ServeForever() {
	var (
		outputsWg = new(sync.WaitGroup)
		filtersWg = new(sync.WaitGroup)
		inputsWg  = new(sync.WaitGroup)
		routerWg  = new(sync.WaitGroup)

		globals = Globals()
		err     error
	)

	// setup signal handler first to avoid race condition
	// if Input terminates very soon, global.Shutdown will
	// not be able to trap it
	globals.sigChan = make(chan os.Signal)
	signal.Notify(globals.sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGUSR1, syscall.SIGUSR2)

	e.launchHttpServ()

	if telemetry.Default != nil {
		log.Info("launching telemetry dumper...")

		go func() {
			if err := telemetry.Default.Start(); err != nil {
				log.Error("telemetry[%s]: %s", telemetry.Default.Name(), err)
			}
		}()
	}

	for _, outputRunner := range e.OutputRunners {
		log.Trace("launching Output[%s]...", outputRunner.Name())

		outputsWg.Add(1)
		if err = outputRunner.start(e, outputsWg); err != nil {
			panic(err)
		}
	}

	for _, filterRunner := range e.FilterRunners {
		log.Trace("launching Filter[%s]...", filterRunner.Name())

		filtersWg.Add(1)
		if err = filterRunner.start(e, filtersWg); err != nil {
			panic(err)
		}
	}

	log.Info("initializing Input Packet pool with size=%d", globals.InputRecyclePoolSize)
	for i := 0; i < globals.InputRecyclePoolSize; i++ {
		inputPack := newPacket(e.inputRecycleChan)
		e.inputRecycleChan <- inputPack
	}

	log.Info("initializing Filter Packet pool with size=%d", globals.FilterRecyclePoolSize)
	for i := 0; i < globals.FilterRecyclePoolSize; i++ {
		filterPack := newPacket(e.filterRecycleChan)
		e.filterRecycleChan <- filterPack
	}

	log.Info("launching Watchdog with ticker=%s", globals.WatchdogTick)
	go e.runWatchdog(globals.WatchdogTick)

	routerWg.Add(1)
	go e.router.Start(routerWg)

	for _, inputRunner := range e.InputRunners {
		log.Trace("launching Input[%s]...", inputRunner.Name())

		inputsWg.Add(1)
		if err = inputRunner.start(e, inputsWg); err != nil {
			inputsWg.Done()
			panic(err)
		}
	}

	cfChanged := make(chan *conf.Conf)
	poller := time.Second
	log.Info("hot reload watching %s with poller=%s", e.fn, poller)
	go conf.Watch(e.Conf, poller, cfChanged)

	for !globals.Stopping {
		select {
		case <-cfChanged:
			log.Info("%s updated, reloading...", e.fn)
			// TODO

		case sig := <-globals.sigChan:
			log.Info("Got signal %s", strings.ToUpper(sig.String()))

			switch sig {
			case syscall.SIGHUP:
				log.Info("Reloading...")
				observer.Publish(RELOAD, nil)

			case syscall.SIGINT, syscall.SIGTERM:
				log.Info("shutdown...")
				globals.Stopping = true
				if telemetry.Default != nil {
					telemetry.Default.Stop()
				}

			case syscall.SIGUSR1:
				observer.Publish(SIGUSR1, nil)

			case syscall.SIGUSR2:
				observer.Publish(SIGUSR2, nil)
			}
		}
	}

	e.Lock()
	for _, inputRunner := range e.InputRunners {
		if inputRunner == nil {
			// the Input plugin already exit
			continue
		}

		log.Trace("Stop message sent to %s", inputRunner.Name())
		inputRunner.Input().Stop(inputRunner)
	}
	e.Unlock()
	inputsWg.Wait() // wait for all inputs done
	log.Info("all Inputs stopped")

	// ok, now we are sure no more inputs, but in route.inChan there
	// still may be filter injected packs and output not consumed packs
	// we must wait for all the packs to be consumed before shutdown

	for _, filterRunner := range e.FilterRunners {
		log.Trace("Stop message sent to %s", filterRunner.Name())
		e.router.removeFilterMatcher <- filterRunner.getMatcher()
	}
	filtersWg.Wait()
	if len(e.FilterRunners) > 0 {
		log.Info("all Filters stopped")
	}

	for _, outputRunner := range e.OutputRunners {
		log.Trace("Stop message sent to %s", outputRunner.Name())
		e.router.removeOutputMatcher <- outputRunner.getMatcher()
	}
	outputsWg.Wait()
	log.Info("all Outputs stopped")

	close(e.router.hub)
	routerWg.Wait()
	log.Info("Router stopped")

	e.stopHttpServ()

	log.Info("shutdown complete")
}
<|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 gcscaching

import (
	"time"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/util/lrucache"
)

// A cache mapping from name to most recent known record for the object of that
// name. External synchronization must be provided.
type StatCache interface {
	// Insert an entry for the given object record. The entry will not replace
	// any entry with a newer generation number, or any entry with an equivalent
	// generation number but newer metadata generation number, and will not be
	// available after the supplied expiration time.
	Insert(o *gcs.Object, expiration time.Time)

	// Erase the entry for the given object name, if any.
	Erase(name string)

	// Return the current entry for the given name, or nil if none. Use the
	// supplied time to decide whether entries have expired.
	LookUp(name string, now time.Time) (o *gcs.Object)

	// Panic if any internal invariants have been violated. The careful user can
	// arrange to call this at crucial moments.
	CheckInvariants()
}

// Create a new stat cache that holds the given number of entries, which must
// be positive.
func NewStatCache(capacity int) (sc StatCache) {
	sc = &statCache{
		c: lrucache.New(capacity),
	}

	return
}

type statCache struct {
	c lrucache.Cache
}

type entry struct {
	o          *gcs.Object
	expiration time.Time
}

func (sc *statCache) Insert(o *gcs.Object, expiration time.Time) {
	e := entry{
		o:          o,
		expiration: expiration,
	}

	sc.c.Insert(o.Name, e)
}

func (sc *statCache) Erase(name string) {
	sc.c.Erase(name)
}

func (sc *statCache) LookUp(name string, now time.Time) (o *gcs.Object) {
	// Look up in the LRU cache.
	value := sc.c.LookUp(name)
	if value == nil {
		return
	}

	e := value.(entry)

	// Has this entry expired?
	if e.expiration.Before(now) {
		sc.Erase(name)
		return
	}

	o = e.o
	return
}

func (sc *statCache) CheckInvariants() {
	sc.c.CheckInvariants()
}
<commit_msg>Check existing when overwriting.<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 gcscaching

import (
	"time"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/util/lrucache"
)

// A cache mapping from name to most recent known record for the object of that
// name. External synchronization must be provided.
type StatCache interface {
	// Insert an entry for the given object record. The entry will not replace
	// any entry with a newer generation number, or any entry with an equivalent
	// generation number but newer metadata generation number, and will not be
	// available after the supplied expiration time.
	Insert(o *gcs.Object, expiration time.Time)

	// Erase the entry for the given object name, if any.
	Erase(name string)

	// Return the current entry for the given name, or nil if none. Use the
	// supplied time to decide whether entries have expired.
	LookUp(name string, now time.Time) (o *gcs.Object)

	// Panic if any internal invariants have been violated. The careful user can
	// arrange to call this at crucial moments.
	CheckInvariants()
}

// Create a new stat cache that holds the given number of entries, which must
// be positive.
func NewStatCache(capacity int) (sc StatCache) {
	sc = &statCache{
		c: lrucache.New(capacity),
	}

	return
}

type statCache struct {
	c lrucache.Cache
}

type entry struct {
	o          *gcs.Object
	expiration time.Time
}

func shouldReplace(o *gcs.Object, existing *gcs.Object) bool {
	if existing == nil {
		return false
	}

	// Compare first on generation.
	if o.Generation != existing.Generation {
		return o.Generation < existing.Generation
	}

	// Break ties on metadata generation.
	if o.MetaGeneration != existing.MetaGeneration {
		return o.MetaGeneration < existing.MetaGeneration
	}

	// Break ties by preferring fresher entries.
	return true
}

func (sc *statCache) Insert(o *gcs.Object, expiration time.Time) {
	// Is there already a better entry?
	if existing := sc.c.LookUp(o.Name); existing != nil {
		if !shouldReplace(o, existing.(entry).o) {
			return
		}
	}

	// Insert an entry.
	e := entry{
		o:          o,
		expiration: expiration,
	}

	sc.c.Insert(o.Name, e)
}

func (sc *statCache) Erase(name string) {
	sc.c.Erase(name)
}

func (sc *statCache) LookUp(name string, now time.Time) (o *gcs.Object) {
	// Look up in the LRU cache.
	value := sc.c.LookUp(name)
	if value == nil {
		return
	}

	e := value.(entry)

	// Has this entry expired?
	if e.expiration.Before(now) {
		sc.Erase(name)
		return
	}

	o = e.o
	return
}

func (sc *statCache) CheckInvariants() {
	sc.c.CheckInvariants()
}
<|endoftext|>


<commit_before>package main

import (
	"os/exec"
	"strings"
	"time"
)

type executor struct {
	exe  string
	args []string
}

func (e *executor) generateExeAndArgs(scriptFile string) (outExe string, outArgs []string) {
	if e.exe == "" {
		return scriptFile, []string{}
	} else {
		outExe = e.exe
		outArgs = e.args
		outArgs = append(outArgs, scriptFile)
		// outArgs = append(outArgs, args...)
		return
	}
}

func (e *executor) execute(a *app, scriptFile string) {
	defer a.deleteFile(scriptFile)

	sleepDur := 2 * time.Second
	a.logger.Infof("Sleeping for '%s' to allow file disk-write to complete for file '%s'", sleepDur.String(), scriptFile)
	time.Sleep(sleepDur)

	exe, args := e.generateExeAndArgs(scriptFile)
	cmd := exec.Command(exe, args...)

	out, err := cmd.CombinedOutput()
	cleanedOutput := strings.Replace(strings.Replace(string(out), "\n", "\\n", -1), "\r", "", -1)
	if err != nil {
		a.logger.Errorf("Could not execute script '%s'. ERROR: '%s', CombinedOutput: '%s'", scriptFile, err.Error(), cleanedOutput)
		return
	}

	a.logger.Infof("Output of script '%s' was '%s'", scriptFile, cleanedOutput)
}

func getScriptExecutor(scriptFilePath string) *executor {
	lowerPath := strings.ToLower(scriptFilePath)

	if strings.HasSuffix(lowerPath, ".py") {
		return &executor{"python", []string{}}
	}

	if strings.HasSuffix(lowerPath, ".go") {
		return &executor{"go", []string{"run"}}
	}

	return nil
}
<commit_msg>Add .bat and .sh executors.<commit_after>package main

import (
	"os/exec"
	"strings"
	"time"
)

type executor struct {
	exe  string
	args []string
}

func (e *executor) generateExeAndArgs(scriptFile string) (outExe string, outArgs []string) {
	if e.exe == "" {
		return scriptFile, []string{}
	} else {
		outExe = e.exe
		outArgs = e.args
		outArgs = append(outArgs, scriptFile)
		// outArgs = append(outArgs, args...)
		return
	}
}

func (e *executor) execute(a *app, scriptFile string) {
	defer a.deleteFile(scriptFile)

	sleepDur := 2 * time.Second
	a.logger.Infof("Sleeping for '%s' to allow file disk-write to complete for file '%s'", sleepDur.String(), scriptFile)
	time.Sleep(sleepDur)

	exe, args := e.generateExeAndArgs(scriptFile)
	cmd := exec.Command(exe, args...)

	out, err := cmd.CombinedOutput()
	cleanedOutput := strings.Replace(strings.Replace(string(out), "\n", "\\n", -1), "\r", "", -1)
	if err != nil {
		a.logger.Errorf("Could not execute script '%s'. ERROR: '%s', CombinedOutput: '%s'", scriptFile, err.Error(), cleanedOutput)
		return
	}

	a.logger.Infof("Output of script '%s' was '%s'", scriptFile, cleanedOutput)
}

func getScriptExecutor(scriptFilePath string) *executor {
	lowerPath := strings.ToLower(scriptFilePath)

	if strings.HasSuffix(lowerPath, ".bat") {
		return &executor{"cmd", []string{"/c"}}
	} else if strings.HasSuffix(lowerPath, ".sh") {
		return &executor{"bash", []string{"-c"}}
	} else if strings.HasSuffix(lowerPath, ".py") {
		return &executor{"python", []string{}}
	} else if strings.HasSuffix(lowerPath, ".go") {
		return &executor{"go", []string{"run"}}
	}

	return nil
}
<|endoftext|>


<commit_before>package sqlstore

import (
	"reflect"
	"testing"

	. "github.com/smartystreets/goconvey/convey"

	"github.com/grafana/grafana/pkg/components/simplejson"
	m "github.com/grafana/grafana/pkg/models"
)

func updateTestDashboard(dashboard *m.Dashboard, data map[string]interface{}) {
	data["title"] = dashboard.Title

	saveCmd := m.SaveDashboardCommand{
		OrgId:     dashboard.OrgId,
		Overwrite: true,
		Dashboard: simplejson.NewFromAny(data),
	}

	err := SaveDashboard(&saveCmd)
	So(err, ShouldBeNil)
}

func TestGetDashboardVersion(t *testing.T) {
	Convey("Testing dashboard version retrieval", t, func() {
		InitTestDB(t)

		Convey("Get a Dashboard ID and version ID", func() {
			savedDash := insertTestDashboard("test dash 26", 1, "diff")

			query := m.GetDashboardVersionQuery{
				DashboardId: savedDash.Id,
				Version:     savedDash.Version,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldBeNil)
			So(savedDash.Id, ShouldEqual, query.DashboardId)
			So(savedDash.Version, ShouldEqual, query.Version)

			dashCmd := m.GetDashboardQuery{
				OrgId: savedDash.OrgId,
				Slug:  savedDash.Slug,
			}
			err = GetDashboard(&dashCmd)
			So(err, ShouldBeNil)
			eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data)
			So(eq, ShouldEqual, true)
		})

		Convey("Attempt to get a version that doesn't exist", func() {
			query := m.GetDashboardVersionQuery{
				DashboardId: int64(999),
				Version:     123,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrDashboardVersionNotFound)
		})
	})
}

func TestGetDashboardVersions(t *testing.T) {
	Convey("Testing dashboard versions retrieval", t, func() {
		InitTestDB(t)
		savedDash := insertTestDashboard("test dash 43", 1, "diff-all")

		Convey("Get all versions for a given Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 1)
		})

		Convey("Attempt to get the versions for a non-existent Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: int64(999), OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrNoVersionsForDashboardId)
			So(len(query.Result), ShouldEqual, 0)
		})

		Convey("Get all versions for an updated dashboard", func() {
			updateTestDashboard(savedDash, map[string]interface{}{
				"tags": "different-tag",
			})

			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}
			err := GetDashboardVersions(&query)

			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 2)
		})
	})
}
<commit_msg>dasboard_history: fixed sql integration test<commit_after>package sqlstore

import (
	"reflect"
	"testing"

	. "github.com/smartystreets/goconvey/convey"

	"github.com/grafana/grafana/pkg/components/simplejson"
	m "github.com/grafana/grafana/pkg/models"
)

func updateTestDashboard(dashboard *m.Dashboard, data map[string]interface{}) {
	data["title"] = dashboard.Title

	saveCmd := m.SaveDashboardCommand{
		OrgId:     dashboard.OrgId,
		Overwrite: true,
		Dashboard: simplejson.NewFromAny(data),
	}

	err := SaveDashboard(&saveCmd)
	So(err, ShouldBeNil)
}

func TestGetDashboardVersion(t *testing.T) {
	Convey("Testing dashboard version retrieval", t, func() {
		InitTestDB(t)

		Convey("Get a Dashboard ID and version ID", func() {
			savedDash := insertTestDashboard("test dash 26", 1, "diff")

			query := m.GetDashboardVersionQuery{
				DashboardId: savedDash.Id,
				Version:     savedDash.Version,
				OrgId:       1,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldBeNil)
			So(savedDash.Id, ShouldEqual, query.DashboardId)
			So(savedDash.Version, ShouldEqual, query.Version)

			dashCmd := m.GetDashboardQuery{
				OrgId: savedDash.OrgId,
				Slug:  savedDash.Slug,
			}
			err = GetDashboard(&dashCmd)
			So(err, ShouldBeNil)
			eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data)
			So(eq, ShouldEqual, true)
		})

		Convey("Attempt to get a version that doesn't exist", func() {
			query := m.GetDashboardVersionQuery{
				DashboardId: int64(999),
				Version:     123,
				OrgId:       1,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrDashboardVersionNotFound)
		})
	})
}

func TestGetDashboardVersions(t *testing.T) {
	Convey("Testing dashboard versions retrieval", t, func() {
		InitTestDB(t)
		savedDash := insertTestDashboard("test dash 43", 1, "diff-all")

		Convey("Get all versions for a given Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 1)
		})

		Convey("Attempt to get the versions for a non-existent Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: int64(999), OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrNoVersionsForDashboardId)
			So(len(query.Result), ShouldEqual, 0)
		})

		Convey("Get all versions for an updated dashboard", func() {
			updateTestDashboard(savedDash, map[string]interface{}{
				"tags": "different-tag",
			})

			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}
			err := GetDashboardVersions(&query)

			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 2)
		})
	})
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 The Kythe Authors. 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 cmakecmd extracts from a CMake-based repository.
package cmakecmd // import "kythe.io/kythe/go/extractors/config/runextractor/cmakecmd"

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"kythe.io/kythe/go/extractors/config/runextractor/compdb"
	"kythe.io/kythe/go/util/cmdutil"

	"github.com/google/subcommands"
	"github.com/google/uuid"
)

type cmakeCommand struct {
	cmdutil.Info

	extractor string
	buildDir  string
	sourceDir string
}

// New creates a new subcommand for running cmake extraction.
func New() subcommands.Command {
	return &cmakeCommand{
		Info: cmdutil.NewInfo("cmake", "extract a repo build with CMake", `documight`),
	}
}

// SetFlags implements the subcommands interface and provides command-specific
// flags for cmake extraction.
func (c *cmakeCommand) SetFlags(fs *flag.FlagSet) {
	fs.StringVar(&c.extractor, "extractor", "", "A required path to the extractor binary to use.")
	fs.StringVar(&c.sourceDir, "sourcedir", ".", "A required path to the repository root. Defaults to the current directory.")
	fs.StringVar(&c.buildDir, "builddir", "", "An optional path to the directory in which to build. If empty, defaults to a unique subdirectory of sourcedir.")
}

func (c *cmakeCommand) verifyFlags() error {
	for _, key := range []string{"KYTHE_CORPUS", "KYTHE_ROOT_DIRECTORY", "KYTHE_OUTPUT_DIRECTORY"} {
		if os.Getenv(key) == "" {
			return fmt.Errorf("required %s not set", key)
		}
	}
	if c.extractor == "" {
		return fmt.Errorf("required -extractor not set")
	}
	if c.sourceDir == "" {
		return fmt.Errorf("required -sourcedir not set")
	}
	return nil
}

// Execute implements the subcommands interface and runs cmake extraction.
func (c *cmakeCommand) Execute(ctx context.Context, fs *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
	if err := c.verifyFlags(); err != nil {
		return c.Fail("Incorrect flags: %v", err)
	}
	// Since we have to change our working directory, resolve all of our paths early.
	extractor, err := filepath.Abs(c.extractor)
	if err != nil {
		return c.Fail("Unable to resolve path to extractor: %v", err)
	}
	sourceDir, err := filepath.Abs(c.sourceDir)
	if err != nil {
		return c.Fail("Unable to resolve source directory: %v", err)
	}
	var buildDir string
	if c.buildDir == "" {
		// sourceDir is already an absolute directory
		buildDir = filepath.Join(sourceDir, "build-"+uuid.New().String())
		if err := os.Mkdir(buildDir, 0755); err != nil {
			// Unlike below, we need to fail if the "unique" directory exists.
			return c.Fail("Unable to create build directory: %v", err)
		}
		// Only clean up the build directory if it was unspecified.
		defer cleanBuild(buildDir)
	} else {
		buildDir, err = filepath.Abs(c.buildDir)
		if err != nil {
			return c.Fail("Unable to resolve build directory: %v", err)
		}
	}

	// Create the build directory if it doesn't already exist.
	if err := os.MkdirAll(buildDir, 0755); err != nil {
		return c.Fail("Unable to create build directory: %v", err)
	}

	if err := runIn(exec.CommandContext(ctx, "cmake", "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", sourceDir), buildDir); err != nil {
		return c.Fail("Error configuring cmake: %v", err)
	}

	if err := runIn(exec.CommandContext(ctx, "cmake", "--build", "."), buildDir); err != nil {
		return c.Fail("Error building repository: %v", err)
	}

	if err := compdb.ExtractCompilations(ctx, extractor, filepath.Join(buildDir, "compile_commands.json")); err != nil {
		return c.Fail("Error extracting repository: %v", err)
	}
	return subcommands.ExitSuccess
}

// cleanBuild removes dir and all files beneath it, logging an error if it fails.
func cleanBuild(dir string) {
	if err := os.RemoveAll(dir); err != nil {
		log.Printf("unable to remove build directory: %v", err)
	}
}

// runIn changes the cmd working directory to dir and calls Run. The cmd's
// stderr is forwarded to stderr.
func runIn(cmd *exec.Cmd, dir string) error {
	cmd.Dir = dir
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<commit_msg>chore(cmake): log the command we are running (#4318)<commit_after>/*
 * Copyright 2018 The Kythe Authors. 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 cmakecmd extracts from a CMake-based repository.
package cmakecmd // import "kythe.io/kythe/go/extractors/config/runextractor/cmakecmd"

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"kythe.io/kythe/go/extractors/config/runextractor/compdb"
	"kythe.io/kythe/go/util/cmdutil"

	"github.com/google/subcommands"
	"github.com/google/uuid"
)

type cmakeCommand struct {
	cmdutil.Info

	extractor string
	buildDir  string
	sourceDir string
}

// New creates a new subcommand for running cmake extraction.
func New() subcommands.Command {
	return &cmakeCommand{
		Info: cmdutil.NewInfo("cmake", "extract a repo build with CMake", `documight`),
	}
}

// SetFlags implements the subcommands interface and provides command-specific
// flags for cmake extraction.
func (c *cmakeCommand) SetFlags(fs *flag.FlagSet) {
	fs.StringVar(&c.extractor, "extractor", "", "A required path to the extractor binary to use.")
	fs.StringVar(&c.sourceDir, "sourcedir", ".", "A required path to the repository root. Defaults to the current directory.")
	fs.StringVar(&c.buildDir, "builddir", "", "An optional path to the directory in which to build. If empty, defaults to a unique subdirectory of sourcedir.")
}

func (c *cmakeCommand) verifyFlags() error {
	for _, key := range []string{"KYTHE_CORPUS", "KYTHE_ROOT_DIRECTORY", "KYTHE_OUTPUT_DIRECTORY"} {
		if os.Getenv(key) == "" {
			return fmt.Errorf("required %s not set", key)
		}
	}
	if c.extractor == "" {
		return fmt.Errorf("required -extractor not set")
	}
	if c.sourceDir == "" {
		return fmt.Errorf("required -sourcedir not set")
	}
	return nil
}

// Execute implements the subcommands interface and runs cmake extraction.
func (c *cmakeCommand) Execute(ctx context.Context, fs *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
	if err := c.verifyFlags(); err != nil {
		return c.Fail("Incorrect flags: %v", err)
	}
	// Since we have to change our working directory, resolve all of our paths early.
	extractor, err := filepath.Abs(c.extractor)
	if err != nil {
		return c.Fail("Unable to resolve path to extractor: %v", err)
	}
	sourceDir, err := filepath.Abs(c.sourceDir)
	if err != nil {
		return c.Fail("Unable to resolve source directory: %v", err)
	}
	var buildDir string
	if c.buildDir == "" {
		// sourceDir is already an absolute directory
		buildDir = filepath.Join(sourceDir, "build-"+uuid.New().String())
		if err := os.Mkdir(buildDir, 0755); err != nil {
			// Unlike below, we need to fail if the "unique" directory exists.
			return c.Fail("Unable to create build directory: %v", err)
		}
		// Only clean up the build directory if it was unspecified.
		defer cleanBuild(buildDir)
	} else {
		buildDir, err = filepath.Abs(c.buildDir)
		if err != nil {
			return c.Fail("Unable to resolve build directory: %v", err)
		}
	}

	// Create the build directory if it doesn't already exist.
	if err := os.MkdirAll(buildDir, 0755); err != nil {
		return c.Fail("Unable to create build directory: %v", err)
	}

	if err := runIn(exec.CommandContext(ctx, "cmake", "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", sourceDir), buildDir); err != nil {
		return c.Fail("Error configuring cmake: %v", err)
	}

	if err := runIn(exec.CommandContext(ctx, "cmake", "--build", "."), buildDir); err != nil {
		return c.Fail("Error building repository: %v", err)
	}

	if err := compdb.ExtractCompilations(ctx, extractor, filepath.Join(buildDir, "compile_commands.json")); err != nil {
		return c.Fail("Error extracting repository: %v", err)
	}
	return subcommands.ExitSuccess
}

// cleanBuild removes dir and all files beneath it, logging an error if it fails.
func cleanBuild(dir string) {
	if err := os.RemoveAll(dir); err != nil {
		log.Printf("unable to remove build directory: %v", err)
	}
}

// runIn changes the cmd working directory to dir and calls Run. The cmd's
// stderr is forwarded to stderr.
func runIn(cmd *exec.Cmd, dir string) error {
	cmd.Dir = dir
	cmd.Stderr = os.Stderr
	log.Printf("Running: %q in %q", cmd, cmd.Dir)
	return cmd.Run()
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC. 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 expr

import (
	"encoding/binary"

	"github.com/google/nftables/binaryutil"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

type PayloadBase uint32
type PayloadCsumType uint32
type PayloadOperationType uint32

// Possible PayloadBase values.
const (
	PayloadBaseLLHeader        PayloadBase = unix.NFT_PAYLOAD_LL_HEADER
	PayloadBaseNetworkHeader   PayloadBase = unix.NFT_PAYLOAD_NETWORK_HEADER
	PayloadBaseTransportHeader PayloadBase = unix.NFT_PAYLOAD_TRANSPORT_HEADER
)

// Possible PayloadCsumType values.
const (
	CsumTypeNone PayloadCsumType = unix.NFT_PAYLOAD_CSUM_NONE
	CsumTypeInet PayloadCsumType = unix.NFT_PAYLOAD_CSUM_INET
)

// Possible PayloadOperationType values.
const (
	PayloadLoad PayloadOperationType = iota
	PayloadWrite
)

type Payload struct {
	OperationType  PayloadOperationType
	DestRegister   uint32
	SourceRegister uint32
	Base           PayloadBase
	Offset         uint32
	Len            uint32
	CsumType       PayloadCsumType
	CsumOffset     uint32
	CsumFlags      uint32
}

func (e *Payload) marshal() ([]byte, error) {

	var attrs []netlink.Attribute

	if e.OperationType == PayloadWrite {
		attrs = []netlink.Attribute{
			{Type: unix.NFTA_PAYLOAD_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
		}
	} else {
		attrs = []netlink.Attribute{
			{Type: unix.NFTA_PAYLOAD_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
		}
	}

	attrs = append(attrs,
		netlink.Attribute{Type: unix.NFTA_PAYLOAD_BASE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Base))},
		netlink.Attribute{Type: unix.NFTA_PAYLOAD_OFFSET, Data: binaryutil.BigEndian.PutUint32(e.Offset)},
		netlink.Attribute{Type: unix.NFTA_PAYLOAD_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
	)

	if e.CsumType > 0 {
		attrs = append(attrs,
			netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.CsumType))},
			netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_OFFSET, Data: binaryutil.BigEndian.PutUint32(uint32(e.CsumOffset))},
		)
		if e.CsumFlags > 0 {
			attrs = append(attrs,
				netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.CsumFlags)},
			)
		}
	}

	data, err := netlink.MarshalAttributes(attrs)

	if err != nil {
		return nil, err
	}
	return netlink.MarshalAttributes([]netlink.Attribute{
		{Type: unix.NFTA_EXPR_NAME, Data: []byte("payload\x00")},
		{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
	})
}

func (e *Payload) unmarshal(data []byte) error {
	ad, err := netlink.NewAttributeDecoder(data)
	if err != nil {
		return err
	}
	ad.ByteOrder = binary.BigEndian
	for ad.Next() {
		switch ad.Type() {
		case unix.NFTA_PAYLOAD_DREG:
			e.DestRegister = ad.Uint32()
		case unix.NFTA_PAYLOAD_SREG:
			e.SourceRegister = ad.Uint32()
		case unix.NFTA_PAYLOAD_BASE:
			e.Base = PayloadBase(ad.Uint32())
		case unix.NFTA_PAYLOAD_OFFSET:
			e.Offset = ad.Uint32()
		case unix.NFTA_PAYLOAD_LEN:
			e.Len = ad.Uint32()
		case unix.NFTA_PAYLOAD_CSUM_TYPE:
			e.CsumType = PayloadCsumType(ad.Uint32())
		case unix.NFTA_PAYLOAD_CSUM_OFFSET:
			e.CsumOffset = ad.Uint32()
		case unix.NFTA_PAYLOAD_CSUM_FLAGS:
			e.CsumFlags = ad.Uint32()
		}
	}
	return ad.Err()
}
<commit_msg>Fix payload unmarshall operation type.<commit_after>// Copyright 2018 Google LLC. 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 expr

import (
	"encoding/binary"

	"github.com/google/nftables/binaryutil"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

type PayloadBase uint32
type PayloadCsumType uint32
type PayloadOperationType uint32

// Possible PayloadBase values.
const (
	PayloadBaseLLHeader        PayloadBase = unix.NFT_PAYLOAD_LL_HEADER
	PayloadBaseNetworkHeader   PayloadBase = unix.NFT_PAYLOAD_NETWORK_HEADER
	PayloadBaseTransportHeader PayloadBase = unix.NFT_PAYLOAD_TRANSPORT_HEADER
)

// Possible PayloadCsumType values.
const (
	CsumTypeNone PayloadCsumType = unix.NFT_PAYLOAD_CSUM_NONE
	CsumTypeInet PayloadCsumType = unix.NFT_PAYLOAD_CSUM_INET
)

// Possible PayloadOperationType values.
const (
	PayloadLoad PayloadOperationType = iota
	PayloadWrite
)

type Payload struct {
	OperationType  PayloadOperationType
	DestRegister   uint32
	SourceRegister uint32
	Base           PayloadBase
	Offset         uint32
	Len            uint32
	CsumType       PayloadCsumType
	CsumOffset     uint32
	CsumFlags      uint32
}

func (e *Payload) marshal() ([]byte, error) {

	var attrs []netlink.Attribute

	if e.OperationType == PayloadWrite {
		attrs = []netlink.Attribute{
			{Type: unix.NFTA_PAYLOAD_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
		}
	} else {
		attrs = []netlink.Attribute{
			{Type: unix.NFTA_PAYLOAD_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
		}
	}

	attrs = append(attrs,
		netlink.Attribute{Type: unix.NFTA_PAYLOAD_BASE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Base))},
		netlink.Attribute{Type: unix.NFTA_PAYLOAD_OFFSET, Data: binaryutil.BigEndian.PutUint32(e.Offset)},
		netlink.Attribute{Type: unix.NFTA_PAYLOAD_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
	)

	if e.CsumType > 0 {
		attrs = append(attrs,
			netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.CsumType))},
			netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_OFFSET, Data: binaryutil.BigEndian.PutUint32(uint32(e.CsumOffset))},
		)
		if e.CsumFlags > 0 {
			attrs = append(attrs,
				netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.CsumFlags)},
			)
		}
	}

	data, err := netlink.MarshalAttributes(attrs)

	if err != nil {
		return nil, err
	}
	return netlink.MarshalAttributes([]netlink.Attribute{
		{Type: unix.NFTA_EXPR_NAME, Data: []byte("payload\x00")},
		{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
	})
}

func (e *Payload) unmarshal(data []byte) error {
	ad, err := netlink.NewAttributeDecoder(data)
	if err != nil {
		return err
	}
	ad.ByteOrder = binary.BigEndian
	for ad.Next() {
		switch ad.Type() {
		case unix.NFTA_PAYLOAD_DREG:
			e.DestRegister = ad.Uint32()
		case unix.NFTA_PAYLOAD_SREG:
			e.SourceRegister = ad.Uint32()
			e.OperationType = PayloadWrite
		case unix.NFTA_PAYLOAD_BASE:
			e.Base = PayloadBase(ad.Uint32())
		case unix.NFTA_PAYLOAD_OFFSET:
			e.Offset = ad.Uint32()
		case unix.NFTA_PAYLOAD_LEN:
			e.Len = ad.Uint32()
		case unix.NFTA_PAYLOAD_CSUM_TYPE:
			e.CsumType = PayloadCsumType(ad.Uint32())
		case unix.NFTA_PAYLOAD_CSUM_OFFSET:
			e.CsumOffset = ad.Uint32()
		case unix.NFTA_PAYLOAD_CSUM_FLAGS:
			e.CsumFlags = ad.Uint32()
		}
	}
	return ad.Err()
}
<|endoftext|>


<commit_before>package client

import (
	"context"

	"github.com/google/go-github/v28/github"
	"github.com/reviewdog/reviewdog/doghouse"
	"github.com/reviewdog/reviewdog/doghouse/server"
)

// GitHubClient is client which talks to GitHub directly instead of talking to doghouse server.
type GitHubClient struct {
	Client *github.Client
}

func (c *GitHubClient) Check(ctx context.Context, req *doghouse.CheckRequest) (*doghouse.CheckResponse, error) {
	checker := server.NewChecker(req, c.Client)
	return checker.Check(ctx)
}
<commit_msg>simplify code<commit_after>package client

import (
	"context"

	"github.com/google/go-github/v28/github"
	"github.com/reviewdog/reviewdog/doghouse"
	"github.com/reviewdog/reviewdog/doghouse/server"
)

// GitHubClient is client which talks to GitHub directly instead of talking to
// doghouse server.
type GitHubClient struct {
	Client *github.Client
}

func (c *GitHubClient) Check(ctx context.Context, req *doghouse.CheckRequest) (*doghouse.CheckResponse, error) {
	return server.NewChecker(req, c.Client).Check(ctx)
}
<|endoftext|>