<commit_before>package main

import (
	"fmt"
	"github.com/google/uuid"
	"github.com/tejpbit/talarlista/backend/messages"
	"log"
)

type MessageHandler interface {
	handle(UserEvent)
}

type ClientHelo struct {
	hub *Hub
}
type UserGet struct{}

type UsersGet struct {
	hub *Hub
}
type UserUpdate struct {
	hub *Hub
}
type UserDelete struct {
	hub *Hub
}
type AdminLogin struct {
	hub *Hub
}
type AdminGenerateNewPassword struct {
	hub *Hub
}
type ListsGet struct {
	hub *Hub
}
type ListAddUser struct {
	hub *Hub
}
type ListRemoveUser struct {
	hub *Hub
}
type UserConnectionOpened struct {
	hub *Hub
}
type UserConnectionClosed struct {
	hub *Hub
}
type ListCreate struct {
	hub *Hub
}
type ListDelete struct {
	hub *Hub
}
type ListPop struct {
	hub *Hub
}
type ListSetDiscussionStatus struct {
	hub *Hub
}
type ListAdminAddUser struct {
	hub *Hub
}

func CreateHandlers(hub *Hub) map[string]MessageHandler {
	return map[string]MessageHandler{
		messages.CLIENT_HELO:                ClientHelo{hub},
		messages.USER_GET:                   UserGet{},
		messages.USERS_GET:                  UsersGet{hub},
		messages.USER_UPDATE:                UserUpdate{hub},
		messages.USER_DELETE:                UserDelete{hub},
		messages.ADMIN_LOGIN:                AdminLogin{hub},
		messages.ADMIN_GENERATE_PASSWORD:    AdminGenerateNewPassword{hub},
		messages.LISTS_GET:                  ListsGet{hub},
		messages.LIST_ADD_USER:              ListAddUser{hub},
		messages.LIST_REMOVE_USER:           ListRemoveUser{hub},
		messages.USER_CONNECTION_OPENED:     UserConnectionOpened{hub},
		messages.USER_CONNECTION_CLOSED:     UserConnectionClosed{hub},
		messages.LIST_CREATE:                ListCreate{hub},
		messages.LIST_DELETE:                ListDelete{hub},
		messages.LIST_POP:                   ListPop{hub},
		messages.LIST_SET_DISCUSSION_STATUS: ListSetDiscussionStatus{hub},
		messages.LIST_ADMIN_ADD_USER:        ListAdminAddUser{hub},
	}
}

func (m ClientHelo) handle(userEvent UserEvent) {
	sendUserResponse(userEvent.user.input, userEvent.user)
	sendListsResponse(userEvent.user.input, m.hub.SpeakerLists)
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m UserGet) handle(userEvent UserEvent) {
	sendUserResponse(userEvent.user.input, userEvent.user)
}

func (m UsersGet) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	resp, err := m.hub.createUsersResponse()
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	userEvent.user.input <- resp
}

func (m UserUpdate) handle(userEvent UserEvent) {
	if userEvent.ReceivedUser.Nick == "" {
		sendError(userEvent.user.input, "Can't set empty nick.")
		return
	}
	if m.hub.isUserNickTaken(userEvent.ReceivedUser.Nick) {
		sendError(userEvent.user.input, "Nick is taken. If someone has taken your nick ask an admin to update or remove that user.")
		return
	}

	if userEvent.user.Id == userEvent.ReceivedUser.Id {
		userEvent.user.Nick = userEvent.ReceivedUser.Nick
		sendUserResponse(userEvent.user.input, userEvent.user)
	} else {
		if !userEvent.user.IsAdmin {
			sendError(userEvent.user.input, "Needs to be admin to update another users nick.")
			return
		}
		ok := m.hub.updateUser(userEvent.ReceivedUser)
		if !ok {
			sendError(userEvent.user.input, "Couldn't find user in the hub.")
			return
		}

	}

	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		m.hub.Broadcast(resp)
	}
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m UserDelete) handle(userEvent UserEvent) {
	log.Println(userEvent.String())
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	if userEvent.ReceivedUser == nil {
		sendError(userEvent.user.input, "Received user is null")
		return
	}

	user, ok := m.hub.Users[userEvent.ReceivedUser.Id]
	if ok {
		sendNotification(user.input, messages.ERROR, "You have been removed from this hub by an admin.")
	}
	m.hub.deleteUser(userEvent.ReceivedUser)
	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	userEvent.user.input <- resp
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m AdminLogin) handle(userEvent UserEvent) {
	ok := m.hub.tryAdminLogin(userEvent.user, userEvent.Password)
	if !ok {
		sendError(userEvent.user.input, "Login failed.")
		return
	}
	sendSuccess(userEvent.user.input, "Login successful.")
	sendUserResponse(userEvent.user.input, userEvent.user)
	sendUsersUpdateToAdmins(m.hub, userEvent.user)

	response, err := createPasswordListResponse(m.hub.oneTimePasswords)
	if err != nil {
		sendError(userEvent.user.input, "Could not create password list response.")
		return
	}

	m.hub.AdminBroadcast(response)
}

func (m AdminGenerateNewPassword) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	m.hub.generateNewPassword()
	response, err := createPasswordListResponse(m.hub.oneTimePasswords)
	if err != nil {
		sendError(userEvent.user.input, "Could not create password list response.")
		return
	}

	m.hub.AdminBroadcast(response)
}

func (m ListsGet) handle(userEvent UserEvent) {
	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		userEvent.user.input <- resp
	}

}

func (m ListAddUser) handle(userEvent UserEvent) {
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	if list.Status == Closed && !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Discussion is closed.")
		return
	}

	ok := list.AddUser(userEvent.user)
	if !ok {
		sendError(userEvent.user.input, UserAlreadyInList)
		return
	}

	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		m.hub.Broadcast(resp)
	}
}

func (m ListAdminAddUser) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	if userEvent.ReceivedUser.Nick == "" {
		sendError(userEvent.user.input, "Can't have empty nick.")
		return
	}

	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	var adminCreatedUser *User
	for _, user := range m.hub.AdminCreatedUsers {
		if user.Nick == userEvent.ReceivedUser.Nick {
			adminCreatedUser = user
			break
		}
	}
	if adminCreatedUser == nil {
		if m.hub.isUserNickTaken(userEvent.ReceivedUser.Nick) {
			sendError(userEvent.user.input, "The nick is taken.")
			return
		}
		adminCreatedUser = CreateUser()
		adminCreatedUser.Nick = userEvent.ReceivedUser.Nick
		m.hub.addAdminCreatedUser(adminCreatedUser)
	}

	ok := list.AddUser(adminCreatedUser)
	if !ok {
		sendError(userEvent.user.input, UserAlreadyInList)
		return
	}

	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	} else {
		m.hub.Broadcast(resp)
	}
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m ListRemoveUser) handle(userEvent UserEvent) {
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	ok := list.RemoveUser(userEvent.user)
	if !ok {
		sendError(userEvent.user.input, "User not in list.")
		return
	}

	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		m.hub.Broadcast(resp)
	}
}

func (m UserConnectionOpened) handle(userEvent UserEvent) {
	m.hub.connectedUsers[userEvent.user.Id] = userEvent.user
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m UserConnectionClosed) handle(userEvent UserEvent) {
	delete(m.hub.connectedUsers, userEvent.user.Id)
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m ListCreate) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	if userEvent.List.Title == "" {
		sendError(userEvent.user.input, "Can not create discussion with empty title")
		return
	}
	newList := CreateSpeakerList(userEvent.List.Title)
	m.hub.SpeakerLists = append(m.hub.SpeakerLists, &newList)
	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, fmt.Sprintf("Could not create new discussion, %v", err.Error()))
	} else {
		m.hub.Broadcast(resp)
	}
}

func (m ListDelete) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	err = m.hub.deleteList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	m.hub.Broadcast(resp)
}

func (m ListPop) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	_, err = list.Pop()
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	}
	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	m.hub.Broadcast(resp)

}

func (m ListSetDiscussionStatus) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	if !userEvent.List.Status.Valid() {
		sendError(userEvent.user.input, "Invalid status")
		return
	}
	list.Status = userEvent.List.Status
	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	}
	m.hub.Broadcast(resp)
}

func sendListsResponse(userChannel chan messages.SendEvent, lists []*SpeakerList) {
	resp, err := createListsResponse(lists)
	if err != nil {
		sendError(userChannel, err.Error())
	} else {
		userChannel <- resp
	}

}

func sendUsersUpdateToAdmins(hub *Hub, user *User) {
	resp, err := hub.createUsersResponse()
	if err != nil {
		sendError(user.input, err.Error())
		return
	}
	hub.AdminBroadcast(resp)
}
<commit_msg>Send user response even if user nick is taken. This lets the user know that its state has not been changed.<commit_after>package main

import (
	"fmt"
	"github.com/google/uuid"
	"github.com/tejpbit/talarlista/backend/messages"
	"log"
)

type MessageHandler interface {
	handle(UserEvent)
}

type ClientHelo struct {
	hub *Hub
}
type UserGet struct{}

type UsersGet struct {
	hub *Hub
}
type UserUpdate struct {
	hub *Hub
}
type UserDelete struct {
	hub *Hub
}
type AdminLogin struct {
	hub *Hub
}
type AdminGenerateNewPassword struct {
	hub *Hub
}
type ListsGet struct {
	hub *Hub
}
type ListAddUser struct {
	hub *Hub
}
type ListRemoveUser struct {
	hub *Hub
}
type UserConnectionOpened struct {
	hub *Hub
}
type UserConnectionClosed struct {
	hub *Hub
}
type ListCreate struct {
	hub *Hub
}
type ListDelete struct {
	hub *Hub
}
type ListPop struct {
	hub *Hub
}
type ListSetDiscussionStatus struct {
	hub *Hub
}
type ListAdminAddUser struct {
	hub *Hub
}

func CreateHandlers(hub *Hub) map[string]MessageHandler {
	return map[string]MessageHandler{
		messages.CLIENT_HELO:                ClientHelo{hub},
		messages.USER_GET:                   UserGet{},
		messages.USERS_GET:                  UsersGet{hub},
		messages.USER_UPDATE:                UserUpdate{hub},
		messages.USER_DELETE:                UserDelete{hub},
		messages.ADMIN_LOGIN:                AdminLogin{hub},
		messages.ADMIN_GENERATE_PASSWORD:    AdminGenerateNewPassword{hub},
		messages.LISTS_GET:                  ListsGet{hub},
		messages.LIST_ADD_USER:              ListAddUser{hub},
		messages.LIST_REMOVE_USER:           ListRemoveUser{hub},
		messages.USER_CONNECTION_OPENED:     UserConnectionOpened{hub},
		messages.USER_CONNECTION_CLOSED:     UserConnectionClosed{hub},
		messages.LIST_CREATE:                ListCreate{hub},
		messages.LIST_DELETE:                ListDelete{hub},
		messages.LIST_POP:                   ListPop{hub},
		messages.LIST_SET_DISCUSSION_STATUS: ListSetDiscussionStatus{hub},
		messages.LIST_ADMIN_ADD_USER:        ListAdminAddUser{hub},
	}
}

func (m ClientHelo) handle(userEvent UserEvent) {
	sendUserResponse(userEvent.user.input, userEvent.user)
	sendListsResponse(userEvent.user.input, m.hub.SpeakerLists)
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m UserGet) handle(userEvent UserEvent) {
	sendUserResponse(userEvent.user.input, userEvent.user)
}

