<commit_before>package irckit

import (
	"errors"
	"html"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/nlopes/slack"
)

type SlackInfo struct {
	Token      string
	sc         *slack.Client
	rtm        *slack.RTM
	sinfo      *slack.Info
	susers     map[string]slack.User
	connected  bool
	inprogress bool
	sync.RWMutex
}

func (u *User) loginToSlack() (*slack.Client, error) {
	u.sc = slack.New(u.Token)
	u.rtm = u.sc.NewRTM()
	u.Lock()
	u.susers = make(map[string]slack.User)
	u.Unlock()
	go u.rtm.ManageConnection()
	//time.Sleep(time.Second * 2)
	u.sinfo = u.rtm.GetInfo()
	count := 0
	for u.sinfo == nil {
		time.Sleep(time.Millisecond * 500)
		logger.Debug("still waiting for sinfo")
		u.sinfo = u.rtm.GetInfo()
		count++
		if count == 20 {
			return nil, errors.New("couldn't connect in 10 seconds. Check your credentials")
		}
	}

	// we only know which server we are connecting to when we actually are connected.
	// disconnect if we're not allowed
	if len(u.MmInfo.Cfg.SlackSettings.Restrict) > 0 {
		ok := false
		for _, domain := range u.MmInfo.Cfg.SlackSettings.Restrict {
			if domain == u.sinfo.Team.Domain {
				ok = true
				break
			}
		}
		if !ok {
			u.rtm.Disconnect()
			return nil, errors.New("Not allowed to connect to " + u.sinfo.Team.Domain + " slack")
		}
	}
	// we only know which user we are when we actually are connected.
	// disconnect if we're not allowed
	if len(u.MmInfo.Cfg.SlackSettings.BlackListUser) > 0 {
		ok := false
		for _, user := range u.MmInfo.Cfg.SlackSettings.BlackListUser {
			if user == u.sinfo.User.Name {
				ok = true
				break
			}
		}
		if ok {
			u.rtm.Disconnect()
			return nil, errors.New("Not allowed to connect")
		}
	}

	go u.handleSlack()
	u.addSlackUsersToChannels()
	u.connected = true
	return u.sc, nil
}

func (u *User) logoutFromSlack() error {
	logger.Debug("calling logout from slack")
	err := u.rtm.Disconnect()
	if err != nil {
		logger.Debug("logoutfrom slack", err)
		return err
	}
	u.Srv.Logout(u)
	u.sc = nil
	logger.Info("logout succeeded")
	u.connected = false
	return nil
}

func (u *User) createSlackUser(slackuser *slack.User) *User {
	if slackuser == nil {
		return nil
	}
	if ghost, ok := u.Srv.HasUser(slackuser.Name); ok {
		return ghost
	}
	ghost := &User{Nick: slackuser.Name, User: slackuser.ID, Real: slackuser.RealName, Host: "host", Roles: "", channels: map[Channel]struct{}{}, DisplayName: slackuser.Profile.DisplayName}
	ghost.MmGhostUser = true
	u.Srv.Add(ghost)
	return ghost
}

func (u *User) addSlackUserToChannel(user *slack.User, channel string, channelId string) {
	if user == nil {
		return
	}
	ghost := u.createSlackUser(user)
	if ghost == nil {
		logger.Warnf("Cannot join %v into %s", user, channel)
		return
	}
	logger.Debugf("adding %s to %s (%s)", ghost.Nick, channel, channelId)
	ch := u.Srv.Channel(channelId)
	logger.Debugf("channel: %#v %#v", ch.String(), ch.ID())
	ch.Join(ghost)
}

func (u *User) addSlackUsersToChannels() {
	srv := u.Srv
	throttle := time.Tick(time.Millisecond * 100)
	logger.Debug("in addUsersToChannels()")
	// add all users, also who are not on channels
	ch := srv.Channel("&users")
	users, _ := u.sc.GetUsers()
	for _, mmuser := range users {
		// do not add our own nick
		if mmuser.ID == u.sinfo.User.ID {
			continue
		}
		u.createSlackUser(&mmuser)
		u.addSlackUserToChannel(&mmuser, "&users", "&users")
		u.Lock()
		u.susers[mmuser.ID] = mmuser
		u.Unlock()
	}
	ch.Join(u)

	channels := make(chan interface{}, 10)
	for i := 0; i < 10; i++ {
		go u.addSlackUserToChannelWorker(channels, throttle)
	}
	groups, _ := u.sc.GetGroups(true)
	mmchannels, _ := u.sc.GetChannels(true)
	for _, mmchannel := range mmchannels {
		if mmchannel.IsMember {
			logger.Debug("Adding channel", mmchannel)
			channels <- mmchannel
		}
	}
	for _, mmchannel := range groups {
		logger.Debug("Adding private channel", mmchannel)
		channels <- mmchannel
	}
	close(channels)
}

func (u *User) addSlackUserToChannelWorker(channels <-chan interface{}, throttle <-chan time.Time) {
	var ID, name string
	for {
		mmchannel, ok := <-channels
		if !ok {
			logger.Debug("Done adding user to channels")
			return
		}
		<-throttle
		switch mmchannel.(type) {
		case slack.Channel:
			ID = mmchannel.(slack.Channel).ID
			name = mmchannel.(slack.Channel).Name
			u.syncSlackChannel(ID, name)
		case slack.Group:
			ID = mmchannel.(slack.Group).ID
			name = mmchannel.(slack.Group).Name
			logger.Debugf("GROUP %#v", mmchannel.(slack.Group))
			u.syncSlackGroup(ID, name)

		}
		// exclude direct messages
		//var spoof func(string, string)
		//ch := u.Srv.Channel(mmchannel.ID)
		// post everything to the channel you haven't seen yet
	}
}

func (u *User) handleSlack() {
	for {
		/*
			if u.mc.WsQuit {
				logger.Debug("exiting handleWsMessage")
				return
			}
		*/
		logger.Debug("in handleSlack")
		for msg := range u.rtm.IncomingEvents {
			switch ev := msg.Data.(type) {
			case *slack.MessageEvent:
				u.handleSlackActionPost(ev)
			case *slack.DisconnectedEvent:
				logger.Debug("disconnected event received, we should reconnect now..")
				//return
			}
		}
	}
	/*
			logger.Debugf("MMUser WsReceiver: %#v", message.Raw)
			// check if we have the users/channels in our cache. If not update
			u.checkWsActionMessage(message.Raw, updateChannelsThrottle)
			switch message.Raw.Event {
			case model.WEBSOCKET_EVENT_POSTED:
				u.handleWsActionPost(message.Raw)
			case model.WEBSOCKET_EVENT_POST_EDITED:
				u.handleWsActionPost(message.Raw)
			case model.WEBSOCKET_EVENT_USER_REMOVED:
				u.handleWsActionUserRemoved(message.Raw)
			case model.WEBSOCKET_EVENT_USER_ADDED:
				u.handleWsActionUserAdded(message.Raw)
			}
		}
	*/
}

func (u *User) handleSlackActionPost(rmsg *slack.MessageEvent) {
	var ch Channel
	logger.Debugf("handleSlackActionPost() receiving msg %#v", rmsg)
	if len(rmsg.Attachments) > 0 {
		// skip messages we made ourselves
		if rmsg.Attachments[0].CallbackID == "matterircd" {
			return
		}
	}

	user, err := u.rtm.GetUserInfo(rmsg.User)
	if err != nil {
		if rmsg.BotID == "" {
			return
		}
	}

	// handle bot messages
	botname := ""
	if rmsg.User == "" && rmsg.BotID != "" {
		botname = rmsg.Username
		if botname == "" {
			bot, _ := u.rtm.GetBotInfo(rmsg.BotID)
			if bot.Name != "" {
				botname = bot.Name
			}
		}
	}

	// create new "ghost" user
	ghost := u.createSlackUser(user)

	spoofUsername := ""
	if user != nil {
		spoofUsername = user.ID
		if ghost != nil {
			spoofUsername = ghost.Nick
			if ghost.DisplayName != "" && ghost.DisplayName != ghost.Nick && u.MmInfo.Cfg.SlackSettings.UseDisplayName {
				spoofUsername = "|"
				//	spoofUsername = ghost.DisplayName
			}
		}
	}

	// if we have a botname, use it
	if botname != "" {
		spoofUsername = botname
	}

	msgs := strings.Split(rmsg.Text, "\n")
	// direct message

	ch = u.Srv.Channel(rmsg.Channel)

	if ghost != nil {
		// join if not in channel
		if !ch.HasUser(ghost) {
			ch.Join(ghost)
		}
	}

	for _, m := range msgs {
		// cleanup the message
		m = u.replaceMention(m)
		m = u.replaceVariable(m)
		m = u.replaceChannel(m)
		m = u.replaceURL(m)
		m = html.UnescapeString(m)

		// look in attachments if we have no text
		if m == "" {
			for _, attach := range rmsg.Attachments {
				if attach.Text != "" {
					m = attach.Text
				} else {
					m = attach.Fallback
				}
			}
		}

		// still no text, ignore this message
		if m == "" {
			continue
		}

		if strings.HasPrefix(rmsg.Channel, "D") {
			u.MsgSpoofUser(spoofUsername, m)
		} else {
			if ghost != nil && ghost.DisplayName != "" && ghost.DisplayName != ghost.Nick &&
				u.MmInfo.Cfg.SlackSettings.UseDisplayName {
				m = "<" + ghost.DisplayName + "> " + m
			}
			ch.SpoofMessage(spoofUsername, m)
		}
	}
}

// sync IRC with mattermost channel state
func (u *User) syncSlackChannel(id string, name string) {
	srv := u.Srv
	info, err := u.sc.GetChannelInfo(id)
	if err != nil {
		logger.Info(err)
	}

	for _, user := range info.Members {
		if u.sinfo.User.ID != user {
			//slackuser, _ := u.sc.GetUserInfo(user)
			slackuser := u.getSlackUser(user)
			if slackuser != nil {
				u.addSlackUserToChannel(slackuser, "#"+name, id)
			}
		}
	}

	ch := srv.Channel(id)
	ch.Topic(u, info.Topic.Value)
	if !ch.HasUser(u) {
		logger.Debugf("syncSlackchannel adding myself to %s (id: %s)", name, id)
		ch.Join(u)
	}
}

// sync IRC with mattermost channel state
func (u *User) syncSlackGroup(id string, name string) {
	srv := u.Srv
	info, err := u.sc.GetGroupInfo(id)
	if err != nil {
		logger.Info(err)
	}

	for _, user := range info.Members {
		if u.sinfo.User.ID != user {
			//slackuser, _ := u.sc.GetUserInfo(user)
			slackuser := u.getSlackUser(user)
			if slackuser != nil {
				u.addSlackUserToChannel(slackuser, "#"+name, id)
			}
		}
	}

	ch := srv.Channel(id)
	ch.Topic(u, info.Topic.Value)
	if !ch.HasUser(u) {
		logger.Debugf("syncSlackchannel adding myself to %s (id: %s)", name, id)
		ch.Join(u)
	}
}

// @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users
func (u *User) replaceMention(text string) string {
	results := regexp.MustCompile(`<@([a-zA-z0-9]+)>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, "<@"+r[1]+">", "@"+u.userName(r[1]), -1)
	}
	return text
}

// @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users
func (u *User) replaceChannel(text string) string {
	results := regexp.MustCompile(`<#[a-zA-Z0-9]+\|(.+?)>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, r[0], "#"+r[1], -1)
	}
	return text
}

// @see https://api.slack.com/docs/message-formatting#variables
func (u *User) replaceVariable(text string) string {
	results := regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		if r[2] != "" {
			text = strings.Replace(text, r[0], "@"+r[2], -1)
		} else {
			text = strings.Replace(text, r[0], "@"+r[1], -1)
		}
	}
	return text
}