func (m UsersGet) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	resp, err := m.hub.createUsersResponse()
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	userEvent.user.input <- resp
}

func (m UserUpdate) handle(userEvent UserEvent) {
	if userEvent.ReceivedUser.Nick == "" {
		sendError(userEvent.user.input, "Can't set empty nick.")
		return
	}
	if m.hub.isUserNickTaken(userEvent.ReceivedUser.Nick) {
		sendUserResponse(userEvent.user.input, userEvent.user)
		sendError(userEvent.user.input, "Nick is taken. If someone has taken your nick ask an admin to update or remove that user.")
		return
	}

	if userEvent.user.Id == userEvent.ReceivedUser.Id {
		userEvent.user.Nick = userEvent.ReceivedUser.Nick
		sendUserResponse(userEvent.user.input, userEvent.user)
	} else {
		if !userEvent.user.IsAdmin {
			sendError(userEvent.user.input, "Needs to be admin to update another users nick.")
			return
		}
		ok := m.hub.updateUser(userEvent.ReceivedUser)
		if !ok {
			sendError(userEvent.user.input, "Couldn't find user in the hub.")
			return
		}

	}

	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		m.hub.Broadcast(resp)
	}
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m UserDelete) handle(userEvent UserEvent) {
	log.Println(userEvent.String())
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	if userEvent.ReceivedUser == nil {
		sendError(userEvent.user.input, "Received user is null")
		return
	}

	user, ok := m.hub.Users[userEvent.ReceivedUser.Id]
	if ok {
		sendNotification(user.input, messages.ERROR, "You have been removed from this hub by an admin.")
	}
	m.hub.deleteUser(userEvent.ReceivedUser)
	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	userEvent.user.input <- resp
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m AdminLogin) handle(userEvent UserEvent) {
	ok := m.hub.tryAdminLogin(userEvent.user, userEvent.Password)
	if !ok {
		sendError(userEvent.user.input, "Login failed.")
		return
	}
	sendSuccess(userEvent.user.input, "Login successful.")
	sendUserResponse(userEvent.user.input, userEvent.user)
	sendUsersUpdateToAdmins(m.hub, userEvent.user)

	response, err := createPasswordListResponse(m.hub.oneTimePasswords)
	if err != nil {
		sendError(userEvent.user.input, "Could not create password list response.")
		return
	}

	m.hub.AdminBroadcast(response)
}

func (m AdminGenerateNewPassword) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	m.hub.generateNewPassword()
	response, err := createPasswordListResponse(m.hub.oneTimePasswords)
	if err != nil {
		sendError(userEvent.user.input, "Could not create password list response.")
		return
	}

	m.hub.AdminBroadcast(response)
}

func (m ListsGet) handle(userEvent UserEvent) {
	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		userEvent.user.input <- resp
	}

}

func (m ListAddUser) handle(userEvent UserEvent) {
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	if list.Status == Closed && !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Discussion is closed.")
		return
	}

	ok := list.AddUser(userEvent.user)
	if !ok {
		sendError(userEvent.user.input, UserAlreadyInList)
		return
	}

	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		m.hub.Broadcast(resp)
	}
}

func (m ListAdminAddUser) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}

	if userEvent.ReceivedUser.Nick == "" {
		sendError(userEvent.user.input, "Can't have empty nick.")
		return
	}

	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	var adminCreatedUser *User
	for _, user := range m.hub.AdminCreatedUsers {
		if user.Nick == userEvent.ReceivedUser.Nick {
			adminCreatedUser = user
			break
		}
	}
	if adminCreatedUser == nil {
		if m.hub.isUserNickTaken(userEvent.ReceivedUser.Nick) {
			sendError(userEvent.user.input, "The nick is taken.")
			return
		}
		adminCreatedUser = CreateUser()
		adminCreatedUser.Nick = userEvent.ReceivedUser.Nick
		m.hub.addAdminCreatedUser(adminCreatedUser)
	}

	ok := list.AddUser(adminCreatedUser)
	if !ok {
		sendError(userEvent.user.input, UserAlreadyInList)
		return
	}

	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	} else {
		m.hub.Broadcast(resp)
	}
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m ListRemoveUser) handle(userEvent UserEvent) {
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	ok := list.RemoveUser(userEvent.user)
	if !ok {
		sendError(userEvent.user.input, "User not in list.")
		return
	}

	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	} else {
		m.hub.Broadcast(resp)
	}
}

func (m UserConnectionOpened) handle(userEvent UserEvent) {
	m.hub.connectedUsers[userEvent.user.Id] = userEvent.user
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m UserConnectionClosed) handle(userEvent UserEvent) {
	delete(m.hub.connectedUsers, userEvent.user.Id)
	sendUsersUpdateToAdmins(m.hub, userEvent.user)
}

func (m ListCreate) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	if userEvent.List.Title == "" {
		sendError(userEvent.user.input, "Can not create discussion with empty title")
		return
	}
	newList := CreateSpeakerList(userEvent.List.Title)
	m.hub.SpeakerLists = append(m.hub.SpeakerLists, &newList)
	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, fmt.Sprintf("Could not create new discussion, %v", err.Error()))
	} else {
		m.hub.Broadcast(resp)
	}
}

func (m ListDelete) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	err = m.hub.deleteList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	resp, err := createListsResponse(m.hub.SpeakerLists)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	m.hub.Broadcast(resp)
}

func (m ListPop) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}

	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	_, err = list.Pop()
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	}
	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	m.hub.Broadcast(resp)

}

func (m ListSetDiscussionStatus) handle(userEvent UserEvent) {
	if !userEvent.user.IsAdmin {
		sendError(userEvent.user.input, "Unauthorized")
		return
	}
	id, err := uuid.Parse(userEvent.ListId)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	list, err := m.hub.getList(id)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
		return
	}
	if !userEvent.List.Status.Valid() {
		sendError(userEvent.user.input, "Invalid status")
		return
	}
	list.Status = userEvent.List.Status
	resp, err := createListResponse(list)
	if err != nil {
		sendError(userEvent.user.input, err.Error())
	}
	m.hub.Broadcast(resp)
}

func sendListsResponse(userChannel chan messages.SendEvent, lists []*SpeakerList) {
	resp, err := createListsResponse(lists)
	if err != nil {
		sendError(userChannel, err.Error())
	} else {
		userChannel <- resp
	}

}

func sendUsersUpdateToAdmins(hub *Hub, user *User) {
	resp, err := hub.createUsersResponse()
	if err != nil {
		sendError(user.input, err.Error())
		return
	}
	hub.AdminBroadcast(resp)
}
<|endoftext|>


<commit_before>package plugins

import (
	"strconv"
	"ircclient"
	"fmt"
	"regexp"
)

type AuthPlugin struct {
	ic       *ircclient.IRCClient
	confplugin *ConfigPlugin
}

func NewAuthPlugin() *AuthPlugin {
	return &AuthPlugin{nil, nil}
}
func (a *AuthPlugin) Register(cl *ircclient.IRCClient) {
	a.ic = cl
	plugin, ok := a.ic.GetPlugin("config")
	if !ok {
		panic("AuthPlugin: Register: Unable to get configuration manager plugin")
	}
	a.confplugin, _ = plugin.(*ConfigPlugin)
	if !a.confplugin.Conf.HasSection("Auth") {
		panic("No \"Auth\" section in config file present")
	}
	options, _ := a.confplugin.Conf.Options("Auth")
	for _, mask := range options {
		if _, err := regexp.Compile(mask); err != nil {
			panic(err.String())
		}
	}
}
func (a *AuthPlugin) String() string {
	return "auth"
}
func (a *AuthPlugin) ProcessLine(msg *ircclient.IRCMessage) {
	// Empty
}
func (a *AuthPlugin) Unregister() {
	// Empty
}
func (a *AuthPlugin) Info() string {
	return "Access control manager"
}
func (a *AuthPlugin) ProcessCommand(cmd *ircclient.IRCCommand) {
	switch cmd.Command {
	case "myaccess": fallthrough
	case "mya":
		level := a.GetAccessLevel(cmd.Source)
		slevel := fmt.Sprintf("%d", level)
		a.ic.Reply(cmd, "Your access level is: " + slevel)
	case "addaccess":
		if len(cmd.Args) != 2 {
			a.ic.Reply(cmd, "addaccess takes two arguments: mask and access level")
			return
		}
		level := a.GetAccessLevel(cmd.Source)
		newlevel, err := strconv.Atoi(cmd.Args[1])
		if err != nil {
			a.ic.Reply(cmd, "Error: " + err.String())
		}
		if level < newlevel || level < 400 {
			a.ic.Reply(cmd, "You are not authorized to do this")
		}
		if _, err := regexp.Compile(cmd.Args[0]); err != nil {
			a.ic.Reply(cmd, "Error: Unable to compile regexp: " + err.String())
			return
		}
		a.confplugin.Lock()
		a.confplugin.Conf.AddOption("Auth", cmd.Args[0], fmt.Sprintf("%d", newlevel))
		a.confplugin.Unlock()
		a.ic.Reply(cmd, "Permissions granted")
	case "delaccess":
		if len(cmd.Args) != 1 {
			a.ic.Reply(cmd, "delaccess takes mask to delete as an argument")
			return
		}
		success := a.confplugin.Conf.RemoveOption("Auth", cmd.Args[0])
		if success {
			a.ic.Reply(cmd, "Successfully removed mask")
		} else {
			a.ic.Reply(cmd, "Mask not found")
		}
	}
}
func (a *AuthPlugin) GetAccessLevel(host string) int {
	a.confplugin.Lock()
	options, _ := a.confplugin.Conf.Options("Auth")
	maxaccess := 0
	for _, mask := range options {
		if match, _ := regexp.MatchString(mask, host); match == true {
			newaccess, _ := a.confplugin.Conf.Int("Auth", mask)
			if newaccess > maxaccess {
				maxaccess = newaccess
			}
		}
	}
	defer a.confplugin.Unlock()
	return maxaccess
}
<commit_msg>Some fixes in auth.go (/me is too tired)<commit_after>package plugins

import (
	"strconv"
	"ircclient"
	"fmt"
	"regexp"
)

type AuthPlugin struct {
	ic       *ircclient.IRCClient
	confplugin *ConfigPlugin
}

func NewAuthPlugin() *AuthPlugin {
	return &AuthPlugin{nil, nil}
}
func (a *AuthPlugin) Register(cl *ircclient.IRCClient) {
	a.ic = cl
	plugin, ok := a.ic.GetPlugin("config")
	if !ok {
		panic("AuthPlugin: Register: Unable to get configuration manager plugin")
	}
	a.confplugin, _ = plugin.(*ConfigPlugin)
	if !a.confplugin.Conf.HasSection("Auth") {
		panic("No \"Auth\" section in config file present")
	}
	options, _ := a.confplugin.Conf.Options("Auth")
	for _, mask := range options {
		if _, err := regexp.Compile(mask); err != nil {
			panic(err.String())
		}
	}
}
func (a *AuthPlugin) String() string {
	return "auth"
}
func (a *AuthPlugin) ProcessLine(msg *ircclient.IRCMessage) {
	// Empty
}
func (a *AuthPlugin) Unregister() {
	// Empty
}
func (a *AuthPlugin) Info() string {
	return "Access control manager"
}
func (a *AuthPlugin) ProcessCommand(cmd *ircclient.IRCCommand) {
	switch cmd.Command {
	case "myaccess": fallthrough
	case "mya":
		level := a.GetAccessLevel(cmd.Source)
		slevel := fmt.Sprintf("%d", level)
		a.ic.Reply(cmd, "Your access level is: " + slevel)
	case "addaccess":
		if len(cmd.Args) != 2 {
			a.ic.Reply(cmd, "addaccess takes two arguments: mask and access level")
			return
		}
		level := a.GetAccessLevel(cmd.Source)
		newlevel, err := strconv.Atoi(cmd.Args[1])
		if err != nil {
			a.ic.Reply(cmd, "Error: " + err.String())
		}
		if level < newlevel || level < 400 {
			a.ic.Reply(cmd, "You are not authorized to do this")
			return
		}
		if _, err := regexp.Compile(cmd.Args[0]); err != nil {
			a.ic.Reply(cmd, "Error: Unable to compile regexp: " + err.String())
			return
		}
		a.confplugin.Lock()
		a.confplugin.Conf.AddOption("Auth", cmd.Args[0], fmt.Sprintf("%d", newlevel))
		a.confplugin.Unlock()
		a.ic.Reply(cmd, "Permissions granted")
	case "delaccess":
		if len(cmd.Args) != 1 {
			a.ic.Reply(cmd, "delaccess takes mask to delete as an argument")
			return
		}
		level := a.GetAccessLevel(cmd.Source)
		dlevel, success := a.confplugin.Conf.Int("Auth", cmd.Args[0])
		if success == nil {
			if dlevel >= level || level != 500 {
				a.ic.Reply(cmd, "Can't remove mask: Has higher privileges than you")
				return
			}
			a.confplugin.Conf.RemoveOption("Auth", cmd.Args[0])
			a.ic.Reply(cmd, "Successfully removed mask")
		} else {
			a.ic.Reply(cmd, "Mask not found")
		}
	}
}
func (a *AuthPlugin) GetAccessLevel(host string) int {
	a.confplugin.Lock()
	options, _ := a.confplugin.Conf.Options("Auth")
	maxaccess := 0
	for _, mask := range options {
		if match, _ := regexp.MatchString(mask, host); match == true {
			newaccess, _ := a.confplugin.Conf.Int("Auth", mask)
			if newaccess > maxaccess {
				maxaccess = newaccess
			}
		}
	}
	defer a.confplugin.Unlock()
	return maxaccess
}
<|endoftext|>


<commit_before>package net

import (
	"errors"
	"net"
	"os/exec"
	"strings"
	"subutai/log"
)

func RemovePort(tunnelPortName string) error {

	log.Check(log.FatalLevel, "remove port 1",
		exec.Command("ovs-vsctl", "--if-exists", "del-port", tunnelPortName).Run())
	log.Check(log.FatalLevel, "remove port 2",
		exec.Command("ovs-vsctl", "--if-exists", "del-br", "br-"+tunnelPortName).Run())
	log.Check(log.FatalLevel, "remove port 3",
		exec.Command("ovs-vsctl", "--if-exists", "del-port", "br-int", "intto"+tunnelPortName).Run())
	return nil
}
func CheckTunnelPortNameValidity(name string) error {

	ret, _ := exec.Command("ovs-vsctl", "list-ports", "br-"+name).CombinedOutput()
	str := strings.Split(string(ret), "\n")
	if !strings.Contains(name, "tunnel") {
		return errors.New("tunnel name must containe \"tunnel\" tag")
	}
	for _, v := range str {
		if strings.Contains(string(v), "no bridge named") {
			return nil
		} else if strings.Contains(string(v), name) {
			return errors.New("Tunnel Port Name " + name + " is already exists")
		}
	}
	return nil
}

func ListTunnels() string {
	list, err := exec.Command("ovs-vsctl", "show").CombinedOutput()
	log.Check(log.FatalLevel, "Getting OVS interfaces", err)
	return string(list)
}

func CheckIPValidity(l []string, name string) error {
	ip := net.ParseIP(name) // to see if it is valid ip...

	for _, v := range l {
		if strings.Contains(string(v), ip.String()) {
			return errors.New(ip.String() + " is already used")
		}
	}
	return nil
}

func CreateTunnel(l []string, tunnelPortName, tunnelIPAddress, tunnelType string) error {
	// check: ip addr is already checked if valid... so
	var getTun string
	t := strings.Split(tunnelIPAddress, ".")
	t1 := t[0] + "." + t[1] + "." + t[2]
	for _, v := range l {
		if strings.Contains(string(v), t1) {
			ss := strings.Split(v, " ")
			getTun = ss[0]
		}
	}
	if getTun != "" {
		log.Info("getTun: " + getTun)
		out, err := exec.Command("ovs-vsctl", "--may-exist", "add-port", "br-"+getTun, tunnelPortName).CombinedOutput()
		log.Check(log.FatalLevel, "Adding port to Open vSwitch"+string(out), err)
		out, err = exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName, "type="+tunnelType, "options:key=flow", "options:remote_ip="+tunnelIPAddress).CombinedOutput()
		log.Check(log.FatalLevel, "Adding tunnel to Open vSwitch"+string(out), err)
	} else {
		log.Check(log.FatalLevel, "Create tunnel 0",
			exec.Command("ovs-vsctl", "--may-exist", "add-br", "br-"+tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 1",
			exec.Command("ovs-vsctl", "set", "bridge", "br-"+tunnelPortName, "stp_enable=true").Run())
		log.Check(log.FatalLevel, "Create tunnel 2",
			exec.Command("ovs-vsctl", "add-port", "br-"+tunnelPortName, tunnelPortName+"toint").Run())
		log.Check(log.FatalLevel, "Create tunnel 3",
			exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName+"toint", "type=patch").Run())
		log.Check(log.FatalLevel, "Create tunnel 4",
			exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName+"toint", "options:peer=intto"+tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 5",
			exec.Command("ovs-vsctl", "add-port", "br-int", "intto"+tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 6",
			exec.Command("ovs-vsctl", "set", "Interface", "intto"+tunnelPortName, "type=patch").Run())
		log.Check(log.FatalLevel, "Create tunnel 7",
			exec.Command("ovs-vsctl", "set", "Interface", "intto"+tunnelPortName, "options:peer="+tunnelPortName+"toint").Run())
		log.Check(log.FatalLevel, "Create tunnel 8",
			exec.Command("ovs-vsctl", "--may-exist", "add-port", "br-"+tunnelPortName, tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 9",
			exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName, "type="+tunnelType,
				"options:key=flow", "options:remote_ip="+tunnelIPAddress).Run())
	}
	return nil
}

func checkBridgeName(bridgeName string) error {
	result, err := exec.Command("ovs-vsctl", "list-br").Output()
	if err != nil {
		return err
	}
	if !strings.Contains(string(result), bridgeName) {
		return errors.New(bridgeName + " is not in the list of bridges.")
	}
	return nil
}

func AddFlowConfig(bridgeName, flowCfg string) error {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	log.Info("Bridge name is ok")
	result, errExec := exec.Command("ovs-ofctl", "add-flow", bridgeName, flowCfg).CombinedOutput()
	if errExec != nil {
		return errors.New(string(result))
	}
	return nil
}

func DumpBridge(bridgeName string) (string, error) {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	result, err := exec.Command("ovs-ofctl", "dump-flows", bridgeName).CombinedOutput()
	if err != nil {
		return string(result), err
	}
	return string(result), nil
}

func DumpPort(bridgeName string) (string, error) {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	result, err := exec.Command("ovs-ofctl", "show", bridgeName).CombinedOutput()
	if err != nil {
		return string(result), err
	}
	return string(result), nil
}

func DeleteFlow(bridgeName, matchCase string) error {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	if matchCase == "all" {
		s, err := exec.Command("ovs-ofctl", "del-flows", bridgeName).CombinedOutput()
		if err != nil {
			return errors.New(string(s))
		}
	} else {
		s, err := exec.Command("ovs-ofctl", "del-flows", bridgeName, matchCase).CombinedOutput()
		if err != nil {
			return errors.New(string(s))
		}
	}
	return nil
}
<commit_msg>Fixed tunnel creating output in CLI. SS-4100<commit_after>package net

import (
	"errors"
	"net"
	"os/exec"
	"strings"
	"subutai/log"
)

func RemovePort(tunnelPortName string) error {

	log.Check(log.FatalLevel, "remove port 1",
		exec.Command("ovs-vsctl", "--if-exists", "del-port", tunnelPortName).Run())
	log.Check(log.FatalLevel, "remove port 2",
		exec.Command("ovs-vsctl", "--if-exists", "del-br", "br-"+tunnelPortName).Run())
	log.Check(log.FatalLevel, "remove port 3",
		exec.Command("ovs-vsctl", "--if-exists", "del-port", "br-int", "intto"+tunnelPortName).Run())
	return nil
}
func CheckTunnelPortNameValidity(name string) error {

	ret, _ := exec.Command("ovs-vsctl", "list-ports", "br-"+name).CombinedOutput()
	str := strings.Split(string(ret), "\n")
	if !strings.Contains(name, "tunnel") {
		return errors.New("tunnel name must containe \"tunnel\" tag")
	}
	for _, v := range str {
		if strings.Contains(string(v), "no bridge named") {
			return nil
		} else if strings.Contains(string(v), name) {
			return errors.New("Tunnel Port Name " + name + " is already exists")
		}
	}
	return nil
}

func ListTunnels() string {
	list, err := exec.Command("ovs-vsctl", "show").CombinedOutput()
	log.Check(log.FatalLevel, "Getting OVS interfaces", err)
	return string(list)
}

func CheckIPValidity(l []string, name string) error {
	ip := net.ParseIP(name) // to see if it is valid ip...

	for _, v := range l {
		if strings.Contains(string(v), ip.String()) {
			return errors.New(ip.String() + " is already used")
		}
	}
	return nil
}

func CreateTunnel(l []string, tunnelPortName, tunnelIPAddress, tunnelType string) error {
	// check: ip addr is already checked if valid... so
	var getTun string
	t := strings.Split(tunnelIPAddress, ".")
	t1 := t[0] + "." + t[1] + "." + t[2]
	for _, v := range l {
		if strings.Contains(string(v), t1) {
			ss := strings.Split(v, "-")
			getTun = ss[0]
		}
	}
	if getTun != "" {
		log.Info("getTun: " + getTun)
		out, err := exec.Command("ovs-vsctl", "--may-exist", "add-port", "br-"+getTun, tunnelPortName).CombinedOutput()
		log.Check(log.FatalLevel, "Adding port to Open vSwitch"+string(out), err)
		out, err = exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName, "type="+tunnelType, "options:key=flow", "options:remote_ip="+tunnelIPAddress).CombinedOutput()
		log.Check(log.FatalLevel, "Adding tunnel to Open vSwitch"+string(out), err)
	} else {
		log.Check(log.FatalLevel, "Create tunnel 0",
			exec.Command("ovs-vsctl", "--may-exist", "add-br", "br-"+tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 1",
			exec.Command("ovs-vsctl", "set", "bridge", "br-"+tunnelPortName, "stp_enable=true").Run())
		log.Check(log.FatalLevel, "Create tunnel 2",
			exec.Command("ovs-vsctl", "add-port", "br-"+tunnelPortName, tunnelPortName+"toint").Run())
		log.Check(log.FatalLevel, "Create tunnel 3",
			exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName+"toint", "type=patch").Run())
		log.Check(log.FatalLevel, "Create tunnel 4",
			exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName+"toint", "options:peer=intto"+tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 5",
			exec.Command("ovs-vsctl", "add-port", "br-int", "intto"+tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 6",
			exec.Command("ovs-vsctl", "set", "Interface", "intto"+tunnelPortName, "type=patch").Run())
		log.Check(log.FatalLevel, "Create tunnel 7",
			exec.Command("ovs-vsctl", "set", "Interface", "intto"+tunnelPortName, "options:peer="+tunnelPortName+"toint").Run())
		log.Check(log.FatalLevel, "Create tunnel 8",
			exec.Command("ovs-vsctl", "--may-exist", "add-port", "br-"+tunnelPortName, tunnelPortName).Run())
		log.Check(log.FatalLevel, "Create tunnel 9",
			exec.Command("ovs-vsctl", "set", "Interface", tunnelPortName, "type="+tunnelType,
				"options:key=flow", "options:remote_ip="+tunnelIPAddress).Run())
	}
	return nil
}