// @see https://api.slack.com/docs/message-formatting#linking_to_urls
func (u *User) replaceURL(text string) string {
	results := regexp.MustCompile(`<(.*?)(\|.*?)?>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, r[0], r[1], -1)
	}
	return text
}

func (u *User) getSlackUser(name string) *slack.User {
	u.RLock()
	defer u.RUnlock()
	if user, ok := u.susers[name]; ok {
		return &user
	}
	return nil
}

func (u *User) userName(id string) string {
	u.RLock()
	defer u.RUnlock()
	// TODO dynamically update when new users are joining slack
	for _, us := range u.susers {
		if us.ID == id {
			if us.Profile.DisplayName != "" {
				return us.Profile.DisplayName
			}
			return us.Name
		}
	}
	if id == u.sinfo.User.ID {
		return u.sinfo.User.Name
	}
	return ""
}

func (u *User) isConnected() bool {
	return u.connected
}
<commit_msg>Implement JoinMpImOnTalk setting (slack)<commit_after>package irckit

import (
	"errors"
	"html"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/nlopes/slack"
)

type SlackInfo struct {
	Token      string
	sc         *slack.Client
	rtm        *slack.RTM
	sinfo      *slack.Info
	susers     map[string]slack.User
	connected  bool
	inprogress bool
	sync.RWMutex
}

func (u *User) loginToSlack() (*slack.Client, error) {
	u.sc = slack.New(u.Token)
	u.rtm = u.sc.NewRTM()
	u.Lock()
	u.susers = make(map[string]slack.User)
	u.Unlock()
	go u.rtm.ManageConnection()
	//time.Sleep(time.Second * 2)
	u.sinfo = u.rtm.GetInfo()
	count := 0
	for u.sinfo == nil {
		time.Sleep(time.Millisecond * 500)
		logger.Debug("still waiting for sinfo")
		u.sinfo = u.rtm.GetInfo()
		count++
		if count == 20 {
			return nil, errors.New("couldn't connect in 10 seconds. Check your credentials")
		}
	}

	// we only know which server we are connecting to when we actually are connected.
	// disconnect if we're not allowed
	if len(u.MmInfo.Cfg.SlackSettings.Restrict) > 0 {
		ok := false
		for _, domain := range u.MmInfo.Cfg.SlackSettings.Restrict {
			if domain == u.sinfo.Team.Domain {
				ok = true
				break
			}
		}
		if !ok {
			u.rtm.Disconnect()
			return nil, errors.New("Not allowed to connect to " + u.sinfo.Team.Domain + " slack")
		}
	}
	// we only know which user we are when we actually are connected.
	// disconnect if we're not allowed
	if len(u.MmInfo.Cfg.SlackSettings.BlackListUser) > 0 {
		ok := false
		for _, user := range u.MmInfo.Cfg.SlackSettings.BlackListUser {
			if user == u.sinfo.User.Name {
				ok = true
				break
			}
		}
		if ok {
			u.rtm.Disconnect()
			return nil, errors.New("Not allowed to connect")
		}
	}

	go u.handleSlack()
	u.addSlackUsersToChannels()
	u.connected = true
	return u.sc, nil
}

func (u *User) logoutFromSlack() error {
	logger.Debug("calling logout from slack")
	err := u.rtm.Disconnect()
	if err != nil {
		logger.Debug("logoutfrom slack", err)
		return err
	}
	u.Srv.Logout(u)
	u.sc = nil
	logger.Info("logout succeeded")
	u.connected = false
	return nil
}

func (u *User) createSlackUser(slackuser *slack.User) *User {
	if slackuser == nil {
		return nil
	}
	if ghost, ok := u.Srv.HasUser(slackuser.Name); ok {
		return ghost
	}
	ghost := &User{Nick: slackuser.Name, User: slackuser.ID, Real: slackuser.RealName, Host: "host", Roles: "", channels: map[Channel]struct{}{}, DisplayName: slackuser.Profile.DisplayName}
	ghost.MmGhostUser = true
	u.Srv.Add(ghost)
	return ghost
}

func (u *User) addSlackUserToChannel(user *slack.User, channel string, channelId string) {
	if user == nil {
		return
	}
	ghost := u.createSlackUser(user)
	if ghost == nil {
		logger.Warnf("Cannot join %v into %s", user, channel)
		return
	}
	logger.Debugf("adding %s to %s (%s)", ghost.Nick, channel, channelId)
	ch := u.Srv.Channel(channelId)
	logger.Debugf("channel: %#v %#v", ch.String(), ch.ID())
	ch.Join(ghost)
}

func (u *User) addSlackUsersToChannels() {
	srv := u.Srv
	throttle := time.Tick(time.Millisecond * 100)
	logger.Debug("in addUsersToChannels()")
	// add all users, also who are not on channels
	ch := srv.Channel("&users")
	users, _ := u.sc.GetUsers()
	for _, mmuser := range users {
		// do not add our own nick
		if mmuser.ID == u.sinfo.User.ID {
			continue
		}
		u.createSlackUser(&mmuser)
		u.addSlackUserToChannel(&mmuser, "&users", "&users")
		u.Lock()
		u.susers[mmuser.ID] = mmuser
		u.Unlock()
	}
	ch.Join(u)

	channels := make(chan interface{}, 10)
	for i := 0; i < 10; i++ {
		go u.addSlackUserToChannelWorker(channels, throttle)
	}
	groups, _ := u.sc.GetGroups(true)
	mmchannels, _ := u.sc.GetChannels(true)
	for _, mmchannel := range mmchannels {
		if mmchannel.IsMember {
			if mmchannel.IsMpIM && u.Cfg.SlackSettings.JoinMpImOnTalk {
				continue
			}
			logger.Debug("Adding channel", mmchannel)
			channels <- mmchannel
		}
	}
	for _, mmchannel := range groups {
		if mmchannel.IsMpIM && u.Cfg.SlackSettings.JoinMpImOnTalk {
			continue
		}
		logger.Debug("Adding private channel", mmchannel)
		channels <- mmchannel
	}
	close(channels)
}

func (u *User) addSlackUserToChannelWorker(channels <-chan interface{}, throttle <-chan time.Time) {
	var ID, name string
	for {
		mmchannel, ok := <-channels
		if !ok {
			logger.Debug("Done adding user to channels")
			return
		}
		<-throttle
		switch mmchannel.(type) {
		case slack.Channel:
			ID = mmchannel.(slack.Channel).ID
			name = mmchannel.(slack.Channel).Name
			u.syncSlackChannel(ID, name)
		case slack.Group:
			ID = mmchannel.(slack.Group).ID
			name = mmchannel.(slack.Group).Name
			logger.Debugf("GROUP %#v", mmchannel.(slack.Group))
			u.syncSlackGroup(ID, name)

		}
		// exclude direct messages
		//var spoof func(string, string)
		//ch := u.Srv.Channel(mmchannel.ID)
		// post everything to the channel you haven't seen yet
	}
}

func (u *User) handleSlack() {
	for {
		/*
			if u.mc.WsQuit {
				logger.Debug("exiting handleWsMessage")
				return
			}
		*/
		logger.Debug("in handleSlack")
		for msg := range u.rtm.IncomingEvents {
			switch ev := msg.Data.(type) {
			case *slack.MessageEvent:
				u.handleSlackActionPost(ev)
			case *slack.DisconnectedEvent:
				logger.Debug("disconnected event received, we should reconnect now..")
				//return
			}
		}
	}
	/*
			logger.Debugf("MMUser WsReceiver: %#v", message.Raw)
			// check if we have the users/channels in our cache. If not update
			u.checkWsActionMessage(message.Raw, updateChannelsThrottle)
			switch message.Raw.Event {
			case model.WEBSOCKET_EVENT_POSTED:
				u.handleWsActionPost(message.Raw)
			case model.WEBSOCKET_EVENT_POST_EDITED:
				u.handleWsActionPost(message.Raw)
			case model.WEBSOCKET_EVENT_USER_REMOVED:
				u.handleWsActionUserRemoved(message.Raw)
			case model.WEBSOCKET_EVENT_USER_ADDED:
				u.handleWsActionUserAdded(message.Raw)
			}
		}
	*/
}

func (u *User) handleSlackActionPost(rmsg *slack.MessageEvent) {
	var ch Channel
	logger.Debugf("handleSlackActionPost() receiving msg %#v", rmsg)
	if len(rmsg.Attachments) > 0 {
		// skip messages we made ourselves
		if rmsg.Attachments[0].CallbackID == "matterircd" {
			return
		}
	}

	user, err := u.rtm.GetUserInfo(rmsg.User)
	if err != nil {
		if rmsg.BotID == "" {
			return
		}
	}

	// handle bot messages
	botname := ""
	if rmsg.User == "" && rmsg.BotID != "" {
		botname = rmsg.Username
		if botname == "" {
			bot, _ := u.rtm.GetBotInfo(rmsg.BotID)
			if bot.Name != "" {
				botname = bot.Name
			}
		}
	}

	// create new "ghost" user
	ghost := u.createSlackUser(user)

	spoofUsername := ""
	if user != nil {
		spoofUsername = user.ID
		if ghost != nil {
			spoofUsername = ghost.Nick
			if ghost.DisplayName != "" && ghost.DisplayName != ghost.Nick && u.MmInfo.Cfg.SlackSettings.UseDisplayName {
				spoofUsername = "|"
				//	spoofUsername = ghost.DisplayName
			}
		}
	}

	// if we have a botname, use it
	if botname != "" {
		spoofUsername = botname
	}

	msgs := strings.Split(rmsg.Text, "\n")
	// direct message

	ch = u.Srv.Channel(rmsg.Channel)

	if ghost != nil {
		// join if not in channel
		if !ch.HasUser(ghost) {
			ch.Join(ghost)
		}
	}

	for _, m := range msgs {
		// cleanup the message
		m = u.replaceMention(m)
		m = u.replaceVariable(m)
		m = u.replaceChannel(m)
		m = u.replaceURL(m)
		m = html.UnescapeString(m)

		// look in attachments if we have no text
		if m == "" {
			for _, attach := range rmsg.Attachments {
				if attach.Text != "" {
					m = attach.Text
				} else {
					m = attach.Fallback
				}
			}
		}

		// still no text, ignore this message
		if m == "" {
			continue
		}

		if strings.HasPrefix(rmsg.Channel, "D") {
			u.MsgSpoofUser(spoofUsername, m)
		} else {
			if ghost != nil && ghost.DisplayName != "" && ghost.DisplayName != ghost.Nick &&
				u.MmInfo.Cfg.SlackSettings.UseDisplayName {
				m = "<" + ghost.DisplayName + "> " + m
			}
			ch.SpoofMessage(spoofUsername, m)
		}
	}
}

// sync IRC with mattermost channel state
func (u *User) syncSlackChannel(id string, name string) {
	srv := u.Srv
	info, err := u.sc.GetChannelInfo(id)
	if err != nil {
		logger.Info(err)
	}

	for _, user := range info.Members {
		if u.sinfo.User.ID != user {
			//slackuser, _ := u.sc.GetUserInfo(user)
			slackuser := u.getSlackUser(user)
			if slackuser != nil {
				u.addSlackUserToChannel(slackuser, "#"+name, id)
			}
		}
	}

	ch := srv.Channel(id)
	ch.Topic(u, info.Topic.Value)
	if !ch.HasUser(u) {
		logger.Debugf("syncSlackchannel adding myself to %s (id: %s)", name, id)
		ch.Join(u)
	}
}

// sync IRC with mattermost channel state
func (u *User) syncSlackGroup(id string, name string) {
	srv := u.Srv
	info, err := u.sc.GetGroupInfo(id)
	if err != nil {
		logger.Info(err)
	}

	for _, user := range info.Members {
		if u.sinfo.User.ID != user {
			//slackuser, _ := u.sc.GetUserInfo(user)
			slackuser := u.getSlackUser(user)
			if slackuser != nil {
				u.addSlackUserToChannel(slackuser, "#"+name, id)
			}
		}
	}

	ch := srv.Channel(id)
	ch.Topic(u, info.Topic.Value)
	if !ch.HasUser(u) {
		logger.Debugf("syncSlackchannel adding myself to %s (id: %s)", name, id)
		ch.Join(u)
	}
}

// @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users
func (u *User) replaceMention(text string) string {
	results := regexp.MustCompile(`<@([a-zA-z0-9]+)>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, "<@"+r[1]+">", "@"+u.userName(r[1]), -1)
	}
	return text
}

// @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users
func (u *User) replaceChannel(text string) string {
	results := regexp.MustCompile(`<#[a-zA-Z0-9]+\|(.+?)>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, r[0], "#"+r[1], -1)
	}
	return text
}

// @see https://api.slack.com/docs/message-formatting#variables
func (u *User) replaceVariable(text string) string {
	results := regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		if r[2] != "" {
			text = strings.Replace(text, r[0], "@"+r[2], -1)
		} else {
			text = strings.Replace(text, r[0], "@"+r[1], -1)
		}
	}
	return text
}

// @see https://api.slack.com/docs/message-formatting#linking_to_urls
func (u *User) replaceURL(text string) string {
	results := regexp.MustCompile(`<(.*?)(\|.*?)?>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, r[0], r[1], -1)
	}
	return text
}

func (u *User) getSlackUser(name string) *slack.User {
	u.RLock()
	defer u.RUnlock()
	if user, ok := u.susers[name]; ok {
		return &user
	}
	return nil
}

func (u *User) userName(id string) string {
	u.RLock()
	defer u.RUnlock()
	// TODO dynamically update when new users are joining slack
	for _, us := range u.susers {
		if us.ID == id {
			if us.Profile.DisplayName != "" {
				return us.Profile.DisplayName
			}
			return us.Name
		}
	}
	if id == u.sinfo.User.ID {
		return u.sinfo.User.Name
	}
	return ""
}

func (u *User) isConnected() bool {
	return u.connected
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"sort"
	"text/tabwriter"
)

const VERSION = `0.1.1`

var languages = []Language{
	Language{"Thrift", mExt(".thrift"), cComments},

	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Scala", mExt(".scala"), cComments},
	Language{"Java", mExt(".java"), cComments},

	Language{"YACC", mExt(".y"), cComments},
	Language{"Lex", mExt(".l"), cComments},

	Language{"SQL", mExt(".sql"), sqlComments},

	Language{"Haskell", mExt(".hs", ".lhs"), hsComments},

	Language{"Perl", mExt(".pl", ".pm"), shComments},
	Language{"PHP", mExt(".php"), cComments},

	Language{"Shell", mExt(".sh"), shComments},
	Language{"Bash", mExt(".bash"), shComments},

	Language{"Ruby", mExt(".rb"), shComments},
	Language{"Python", mExt(".py"), pyComments},
	Language{"Assembly", mExt(".asm", ".s"), semiComments},
	Language{"Lisp", mExt(".lsp", ".lisp"), semiComments},
	Language{"Scheme", mExt(".scm", ".scheme"), semiComments},

	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"CMake", mName("CMakeLists.txt"), shComments},
	Language{"Jam", mName("Jamfile", "Jamrules"), shComments},

	Language{"Markdown", mExt(".md"), noComments},

	Language{"HAML", mExt(".haml"), noComments},
	Language{"SASS", mExt(".sass"), cssComments},
	Language{"SCSS", mExt(".scss"), cssComments},

	Language{"HTML", mExt(".htm", ".html", ".xhtml"), xmlComments},
	Language{"XML", mExt(".xml"), xmlComments},
	Language{"CSS", mExt(".css"), cssComments},
	Language{"JavaScript", mExt(".js"), cComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments = Commenter{"\000", "\000", "\000", false}
	xmlComments = Commenter{"\000", `<!--`, `-->`, false}
	cComments  = Commenter{`//`, `/*`, `*/`, false}
	cssComments  = Commenter{"\000", `/*`, `*/`, false}
	shComments = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
	hsComments  = Commenter{`--`, `{-`, `-}`, true}
	sqlComments  = Commenter{`--`, "\000", "\000", false}
	pyComments = Commenter{`#`, `"""`, `"""`, false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

// TODO work properly with unicode
func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if inComment == 0 && b == lc[lp] {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else { lp = 0 }
		if !inLComment && b == sc[sp] {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else { sp = 0 }
		if !inLComment && inComment > 0 && b == ec[ep] {
			ep++
			if ep == len(ec) {
				if inComment > 0 { inComment-- }
				ep = 0
			}
		} else { ep = 0 }

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// BUG(srl): lines with comment don't count towards code
		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if inComment > 0 || inLComment {
				inLComment = false
				s.CommentLines++
			} else if blank {
				s.BlankLines++
			} else { s.CodeLines++ }
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFile(fname string) {
	var l Language
	ok := false
	for _, lang := range languages {
		if lang.Match(fname) {
			ok = true
			l = lang
			break
		}
	}
	if !ok {
		return // ignore this file
	}
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

type LData []LResult

func (d LData) Len() int { return len(d) }

func (d LData) Less(i, j int) bool {
	if d[i].CodeLines == d[j].CodeLines {
		return d[i].Name > d[j].Name
	}
	return d[i].CodeLines > d[j].CodeLines
}

func (d LData) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

type LResult struct {
	Name string
	FileCount int
	CodeLines int
	CommentLines int
	BlankLines int
	TotalLines int
}

func (r *LResult) Add(a LResult) {
	r.FileCount += a.FileCount
	r.CodeLines += a.CodeLines
	r.CommentLines += a.CommentLines
	r.BlankLines += a.BlankLines
	r.TotalLines += a.TotalLines
}

func printJSON() {
	bs, err := json.MarshalIndent(info, "", "  ")
	if err != nil { panic(err) }
	fmt.Println(string(bs))
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	d := LData([]LResult{})
	total := &LResult{}
	total.Name = "Total"
	for n, i := range info {
		r := LResult{
			n,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines,
		}
		d = append(d, r)
		total.Add(r)
	}
	d = append(d, *total)
	sort.Sort(d)
	//d[0].Name = "Total"
	for _, i := range d {
		fmt.Fprintf(
			w,
			"%s\t%d\t%d\t%d\t%d\t%d\t\n",
			i.Name,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines)
	}

	w.Flush()
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	useJson = flag.Bool("json", false, "JSON-format output")
	version = flag.Bool("V", false, "display version info and exit")
)

func main() {
	flag.Parse()
	if *version {
		fmt.Printf("sloc %s\n", VERSION)
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}

	if *useJson {
		printJSON()
	} else {
		printInfo()
	}
}
<commit_msg>Updating version<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"sort"
	"text/tabwriter"
)

const VERSION = `0.1.2`

var languages = []Language{
	Language{"Thrift", mExt(".thrift"), cComments},

	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Scala", mExt(".scala"), cComments},
	Language{"Java", mExt(".java"), cComments},

	Language{"YACC", mExt(".y"), cComments},
	Language{"Lex", mExt(".l"), cComments},

	Language{"SQL", mExt(".sql"), sqlComments},

	Language{"Haskell", mExt(".hs", ".lhs"), hsComments},

	Language{"Perl", mExt(".pl", ".pm"), shComments},
	Language{"PHP", mExt(".php"), cComments},

	Language{"Shell", mExt(".sh"), shComments},
	Language{"Bash", mExt(".bash"), shComments},

	Language{"Ruby", mExt(".rb"), shComments},
	Language{"Python", mExt(".py"), pyComments},
	Language{"Assembly", mExt(".asm", ".s"), semiComments},
	Language{"Lisp", mExt(".lsp", ".lisp"), semiComments},
	Language{"Scheme", mExt(".scm", ".scheme"), semiComments},

	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"CMake", mName("CMakeLists.txt"), shComments},
	Language{"Jam", mName("Jamfile", "Jamrules"), shComments},

	Language{"Markdown", mExt(".md"), noComments},

	Language{"HAML", mExt(".haml"), noComments},
	Language{"SASS", mExt(".sass"), cssComments},
	Language{"SCSS", mExt(".scss"), cssComments},

	Language{"HTML", mExt(".htm", ".html", ".xhtml"), xmlComments},
	Language{"XML", mExt(".xml"), xmlComments},
	Language{"CSS", mExt(".css"), cssComments},
	Language{"JavaScript", mExt(".js"), cComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments = Commenter{"\000", "\000", "\000", false}
	xmlComments = Commenter{"\000", `<!--`, `-->`, false}
	cComments  = Commenter{`//`, `/*`, `*/`, false}
	cssComments  = Commenter{"\000", `/*`, `*/`, false}
	shComments = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
	hsComments  = Commenter{`--`, `{-`, `-}`, true}
	sqlComments  = Commenter{`--`, "\000", "\000", false}
	pyComments = Commenter{`#`, `"""`, `"""`, false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

// TODO work properly with unicode
func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if inComment == 0 && b == lc[lp] {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else { lp = 0 }
		if !inLComment && b == sc[sp] {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else { sp = 0 }
		if !inLComment && inComment > 0 && b == ec[ep] {
			ep++
			if ep == len(ec) {
				if inComment > 0 { inComment-- }
				ep = 0
			}
		} else { ep = 0 }

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// BUG(srl): lines with comment don't count towards code
		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if inComment > 0 || inLComment {
				inLComment = false
				s.CommentLines++
			} else if blank {
				s.BlankLines++
			} else { s.CodeLines++ }
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFile(fname string) {
	var l Language
	ok := false
	for _, lang := range languages {
		if lang.Match(fname) {
			ok = true
			l = lang
			break
		}
	}
	if !ok {
		return // ignore this file
	}
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

type LData []LResult

func (d LData) Len() int { return len(d) }

func (d LData) Less(i, j int) bool {
	if d[i].CodeLines == d[j].CodeLines {
		return d[i].Name > d[j].Name
	}
	return d[i].CodeLines > d[j].CodeLines
}

func (d LData) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

type LResult struct {
	Name string
	FileCount int
	CodeLines int
	CommentLines int
	BlankLines int
	TotalLines int
}

func (r *LResult) Add(a LResult) {
	r.FileCount += a.FileCount
	r.CodeLines += a.CodeLines
	r.CommentLines += a.CommentLines
	r.BlankLines += a.BlankLines
	r.TotalLines += a.TotalLines
}

func printJSON() {
	bs, err := json.MarshalIndent(info, "", "  ")
	if err != nil { panic(err) }
	fmt.Println(string(bs))
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	d := LData([]LResult{})
	total := &LResult{}
	total.Name = "Total"
	for n, i := range info {
		r := LResult{
			n,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines,
		}
		d = append(d, r)
		total.Add(r)
	}
	d = append(d, *total)
	sort.Sort(d)
	//d[0].Name = "Total"
	for _, i := range d {
		fmt.Fprintf(
			w,
			"%s\t%d\t%d\t%d\t%d\t%d\t\n",
			i.Name,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines)
	}

	w.Flush()
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	useJson = flag.Bool("json", false, "JSON-format output")
	version = flag.Bool("V", false, "display version info and exit")
)

func main() {
	flag.Parse()
	if *version {
		fmt.Printf("sloc %s\n", VERSION)
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}

	if *useJson {
		printJSON()
	} else {
		printInfo()
	}
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "github.com/satori/go.uuid"
)

func main() {
    // Creating UUID Version 1
    u1 := uuid.NewV1()
    fmt.Printf("UUIDv1: %s\n", u1)

    // Creating UUID Version 2
    u2 := uuid.NewV2(0)
    fmt.Printf("UUIDv2: %s\n", u2)

    // Creating UUID Version 3
    u3 := uuid.NewV3(u2, "MD5")
    fmt.Printf("UUIDv3: %s\n", u3)

    // Creating UUID Version 4
    u4 := uuid.NewV4()
    fmt.Printf("UUIDv4: %s\n", u4)

    // Creating UUID Version 5
    u5 := uuid.NewV5(u4, "SHA-1")
    fmt.Printf("UUIDv5: %s\n", u5)

    // Parsing UUID from string input
    uX, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
    if err != nil {
        fmt.Printf("Something gone wrong: %s\n", err)
    }
    fmt.Printf("Successfully parsed: %s\n", uX)
}

<commit_msg>Add comments with uuid's to sample<commit_after>package main

import (
	"fmt"
	"github.com/satori/go.uuid"
)

func main() {

	// Creating UUID Version 1
	// UUIDv1: 81c7d93d-f581-11e5-ba55-8c89a5c1a947
	u1 := uuid.NewV1()
	fmt.Printf("UUIDv1: %s\n", u1)

	// Creating UUID Version 2
	// UUIDv2: 000003e8-f581-21e5-ba00-8c89a5c1a947
	u2 := uuid.NewV2(0)
	fmt.Printf("UUIDv2: %s\n", u2)

	// Creating UUID Version 3
	// UUIDv3: a00172db-706e-3ac5-97cf-50d25b514754
	u3 := uuid.NewV3(u2, "MD5")
	fmt.Printf("UUIDv3: %s\n", u3)

	// Creating UUID Version 4
	// UUIDv4: a0ef3801-651a-44d7-a6f5-65c26bf77d1d
	u4 := uuid.NewV4()
	fmt.Printf("UUIDv4: %s\n", u4)

	// Creating UUID Version 5
	// UUIDv5: bf50b865-0487-5022-ba8b-6fb7272ff487
	u5 := uuid.NewV5(u4, "SHA-1")
	fmt.Printf("UUIDv5: %s\n", u5)

	// Parsing UUID from string input
	uX, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
	if err != nil {
		fmt.Printf("Something gone wrong: %s\n", err)
	}
	fmt.Printf("Successfully parsed: %s\n", uX)
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "io/ioutil"
  "github.com/hyperledger/fabric/protos/utils"
)

func main(){
  fmt.Println("Use codes to verify fabric")
  blockFile := "/root/go/src/github.com/hyperledger/fabric/examples/e2e_cli/channel-artifacts/genesis.block"
  data, err := ioutil.ReadFile(blockFile)
  if err != nil {
	fmt.Errorf("Could not read block %s", blockFile)
  }
  block, err := utils.GetBlockFromBlockBytes(data)
  if err != nil {
    fmt.Errorf("Could not read block %s", err)
  }
  fmt.Println(block.String())
}
<commit_msg>Update main.go<commit_after>package main

import (
  "fmt"
  "io/ioutil"
  "github.com/hyperledger/fabric/protos/utils"
)

func main(){
  fmt.Println("Use codes to verify fabric")
  blockFile := "/root/go/src/github.com/hyperledger/fabric/examples/e2e_cli/channel-artifacts/genesis.block"
  data, err := ioutil.ReadFile(blockFile)
  if err != nil {
	fmt.Errorf("Could not read block %s", blockFile)
  }
  block, err := utils.GetBlockFromBlockBytes(data)
  if err != nil {
    fmt.Errorf("Could not read block %s", err)
  }
  //fmt.Println(block.String())
  fmt.Println(utils.GetChainIDFromBlock(block))
}
<|endoftext|>


<commit_before>package models_test

import (
	"time"

	"github.com/cloudfoundry-incubator/notifications/db"
	"github.com/cloudfoundry-incubator/notifications/testing/helpers"
	"github.com/cloudfoundry-incubator/notifications/v1/models"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("TemplatesRepo", func() {
	var repo models.TemplatesRepo
	var conn db.ConnectionInterface
	var template models.Template
	var createdAt time.Time

	BeforeEach(func() {
		repo = models.NewTemplatesRepo()
		database := db.NewDatabase(sqlDB, db.Config{})
		helpers.TruncateTables(database)
		conn = database.Connection()
		createdAt = time.Now().Add(-1 * time.Hour).Truncate(1 * time.Second).UTC()

		template = models.Template{
			ID:        "raptor_template",
			Name:      "Raptors On The Run",
			Text:      "run and hide",
			HTML:      "
containment unit breached!
",
			CreatedAt: createdAt,
		}

		conn.Insert(&template)
	})

	Context("#FindByID", func() {
		Context("the template is in the database", func() {
			It("returns the template when it is found", func() {
				raptorTemplate, err := repo.FindByID(conn, "raptor_template")

				Expect(err).ToNot(HaveOccurred())
				Expect(raptorTemplate.ID).To(Equal("raptor_template"))
				Expect(raptorTemplate.Name).To(Equal("Raptors On The Run"))
				Expect(raptorTemplate.Text).To(Equal("run and hide"))
				Expect(raptorTemplate.HTML).To(Equal("
containment unit breached!
"))
			})
		})

		Context("the template is not in the database", func() {
			It("returns a record not found error", func() {
				sillyTemplate, err := repo.FindByID(conn, "silly_template")

				Expect(sillyTemplate).To(Equal(models.Template{}))
				Expect(err).To(HaveOccurred())
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))
			})
		})
	})

	Describe("#Create", func() {
		It("inserts a template into the database", func() {
			newTemplate := models.Template{
				Name:    "A Nice Template",
				Subject: "Kind Words",
				Text:    "Some kind of compliment.",
				HTML:    "
Genuine Smile
",
			}

			createdTemplate, err := repo.Create(conn, newTemplate)
			Expect(err).ToNot(HaveOccurred())

			foundTemplate, err := repo.FindByID(conn, createdTemplate.ID)
			if err != nil {
				panic(err)
			}

			regularExpression := `^[[:xdigit:]]{8}\-[[:xdigit:]]{4}\-[[:xdigit:]]{4}\-[[:xdigit:]]{4}\-[[:xdigit:]]{12}$`
			Expect(foundTemplate.ID).To(MatchRegexp(regularExpression))
			Expect(foundTemplate.ID).To(Equal(createdTemplate.ID))
			Expect(foundTemplate.Name).To(Equal(newTemplate.Name))
			Expect(foundTemplate.Subject).To(Equal(newTemplate.Subject))
			Expect(foundTemplate.Text).To(Equal(newTemplate.Text))
			Expect(foundTemplate.HTML).To(Equal(newTemplate.HTML))
			Expect(foundTemplate.CreatedAt).To(BeTemporally("~", time.Now().UTC(), 1*time.Second))
			Expect(foundTemplate.UpdatedAt).To(BeTemporally("~", time.Now().UTC(), 1*time.Second))
		})
	})

	Describe("Update", func() {
		var aNewTemplate models.Template

		BeforeEach(func() {
			aNewTemplate = models.Template{
				Name:     "a brand new name",
				Subject:  "Some new subject",
				Text:     "some newer text",
				HTML:     "
new HTML
",
				Metadata: "{\"cloudy\": true}",
			}
		})

		Context("the template exists in the database", func() {
			It("updates a template currently in the database", func() {
				_, err := repo.Update(conn, template.ID, aNewTemplate)
				Expect(err).ToNot(HaveOccurred())

				foundTemplate, err := repo.FindByID(conn, template.ID)
				if err != nil {
					panic(err)
				}

				Expect(foundTemplate.Name).To(Equal(aNewTemplate.Name))
				Expect(foundTemplate.Subject).To(Equal(aNewTemplate.Subject))
				Expect(foundTemplate.Text).To(Equal(aNewTemplate.Text))
				Expect(foundTemplate.HTML).To(Equal(aNewTemplate.HTML))
				Expect(foundTemplate.Metadata).To(Equal(aNewTemplate.Metadata))
				Expect(foundTemplate.CreatedAt).To(Equal(createdAt))
				Expect(foundTemplate.UpdatedAt).ToNot(Equal(createdAt))
				Expect(foundTemplate.UpdatedAt).To(BeTemporally(">", createdAt))
				Expect(foundTemplate.Overridden).To(BeTrue())
			})
		})

		Context("the template does not exist in the database", func() {
			It("bubbles up the error", func() {
				_, err := repo.Update(conn, "a-bad-id", aNewTemplate)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError(models.TemplateFindError{Message: "Template a-bad-id not found"}))
			})
		})
	})

	Describe("#ListIDsAndNames", func() {
		Context("there are templates in the database", func() {
			It("returns a list of templates - ID and Name only", func() {
				secondTemplate := models.Template{
					ID:        "star_template",
					Name:      "Shooting Stars",
					Text:      "pretty",
					HTML:      "
Awe
",
					CreatedAt: createdAt,
				}

				conn.Insert(&secondTemplate)

				expectedMetadata := []models.Template{
					{
						ID:   "raptor_template",
						Name: "Raptors On The Run",
					},
					{
						ID:   "star_template",
						Name: "Shooting Stars",
					},
				}
				templatesMetadata, err := repo.ListIDsAndNames(conn)

				Expect(err).ToNot(HaveOccurred())
				Expect(templatesMetadata).To(Equal(expectedMetadata))
				Expect(templatesMetadata[0].Text).To(BeEmpty())
				Expect(templatesMetadata[0].HTML).To(BeEmpty())
				Expect(templatesMetadata[0].Subject).To(BeEmpty())
			})
		})
	})

	Describe("#Destroy", func() {
		Context("the template exists in the database", func() {
			It("deletes the template by templateID", func() {
				_, err := repo.FindByID(conn, template.ID)
				if err != nil {
					panic(err)
				}

				err = repo.Destroy(conn, template.ID)
				Expect(err).ToNot(HaveOccurred())

				_, err = repo.FindByID(conn, template.ID)
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))
			})
		})

		Context("the template does not exist in the database", func() {
			It("returns an RecordNotFoundError", func() {
				err := repo.Destroy(conn, "knockknock")
				Expect(err).To(HaveOccurred())
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))

				_, err = repo.FindByID(conn, "knockknock")
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))
			})
		})
	})
})
<commit_msg>Cares a little bit less about how accurate time is<commit_after>package models_test

import (
	"time"

	"github.com/cloudfoundry-incubator/notifications/db"
	"github.com/cloudfoundry-incubator/notifications/testing/helpers"
	"github.com/cloudfoundry-incubator/notifications/v1/models"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("TemplatesRepo", func() {
	var repo models.TemplatesRepo
	var conn db.ConnectionInterface
	var template models.Template
	var createdAt time.Time

	BeforeEach(func() {
		repo = models.NewTemplatesRepo()
		database := db.NewDatabase(sqlDB, db.Config{})
		helpers.TruncateTables(database)
		conn = database.Connection()
		createdAt = time.Now().Add(-1 * time.Hour).Truncate(1 * time.Second).UTC()

		template = models.Template{
			ID:        "raptor_template",
			Name:      "Raptors On The Run",
			Text:      "run and hide",
			HTML:      "
containment unit breached!
",
			CreatedAt: createdAt,
		}

		conn.Insert(&template)
	})

	Context("#FindByID", func() {
		Context("the template is in the database", func() {
			It("returns the template when it is found", func() {
				raptorTemplate, err := repo.FindByID(conn, "raptor_template")

				Expect(err).ToNot(HaveOccurred())
				Expect(raptorTemplate.ID).To(Equal("raptor_template"))
				Expect(raptorTemplate.Name).To(Equal("Raptors On The Run"))
				Expect(raptorTemplate.Text).To(Equal("run and hide"))
				Expect(raptorTemplate.HTML).To(Equal("
containment unit breached!
"))
			})
		})

		Context("the template is not in the database", func() {
			It("returns a record not found error", func() {
				sillyTemplate, err := repo.FindByID(conn, "silly_template")

				Expect(sillyTemplate).To(Equal(models.Template{}))
				Expect(err).To(HaveOccurred())
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))
			})
		})
	})

	Describe("#Create", func() {
		It("inserts a template into the database", func() {
			newTemplate := models.Template{
				Name:    "A Nice Template",
				Subject: "Kind Words",
				Text:    "Some kind of compliment.",
				HTML:    "
Genuine Smile
",
			}

			createdTemplate, err := repo.Create(conn, newTemplate)
			Expect(err).ToNot(HaveOccurred())

			foundTemplate, err := repo.FindByID(conn, createdTemplate.ID)
			if err != nil {
				panic(err)
			}

			regularExpression := `^[[:xdigit:]]{8}\-[[:xdigit:]]{4}\-[[:xdigit:]]{4}\-[[:xdigit:]]{4}\-[[:xdigit:]]{12}$`
			Expect(foundTemplate.ID).To(MatchRegexp(regularExpression))
			Expect(foundTemplate.ID).To(Equal(createdTemplate.ID))
			Expect(foundTemplate.Name).To(Equal(newTemplate.Name))
			Expect(foundTemplate.Subject).To(Equal(newTemplate.Subject))
			Expect(foundTemplate.Text).To(Equal(newTemplate.Text))
			Expect(foundTemplate.HTML).To(Equal(newTemplate.HTML))
			Expect(foundTemplate.CreatedAt).To(BeTemporally("~", time.Now().UTC(), 2*time.Second))
			Expect(foundTemplate.UpdatedAt).To(BeTemporally("~", time.Now().UTC(), 2*time.Second))
		})
	})

	Describe("Update", func() {
		var aNewTemplate models.Template

		BeforeEach(func() {
			aNewTemplate = models.Template{
				Name:     "a brand new name",
				Subject:  "Some new subject",
				Text:     "some newer text",
				HTML:     "
new HTML
",
				Metadata: "{\"cloudy\": true}",
			}
		})

		Context("the template exists in the database", func() {
			It("updates a template currently in the database", func() {
				_, err := repo.Update(conn, template.ID, aNewTemplate)
				Expect(err).ToNot(HaveOccurred())

				foundTemplate, err := repo.FindByID(conn, template.ID)
				if err != nil {
					panic(err)
				}

				Expect(foundTemplate.Name).To(Equal(aNewTemplate.Name))
				Expect(foundTemplate.Subject).To(Equal(aNewTemplate.Subject))
				Expect(foundTemplate.Text).To(Equal(aNewTemplate.Text))
				Expect(foundTemplate.HTML).To(Equal(aNewTemplate.HTML))
				Expect(foundTemplate.Metadata).To(Equal(aNewTemplate.Metadata))
				Expect(foundTemplate.CreatedAt).To(Equal(createdAt))
				Expect(foundTemplate.UpdatedAt).ToNot(Equal(createdAt))
				Expect(foundTemplate.UpdatedAt).To(BeTemporally(">", createdAt))
				Expect(foundTemplate.Overridden).To(BeTrue())
			})
		})

		Context("the template does not exist in the database", func() {
			It("bubbles up the error", func() {
				_, err := repo.Update(conn, "a-bad-id", aNewTemplate)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError(models.TemplateFindError{Message: "Template a-bad-id not found"}))
			})
		})
	})

	Describe("#ListIDsAndNames", func() {
		Context("there are templates in the database", func() {
			It("returns a list of templates - ID and Name only", func() {
				secondTemplate := models.Template{
					ID:        "star_template",
					Name:      "Shooting Stars",
					Text:      "pretty",
					HTML:      "
Awe
",
					CreatedAt: createdAt,
				}

				conn.Insert(&secondTemplate)

				expectedMetadata := []models.Template{
					{
						ID:   "raptor_template",
						Name: "Raptors On The Run",
					},
					{
						ID:   "star_template",
						Name: "Shooting Stars",
					},
				}
				templatesMetadata, err := repo.ListIDsAndNames(conn)

				Expect(err).ToNot(HaveOccurred())
				Expect(templatesMetadata).To(Equal(expectedMetadata))
				Expect(templatesMetadata[0].Text).To(BeEmpty())
				Expect(templatesMetadata[0].HTML).To(BeEmpty())
				Expect(templatesMetadata[0].Subject).To(BeEmpty())
			})
		})
	})

	Describe("#Destroy", func() {
		Context("the template exists in the database", func() {
			It("deletes the template by templateID", func() {
				_, err := repo.FindByID(conn, template.ID)
				if err != nil {
					panic(err)
				}

				err = repo.Destroy(conn, template.ID)
				Expect(err).ToNot(HaveOccurred())

				_, err = repo.FindByID(conn, template.ID)
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))
			})
		})

		Context("the template does not exist in the database", func() {
			It("returns an RecordNotFoundError", func() {
				err := repo.Destroy(conn, "knockknock")
				Expect(err).To(HaveOccurred())
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))

				_, err = repo.FindByID(conn, "knockknock")
				Expect(err).To(BeAssignableToTypeOf(models.RecordNotFoundError("")))
			})
		})
	})
})
<|endoftext|>