func checkBridgeName(bridgeName string) error {
	result, err := exec.Command("ovs-vsctl", "list-br").Output()
	if err != nil {
		return err
	}
	if !strings.Contains(string(result), bridgeName) {
		return errors.New(bridgeName + " is not in the list of bridges.")
	}
	return nil
}

func AddFlowConfig(bridgeName, flowCfg string) error {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	log.Info("Bridge name is ok")
	result, errExec := exec.Command("ovs-ofctl", "add-flow", bridgeName, flowCfg).CombinedOutput()
	if errExec != nil {
		return errors.New(string(result))
	}
	return nil
}

func DumpBridge(bridgeName string) (string, error) {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	result, err := exec.Command("ovs-ofctl", "dump-flows", bridgeName).CombinedOutput()
	if err != nil {
		return string(result), err
	}
	return string(result), nil
}

func DumpPort(bridgeName string) (string, error) {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	result, err := exec.Command("ovs-ofctl", "show", bridgeName).CombinedOutput()
	if err != nil {
		return string(result), err
	}
	return string(result), nil
}

func DeleteFlow(bridgeName, matchCase string) error {
	log.Check(log.FatalLevel, "check bridge name", checkBridgeName(bridgeName))
	if matchCase == "all" {
		s, err := exec.Command("ovs-ofctl", "del-flows", bridgeName).CombinedOutput()
		if err != nil {
			return errors.New(string(s))
		}
	} else {
		s, err := exec.Command("ovs-ofctl", "del-flows", bridgeName, matchCase).CombinedOutput()
		if err != nil {
			return errors.New(string(s))
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package swp

import (
	"fmt"
	"time"

	cv "github.com/glycerine/goconvey/convey"
	"testing"
)

// check for:
//
// packet loss - eventually received and/or re-requested.
// duplicate receives - discard the 2nd one.
// out of order receives - reorder correctly.
//
// And flow control - client consumer buffers never overflow.
//

func Test001Network(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 2 * lat

	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	A.Push(p1)

	time.Sleep(time.Second)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, sending a packet on a non-lossy network from A to B, the packet should arrive at B", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 1)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 1)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test002LostPacketTimesOutAndIsRetransmitted(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	net.DiscardOnce = Seqno(0)
	rtt := 2 * lat

	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	A.Push(p1)

	time.Sleep(time.Second)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, if a packet from A to B is lost, the timeout mechanism in the sender should notice that it didn't get the ack, and should resend.", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 1)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 1)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test003MisorderedPacketsAreReordered(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 2 * lat

	p("effectively turning off replays for this test")
	rtt = time.Hour
	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	p2 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("two"),
	}

	net.SimulateReorderNext = 1

	A.Push(p1)

	time.Sleep(50 * time.Millisecond)

	p("due to the hold-back, B should not have gotten anything, packet should have been held.")
	cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 0)

	A.Push(p2)

	time.Sleep(300 * time.Millisecond)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, if a packets 0 and 1 from A to B are reordered so as to arrive in order 1, 0; the sliding window protocol should correctly re-order and deliver them in order.", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 2)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 2)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test004DuplicatedPacketIsDiscarded(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 2 * lat

	p("effectively turning off replays for this test")
	rtt = time.Hour
	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p2 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("two"),
	}

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	A.Push(p1)
	net.DuplicateNext = true
	A.Push(p2)

	time.Sleep(100 * time.Millisecond)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, if the network (or resends) results in a packet with a duplicate SeqNum to one already received; the sliding window protocol should reject the delivery and drop the packet.", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 2)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 2)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test006AlgorithmWithstandsNoisyNetworks(t *testing.T) {

	// works quickly even with 20% packet loss:
	lossProb := float64(0.20)
	//	lossProb := float64(0.10)
	//	lossProb := float64(0.05)
	//  lossProb := float64(0)
	lat := 1 * time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 3 * lat

	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	B.Swp.Sender.LastFrameSent = 999
	panicOn(err)

	n := 100
	seq := make([]*Packet, n)
	for i := range seq {
		pack := &Packet{
			From: "A",
			Dest: "B",
			Data: []byte(fmt.Sprintf("%v", i)),
		}
		seq[i] = pack
	}

	for i := range seq {
		A.Push(seq[i])
	}

	time.Sleep(1000 * time.Millisecond)

	A.Stop()
	B.Stop()

	smy := net.Summary()
	smy.Print()

	cv.Convey("Given two nodes A and B, even if the network is noisy, the SWP should eventually deliver our sequence in order.", t, func() {
		//cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 100)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 100)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}
<commit_msg>atg. keep goconvey happy<commit_after>package swp

import (
	"fmt"
	"time"

	cv "github.com/glycerine/goconvey/convey"
	"testing"
)

// check for:
//
// packet loss - eventually received and/or re-requested.
// duplicate receives - discard the 2nd one.
// out of order receives - reorder correctly.
//
// And flow control - client consumer buffers never overflow.
//

func Test001Network(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 2 * lat

	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	A.Push(p1)

	time.Sleep(time.Second)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, sending a packet on a non-lossy network from A to B, the packet should arrive at B", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 1)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 1)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test002LostPacketTimesOutAndIsRetransmitted(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	net.DiscardOnce = Seqno(0)
	rtt := 2 * lat

	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	A.Push(p1)

	time.Sleep(time.Second)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, if a packet from A to B is lost, the timeout mechanism in the sender should notice that it didn't get the ack, and should resend.", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 1)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 1)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test003MisorderedPacketsAreReordered(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 2 * lat

	p("effectively turning off replays for this test")
	rtt = time.Hour
	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	p2 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("two"),
	}

	net.SimulateReorderNext = 1

	A.Push(p1)

	time.Sleep(50 * time.Millisecond)

	p("due to the hold-back, B should not have gotten anything, packet should have been held.")
	if len(B.Swp.Recver.RecvHistory) != 0 {
		panic("should have some B history")
	}

	A.Push(p2)

	time.Sleep(300 * time.Millisecond)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, if a packets 0 and 1 from A to B are reordered so as to arrive in order 1, 0; the sliding window protocol should correctly re-order and deliver them in order.", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 2)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 2)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test004DuplicatedPacketIsDiscarded(t *testing.T) {

	lossProb := float64(0)
	lat := time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 2 * lat

	p("effectively turning off replays for this test")
	rtt = time.Hour
	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	panicOn(err)

	p2 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("two"),
	}

	p1 := &Packet{
		From: "A",
		Dest: "B",
		Data: []byte("one"),
	}

	A.Push(p1)
	net.DuplicateNext = true
	A.Push(p2)

	time.Sleep(100 * time.Millisecond)

	A.Stop()
	B.Stop()

	cv.Convey("Given two nodes A and B, if the network (or resends) results in a packet with a duplicate SeqNum to one already received; the sliding window protocol should reject the delivery and drop the packet.", t, func() {
		cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 2)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 2)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}

func Test006AlgorithmWithstandsNoisyNetworks(t *testing.T) {

	// works quickly even with 20% packet loss:
	lossProb := float64(0.20)
	//	lossProb := float64(0.10)
	//	lossProb := float64(0.05)
	//  lossProb := float64(0)
	lat := 1 * time.Millisecond
	net := NewSimNet(lossProb, lat)
	rtt := 3 * lat

	A, err := NewSession(net, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(net, "B", "A", 3, rtt)
	B.Swp.Sender.LastFrameSent = 999
	panicOn(err)

	n := 100
	seq := make([]*Packet, n)
	for i := range seq {
		pack := &Packet{
			From: "A",
			Dest: "B",
			Data: []byte(fmt.Sprintf("%v", i)),
		}
		seq[i] = pack
	}

	for i := range seq {
		A.Push(seq[i])
	}

	time.Sleep(1000 * time.Millisecond)

	A.Stop()
	B.Stop()

	smy := net.Summary()
	smy.Print()

	cv.Convey("Given two nodes A and B, even if the network is noisy, the SWP should eventually deliver our sequence in order.", t, func() {
		//cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 100)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 100)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}
<|endoftext|>


<commit_before>package structure

import (
	"testing"
)

func TestNormalizeJsonString(t *testing.T) {
	var err error
	var actual string

	// Well formatted and valid.
	validJson := `{
   "abc": {
      "def": 123,
      "xyz": [
         {
            "a": "ホリネズミ"
         },
         {
            "b": "1\\n2"
         }
      ]
   }
}`
	expected := `{"abc":{"def":123,"xyz":[{"a":"ホリネズミ"},{"b":"1\\n2"}]}}`

	actual, err = NormalizeJsonString(validJson)
	if err != nil {
		t.Fatalf("Expected not to throw an error while parsing JSON, but got: %s", err)
	}

	if actual != expected {
		t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, expected)
	}

	// Well formatted but not valid,
	// missing closing squre bracket.
	invalidJson := `{
   "abc": {
      "def": 123,
      "xyz": [
         {
            "a": "1"
         }
      }
   }
}`
	actual, err = NormalizeJsonString(invalidJson)
	if err == nil {
		t.Fatalf("Expected to throw an error while parsing JSON, but got: %s", err)
	}

	// We expect the invalid JSON to be shown back to us again.
	if actual != invalidJson {
		t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", expected, invalidJson)
	}
}
<commit_msg>Splitting the structure tests<commit_after>package structure

import (
	"testing"
)

func TestNormalizeJsonString_valid(t *testing.T) {
	// Well formatted and valid.
	validJson := `{
   "abc": {
      "def": 123,
      "xyz": [
         {
            "a": "ホリネズミ"
         },
         {
            "b": "1\\n2"
         }
      ]
   }
}`
	expected := `{"abc":{"def":123,"xyz":[{"a":"ホリネズミ"},{"b":"1\\n2"}]}}`

	actual, err := NormalizeJsonString(validJson)
	if err != nil {
		t.Fatalf("Expected not to throw an error while parsing JSON, but got: %s", err)
	}

	if actual != expected {
		t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, expected)
	}
}

func TestNormalizeJsonString_invalid(t *testing.T) {
	// Well formatted but not valid,
	// missing closing squre bracket.
	invalidJson := `{
   "abc": {
      "def": 123,
      "xyz": [
         {
            "a": "1"
         }
      }
   }
}`
	expected := `{"abc":{"def":123,"xyz":[{"a":"ホリネズミ"},{"b":"1\\n2"}]}}`
	actual, err := NormalizeJsonString(invalidJson)
	if err == nil {
		t.Fatalf("Expected to throw an error while parsing JSON, but got: %s", err)
	}

	// We expect the invalid JSON to be shown back to us again.
	if actual != invalidJson {
		t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", expected, invalidJson)
	}
}
<|endoftext|>


<commit_before>package logger

import (
	"io"
	"os"
)

var MyLogger *Logger

func SetLevel(lv uint8) {
	MyLogger.lv = lv
}

func SetTimeFormat(timeFormat string) {
	MyLogger.timeFormat = timeFormat
}

func SetPrefix(prefix string) {
	MyLogger.prefix = prefix
}

func SetColor(color bool) {
	MyLogger.color = color
}

func SetOutput(out ...io.Writer) {
	MyLogger.out = out
}

func Trace(format string, msg ...interface{}) {
	MyLogger.Trace(format, msg...)
}
func Debug(format string, msg ...interface{}) {
	MyLogger.Debug(format, msg...)
}
func Info(format string, msg ...interface{}) {
	MyLogger.Info(format, msg...)
}
func Warn(format string, msg ...interface{}) {
	MyLogger.Warn(format, msg...)
}
func Error(format string, msg ...interface{}) {
	MyLogger.Error(format, msg...)
}
func Fatal(format string, msg ...interface{}) {
	MyLogger.Fatal(format, msg...)
}
func Panic(format string, msg ...interface{}) {
	MyLogger.Panic(format, msg...)
}

func init() {
	MyLogger = NewLogger("2006/01/02 15:04:05.000", DEBUG, os.Stdout)
	MyLogger.SetStack(false)
}
<commit_msg>Update logger<commit_after>package logger

import (
	"io"
	"os"
)

var MyLogger *Logger

func SetLevel(lv uint8) {
	MyLogger.lv = lv
}

func SetTimeFormat(timeFormat string) {
	MyLogger.timeFormat = timeFormat
}

func SetPrefix(prefix string) {
	MyLogger.prefix = prefix
}

func SetColor(color bool) {
	MyLogger.color = color
}

func SetOutput(out ...io.Writer) {
	MyLogger.out = out
}
func Output(lv uint8, format string, msg ...interface{}) {
	MyLogger.Output(lv, format, msg...)
}

func Trace(format string, msg ...interface{}) {
	MyLogger.Trace(format, msg...)
}
func Debug(format string, msg ...interface{}) {
	MyLogger.Debug(format, msg...)
}
func Info(format string, msg ...interface{}) {
	MyLogger.Info(format, msg...)
}
func Warn(format string, msg ...interface{}) {
	MyLogger.Warn(format, msg...)
}
func Error(format string, msg ...interface{}) {
	MyLogger.Error(format, msg...)
}
func Fatal(format string, msg ...interface{}) {
	MyLogger.Fatal(format, msg...)
}
func Panic(format string, msg ...interface{}) {
	MyLogger.Panic(format, msg...)
}

func init() {
	MyLogger = NewLogger("2006/01/02 15:04:05.000", DEBUG, os.Stdout)
	MyLogger.SetStack(false)
}
<|endoftext|>


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

package binprot

import (
	"encoding/binary"
	"errors"
	"io"

	"github.com/netflix/rend/common"
	"github.com/netflix/rend/metrics"
)

var ErrBadMagic = errors.New("Bad magic value")

const (
	MagicRequest  = uint8(0x80)
	MagicResponse = uint8(0x81)

	// All opcodes as defined in memcached
	// Minus SASL and range ops
	OpcodeGet        = uint8(0x00)
	OpcodeSet        = uint8(0x01)
	OpcodeAdd        = uint8(0x02)
	OpcodeReplace    = uint8(0x03)
	OpcodeDelete     = uint8(0x04)
	OpcodeIncrement  = uint8(0x05)
	OpcodeDecrement  = uint8(0x06)
	OpcodeQuit       = uint8(0x07)
	OpcodeFlush      = uint8(0x08)
	OpcodeGetQ       = uint8(0x09)
	OpcodeNoop       = uint8(0x0a)
	OpcodeVersion    = uint8(0x0b)
	OpcodeGetK       = uint8(0x0c)
	OpcodeGetKQ      = uint8(0x0d)
	OpcodeAppend     = uint8(0x0e)
	OpcodePrepend    = uint8(0x0f)
	OpcodeStat       = uint8(0x10)
	OpcodeSetQ       = uint8(0x11)
	OpcodeAddQ       = uint8(0x12)
	OpcodeReplaceQ   = uint8(0x13)
	OpcodeDeleteQ    = uint8(0x14)
	OpcodeIncrementQ = uint8(0x15)
	OpcodeDecrementQ = uint8(0x16)
	OpcodeQuitQ      = uint8(0x17)
	OpcodeFlushQ     = uint8(0x18)
	OpcodeAppendQ    = uint8(0x19)
	OpcodePrependQ   = uint8(0x1a)
	OpcodeTouch      = uint8(0x1c)
	OpcodeGat        = uint8(0x1d)
	OpcodeGatQ       = uint8(0x1e)
	OpcodeGatK       = uint8(0x23)
	OpcodeGatKQ      = uint8(0x24)
	OpcodeInvalid    = uint8(0xFF)

	StatusSuccess        = uint16(0x00)
	StatusKeyEnoent      = uint16(0x01)
	StatusKeyEexists     = uint16(0x02)
	StatusE2big          = uint16(0x03)
	StatusEinval         = uint16(0x04)
	StatusNotStored      = uint16(0x05)
	StatusDeltaBadval    = uint16(0x06)
	StatusAuthError      = uint16(0x20)
	StatusAuthContinue   = uint16(0x21)
	StatusUnknownCommand = uint16(0x81)
	StatusEnomem         = uint16(0x82)
	StatusNotSupported   = uint16(0x83)
	StatusInternalError  = uint16(0x84)
	StatusBusy           = uint16(0x85)
	StatusTempFailure    = uint16(0x86)
	StatusInvalid        = uint16(0xFFFF)
)

func DecodeError(header ResponseHeader) error {
	switch header.Status {
	case StatusKeyEnoent:
		return common.ErrKeyNotFound
	case StatusKeyEexists:
		return common.ErrKeyExists
	case StatusE2big:
		return common.ErrValueTooBig
	case StatusEinval:
		return common.ErrInvalidArgs
	case StatusNotStored:
		return common.ErrItemNotStored
	case StatusDeltaBadval:
		return common.ErrBadIncDecValue
	case StatusAuthError:
		return common.ErrAuth
	case StatusUnknownCommand:
		return common.ErrUnknownCmd
	case StatusEnomem:
		return common.ErrNoMem
	case StatusNotSupported:
		return common.ErrNotSupported
	case StatusInternalError:
		return common.ErrInternal
	case StatusBusy:
		return common.ErrBusy
	case StatusTempFailure:
		return common.ErrTempFailure
	}
	return nil
}

func errorToCode(err error) uint16 {
	switch err {
	case common.ErrKeyNotFound:
		return StatusKeyEnoent
	case common.ErrKeyExists:
		return StatusKeyEexists
	case common.ErrValueTooBig:
		return StatusE2big
	case common.ErrInvalidArgs:
		return StatusEinval
	case common.ErrItemNotStored:
		return StatusNotStored
	case common.ErrBadIncDecValue:
		return StatusDeltaBadval
	case common.ErrAuth:
		return StatusAuthError
	case common.ErrUnknownCmd:
		return StatusUnknownCommand
	case common.ErrNoMem:
		return StatusEnomem
	case common.ErrNotSupported:
		return StatusNotSupported
	case common.ErrInternal:
		return StatusInternalError
	case common.ErrBusy:
		return StatusBusy
	case common.ErrTempFailure:
		return StatusTempFailure
	}
	return StatusInvalid
}

const ReqHeaderLen = 24

type RequestHeader struct {
	Magic           uint8 // Already known, since we're here
	Opcode          uint8
	KeyLength       uint16
	ExtraLength     uint8
	DataType        uint8  // Always 0
	VBucket         uint16 // Not used
	TotalBodyLength uint32
	OpaqueToken     uint32 // Echoed to the client
	CASToken        uint64 // Unused in current implementation
}

func MakeRequestHeader(opcode uint8, keyLength, extraLength, totalBodyLength int) RequestHeader {
	return RequestHeader{
		Magic:           MagicRequest,
		Opcode:          uint8(opcode),
		KeyLength:       uint16(keyLength),
		ExtraLength:     uint8(extraLength),
		DataType:        uint8(0),
		VBucket:         uint16(0),
		TotalBodyLength: uint32(totalBodyLength),
		OpaqueToken:     uint32(0),
		CASToken:        uint64(0),
	}
}

func ReadRequestHeader(reader io.Reader) (RequestHeader, error) {
	var reqHeader RequestHeader
	if err := binary.Read(reader, binary.BigEndian, &reqHeader); err != nil {
		return RequestHeader{}, err
	}

	metrics.IncCounterBy(common.MetricBytesReadRemote, ReqHeaderLen)

	if reqHeader.Magic != MagicRequest {
		return RequestHeader{}, ErrBadMagic
	}

	return reqHeader, nil
}

const resHeaderLen = 24

type ResponseHeader struct {
	Magic           uint8 // always 0x81
	Opcode          uint8
	KeyLength       uint16
	ExtraLength     uint8
	DataType        uint8 // unused, always 0
	Status          uint16
	TotalBodyLength uint32
	OpaqueToken     uint32 // same as the user passed in
	CASToken        uint64
}

func ReadResponseHeader(reader io.Reader) (ResponseHeader, error) {
	var resHeader ResponseHeader
	if err := binary.Read(reader, binary.BigEndian, &resHeader); err != nil {
		return ResponseHeader{}, err
	}

	metrics.IncCounterBy(common.MetricBytesReadLocal, resHeaderLen)

	if resHeader.Magic != MagicResponse {
		return ResponseHeader{}, ErrBadMagic
	}

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

package binprot

import (
	"encoding/binary"
	"errors"
	"io"

	"github.com/netflix/rend/common"
	"github.com/netflix/rend/metrics"
)

var ErrBadMagic = errors.New("Bad magic value")

const (
	MagicRequest  = uint8(0x80)
	MagicResponse = uint8(0x81)

	// All opcodes as defined in memcached
	// Minus SASL and range ops
	OpcodeGet        = uint8(0x00)
	OpcodeSet        = uint8(0x01)
	OpcodeAdd        = uint8(0x02)
	OpcodeReplace    = uint8(0x03)
	OpcodeDelete     = uint8(0x04)
	OpcodeIncrement  = uint8(0x05)
	OpcodeDecrement  = uint8(0x06)
	OpcodeQuit       = uint8(0x07)
	OpcodeFlush      = uint8(0x08)
	OpcodeGetQ       = uint8(0x09)
	OpcodeNoop       = uint8(0x0a)
	OpcodeVersion    = uint8(0x0b)
	OpcodeGetK       = uint8(0x0c)
	OpcodeGetKQ      = uint8(0x0d)
	OpcodeAppend     = uint8(0x0e)
	OpcodePrepend    = uint8(0x0f)
	OpcodeStat       = uint8(0x10)
	OpcodeSetQ       = uint8(0x11)
	OpcodeAddQ       = uint8(0x12)
	OpcodeReplaceQ   = uint8(0x13)
	OpcodeDeleteQ    = uint8(0x14)
	OpcodeIncrementQ = uint8(0x15)
	OpcodeDecrementQ = uint8(0x16)
	OpcodeQuitQ      = uint8(0x17)
	OpcodeFlushQ     = uint8(0x18)
	OpcodeAppendQ    = uint8(0x19)
	OpcodePrependQ   = uint8(0x1a)
	OpcodeTouch      = uint8(0x1c)
	OpcodeGat        = uint8(0x1d)
	OpcodeGatQ       = uint8(0x1e)
	OpcodeGatK       = uint8(0x23)
	OpcodeGatKQ      = uint8(0x24)
	OpcodeInvalid    = uint8(0xFF)

	StatusSuccess        = uint16(0x00)
	StatusKeyEnoent      = uint16(0x01)
	StatusKeyExists      = uint16(0x02)
	StatusE2big          = uint16(0x03)
	StatusEinval         = uint16(0x04)
	StatusNotStored      = uint16(0x05)
	StatusDeltaBadval    = uint16(0x06)
	StatusAuthError      = uint16(0x20)
	StatusAuthContinue   = uint16(0x21)
	StatusUnknownCommand = uint16(0x81)
	StatusEnomem         = uint16(0x82)
	StatusNotSupported   = uint16(0x83)
	StatusInternalError  = uint16(0x84)
	StatusBusy           = uint16(0x85)
	StatusTempFailure    = uint16(0x86)
	StatusInvalid        = uint16(0xFFFF)
)

func DecodeError(header ResponseHeader) error {
	switch header.Status {
	case StatusKeyEnoent:
		return common.ErrKeyNotFound
	case StatusKeyExists:
		return common.ErrKeyExists
	case StatusE2big:
		return common.ErrValueTooBig
	case StatusEinval:
		return common.ErrInvalidArgs
	case StatusNotStored:
		return common.ErrItemNotStored
	case StatusDeltaBadval:
		return common.ErrBadIncDecValue
	case StatusAuthError:
		return common.ErrAuth
	case StatusUnknownCommand:
		return common.ErrUnknownCmd
	case StatusEnomem:
		return common.ErrNoMem
	case StatusNotSupported:
		return common.ErrNotSupported
	case StatusInternalError:
		return common.ErrInternal
	case StatusBusy:
		return common.ErrBusy
	case StatusTempFailure:
		return common.ErrTempFailure
	}
	return nil
}

func errorToCode(err error) uint16 {
	switch err {
	case common.ErrKeyNotFound:
		return StatusKeyEnoent
	case common.ErrKeyExists:
		return StatusKeyExists
	case common.ErrValueTooBig:
		return StatusE2big
	case common.ErrInvalidArgs:
		return StatusEinval
	case common.ErrItemNotStored:
		return StatusNotStored
	case common.ErrBadIncDecValue:
		return StatusDeltaBadval
	case common.ErrAuth:
		return StatusAuthError
	case common.ErrUnknownCmd:
		return StatusUnknownCommand
	case common.ErrNoMem:
		return StatusEnomem
	case common.ErrNotSupported:
		return StatusNotSupported
	case common.ErrInternal:
		return StatusInternalError
	case common.ErrBusy:
		return StatusBusy
	case common.ErrTempFailure:
		return StatusTempFailure
	}
	return StatusInvalid
}

const ReqHeaderLen = 24

type RequestHeader struct {
	Magic           uint8 // Already known, since we're here
	Opcode          uint8
	KeyLength       uint16
	ExtraLength     uint8
	DataType        uint8  // Always 0
	VBucket         uint16 // Not used
	TotalBodyLength uint32
	OpaqueToken     uint32 // Echoed to the client
	CASToken        uint64 // Unused in current implementation
}

func MakeRequestHeader(opcode uint8, keyLength, extraLength, totalBodyLength int) RequestHeader {
	return RequestHeader{
		Magic:           MagicRequest,
		Opcode:          uint8(opcode),
		KeyLength:       uint16(keyLength),
		ExtraLength:     uint8(extraLength),
		DataType:        uint8(0),
		VBucket:         uint16(0),
		TotalBodyLength: uint32(totalBodyLength),
		OpaqueToken:     uint32(0),
		CASToken:        uint64(0),
	}
}

func ReadRequestHeader(reader io.Reader) (RequestHeader, error) {
	var reqHeader RequestHeader
	if err := binary.Read(reader, binary.BigEndian, &reqHeader); err != nil {
		return RequestHeader{}, err
	}

	metrics.IncCounterBy(common.MetricBytesReadRemote, ReqHeaderLen)

	if reqHeader.Magic != MagicRequest {
		return RequestHeader{}, ErrBadMagic
	}

	return reqHeader, nil
}

const resHeaderLen = 24

type ResponseHeader struct {
	Magic           uint8 // always 0x81
	Opcode          uint8
	KeyLength       uint16
	ExtraLength     uint8
	DataType        uint8 // unused, always 0
	Status          uint16
	TotalBodyLength uint32
	OpaqueToken     uint32 // same as the user passed in
	CASToken        uint64
}

func ReadResponseHeader(reader io.Reader) (ResponseHeader, error) {
	var resHeader ResponseHeader
	if err := binary.Read(reader, binary.BigEndian, &resHeader); err != nil {
		return ResponseHeader{}, err
	}

	metrics.IncCounterBy(common.MetricBytesReadLocal, resHeaderLen)

	if resHeader.Magic != MagicResponse {
		return ResponseHeader{}, ErrBadMagic
	}

	return resHeader, nil
}
<|endoftext|>


<commit_before>package routes

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"regexp"

	"log"

	"github.com/DVI-GI-2017/Jira__backend/params"
)

func NewRouter(rootPath string) (*router, error) {
	r := &router{}
	r.routes = make(map[string]map[*regexp.Regexp]Route)

	r.routes[http.MethodGet] = make(map[*regexp.Regexp]Route)
	r.routes[http.MethodPost] = make(map[*regexp.Regexp]Route)

	err := r.SetRootPath(rootPath)
	if err != nil {
		return r, err
	}

	return r, nil
}

type router struct {
	root *url.URL

	routes map[string]map[*regexp.Regexp]Route
}

// Set router root path, other paths will be relative to it
func (r *router) SetRootPath(path string) error {
	newRoot, err := url.Parse(path)
	if err != nil {
		return fmt.Errorf("invalid path format %s: %v", path, err)
	}

	r.root = newRoot

	return nil
}

// Listen on given port
func (r *router) ListenAndServe(port string) error {
	return http.ListenAndServe(fmt.Sprintf(":%s", port), r)
}

// Implements http.Handler interface
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	relPath, err := relativePath(r.root.Path, req.URL.Path)
	if err != nil {
		http.NotFound(w, req)
	}

	r.handleRequest(w, req, relPath)
}

// Handles request: iterate over all routes before finds first matching route.
func (r *router) handleRequest(w http.ResponseWriter, req *http.Request, path string) {

	if routeMap, ok := r.routes[req.Method]; ok {
		for pattern, route := range routeMap {
			if pattern.MatchString(path) {
				parameters, err := params.NewParams(req, pattern, path)

				if err != nil {
					fmt.Printf("error while parsing params: %v", err)
					w.WriteHeader(http.StatusBadRequest)
					return
				}

				req = req.WithContext(context.WithValue(req.Context(), "params", parameters))
				route.Handler(w, req)

				return
			}
		}

		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method: %s not allowed on path: %s", req.Method, req.URL.Path)

		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
	fmt.Fprintf(w, "Method: %s not supported", req.Method)
}

// Add new route.
func (r *router) Add(route Route) error {
	pattern := route.Pattern
	pattern = convertSimplePatternToRegexp(pattern)

	compiledPattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}

	switch route.Method {
	case http.MethodGet:
		r.routes[http.MethodGet][compiledPattern] = route
		return nil
	case http.MethodPost:
		r.routes[http.MethodPost][compiledPattern] = route
		return nil
	}

	return fmt.Errorf("Error method '%s' not supported.", route.Method)
}

// Pretty prints routes
func (r *router) PrintRoutes() {
	log.Printf("%v\n", r.routes)
}
<commit_msg>Add pretty print for all routes.<commit_after>package routes

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"regexp"

	"log"

	"strings"

	"github.com/DVI-GI-2017/Jira__backend/params"
)

func NewRouter(rootPath string) (*router, error) {
	r := &router{}
	r.routes = make(map[string]map[*regexp.Regexp]Route)

	r.routes[http.MethodGet] = make(map[*regexp.Regexp]Route)
	r.routes[http.MethodPost] = make(map[*regexp.Regexp]Route)

	err := r.SetRootPath(rootPath)
	if err != nil {
		return r, err
	}

	return r, nil
}

type router struct {
	root *url.URL

	routes map[string]map[*regexp.Regexp]Route
}

// Set router root path, other paths will be relative to it
func (r *router) SetRootPath(path string) error {
	newRoot, err := url.Parse(path)
	if err != nil {
		return fmt.Errorf("invalid path format %s: %v", path, err)
	}

	r.root = newRoot

	return nil
}

// Listen on given port
func (r *router) ListenAndServe(port string) error {
	return http.ListenAndServe(fmt.Sprintf(":%s", port), r)
}

// Implements http.Handler interface
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	relPath, err := relativePath(r.root.Path, req.URL.Path)
	if err != nil {
		http.NotFound(w, req)
	}

	r.handleRequest(w, req, relPath)
}