<commit_before>// Copyright (c) 2016 by António Meireles  <antonio.meireles@reformi.st>.
//
// 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 session

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/TheNewNormal/corectl/components/target/coreos"
	"github.com/TheNewNormal/corectl/release"
	"github.com/bugsnag/osext"
	"github.com/helm/helm/log"
	"github.com/spf13/viper"
)

var (
	// Caller ...
	Caller               *Context
	ErrServerUnreachable = fmt.Errorf("Failed to connect to server\n" +
		"Please check your connection settings and ensure that 'corectld' " +
		"is running.\n")
)

// Network ...
type Network struct {
	Address string
	Mask    string
}

// Context ...
type Context struct {
	Privileged    bool          `json:"-"`
	Meta          *release.Info `json:"-"`
	CmdLine       *viper.Viper  `json:"-"`
	ServerAddress string
	*user.User    `json:"User"`
	*Network      `json:"Network"`
}

// New session context
func New() (ctx *Context, err error) {
	var (
		usr                 *user.User
		isSuperUser         bool
		netMask, netAddress []byte
	)

	// viper & cobra
	rawArgs := viper.New()
	rawArgs.SetEnvPrefix("COREOS")
	rawArgs.AutomaticEnv()
	euid := os.Getuid()

	if euid == 0 {
		usr = nil
		isSuperUser = true
	} else if usr, err = user.Current(); err != nil {
		return
	}

	return &Context{
		isSuperUser,
		&release.Info{
			release.Version,
			time.Now(),
			os.Getpid(),
			release.BuildDate,
			runtime.Version(),
			runtime.GOOS,
			runtime.GOARCH,
		},
		rawArgs,
		"127.0.0.1:2511",
		usr,
		&Network{
			strings.TrimSpace(string(netAddress)),
			strings.TrimSpace(string(netMask)),
		},
	}, err
}

// Base IP
func (n *Network) Base() string {
	return net.ParseIP(n.Address).Mask(
		net.IPMask(net.ParseIP(n.Mask).To4())).String()
}

// Debug ...
func (ctx *Context) Debug() bool {
	return ctx.CmdLine.GetBool("debug")
}

// JSON ...
func (ctx *Context) JSON() bool {
	return ctx.CmdLine.GetBool("json")
}

// ConfigDir ...
func (ctx *Context) ConfigDir() string {
	return path.Join(ctx.HomeDir, "/.coreos/")
}

// ImageStore ...
func (ctx *Context) ImageStore() string {
	return path.Join(ctx.ConfigDir(), "/images/")
}

// RunDir ...
func (ctx *Context) RunDir() string {
	return path.Join(ctx.ConfigDir(), "/running/")
}

// TmpDir ...
func (ctx *Context) TmpDir() string {
	return path.Join(ctx.ConfigDir(), "/tmp/")
}

// EtcDir ...
func (ctx *Context) EtcDir() string {
	return path.Join(ctx.ConfigDir(), "/embedded.etcd/")
}

// NormalizeOnDiskLayout ...
func (ctx *Context) NormalizeOnDiskLayout() (err error) {
	// first run
	for _, i := range coreos.Channels {
		if err =
			os.MkdirAll(path.Join(ctx.ImageStore(), i),
				0644); err != nil {
			return
		}
	}
	for _, i := range []string{ctx.RunDir(), ctx.TmpDir(), ctx.EtcDir()} {
		if err = os.MkdirAll(i, 0644); err != nil {
			return
		}
	}
	// usually image updates
	if !ctx.Privileged {
		return
	}
	u, _ := strconv.Atoi(ctx.Uid)
	g, _ := strconv.Atoi(ctx.Gid)

	do := func(p string,
		_ os.FileInfo, _ error) error {
		tty := path.Base(p)
		if tty == "tty" {
			return os.Remove(p)
		}
		return os.Chown(p, u, g)
	}
	return filepath.Walk(ctx.ConfigDir(), do)
}

func (ctx *Context) SetNetworkContext() (err error) {
	var (
		netMask, netAddress []byte
		cmdL                = []string{
			"defaults", "read",
			"/Library/Preferences/SystemConfiguration/com.apple.vmnet.plist",
		}
	)
	if netAddress, err = exec.Command(cmdL[0],
		append(cmdL[1:], "Shared_Net_Address")...).Output(); err != nil {
		log.Warn("%v \"%v %v %v\" %v",
			"unable to run", cmdL[0], cmdL[1], cmdL[2], "Shared_Net_Address")
		return
	}

	if netMask, err = exec.Command(cmdL[0],
		append(cmdL[1:], "Shared_Net_Mask")...).Output(); err != nil {
		log.Warn("%v \"%v %v %v\" %v",
			"unable to run", cmdL[0], cmdL[1], cmdL[2], "Shared_Net_Mask")
		return
	}
	ctx.Network.Address = strings.TrimSpace(string(netAddress))
	ctx.Network.Mask = strings.TrimSpace(string(netMask))
	return
}
func Executable() string {
	s, _ := osext.Executable()
	return s
}

func AppName() string {
	s, _ := osext.Executable()
	return filepath.Base(s)
}

func ExecutableFolder() string {
	s, _ := osext.ExecutableFolder()
	return s
}
<commit_msg>workarounds #80<commit_after>// Copyright (c) 2016 by António Meireles  <antonio.meireles@reformi.st>.
//
// 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 session

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/TheNewNormal/corectl/components/target/coreos"
	"github.com/TheNewNormal/corectl/release"
	"github.com/bugsnag/osext"
	"github.com/helm/helm/log"
	"github.com/spf13/viper"
)

var (
	// Caller ...
	Caller               *Context
	ErrServerUnreachable = fmt.Errorf("Failed to connect to server\n" +
		"Please check your connection settings and ensure that 'corectld' " +
		"is running.\n")
)

// Network ...
type Network struct {
	Address string
	Mask    string
}

// Context ...
type Context struct {
	Privileged    bool          `json:"-"`
	Meta          *release.Info `json:"-"`
	CmdLine       *viper.Viper  `json:"-"`
	ServerAddress string
	*user.User    `json:"User"`
	*Network      `json:"Network"`
}

// New session context
func New() (ctx *Context, err error) {
	var (
		usr                 *user.User
		isSuperUser         bool
		netMask, netAddress []byte
	)

	// viper & cobra
	rawArgs := viper.New()
	rawArgs.SetEnvPrefix("COREOS")
	rawArgs.AutomaticEnv()
	euid := os.Getuid()

	if euid == 0 {
		usr = nil
		isSuperUser = true
	} else if usr, err = user.Current(); err != nil {
		return
	}

	return &Context{
		isSuperUser,
		&release.Info{
			release.Version,
			time.Now(),
			os.Getpid(),
			release.BuildDate,
			runtime.Version(),
			runtime.GOOS,
			runtime.GOARCH,
		},
		rawArgs,
		"127.0.0.1:2511",
		usr,
		&Network{
			strings.TrimSpace(string(netAddress)),
			strings.TrimSpace(string(netMask)),
		},
	}, err
}

// Base IP
func (n *Network) Base() string {
	return net.ParseIP(n.Address).Mask(
		net.IPMask(net.ParseIP(n.Mask).To4())).String()
}

// Debug ...
func (ctx *Context) Debug() bool {
	return ctx.CmdLine.GetBool("debug")
}

// JSON ...
func (ctx *Context) JSON() bool {
	return ctx.CmdLine.GetBool("json")
}

// ConfigDir ...
func (ctx *Context) ConfigDir() string {
	return path.Join(ctx.HomeDir, "/.coreos/")
}

// ImageStore ...
func (ctx *Context) ImageStore() string {
	return path.Join(ctx.ConfigDir(), "/images/")
}

// RunDir ...
func (ctx *Context) RunDir() string {
	return path.Join(ctx.ConfigDir(), "/running/")
}

// TmpDir ...
func (ctx *Context) TmpDir() string {
	return path.Join(ctx.ConfigDir(), "/tmp/")
}

// EtcDir ...
func (ctx *Context) EtcDir() string {
	return path.Join(ctx.ConfigDir(), "/embedded.etcd/")
}

// NormalizeOnDiskLayout ...
func (ctx *Context) NormalizeOnDiskLayout() (err error) {
	// first run
	for _, i := range coreos.Channels {
		if err =
			os.MkdirAll(path.Join(ctx.ImageStore(), i),
				0644); err != nil {
			return
		}
	}
	for _, i := range []string{ctx.RunDir(), ctx.TmpDir(), ctx.EtcDir()} {
		if err = os.MkdirAll(i, 0644); err != nil {
			return
		}
	}
	// usually image updates
	if !ctx.Privileged {
		return
	}
	u, _ := strconv.Atoi(ctx.Uid)
	g, _ := strconv.Atoi(ctx.Gid)

	do := func(p string,
		_ os.FileInfo, _ error) error {
		tty := path.Base(p)
		if tty == "tty" {
			return os.Remove(p)
		}
		return os.Chown(p, u, g)
	}
	return filepath.Walk(ctx.ConfigDir(), do)
}

func (ctx *Context) SetNetworkContext() (err error) {
	var (
		netMask, netAddress []byte
		cmdL                = []string{
			"defaults", "read",
			"/Library/Preferences/SystemConfiguration/com.apple.vmnet.plist",
		}
	)
	if netAddress, err = exec.Command(cmdL[0],
		append(cmdL[1:], "Shared_Net_Address")...).Output(); err != nil {
		log.Warn("%v \"%v %v %v\" %v ...",
			"unable to run", cmdL[0], cmdL[1], cmdL[2], "Shared_Net_Address")
		log.Warn("... assuming macOS default value (192.168.64.1)")
		netAddress = []byte("192.168.64.1")
	}

	if netMask, err = exec.Command(cmdL[0],
		append(cmdL[1:], "Shared_Net_Mask")...).Output(); err != nil {
		log.Warn("%v \"%v %v %v\" %v ...",
			"unable to run", cmdL[0], cmdL[1], cmdL[2], "Shared_Net_Mask")
		log.Warn("... assuming macOS default value (255.255.255.0)")
		netMask = []byte("255.255.255.0")
	}
	ctx.Network.Address = strings.TrimSpace(string(netAddress))
	ctx.Network.Mask = strings.TrimSpace(string(netMask))
	return
}
func Executable() string {
	s, _ := osext.Executable()
	return s
}

func AppName() string {
	s, _ := osext.Executable()
	return filepath.Base(s)
}

func ExecutableFolder() string {
	s, _ := osext.ExecutableFolder()
	return s
}
<|endoftext|>


<commit_before>// Copyright Istio 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.

// nolint: golint
package fuzz

import (
	"os"
	"testing"

	fuzz "github.com/AdaLogics/go-fuzz-headers"

	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pilot/pkg/networking/core/v1alpha3"
	"istio.io/istio/pkg/test"
)

func init() {
	testing.Init()
}

type NopTester struct{}

func (n NopTester) Fail() {}

func (n NopTester) FailNow() {}

func (n NopTester) Fatal(args ...interface{}) {}

func (n NopTester) Fatalf(format string, args ...interface{}) {}

func (n NopTester) Log(args ...interface{}) {}

func (n NopTester) Logf(format string, args ...interface{}) {}

func (n NopTester) TempDir() string {
	tempDir, _ := os.MkdirTemp("", "test")
	return tempDir
}

func (n NopTester) Helper() {}

func (n NopTester) Cleanup(f func()) {}

var _ test.Failer = NopTester{}