// Handles request: iterate over all routes before finds first matching route.
func (r *router) handleRequest(w http.ResponseWriter, req *http.Request, path string) {

	if routeMap, ok := r.routes[req.Method]; ok {
		for pattern, route := range routeMap {
			if pattern.MatchString(path) {
				parameters, err := params.NewParams(req, pattern, path)

				if err != nil {
					fmt.Printf("error while parsing params: %v", err)
					w.WriteHeader(http.StatusBadRequest)
					return
				}

				req = req.WithContext(context.WithValue(req.Context(), "params", parameters))
				route.Handler(w, req)

				return
			}
		}

		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method: %s not allowed on path: %s", req.Method, req.URL.Path)

		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
	fmt.Fprintf(w, "Method: %s not supported", req.Method)
}

// Add new route.
func (r *router) Add(route Route) error {
	pattern := route.Pattern
	pattern = convertSimplePatternToRegexp(pattern)

	compiledPattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}

	switch route.Method {
	case http.MethodGet:
		r.routes[http.MethodGet][compiledPattern] = route
		return nil
	case http.MethodPost:
		r.routes[http.MethodPost][compiledPattern] = route
		return nil
	}

	return fmt.Errorf("Error method '%s' not supported.", route.Method)
}

// Pretty prints routes
func (r *router) PrintRoutes() {
	log.Println(strings.Repeat("-", 10))

	for method, list := range r.routes {
		for re := range list {
			log.Printf("'%s': '%s'", method, re)
		}
	}

	log.Println(strings.Repeat("-", 10))
}
<|endoftext|>