func FuzzValidateClusters(data []byte) int {
	proxy := model.Proxy{}
	f := fuzz.NewConsumer(data)
	err := f.GenerateStruct(&proxy)
	if err != nil {
		return 0
	}
	to := v1alpha3.TestOptions{}
	err = f.GenerateStruct(&to)
	if err != nil {
		return 0
	}
	cg := v1alpha3.NewConfigGenTest(NopTester{}, to)
	p := cg.SetupProxy(&proxy)
	_ = cg.Clusters(p)
	_ = cg.Routes(p)
	return 1
}
<commit_msg>Fuzzing: Fiz OSS-fuzz issue 36646 (#34447)<commit_after>// Copyright Istio 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.

// nolint: golint
package fuzz

import (
	"errors"
	"os"
	"testing"

	fuzz "github.com/AdaLogics/go-fuzz-headers"

	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pilot/pkg/networking/core/v1alpha3"
	"istio.io/istio/pkg/test"
)

func init() {
	testing.Init()
}

type NopTester struct{}

func (n NopTester) Fail() {}

func (n NopTester) FailNow() {}

func (n NopTester) Fatal(args ...interface{}) {}

func (n NopTester) Fatalf(format string, args ...interface{}) {}

func (n NopTester) Log(args ...interface{}) {}

func (n NopTester) Logf(format string, args ...interface{}) {}

func (n NopTester) TempDir() string {
	tempDir, _ := os.MkdirTemp("", "test")
	return tempDir
}

func (n NopTester) Helper() {}

func (n NopTester) Cleanup(f func()) {}

var _ test.Failer = NopTester{}

func ValidateTestOptions(to v1alpha3.TestOptions) error {
	for _, plugin := range to.Plugins {
		if plugin == nil {
			return errors.New("a Plugin was nil")
		}
	}
	for _, csc := range to.ConfigStoreCaches {
		if csc == nil {
			return errors.New("a ConfigStoreCache was nil")
		}
	}
	for _, sr := range to.ServiceRegistries {
		if sr == nil {
			return errors.New("a ServiceRegistry was nil")
		}
	}
	return nil
}

func FuzzValidateClusters(data []byte) int {
	proxy := model.Proxy{}
	f := fuzz.NewConsumer(data)
	to := v1alpha3.TestOptions{}
	err := f.GenerateStruct(&to)
	if err != nil {
		return 0
	}
	err = ValidateTestOptions(to)
	if err != nil {
		return 0
	}
	err = f.GenerateStruct(&proxy)
	if err != nil {
		return 0
	}
	cg := v1alpha3.NewConfigGenTest(NopTester{}, to)
	p := cg.SetupProxy(&proxy)
	_ = cg.Clusters(p)
	_ = cg.Routes(p)
	return 1
}
<|endoftext|>


<commit_before>package xml

import (
	"testing"
	"gokogiri/help"
	"io/ioutil"
	"path/filepath"
	"strings"
	"fmt"
)

func TestDocuments(t *testing.T) {
	tests, err := collectTests("document")

	if len(err) > 0 {
		t.Errorf(err)
	}

	errors := make([]string, 0)

	print("\nTesting: Basic Parsing [")

	for _, test := range tests {
		error := RunDocumentParseTest(t, test)

		if error != nil {
			errors = append(errors, fmt.Sprintf("Test %v failed:\n%v\n", test, *error))
			print("F")
		} else {
			print(".")
		}
	}

	println("]")

	if len(errors) > 0 {
		errorMessage := "\t" + strings.Join(strings.Split(strings.Join(errors, "\n\n"), "\n"), "\n\t")
		t.Errorf("\nSome tests failed! (%d passed / %d total) :\n%v", len(tests)-len(errors), len(tests), errorMessage)
	} else {
		fmt.Printf("\nAll (%d) tests passed!\n", len(tests))
	}
}

func _TestBufferedDocuments(t *testing.T) {
	tests, err := collectTests("document")

	if len(err) > 0 {
		t.Errorf(err)
	}

	errors := make([]string, 0)

	print("\nTesting: Buffered Parsing [")

	for _, test := range tests {
		error := RunParseDocumentWithBufferTest(t, test)

		if error != nil {
			errors = append(errors, fmt.Sprintf("Test %v failed:\n%v\n", test, *error))
			print("F")
		} else {
			print(".")
		}
	}

	println("]")

	if len(errors) > 0 {
		errorMessage := "\t" + strings.Join(strings.Split(strings.Join(errors, "\n\n"), "\n"), "\n\t")
		t.Errorf("\nSome tests failed! (%d passed / %d total) :\n%v", len(tests)-len(errors), len(tests), errorMessage)
	} else {
		fmt.Printf("\nAll (%d) tests passed!\n", len(tests))
	}
}

func RunParseDocumentWithBufferTest(t *testing.T, name string) (error *string) {
	var errorMessage string
	offset := "\t"

	defer help.CheckXmlMemoryLeaks(t)

	input, output, dataError := getTestData(name)

	if len(dataError) > 0 {
		errorMessage += dataError
	}

	buffer := make([]byte, 1000000)

	doc, err := ParseWithBuffer(input, DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes, buffer)

	if err != nil {
		errorMessage = fmt.Sprintf("parsing error:%v\n", err)
	}

	if doc.String() != string(output) {
		formattedOutput := offset + strings.Join(strings.Split("["+doc.String()+"]", "\n"), "\n"+offset)
		formattedExpectedOutput := offset + strings.Join(strings.Split("["+string(output)+"]", "\n"), "\n"+offset)
		errorMessage = fmt.Sprintf("%v-- Got --\n%v\n%v-- Expected --\n%v\n", offset, formattedOutput, offset, formattedExpectedOutput)
	}
	doc.Free()

	if len(errorMessage) > 0 {
		return &errorMessage
	}
	return nil

}

func RunDocumentParseTest(t *testing.T, name string) (error *string) {

	var errorMessage string
	offset := "\t"

	defer help.CheckXmlMemoryLeaks(t)

	input, output, dataError := getTestData(name)

	if len(dataError) > 0 {
		errorMessage += dataError
	}

	doc, err := Parse(input, DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)

	if err != nil {
		errorMessage = fmt.Sprintf("parsing error:%v\n", err)
	}

	if doc.String() != string(output) {
		formattedOutput := offset + strings.Join(strings.Split("["+doc.String()+"]", "\n"), "\n"+offset)
		formattedExpectedOutput := offset + strings.Join(strings.Split("["+string(output)+"]", "\n"), "\n"+offset)
		errorMessage = fmt.Sprintf("%v-- Got --\n%v\n%v-- Expected --\n%v\n", offset, formattedOutput, offset, formattedExpectedOutput)
		testOutput := filepath.Join(name, "test_output.txt")
		ioutil.WriteFile(testOutput, []byte(doc.String()), uint32(0666))
		errorMessage += fmt.Sprintf("%v Output test output to: %v\n", offset, testOutput)
	}
	doc.Free()

	if len(errorMessage) > 0 {
		return &errorMessage
	}
	return nil

}

func BenchmarkDocParsing(b *testing.B) {
	b.StopTimer()

	tests, err := collectTests("document")

	if len(err) > 0 {
		fmt.Printf(err)
		return
	}

	data := make([][]byte, 0)

	for _, testName := range tests {

		input, _, dataError := getTestData(testName)

		if len(dataError) > 0 {
			fmt.Printf(dataError)
			return
		}

		data = append(data, input)
	}

	b.StartTimer()

	for i := 0; i < b.N; i++ {

		for index, _ := range tests {

			_, err := Parse(data[index], DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)

			if err != nil {
				fmt.Printf("parsing error:%v\n", err)
				return
			}

		}
	}

}

func BenchmarkBufferedDocParsing(b *testing.B) {
	b.StopTimer()

	tests, err := collectTests("document")

	if len(err) > 0 {
		fmt.Printf(err)
		return
	}

	data := make([][]byte, 0)

	for _, testName := range tests {

		input, _, dataError := getTestData(testName)

		if len(dataError) > 0 {
			fmt.Printf(dataError)
			return
		}

		data = append(data, input)
	}

	buffer := make([]byte, 100)

	b.StartTimer()

	for i := 0; i < b.N; i++ {

		for index, _ := range tests {

			_, err := ParseWithBuffer(data[index], DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes, buffer)

			if err != nil {
				fmt.Printf("parsing error:%v\n", err)
				return
			}

		}
	}

}
<commit_msg>use the new interface<commit_after>package xml

import (
	"testing"
	"gokogiri/help"
	"io/ioutil"
	"path/filepath"
	"strings"
	"fmt"
)

func TestDocuments(t *testing.T) {
	tests, err := collectTests("document")

	if len(err) > 0 {
		t.Errorf(err)
	}

	errors := make([]string, 0)

	print("\nTesting: Basic Parsing [")

	for _, test := range tests {
		error := RunDocumentParseTest(t, test)

		if error != nil {
			errors = append(errors, fmt.Sprintf("Test %v failed:\n%v\n", test, *error))
			print("F")
		} else {
			print(".")
		}
	}

	println("]")

	if len(errors) > 0 {
		errorMessage := "\t" + strings.Join(strings.Split(strings.Join(errors, "\n\n"), "\n"), "\n\t")
		t.Errorf("\nSome tests failed! (%d passed / %d total) :\n%v", len(tests)-len(errors), len(tests), errorMessage)
	} else {
		fmt.Printf("\nAll (%d) tests passed!\n", len(tests))
	}
}

func TestBufferedDocuments(t *testing.T) {
	tests, err := collectTests("document")

	if len(err) > 0 {
		t.Errorf(err)
	}

	errors := make([]string, 0)

	print("\nTesting: Buffered Parsing [")

	for _, test := range tests {
		error := RunParseDocumentWithBufferTest(t, test)

		if error != nil {
			errors = append(errors, fmt.Sprintf("Test %v failed:\n%v\n", test, *error))
			print("F")
		} else {
			print(".")
		}
	}

	println("]")

	if len(errors) > 0 {
		errorMessage := "\t" + strings.Join(strings.Split(strings.Join(errors, "\n\n"), "\n"), "\n\t")
		t.Errorf("\nSome tests failed! (%d passed / %d total) :\n%v", len(tests)-len(errors), len(tests), errorMessage)
	} else {
		fmt.Printf("\nAll (%d) tests passed!\n", len(tests))
	}
}

func RunParseDocumentWithBufferTest(t *testing.T, name string) (error *string) {
	var errorMessage string
	offset := "\t"

	defer help.CheckXmlMemoryLeaks(t)

	input, output, dataError := getTestData(name)

	if len(dataError) > 0 {
		errorMessage += dataError
	}

	buffer := make([]byte, 500000)

	doc, err := Parse(input, DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)

	if err != nil {
		errorMessage = fmt.Sprintf("parsing error:%v\n", err)
	}

	if string(doc.ToXml(nil, buffer)) != string(output) {
		formattedOutput := offset + strings.Join(strings.Split("["+doc.String()+"]", "\n"), "\n"+offset)
		formattedExpectedOutput := offset + strings.Join(strings.Split("["+string(output)+"]", "\n"), "\n"+offset)
		errorMessage = fmt.Sprintf("%v-- Got --\n%v\n%v-- Expected --\n%v\n", offset, formattedOutput, offset, formattedExpectedOutput)
	}
	doc.Free()

	if len(errorMessage) > 0 {
		return &errorMessage
	}
	return nil

}

func RunDocumentParseTest(t *testing.T, name string) (error *string) {

	var errorMessage string
	offset := "\t"

	defer help.CheckXmlMemoryLeaks(t)

	input, output, dataError := getTestData(name)

	if len(dataError) > 0 {
		errorMessage += dataError
	}

	doc, err := Parse(input, DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)

	if err != nil {
		errorMessage = fmt.Sprintf("parsing error:%v\n", err)
	}

	if doc.String() != string(output) {
		formattedOutput := offset + strings.Join(strings.Split("["+doc.String()+"]", "\n"), "\n"+offset)
		formattedExpectedOutput := offset + strings.Join(strings.Split("["+string(output)+"]", "\n"), "\n"+offset)
		errorMessage = fmt.Sprintf("%v-- Got --\n%v\n%v-- Expected --\n%v\n", offset, formattedOutput, offset, formattedExpectedOutput)
		testOutput := filepath.Join(name, "test_output.txt")
		ioutil.WriteFile(testOutput, []byte(doc.String()), uint32(0666))
		errorMessage += fmt.Sprintf("%v Output test output to: %v\n", offset, testOutput)
	}
	doc.Free()

	if len(errorMessage) > 0 {
		return &errorMessage
	}
	return nil

}

func BenchmarkDocOutput(b *testing.B) {
	b.StopTimer()

	tests, err := collectTests("document")

	if len(err) > 0 {
		fmt.Printf(err)
		return
	}

	docs := make([]*XmlDocument, 0)

	for _, testName := range tests {

		input, _, dataError := getTestData(testName)

		if len(dataError) > 0 {
			fmt.Printf(dataError)
			return
		}
		doc, err := Parse(input, DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)

		if err != nil {
			fmt.Printf("parsing error:%v\n", err)
			return
		}
		docs = append(docs, doc)
	}

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		for index, _ := range tests {
			_ = docs[index].String()
		}
	}

}

func BenchmarkDocOutputToBuffer(b *testing.B) {
	b.StopTimer()

	tests, err := collectTests("document")

	if len(err) > 0 {
		fmt.Printf(err)
		return
	}

	docs := make([]*XmlDocument, 0)

	for _, testName := range tests {

		input, _, dataError := getTestData(testName)

		if len(dataError) > 0 {
			fmt.Printf(dataError)
			return
		}
		doc, err := Parse(input, DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)

		if err != nil {
			fmt.Printf("parsing error:%v\n", err)
			return
		}
		docs = append(docs, doc)
	}

	buffer := make([]byte, 500*1024)

	b.StartTimer()

	for i := 0; i < b.N; i++ {

		for index, _ := range tests {

			_ = docs[index].ToXml(nil, buffer)

		}
	}

}
<|endoftext|>


<commit_before>package schema

import (
	"encoding/json"
	"fmt"
	"testing"

	"github.com/stretchr/testify/require"
	"nimona.io/pkg/object"
	"nimona.io/pkg/tilde"
)

func TestSchema_Self(t *testing.T) {
	c := &Context{
		Name: "schema/Context",
		Types: []*Type{{
			Properties: []*Property{{
				Name:     "name",
				Hint:     tilde.StringHint,
				Required: true,
			}, {
				Name: "description",
				Hint: tilde.StringHint,
			}, {
				Name: "version",
				Hint: tilde.StringHint,
			}, {
				Name:     "types",
				Hint:     tilde.MapHint,
				Repeated: true,
			}},
		}, {
			Properties: []*Property{{
				Name:     "name",
				Hint:     tilde.StringHint,
				Required: true,
			}, {
				Name: "description",
				Hint: tilde.StringHint,
			}, {
				Name:     "properties",
				Hint:     tilde.MapHint,
				Repeated: true,
			}, {
				Name: "strict",
				Hint: tilde.BoolHint,
			}},
		}, {
			Properties: []*Property{{
				Name:     "name",
				Hint:     tilde.StringHint,
				Required: true,
			}, {
				Name: "description",
				Hint: tilde.StringHint,
			}, {
				Name: "hint",
				Hint: tilde.StringHint,
			}, {
				Name: "type",
				Hint: tilde.MapHint,
			}, {
				Name: "context",
				Hint: tilde.MapHint,
			}, {
				Name: "required",
				Hint: tilde.BoolHint,
			}, {
				Name: "repeated",
				Hint: tilde.BoolHint,
			}},
		}},
	}

	o, err := object.Marshal(c)
	require.NoError(t, err)

	b, err := json.MarshalIndent(o, "", "  ")
	require.NoError(t, err)
	fmt.Println(string(b))
}
<commit_msg>chore(schema): lint imports<commit_after>package schema

import (
	"encoding/json"
	"fmt"
	"testing"

	"nimona.io/pkg/object"
	"nimona.io/pkg/tilde"

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

func TestSchema_Self(t *testing.T) {
	c := &Context{
		Name: "schema/Context",
		Types: []*Type{{
			Properties: []*Property{{
				Name:     "name",
				Hint:     tilde.StringHint,
				Required: true,
			}, {
				Name: "description",
				Hint: tilde.StringHint,
			}, {
				Name: "version",
				Hint: tilde.StringHint,
			}, {
				Name:     "types",
				Hint:     tilde.MapHint,
				Repeated: true,
			}},
		}, {
			Properties: []*Property{{
				Name:     "name",
				Hint:     tilde.StringHint,
				Required: true,
			}, {
				Name: "description",
				Hint: tilde.StringHint,
			}, {
				Name:     "properties",
				Hint:     tilde.MapHint,
				Repeated: true,
			}, {
				Name: "strict",
				Hint: tilde.BoolHint,
			}},
		}, {
			Properties: []*Property{{
				Name:     "name",
				Hint:     tilde.StringHint,
				Required: true,
			}, {
				Name: "description",
				Hint: tilde.StringHint,
			}, {
				Name: "hint",
				Hint: tilde.StringHint,
			}, {
				Name: "type",
				Hint: tilde.MapHint,
			}, {
				Name: "context",
				Hint: tilde.MapHint,
			}, {
				Name: "required",
				Hint: tilde.BoolHint,
			}, {
				Name: "repeated",
				Hint: tilde.BoolHint,
			}},
		}},
	}

	o, err := object.Marshal(c)
	require.NoError(t, err)

	b, err := json.MarshalIndent(o, "", "  ")
	require.NoError(t, err)
	fmt.Println(string(b))
}
<|endoftext|>


<commit_before>package main

import (
	"dokugen/sudoku"
	"flag"
)

//TODO: let people pass in a filename to export to.

var GENERATE bool
var HELP bool
var PUZZLE_TO_SOLVE string
var NUM int

func main() {

	flag.BoolVar(&GENERATE, "g", false, "if true, will generate a puzzle.")
	flag.BoolVar(&HELP, "h", false, "If provided, will print help and exit.")
	flag.IntVar(&NUM, "n", 1, "Number of things to generate")
	flag.StringVar(&PUZZLE_TO_SOLVE, "s", "", "If provided, will solve the puzzle at the given filename and print solution.")

	flag.Parse()

	if HELP {
		flag.PrintDefaults()
		return
	}

	if GENERATE {
		for i := 0; i < NUM; i++ {
			grid := sudoku.GenerateGrid()
			print(grid.DataString())
			print("\n\n")
			print(grid.Difficulty())
			print("\n\n")
		}
		return
	}

	if PUZZLE_TO_SOLVE != "" {
		grid := sudoku.NewGrid()
		grid.LoadFromFile(PUZZLE_TO_SOLVE)
		//TODO: detect if the load failed.
		grid.Solve()
		print(grid.DataString())
		return
	}

	//If we get to here, print defaults.
	flag.PrintDefaults()

}
<commit_msg>Added a TODO<commit_after>package main

import (
	"dokugen/sudoku"
	"flag"
)

//TODO: let people pass in a filename to export to.

var GENERATE bool
var HELP bool
var PUZZLE_TO_SOLVE string
var NUM int

func main() {

	//TODO: figure out how to test this.

	flag.BoolVar(&GENERATE, "g", false, "if true, will generate a puzzle.")
	flag.BoolVar(&HELP, "h", false, "If provided, will print help and exit.")
	flag.IntVar(&NUM, "n", 1, "Number of things to generate")
	flag.StringVar(&PUZZLE_TO_SOLVE, "s", "", "If provided, will solve the puzzle at the given filename and print solution.")

	flag.Parse()

	if HELP {
		flag.PrintDefaults()
		return
	}

	if GENERATE {
		for i := 0; i < NUM; i++ {
			grid := sudoku.GenerateGrid()
			print(grid.DataString())
			print("\n\n")
			print(grid.Difficulty())
			print("\n\n")
		}
		return
	}

	if PUZZLE_TO_SOLVE != "" {
		grid := sudoku.NewGrid()
		grid.LoadFromFile(PUZZLE_TO_SOLVE)
		//TODO: detect if the load failed.
		grid.Solve()
		print(grid.DataString())
		return
	}

	//If we get to here, print defaults.
	flag.PrintDefaults()

}
<|endoftext|>


<commit_before>package test_helpers

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"syscall"
	"testing"
	"time"

	"github.com/rfjakob/gocryptfs/internal/ctlsock"
	"github.com/rfjakob/gocryptfs/internal/nametransform"
)

// TmpDir will be created inside this directory
const testParentDir = "/tmp/gocryptfs-test-parent"

// GocryptfsBinary is the assumed path to the gocryptfs build.
const GocryptfsBinary = "../../gocryptfs"

// TmpDir is a unique temporary directory. "go test" runs package tests in parallel. We create a
// unique TmpDir in init() so the tests do not interfere.
var TmpDir string

// DefaultPlainDir is TmpDir + "/default-plain"
var DefaultPlainDir string

// DefaultCipherDir is TmpDir + "/default-cipher"
var DefaultCipherDir string

func init() {
	os.MkdirAll(testParentDir, 0700)
	var err error
	TmpDir, err = ioutil.TempDir(testParentDir, "")
	if err != nil {
		panic(err)
	}
	DefaultPlainDir = TmpDir + "/default-plain"
	DefaultCipherDir = TmpDir + "/default-cipher"
}

// ResetTmpDir deletes TmpDir, create new dir tree:
//
// TmpDir
// |-- DefaultPlainDir
// *-- DefaultCipherDir
//     *-- gocryptfs.diriv
func ResetTmpDir(createDirIV bool) {
	// Try to unmount and delete everything
	entries, err := ioutil.ReadDir(TmpDir)
	if err == nil {
		for _, e := range entries {
			d := filepath.Join(TmpDir, e.Name())
			err = os.Remove(d)
			if err != nil {
				pe := err.(*os.PathError)
				if pe.Err == syscall.EBUSY {
					if testing.Verbose() {
						fmt.Printf("Remove failed: %v. Maybe still mounted?\n", pe)
					}
					err = UnmountErr(d)
					if err != nil {
						panic(err)
					}
				} else if pe.Err != syscall.ENOTEMPTY {
					panic("Unhandled error: " + pe.Err.Error())
				}
				err = os.RemoveAll(d)
				if err != nil {
					panic(err)
				}
			}
		}
	}
	err = os.Mkdir(DefaultPlainDir, 0700)
	if err != nil {
		panic(err)
	}
	err = os.Mkdir(DefaultCipherDir, 0700)
	if err != nil {
		panic(err)
	}
	if createDirIV {
		err = nametransform.WriteDirIV(DefaultCipherDir)
		if err != nil {
			panic(err)
		}
	}
}

// InitFS calls "gocryptfs -init" on a new directory in TmpDir, passing
// "extraArgs" in addition to useful defaults.
//
// The returned cipherdir has NO trailing slash.
func InitFS(t *testing.T, extraArgs ...string) string {
	dir, err := ioutil.TempDir(TmpDir, "")
	if err != nil {
		t.Fatal(err)
	}
	args := []string{"-q", "-init", "-extpass", "echo test", "-scryptn=10"}
	args = append(args, extraArgs...)
	args = append(args, dir)

	cmd := exec.Command(GocryptfsBinary, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err = cmd.Run()
	if err != nil {
		t.Fatalf("InitFS with args %v failed: %v", args, err)
	}

	return dir
}

// Mount CIPHERDIR "c" on PLAINDIR "p"
// Creates "p" if it does not exist.
func Mount(c string, p string, showOutput bool, extraArgs ...string) error {
	var args []string
	args = append(args, "-q", "-wpanic", "-nosyslog")
	args = append(args, extraArgs...)
	//args = append(args, "-fusedebug")
	//args = append(args, "-d")
	args = append(args, c)
	args = append(args, p)

	if _, err := os.Stat(p); err != nil {
		err = os.Mkdir(p, 0777)
		if err != nil {
			return err
		}
	}

	cmd := exec.Command(GocryptfsBinary, args...)
	if showOutput {
		cmd.Stderr = os.Stderr
		cmd.Stdout = os.Stdout
	}

	return cmd.Run()
}

// MountOrExit calls Mount() and exits on failure.
func MountOrExit(c string, p string, extraArgs ...string) {
	err := Mount(c, p, true, extraArgs...)
	if err != nil {
		fmt.Printf("mount failed: %v", err)
		os.Exit(1)
	}
}

// MountOrFatal calls Mount() and calls t.Fatal() on failure.
func MountOrFatal(t *testing.T, c string, p string, extraArgs ...string) {
	err := Mount(c, p, true, extraArgs...)
	if err != nil {
		t.Fatal(fmt.Errorf("mount failed: %v", err))
	}
}

// UnmountPanic tries to umount "dir" and panics on error.
func UnmountPanic(dir string) {
	err := UnmountErr(dir)
	if err != nil {
		fmt.Println(err)
		panic(err)
	}
}

// UnmountErr tries to unmount "dir" and returns the resulting error.
func UnmountErr(dir string) error {
	var cmd *exec.Cmd
	if runtime.GOOS == "darwin" {
		cmd = exec.Command("umount", dir)
	} else {
		cmd = exec.Command("fusermount", "-u", "-z", dir)
	}
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// Md5fn returns an md5 string for file "filename"
func Md5fn(filename string) string {
	buf, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Printf("ReadFile: %v\n", err)
		return ""
	}
	return Md5hex(buf)
}

// Md5hex returns an md5 string for "buf"
func Md5hex(buf []byte) string {
	rawHash := md5.Sum(buf)
	hash := hex.EncodeToString(rawHash[:])
	return hash
}

// VerifySize checks that the file size equals "want". This checks:
// 1) Size reported by Stat()
// 2) Number of bytes returned when reading the whole file
func VerifySize(t *testing.T, path string, want int) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		t.Errorf("ReadFile failed: %v", err)
	} else if len(buf) != want {
		t.Errorf("wrong read size: got=%d want=%d", len(buf), want)
	}

	fi, err := os.Stat(path)
	if err != nil {
		t.Errorf("Stat failed: %v", err)
	} else if fi.Size() != int64(want) {
		t.Errorf("wrong stat file size, got=%d want=%d", fi.Size(), want)
	}
}