<commit_before>package router

import (
	"net/http"
	"path"

	"github.com/go-ggz/ggz/assets"
	"github.com/go-ggz/ggz/config"
	"github.com/go-ggz/ggz/model"
	"github.com/go-ggz/ggz/module/loader"
	// "github.com/go-ggz/ggz/module/socket"
	"github.com/go-ggz/ggz/module/storage"
	"github.com/go-ggz/ggz/router/middleware/auth"
	"github.com/go-ggz/ggz/router/middleware/graphql"
	"github.com/go-ggz/ggz/router/middleware/header"
	"github.com/go-ggz/ggz/router/middleware/prometheus"
	"github.com/go-ggz/ggz/web"

	"github.com/gin-contrib/gzip"
	"github.com/gin-contrib/logger"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/rs/zerolog/log"
)

// GlobalInit is for global configuration reload-able.
func GlobalInit() {
	if err := model.NewEngine(); err != nil {
		log.Fatal().Err(err).Msg("Failed to initialize ORM engine.")
	}

	// initial socket module
	// if err := socket.NewEngine(); err != nil {
	// 	log.Fatal().Err(err).Msg("Failed to initialize Socket IO engine")
	// }

	if config.QRCode.Enable {
		var err error
		storage.S3, err = storage.NewEngine()
		if err != nil {
			log.Fatal().Err(err).Msg("Failed to create s3 interface")
		}

		if err := storage.S3.CreateBucket(config.Minio.Bucket, config.Minio.Region); err != nil {
			log.Fatal().Err(err).Msg("Failed to create s3 bucket")
		}
	}

	// initial dataloader cache
	if err := loader.NewEngine(config.Cache.Driver, config.Cache.Prefix, config.Cache.Expire); err != nil {
		log.Fatal().Err(err).Msg("Failed to initial dataloader.")
	}
}

// Load initializes the routing of the application.
func Load(middleware ...gin.HandlerFunc) http.Handler {
	if config.Server.Debug {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	e := gin.New()

	e.Use(gin.Recovery())
	e.Use(logger.SetLogger())
	// e.Use(gzip.Gzip(gzip.DefaultCompression))
	e.Use(header.Options)
	e.Use(header.Secure)
	e.Use(middleware...)

	if config.Server.Pprof {
		pprof.Register(
			e,
			path.Join(config.Server.Root, "debug", "pprof"),
		)
	}

	// redirect to vue page
	e.NoRoute(gzip.Gzip(gzip.DefaultCompression), web.Index)

	// default route /
	root := e.Group(config.Server.Root)
	{
		if config.Storage.Driver == "disk" {
			root.StaticFS(
				"/storage",
				gin.Dir(
					config.Storage.Path,
					false,
				),
			)
		}

		root.StaticFS(
			"/public",
			assets.Load(),
		)

		root.GET("", gzip.Gzip(gzip.DefaultCompression), web.Index)
		root.GET("/favicon.ico", web.Favicon)
		root.GET("/metrics", prometheus.Handler())
		root.GET("/healthz", web.Heartbeat)
		root.GET("/assets/*name", gzip.Gzip(gzip.DefaultCompression), assets.ViewHandler())

		api := e.Group("/v1")
		api.Use(auth.Check())
		{
			api.POST("/url/meta", web.URLMeta)
			api.POST("/s", web.CreateShortenURL)
		}

		g := e.Group("/graphql")
		g.Use(auth.Check())
		{
			g.POST("", graphql.Handler())
			if config.Server.GraphiQL {
				g.GET("", graphql.Handler())
			}
		}

		// socket connection
		// root.GET("/socket.io/", socket.Handler())
		// root.POST("/socket.io/", socket.Handler())
		// root.Handle("WS", "/socket.io", socket.Handler())
		// root.Handle("WSS", "/socket.io", socket.Handler())
	}

	return e
}

// LoadRedirct initializes the routing of the shorten URL application.
func LoadRedirct(middleware ...gin.HandlerFunc) http.Handler {
	if config.Server.Debug {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	e := gin.New()

	e.Use(gin.Recovery())
	e.Use(logger.SetLogger())
	e.Use(gzip.Gzip(gzip.DefaultCompression))
	e.Use(header.Options)
	e.Use(header.Secure)
	e.Use(middleware...)

	if config.Server.Pprof {
		pprof.Register(
			e,
			path.Join(config.Server.Root, "debug", "pprof"),
		)
	}

	// 404 not found
	e.NoRoute(web.NotFound)

	// default route /
	root := e.Group(config.Server.Root)
	{
		root.GET("", web.Index)
		root.GET("/:slug", web.RedirectURL)
	}

	return e
}
<commit_msg>chore: ignore graphql url path in logger<commit_after>package router

import (
	"net/http"
	"path"
	"regexp"

	"github.com/go-ggz/ggz/assets"
	"github.com/go-ggz/ggz/config"
	"github.com/go-ggz/ggz/model"
	"github.com/go-ggz/ggz/module/loader"
	// "github.com/go-ggz/ggz/module/socket"
	"github.com/go-ggz/ggz/module/storage"
	"github.com/go-ggz/ggz/router/middleware/auth"
	"github.com/go-ggz/ggz/router/middleware/graphql"
	"github.com/go-ggz/ggz/router/middleware/header"
	"github.com/go-ggz/ggz/router/middleware/prometheus"
	"github.com/go-ggz/ggz/web"

	"github.com/gin-contrib/gzip"
	"github.com/gin-contrib/logger"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/rs/zerolog/log"
)

var (
	rxURL = regexp.MustCompile(`^/(socket.io|graphql).*`)
)

// GlobalInit is for global configuration reload-able.
func GlobalInit() {
	if err := model.NewEngine(); err != nil {
		log.Fatal().Err(err).Msg("Failed to initialize ORM engine.")
	}

	// initial socket module
	// if err := socket.NewEngine(); err != nil {
	// 	log.Fatal().Err(err).Msg("Failed to initialize Socket IO engine")
	// }

	if config.QRCode.Enable {
		var err error
		storage.S3, err = storage.NewEngine()
		if err != nil {
			log.Fatal().Err(err).Msg("Failed to create s3 interface")
		}

		if err := storage.S3.CreateBucket(config.Minio.Bucket, config.Minio.Region); err != nil {
			log.Fatal().Err(err).Msg("Failed to create s3 bucket")
		}
	}

	// initial dataloader cache
	if err := loader.NewEngine(config.Cache.Driver, config.Cache.Prefix, config.Cache.Expire); err != nil {
		log.Fatal().Err(err).Msg("Failed to initial dataloader.")
	}
}

// Load initializes the routing of the application.
func Load(middleware ...gin.HandlerFunc) http.Handler {
	if config.Server.Debug {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	e := gin.New()

	e.Use(gin.Recovery())
	e.Use(logger.SetLogger(logger.Config{
		UTC:            true,
		SkipPathRegexp: rxURL,
	}))
	// e.Use(gzip.Gzip(gzip.DefaultCompression))
	e.Use(header.Options)
	e.Use(header.Secure)
	e.Use(middleware...)

	if config.Server.Pprof {
		pprof.Register(
			e,
			path.Join(config.Server.Root, "debug", "pprof"),
		)
	}

	// redirect to vue page
	e.NoRoute(gzip.Gzip(gzip.DefaultCompression), web.Index)

	// default route /
	root := e.Group(config.Server.Root)
	{
		if config.Storage.Driver == "disk" {
			root.StaticFS(
				"/storage",
				gin.Dir(
					config.Storage.Path,
					false,
				),
			)
		}

		root.StaticFS(
			"/public",
			assets.Load(),
		)

		root.GET("", gzip.Gzip(gzip.DefaultCompression), web.Index)
		root.GET("/favicon.ico", web.Favicon)
		root.GET("/metrics", prometheus.Handler())
		root.GET("/healthz", web.Heartbeat)
		root.GET("/assets/*name", gzip.Gzip(gzip.DefaultCompression), assets.ViewHandler())

		api := e.Group("/v1")
		api.Use(auth.Check())
		{
			api.POST("/url/meta", web.URLMeta)
			api.POST("/s", web.CreateShortenURL)
		}

		g := e.Group("/graphql")
		g.Use(auth.Check())
		{
			g.POST("", graphql.Handler())
			if config.Server.GraphiQL {
				g.GET("", graphql.Handler())
			}
		}

		// socket connection
		// root.GET("/socket.io/", socket.Handler())
		// root.POST("/socket.io/", socket.Handler())
		// root.Handle("WS", "/socket.io", socket.Handler())
		// root.Handle("WSS", "/socket.io", socket.Handler())
	}

	return e
}

// LoadRedirct initializes the routing of the shorten URL application.
func LoadRedirct(middleware ...gin.HandlerFunc) http.Handler {
	if config.Server.Debug {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	e := gin.New()

	e.Use(gin.Recovery())
	e.Use(logger.SetLogger(logger.Config{
		UTC:            true,
		SkipPathRegexp: rxURL,
	}))
	e.Use(gzip.Gzip(gzip.DefaultCompression))
	e.Use(header.Options)
	e.Use(header.Secure)
	e.Use(middleware...)

	if config.Server.Pprof {
		pprof.Register(
			e,
			path.Join(config.Server.Root, "debug", "pprof"),
		)
	}

	// 404 not found
	e.NoRoute(web.NotFound)

	// default route /
	root := e.Group(config.Server.Root)
	{
		root.GET("", web.Index)
		root.GET("/:slug", web.RedirectURL)
	}

	return e
}
<|endoftext|>


<commit_before>// +build linux
// +build 386 amd64 arm arm64

package ras

import (
	"fmt"
	"testing"

	"github.com/influxdata/telegraf/testutil"

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

func TestUpdateCounters(t *testing.T) {
	ras := newRas()
	for _, mce := range testData {
		ras.updateCounters(&mce)
	}

	assert.Equal(t, 1, len(ras.cpuSocketCounters), "Should contain counters only for single socket")

	for metric, value := range ras.cpuSocketCounters[0] {
		if metric == processorBase {
			// processor_base_errors is sum of other seven errors: internal_timer_errors, smm_handler_code_access_violation_errors,
			// internal_parity_errors, frc_errors, external_mce_errors, microcode_rom_parity_errors and unclassified_mce_errors
			assert.Equal(t, int64(7), value, fmt.Sprintf("%s should have value of 7", processorBase))
		} else {
			assert.Equal(t, int64(1), value, fmt.Sprintf("%s should have value of 1", metric))
		}
	}

	for metric, value := range ras.serverCounters {
		assert.Equal(t, int64(1), value, fmt.Sprintf("%s should have value of 1", metric))
	}
}

func TestUpdateLatestTimestamp(t *testing.T) {
	ras := newRas()
	ts := "2020-08-01 15:13:27 +0200"
	testData = append(testData, []machineCheckError{
		{
			Timestamp:    "2019-05-20 08:25:55 +0200",
			SocketID:     0,
			ErrorMsg:     "",
			MciStatusMsg: "",
		},
		{
			Timestamp:    "2018-02-21 12:27:22 +0200",
			SocketID:     0,
			ErrorMsg:     "",
			MciStatusMsg: "",
		},
		{
			Timestamp:    ts,
			SocketID:     0,
			ErrorMsg:     "",
			MciStatusMsg: "",
		},
	}...)
	for _, mce := range testData {
		err := ras.updateLatestTimestamp(mce.Timestamp)
		assert.NoError(t, err)
	}
	assert.Equal(t, ts, ras.latestTimestamp.Format(dateLayout))
}

func TestMultipleSockets(t *testing.T) {
	ras := newRas()
	cacheL2 := "Instruction CACHE Level-2 Generic Error"
	overflow := "Error_overflow Corrected_error"
	testData = []machineCheckError{
		{
			Timestamp:    "2019-05-20 08:25:55 +0200",
			SocketID:     0,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
		{
			Timestamp:    "2018-02-21 12:27:22 +0200",
			SocketID:     1,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
		{
			Timestamp:    "2020-03-21 14:17:28 +0200",
			SocketID:     2,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
		{
			Timestamp:    "2020-03-21 17:24:18 +0200",
			SocketID:     3,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
	}
	for _, mce := range testData {
		ras.updateCounters(&mce)
	}
	assert.Equal(t, 4, len(ras.cpuSocketCounters), "Should contain counters for four sockets")

	for _, metricData := range ras.cpuSocketCounters {
		for metric, value := range metricData {
			if metric == levelTwoCache {
				assert.Equal(t, int64(1), value, fmt.Sprintf("%s should have value of 1", levelTwoCache))
			} else {
				assert.Equal(t, int64(0), value, fmt.Sprintf("%s should have value of 0", metric))
			}
		}
	}
}

func TestMissingDatabase(t *testing.T) {
	var acc testutil.Accumulator
	ras := newRas()
	ras.DBPath = "/tmp/test.db"
	err := ras.Start(&acc)
	assert.Error(t, err)
}

func TestEmptyDatabase(t *testing.T) {
	ras := newRas()

	assert.Equal(t, 1, len(ras.cpuSocketCounters), "Should contain default counters for one socket")
	assert.Equal(t, 2, len(ras.serverCounters), "Should contain default counters for server")

	for metric, value := range ras.cpuSocketCounters[0] {
		assert.Equal(t, int64(0), value, fmt.Sprintf("%s should have value of 0", metric))
	}

	for metric, value := range ras.serverCounters {
		assert.Equal(t, int64(0), value, fmt.Sprintf("%s should have value of 0", metric))
	}
}

func newRas() *Ras {
	defaultTimestamp, _ := parseDate("1970-01-01 00:00:01 -0700")
	return &Ras{
		DBPath:          defaultDbPath,
		latestTimestamp: defaultTimestamp,
		cpuSocketCounters: map[int]metricCounters{
			0: *newMetricCounters(),
		},
		serverCounters: map[string]int64{
			levelTwoCache: 0,
			upi:           0,
		},
	}
}

var testData = []machineCheckError{
	{
		Timestamp:    "2020-05-20 07:34:53 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER RD_CHANNEL0_ERR Transaction: Memory read error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 07:35:11 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER RD_CHANNEL0_ERR Transaction: Memory read error",
		MciStatusMsg: "Uncorrected_error",
	},
	{
		Timestamp:    "2020-05-20 07:37:50 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER RD_CHANNEL2_ERR Transaction: Memory write error",
		MciStatusMsg: "Uncorrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:14:51 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER WR_CHANNEL2_ERR Transaction: Memory write error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:15:31 +0200",
		SocketID:     0,
		ErrorMsg:     "corrected filtering (some unreported errors in same region) Instruction CACHE Level-0 Read Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:16:32 +0200",
		SocketID:     0,
		ErrorMsg:     "Instruction TLB Level-0 Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:16:56 +0200",
		SocketID:     0,
		ErrorMsg:     "No Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:17:24 +0200",
		SocketID:     0,
		ErrorMsg:     "Unclassified",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:17:41 +0200",
		SocketID:     0,
		ErrorMsg:     "Microcode ROM parity error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:17:48 +0200",
		SocketID:     0,
		ErrorMsg:     "FRC error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:18:18 +0200",
		SocketID:     0,
		ErrorMsg:     "Internal parity error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:18:34 +0200",
		SocketID:     0,
		ErrorMsg:     "SMM Handler Code Access Violation",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:18:54 +0200",
		SocketID:     0,
		ErrorMsg:     "Internal Timer error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:21:23 +0200",
		SocketID:     0,
		ErrorMsg:     "BUS Level-3 Generic Generic IO Request-did-not-timeout Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:23:23 +0200",
		SocketID:     0,
		ErrorMsg:     "External error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:25:31 +0200",
		SocketID:     0,
		ErrorMsg:     "UPI: COR LL Rx detected CRC error - successful LLR without Phy Reinit",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:25:55 +0200",
		SocketID:     0,
		ErrorMsg:     "Instruction CACHE Level-2 Generic Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
}
<commit_msg>fix plugins/input/ras test (#8350)<commit_after>// +build linux
// +build 386 amd64 arm arm64

package ras

import (
	"fmt"
	"testing"

	"github.com/influxdata/telegraf/testutil"

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

func TestUpdateCounters(t *testing.T) {
	ras := newRas()
	for _, mce := range testData {
		ras.updateCounters(&mce)
	}

	assert.Equal(t, 1, len(ras.cpuSocketCounters), "Should contain counters only for single socket")

	for metric, value := range ras.cpuSocketCounters[0] {
		if metric == processorBase {
			// processor_base_errors is sum of other seven errors: internal_timer_errors, smm_handler_code_access_violation_errors,
			// internal_parity_errors, frc_errors, external_mce_errors, microcode_rom_parity_errors and unclassified_mce_errors
			assert.Equal(t, int64(7), value, fmt.Sprintf("%s should have value of 7", processorBase))
		} else {
			assert.Equal(t, int64(1), value, fmt.Sprintf("%s should have value of 1", metric))
		}
	}

	for metric, value := range ras.serverCounters {
		assert.Equal(t, int64(1), value, fmt.Sprintf("%s should have value of 1", metric))
	}
}

func TestUpdateLatestTimestamp(t *testing.T) {
	ras := newRas()
	ts := "2020-08-01 15:13:27 +0200"
	testData = append(testData, []machineCheckError{
		{
			Timestamp:    "2019-05-20 08:25:55 +0200",
			SocketID:     0,
			ErrorMsg:     "",
			MciStatusMsg: "",
		},
		{
			Timestamp:    "2018-02-21 12:27:22 +0200",
			SocketID:     0,
			ErrorMsg:     "",
			MciStatusMsg: "",
		},
		{
			Timestamp:    ts,
			SocketID:     0,
			ErrorMsg:     "",
			MciStatusMsg: "",
		},
	}...)
	for _, mce := range testData {
		err := ras.updateLatestTimestamp(mce.Timestamp)
		assert.NoError(t, err)
	}
	assert.Equal(t, ts, ras.latestTimestamp.Format(dateLayout))
}

func TestMultipleSockets(t *testing.T) {
	ras := newRas()
	cacheL2 := "Instruction CACHE Level-2 Generic Error"
	overflow := "Error_overflow Corrected_error"
	testData = []machineCheckError{
		{
			Timestamp:    "2019-05-20 08:25:55 +0200",
			SocketID:     0,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
		{
			Timestamp:    "2018-02-21 12:27:22 +0200",
			SocketID:     1,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
		{
			Timestamp:    "2020-03-21 14:17:28 +0200",
			SocketID:     2,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
		{
			Timestamp:    "2020-03-21 17:24:18 +0200",
			SocketID:     3,
			ErrorMsg:     cacheL2,
			MciStatusMsg: overflow,
		},
	}
	for _, mce := range testData {
		ras.updateCounters(&mce)
	}
	assert.Equal(t, 4, len(ras.cpuSocketCounters), "Should contain counters for four sockets")

	for _, metricData := range ras.cpuSocketCounters {
		for metric, value := range metricData {
			if metric == levelTwoCache {
				assert.Equal(t, int64(1), value, fmt.Sprintf("%s should have value of 1", levelTwoCache))
			} else {
				assert.Equal(t, int64(0), value, fmt.Sprintf("%s should have value of 0", metric))
			}
		}
	}
}

func TestMissingDatabase(t *testing.T) {
	var acc testutil.Accumulator
	ras := newRas()
	ras.DBPath = "/nonexistent/ras.db"
	err := ras.Start(&acc)
	assert.Error(t, err)
}

func TestEmptyDatabase(t *testing.T) {
	ras := newRas()

	assert.Equal(t, 1, len(ras.cpuSocketCounters), "Should contain default counters for one socket")
	assert.Equal(t, 2, len(ras.serverCounters), "Should contain default counters for server")

	for metric, value := range ras.cpuSocketCounters[0] {
		assert.Equal(t, int64(0), value, fmt.Sprintf("%s should have value of 0", metric))
	}

	for metric, value := range ras.serverCounters {
		assert.Equal(t, int64(0), value, fmt.Sprintf("%s should have value of 0", metric))
	}
}

func newRas() *Ras {
	defaultTimestamp, _ := parseDate("1970-01-01 00:00:01 -0700")
	return &Ras{
		DBPath:          defaultDbPath,
		latestTimestamp: defaultTimestamp,
		cpuSocketCounters: map[int]metricCounters{
			0: *newMetricCounters(),
		},
		serverCounters: map[string]int64{
			levelTwoCache: 0,
			upi:           0,
		},
	}
}

var testData = []machineCheckError{
	{
		Timestamp:    "2020-05-20 07:34:53 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER RD_CHANNEL0_ERR Transaction: Memory read error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 07:35:11 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER RD_CHANNEL0_ERR Transaction: Memory read error",
		MciStatusMsg: "Uncorrected_error",
	},
	{
		Timestamp:    "2020-05-20 07:37:50 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER RD_CHANNEL2_ERR Transaction: Memory write error",
		MciStatusMsg: "Uncorrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:14:51 +0200",
		SocketID:     0,
		ErrorMsg:     "MEMORY CONTROLLER WR_CHANNEL2_ERR Transaction: Memory write error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:15:31 +0200",
		SocketID:     0,
		ErrorMsg:     "corrected filtering (some unreported errors in same region) Instruction CACHE Level-0 Read Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:16:32 +0200",
		SocketID:     0,
		ErrorMsg:     "Instruction TLB Level-0 Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:16:56 +0200",
		SocketID:     0,
		ErrorMsg:     "No Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:17:24 +0200",
		SocketID:     0,
		ErrorMsg:     "Unclassified",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:17:41 +0200",
		SocketID:     0,
		ErrorMsg:     "Microcode ROM parity error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:17:48 +0200",
		SocketID:     0,
		ErrorMsg:     "FRC error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:18:18 +0200",
		SocketID:     0,
		ErrorMsg:     "Internal parity error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:18:34 +0200",
		SocketID:     0,
		ErrorMsg:     "SMM Handler Code Access Violation",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:18:54 +0200",
		SocketID:     0,
		ErrorMsg:     "Internal Timer error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:21:23 +0200",
		SocketID:     0,
		ErrorMsg:     "BUS Level-3 Generic Generic IO Request-did-not-timeout Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:23:23 +0200",
		SocketID:     0,
		ErrorMsg:     "External error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:25:31 +0200",
		SocketID:     0,
		ErrorMsg:     "UPI: COR LL Rx detected CRC error - successful LLR without Phy Reinit",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
	{
		Timestamp:    "2020-05-20 08:25:55 +0200",
		SocketID:     0,
		ErrorMsg:     "Instruction CACHE Level-2 Generic Error",
		MciStatusMsg: "Error_overflow Corrected_error",
	},
}
<|endoftext|>