// TestMkdirRmdir creates and deletes a directory
func TestMkdirRmdir(t *testing.T, plainDir string) {
	dir := plainDir + "/dir1"
	err := os.Mkdir(dir, 0777)
	if err != nil {
		t.Error(err)
		return
	}
	err = syscall.Rmdir(dir)
	if err != nil {
		t.Error(err)
		return
	}
	// Removing a non-empty dir should fail with ENOTEMPTY
	if os.Mkdir(dir, 0777) != nil {
		t.Error(err)
		return
	}
	f, err := os.Create(dir + "/file")
	if err != nil {
		t.Error(err)
		return
	}
	f.Close()
	err = syscall.Rmdir(dir)
	errno := err.(syscall.Errno)
	if errno != syscall.ENOTEMPTY {
		t.Errorf("Should have gotten ENOTEMPTY, go %v", errno)
	}
	if syscall.Unlink(dir+"/file") != nil {
		t.Error(err)
		return
	}
	if syscall.Rmdir(dir) != nil {
		t.Error(err)
		return
	}
	// We should also be able to remove a directory we do not have permissions to
	// read or write
	err = os.Mkdir(dir, 0000)
	if err != nil {
		t.Error(err)
		return
	}
	err = syscall.Rmdir(dir)
	if err != nil {
		// Make sure the directory can cleaned up by the next test run
		os.Chmod(dir, 0700)
		t.Error(err)
		return
	}
}

// TestRename creates and renames a file
func TestRename(t *testing.T, plainDir string) {
	file1 := plainDir + "/rename1"
	file2 := plainDir + "/rename2"
	err := ioutil.WriteFile(file1, []byte("content"), 0777)
	if err != nil {
		t.Error(err)
		return
	}
	err = syscall.Rename(file1, file2)
	if err != nil {
		t.Error(err)
		return
	}
	syscall.Unlink(file2)
}

// VerifyExistence checks in 3 ways that "path" exists:
// stat, open, readdir
func VerifyExistence(path string) bool {
	// Check that file can be stated
	_, err := os.Stat(path)
	if err != nil {
		//t.Log(err)
		return false
	}
	// Check that file can be opened
	fd, err := os.Open(path)
	if err != nil {
		//t.Log(err)
		return false
	}
	fd.Close()
	// Check that file shows up in directory listing
	dir := filepath.Dir(path)
	name := filepath.Base(path)
	fi, err := ioutil.ReadDir(dir)
	if err != nil {
		//t.Log(err)
		return false
	}
	for _, i := range fi {
		if i.Name() == name {
			return true
		}
	}
	return false
}

// Du returns the disk usage of the file "fd" points to, in bytes.
// Same as "du --block-size=1".
func Du(t *testing.T, fd int) (nBytes int64) {
	var st syscall.Stat_t
	err := syscall.Fstat(fd, &st)
	if err != nil {
		t.Fatal(err)
	}
	// st.Blocks = number of 512-byte blocks
	return st.Blocks * 512
}

// QueryCtlSock sends a request to the control socket at "socketPath" and
// returns the response.
func QueryCtlSock(t *testing.T, socketPath string, req ctlsock.RequestStruct) (response ctlsock.ResponseStruct) {
	conn, err := net.DialTimeout("unix", socketPath, 1*time.Second)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()
	conn.SetDeadline(time.Now().Add(time.Second))
	msg, err := json.Marshal(req)
	if err != nil {
		t.Fatal(err)
	}
	_, err = conn.Write(msg)
	if err != nil {
		t.Fatal(err)
	}
	buf := make([]byte, 2*syscall.PathMax)
	n, err := conn.Read(buf)
	if err != nil {
		t.Fatal(err)
	}
	buf = buf[:n]
	json.Unmarshal(buf, &response)
	return response
}
<commit_msg>tests: use fuse-unmount.bash<commit_after>package test_helpers

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"testing"
	"time"

	"github.com/rfjakob/gocryptfs/internal/ctlsock"
	"github.com/rfjakob/gocryptfs/internal/nametransform"
)

// TmpDir will be created inside this directory
const testParentDir = "/tmp/gocryptfs-test-parent"

// GocryptfsBinary is the assumed path to the gocryptfs build.
const GocryptfsBinary = "../../gocryptfs"

// UnmountScript is the fusermount/umount compatability wrapper script
const UnmountScript = "../fuse-unmount.bash"

// TmpDir is a unique temporary directory. "go test" runs package tests in parallel. We create a
// unique TmpDir in init() so the tests do not interfere.
var TmpDir string

// DefaultPlainDir is TmpDir + "/default-plain"
var DefaultPlainDir string

// DefaultCipherDir is TmpDir + "/default-cipher"
var DefaultCipherDir string

func init() {
	os.MkdirAll(testParentDir, 0700)
	var err error
	TmpDir, err = ioutil.TempDir(testParentDir, "")
	if err != nil {
		panic(err)
	}
	DefaultPlainDir = TmpDir + "/default-plain"
	DefaultCipherDir = TmpDir + "/default-cipher"
}

// ResetTmpDir deletes TmpDir, create new dir tree:
//
// TmpDir
// |-- DefaultPlainDir
// *-- DefaultCipherDir
//     *-- gocryptfs.diriv
func ResetTmpDir(createDirIV bool) {
	// Try to unmount and delete everything
	entries, err := ioutil.ReadDir(TmpDir)
	if err == nil {
		for _, e := range entries {
			d := filepath.Join(TmpDir, e.Name())
			err = os.Remove(d)
			if err != nil {
				pe := err.(*os.PathError)
				if pe.Err == syscall.EBUSY {
					if testing.Verbose() {
						fmt.Printf("Remove failed: %v. Maybe still mounted?\n", pe)
					}
					err = UnmountErr(d)
					if err != nil {
						panic(err)
					}
				} else if pe.Err != syscall.ENOTEMPTY {
					panic("Unhandled error: " + pe.Err.Error())
				}
				err = os.RemoveAll(d)
				if err != nil {
					panic(err)
				}
			}
		}
	}
	err = os.Mkdir(DefaultPlainDir, 0700)
	if err != nil {
		panic(err)
	}
	err = os.Mkdir(DefaultCipherDir, 0700)
	if err != nil {
		panic(err)
	}
	if createDirIV {
		err = nametransform.WriteDirIV(DefaultCipherDir)
		if err != nil {
			panic(err)
		}
	}
}

// InitFS calls "gocryptfs -init" on a new directory in TmpDir, passing
// "extraArgs" in addition to useful defaults.
//
// The returned cipherdir has NO trailing slash.
func InitFS(t *testing.T, extraArgs ...string) string {
	dir, err := ioutil.TempDir(TmpDir, "")
	if err != nil {
		t.Fatal(err)
	}
	args := []string{"-q", "-init", "-extpass", "echo test", "-scryptn=10"}
	args = append(args, extraArgs...)
	args = append(args, dir)

	cmd := exec.Command(GocryptfsBinary, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err = cmd.Run()
	if err != nil {
		t.Fatalf("InitFS with args %v failed: %v", args, err)
	}

	return dir
}

// Mount CIPHERDIR "c" on PLAINDIR "p"
// Creates "p" if it does not exist.
func Mount(c string, p string, showOutput bool, extraArgs ...string) error {
	var args []string
	args = append(args, "-q", "-wpanic", "-nosyslog")
	args = append(args, extraArgs...)
	//args = append(args, "-fusedebug")
	//args = append(args, "-d")
	args = append(args, c)
	args = append(args, p)

	if _, err := os.Stat(p); err != nil {
		err = os.Mkdir(p, 0777)
		if err != nil {
			return err
		}
	}

	cmd := exec.Command(GocryptfsBinary, args...)
	if showOutput {
		cmd.Stderr = os.Stderr
		cmd.Stdout = os.Stdout
	}

	return cmd.Run()
}

// MountOrExit calls Mount() and exits on failure.
func MountOrExit(c string, p string, extraArgs ...string) {
	err := Mount(c, p, true, extraArgs...)
	if err != nil {
		fmt.Printf("mount failed: %v", err)
		os.Exit(1)
	}
}

// MountOrFatal calls Mount() and calls t.Fatal() on failure.
func MountOrFatal(t *testing.T, c string, p string, extraArgs ...string) {
	err := Mount(c, p, true, extraArgs...)
	if err != nil {
		t.Fatal(fmt.Errorf("mount failed: %v", err))
	}
}

// UnmountPanic tries to umount "dir" and panics on error.
func UnmountPanic(dir string) {
	err := UnmountErr(dir)
	if err != nil {
		fmt.Println(err)
		panic(err)
	}
}

// UnmountErr tries to unmount "dir" and returns the resulting error.
func UnmountErr(dir string) error {
	cmd := exec.Command(UnmountScript, "-u", "-z", dir)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// Md5fn returns an md5 string for file "filename"
func Md5fn(filename string) string {
	buf, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Printf("ReadFile: %v\n", err)
		return ""
	}
	return Md5hex(buf)
}

// Md5hex returns an md5 string for "buf"
func Md5hex(buf []byte) string {
	rawHash := md5.Sum(buf)
	hash := hex.EncodeToString(rawHash[:])
	return hash
}

// VerifySize checks that the file size equals "want". This checks:
// 1) Size reported by Stat()
// 2) Number of bytes returned when reading the whole file
func VerifySize(t *testing.T, path string, want int) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		t.Errorf("ReadFile failed: %v", err)
	} else if len(buf) != want {
		t.Errorf("wrong read size: got=%d want=%d", len(buf), want)
	}

	fi, err := os.Stat(path)
	if err != nil {
		t.Errorf("Stat failed: %v", err)
	} else if fi.Size() != int64(want) {
		t.Errorf("wrong stat file size, got=%d want=%d", fi.Size(), want)
	}
}

// TestMkdirRmdir creates and deletes a directory
func TestMkdirRmdir(t *testing.T, plainDir string) {
	dir := plainDir + "/dir1"
	err := os.Mkdir(dir, 0777)
	if err != nil {
		t.Error(err)
		return
	}
	err = syscall.Rmdir(dir)
	if err != nil {
		t.Error(err)
		return
	}
	// Removing a non-empty dir should fail with ENOTEMPTY
	if os.Mkdir(dir, 0777) != nil {
		t.Error(err)
		return
	}
	f, err := os.Create(dir + "/file")
	if err != nil {
		t.Error(err)
		return
	}
	f.Close()
	err = syscall.Rmdir(dir)
	errno := err.(syscall.Errno)
	if errno != syscall.ENOTEMPTY {
		t.Errorf("Should have gotten ENOTEMPTY, go %v", errno)
	}
	if syscall.Unlink(dir+"/file") != nil {
		t.Error(err)
		return
	}
	if syscall.Rmdir(dir) != nil {
		t.Error(err)
		return
	}
	// We should also be able to remove a directory we do not have permissions to
	// read or write
	err = os.Mkdir(dir, 0000)
	if err != nil {
		t.Error(err)
		return
	}
	err = syscall.Rmdir(dir)
	if err != nil {
		// Make sure the directory can cleaned up by the next test run
		os.Chmod(dir, 0700)
		t.Error(err)
		return
	}
}

// TestRename creates and renames a file
func TestRename(t *testing.T, plainDir string) {
	file1 := plainDir + "/rename1"
	file2 := plainDir + "/rename2"
	err := ioutil.WriteFile(file1, []byte("content"), 0777)
	if err != nil {
		t.Error(err)
		return
	}
	err = syscall.Rename(file1, file2)
	if err != nil {
		t.Error(err)
		return
	}
	syscall.Unlink(file2)
}

// VerifyExistence checks in 3 ways that "path" exists:
// stat, open, readdir
func VerifyExistence(path string) bool {
	// Check that file can be stated
	_, err := os.Stat(path)
	if err != nil {
		//t.Log(err)
		return false
	}
	// Check that file can be opened
	fd, err := os.Open(path)
	if err != nil {
		//t.Log(err)
		return false
	}
	fd.Close()
	// Check that file shows up in directory listing
	dir := filepath.Dir(path)
	name := filepath.Base(path)
	fi, err := ioutil.ReadDir(dir)
	if err != nil {
		//t.Log(err)
		return false
	}
	for _, i := range fi {
		if i.Name() == name {
			return true
		}
	}
	return false
}

// Du returns the disk usage of the file "fd" points to, in bytes.
// Same as "du --block-size=1".
func Du(t *testing.T, fd int) (nBytes int64) {
	var st syscall.Stat_t
	err := syscall.Fstat(fd, &st)
	if err != nil {
		t.Fatal(err)
	}
	// st.Blocks = number of 512-byte blocks
	return st.Blocks * 512
}

// QueryCtlSock sends a request to the control socket at "socketPath" and
// returns the response.
func QueryCtlSock(t *testing.T, socketPath string, req ctlsock.RequestStruct) (response ctlsock.ResponseStruct) {
	conn, err := net.DialTimeout("unix", socketPath, 1*time.Second)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()
	conn.SetDeadline(time.Now().Add(time.Second))
	msg, err := json.Marshal(req)
	if err != nil {
		t.Fatal(err)
	}
	_, err = conn.Write(msg)
	if err != nil {
		t.Fatal(err)
	}
	buf := make([]byte, 2*syscall.PathMax)
	n, err := conn.Read(buf)
	if err != nil {
		t.Fatal(err)
	}
	buf = buf[:n]
	json.Unmarshal(buf, &response)
	return response
}
<|endoftext|>