gosora/misc_test.go

600 lines
15 KiB
Go

package main
import (
"fmt"
"runtime/debug"
"strconv"
"testing"
"time"
)
func recordMustExist(t *testing.T, err error, errmsg string) {
if err == ErrNoRows {
t.Error(errmsg)
} else if err != nil {
t.Fatal(err)
}
}
func recordMustNotExist(t *testing.T, err error, errmsg string) {
if err == nil {
t.Error(errmsg)
} else if err != ErrNoRows {
t.Fatal(err)
}
}
func TestUserStore(t *testing.T) {
if !gloinited {
err := gloinit()
if err != nil {
t.Fatal(err)
}
}
if !pluginsInited {
initPlugins()
}
users = NewMemoryUserStore(config.UserCacheCapacity)
users.(UserCache).Flush()
userStoreTest(t, 2)
users = NewSQLUserStore()
userStoreTest(t, 3)
}
func userStoreTest(t *testing.T, newUserID int) {
var user *User
var err error
ucache, hasCache := users.(UserCache)
if hasCache && ucache.Length() != 0 {
t.Error("Initial ucache length isn't zero")
}
_, err = users.Get(-1)
recordMustNotExist(t, err, "UID #-1 shouldn't exist")
if hasCache && ucache.Length() != 0 {
t.Error("There shouldn't be anything in the user cache")
}
_, err = users.Get(0)
recordMustNotExist(t, err, "UID #0 shouldn't exist")
if hasCache && ucache.Length() != 0 {
t.Error("There shouldn't be anything in the user cache")
}
user, err = users.Get(1)
recordMustExist(t, err, "Couldn't find UID #1")
if user.ID != 1 {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
}
if user.Name != "Admin" {
t.Error("user.Name should be 'Admin', not '" + user.Name + "'")
}
if user.Group != 1 {
t.Error("Admin should be in group 1")
}
user, err = users.Get(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist", newUserID))
if hasCache {
expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d")
user, err = ucache.CacheGet(-1)
recordMustNotExist(t, err, "UID #-1 shouldn't exist, even in the cache")
user, err = ucache.CacheGet(0)
recordMustNotExist(t, err, "UID #0 shouldn't exist, even in the cache")
user, err = ucache.CacheGet(1)
recordMustExist(t, err, "Couldn't find UID #1 in the cache")
if user.ID != 1 {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
}
if user.Name != "Admin" {
t.Error("user.Name should be 'Admin', not '" + user.Name + "'")
}
user, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist, even in the cache", newUserID))
ucache.Flush()
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
}
// TODO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message?
var userList map[int]*User
userList, _ = users.BulkGetMap([]int{-1})
if len(userList) > 0 {
t.Error("There shouldn't be any results for UID #-1")
}
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
}
userList, _ = users.BulkGetMap([]int{0})
if len(userList) > 0 {
t.Error("There shouldn't be any results for UID #0")
}
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
}
userList, _ = users.BulkGetMap([]int{1})
if len(userList) == 0 {
t.Error("The returned map is empty for UID #1")
} else if len(userList) > 1 {
t.Error("Too many results were returned for UID #1")
}
user, ok := userList[1]
if !ok {
t.Error("We couldn't find UID #1 in the returned map")
t.Error("userList", userList)
}
if user.ID != 1 {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
}
if hasCache {
expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d")
user, err = ucache.CacheGet(1)
recordMustExist(t, err, "Couldn't find UID #1 in the cache")
if user.ID != 1 {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
}
ucache.Flush()
}
expect(t, !users.Exists(-1), "UID #-1 shouldn't exist")
expect(t, !users.Exists(0), "UID #0 shouldn't exist")
expect(t, users.Exists(1), "UID #1 should exist")
expect(t, !users.Exists(newUserID), fmt.Sprintf("UID #%d shouldn't exist", newUserID))
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
}
expectIntToBeX(t, users.GlobalCount(), 1, "The number of users should be one, not %d")
var awaitingActivation = 5
uid, err := users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, 0)
if err != nil {
t.Error(err)
}
if uid != newUserID {
t.Errorf("The UID of the new user should be %d", newUserID)
}
if !users.Exists(newUserID) {
t.Errorf("UID #%d should exist", newUserID)
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
if user.Name != "Sam" {
t.Error("The user should be named Sam")
}
expectIntToBeX(t, user.Group, 5, "Sam should be in group 5")
if hasCache {
expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d")
user, err = ucache.CacheGet(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d in the cache", newUserID))
if user.ID != newUserID {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
}
}
err = user.Activate()
if err != nil {
t.Error(err)
}
expectIntToBeX(t, user.Group, 5, "Sam should still be in group 5 in this copy")
// ? - What if we change the caching mechanism so it isn't hard purged and reloaded? We'll deal with that when we come to it, but for now, this is a sign of a cache bug
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
expectIntToBeX(t, user.Group, config.DefaultGroup, "Sam should be in group "+strconv.Itoa(config.DefaultGroup))
// Permanent ban
duration, _ := time.ParseDuration("0")
// TODO: Attempt a double ban, double activation, and double unban
err = user.Ban(duration, 1)
if err != nil {
t.Error(err)
}
expectIntToBeX(t, user.Group, config.DefaultGroup, "Sam should still be in the default group in this copy")
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(2)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
expectIntToBeX(t, user.Group, banGroup, "Sam should be in group "+strconv.Itoa(banGroup))
// TODO: Do tests against the scheduled updates table and the task system to make sure the ban exists there and gets revoked when it should
err = user.Unban()
if err != nil {
t.Error(err)
}
expectIntToBeX(t, user.Group, banGroup, "Sam should still be in the ban group in this copy")
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
expectIntToBeX(t, user.Group, config.DefaultGroup, "Sam should be back in group "+strconv.Itoa(config.DefaultGroup))
err = user.Delete()
if err != nil {
t.Error(err)
}
expect(t, !users.Exists(newUserID), fmt.Sprintf("UID #%d should not longer exist", newUserID))
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
// TODO: Works for now but might cause a data race with the task system
//ResetTables()
}
func expectIntToBeX(t *testing.T, item int, expect int, errmsg string) {
if item != expect {
debug.PrintStack()
t.Fatalf(errmsg, item)
}
}
func expect(t *testing.T, item bool, errmsg string) {
if !item {
debug.PrintStack()
t.Fatalf(errmsg)
}
}
func TestTopicStore(t *testing.T) {
if !gloinited {
err := gloinit()
if err != nil {
t.Fatal(err)
}
}
if !pluginsInited {
initPlugins()
}
topics = NewMemoryTopicStore(config.TopicCacheCapacity)
topicStoreTest(t)
topics = NewSQLTopicStore()
topicStoreTest(t)
}
func topicStoreTest(t *testing.T) {
var topic *Topic
var err error
_, err = topics.Get(-1)
if err == nil {
t.Error("TID #-1 shouldn't exist")
} else if err != ErrNoRows {
t.Fatal(err)
}
_, err = topics.Get(0)
if err == nil {
t.Error("TID #0 shouldn't exist")
} else if err != ErrNoRows {
t.Fatal(err)
}
topic, err = topics.Get(1)
recordMustExist(t, err, "Couldn't find TID #1")
if topic.ID != 1 {
t.Error("topic.ID does not match the requested TID. Got '" + strconv.Itoa(topic.ID) + "' instead.")
}
// TODO: Add BulkGetMap() to the TopicStore
ok := topics.Exists(-1)
if ok {
t.Error("TID #-1 shouldn't exist")
}
ok = topics.Exists(0)
if ok {
t.Error("TID #0 shouldn't exist")
}
ok = topics.Exists(1)
if !ok {
t.Error("TID #1 should exist")
}
count := topics.GlobalCount()
if count <= 0 {
t.Error("The number of topics should be bigger than zero")
t.Error("count", count)
}
}
func TestForumStore(t *testing.T) {
if !gloinited {
gloinit()
}
if !pluginsInited {
initPlugins()
}
var forum *Forum
var err error
_, err = fstore.Get(-1)
if err == nil {
t.Error("FID #-1 shouldn't exist")
} else if err != ErrNoRows {
t.Fatal(err)
}
forum, err = fstore.Get(0)
if err == nil {
t.Error("FID #0 shouldn't exist")
} else if err != ErrNoRows {
t.Fatal(err)
}
forum, err = fstore.Get(1)
recordMustExist(t, err, "Couldn't find FID #1")
if forum.ID != 1 {
t.Error("forum.ID doesn't not match the requested FID. Got '" + strconv.Itoa(forum.ID) + "' instead.'")
}
if forum.Name != "Reports" {
t.Error("FID #0 is named '" + forum.Name + "' and not 'Reports'")
}
forum, err = fstore.Get(2)
recordMustExist(t, err, "Couldn't find FID #1")
_ = forum
ok := fstore.Exists(-1)
if ok {
t.Error("FID #-1 shouldn't exist")
}
ok = fstore.Exists(0)
if ok {
t.Error("FID #0 shouldn't exist")
}
ok = fstore.Exists(1)
if !ok {
t.Error("FID #1 should exist")
}
}
func TestGroupStore(t *testing.T) {
if !gloinited {
gloinit()
}
if !pluginsInited {
initPlugins()
}
var group *Group
var err error
_, err = gstore.Get(-1)
if err == nil {
t.Error("GID #-1 shouldn't exist")
} else if err != ErrNoRows {
t.Fatal(err)
}
// TODO: Refactor the group store to remove GID #0
group, err = gstore.Get(0)
recordMustExist(t, err, "Couldn't find GID #0")
if group.ID != 0 {
t.Error("group.ID doesn't not match the requested GID. Got '" + strconv.Itoa(group.ID) + "' instead.")
}
if group.Name != "Unknown" {
t.Error("GID #0 is named '" + group.Name + "' and not 'Unknown'")
}
group, err = gstore.Get(1)
recordMustExist(t, err, "Couldn't find GID #1")
if group.ID != 1 {
t.Error("group.ID doesn't not match the requested GID. Got '" + strconv.Itoa(group.ID) + "' instead.'")
}
_ = group
ok := gstore.Exists(-1)
if ok {
t.Error("GID #-1 shouldn't exist")
}
ok = gstore.Exists(0)
if !ok {
t.Error("GID #0 should exist")
}
ok = gstore.Exists(1)
if !ok {
t.Error("GID #1 should exist")
}
}
func TestReplyStore(t *testing.T) {
if !gloinited {
gloinit()
}
if !pluginsInited {
initPlugins()
}
reply, err := rstore.Get(-1)
if err == nil {
t.Error("RID #-1 shouldn't exist")
}
reply, err = rstore.Get(0)
if err == nil {
t.Error("RID #0 shouldn't exist")
}
reply, err = rstore.Get(1)
if err != nil {
t.Fatal(err)
}
if reply.ID != 1 {
t.Error("RID #1 has the wrong ID. It should be 1 not " + strconv.Itoa(reply.ID))
}
if reply.ParentID != 1 {
t.Error("The parent topic of RID #1 should be 1 not " + strconv.Itoa(reply.ParentID))
}
if reply.CreatedBy != 1 {
t.Error("The creator of RID #1 should be 1 not " + strconv.Itoa(reply.CreatedBy))
}
}
func TestProfileReplyStore(t *testing.T) {
if !gloinited {
gloinit()
}
if !pluginsInited {
initPlugins()
}
_, err := prstore.Get(-1)
if err == nil {
t.Error("RID #-1 shouldn't exist")
}
_, err = prstore.Get(0)
if err == nil {
t.Error("RID #0 shouldn't exist")
}
}
func TestSlugs(t *testing.T) {
var res string
var msgList []MEPair
msgList = addMEPair(msgList, "Unknown", "unknown")
msgList = addMEPair(msgList, "Unknown2", "unknown2")
msgList = addMEPair(msgList, "Unknown ", "unknown")
msgList = addMEPair(msgList, "Unknown 2", "unknown-2")
msgList = addMEPair(msgList, "Unknown 2", "unknown-2")
msgList = addMEPair(msgList, "Admin Alice", "admin-alice")
msgList = addMEPair(msgList, "Admin_Alice", "adminalice")
msgList = addMEPair(msgList, "Admin_Alice-", "adminalice")
msgList = addMEPair(msgList, "-Admin_Alice-", "adminalice")
msgList = addMEPair(msgList, "-Admin@Alice-", "adminalice")
msgList = addMEPair(msgList, "-Admin😀Alice-", "adminalice")
msgList = addMEPair(msgList, "u", "u")
msgList = addMEPair(msgList, "", "untitled")
msgList = addMEPair(msgList, " ", "untitled")
msgList = addMEPair(msgList, "-", "untitled")
msgList = addMEPair(msgList, "--", "untitled")
msgList = addMEPair(msgList, "é", "é")
msgList = addMEPair(msgList, "-é-", "é")
for _, item := range msgList {
t.Log("Testing string '" + item.Msg + "'")
res = nameToSlug(item.Msg)
if res != item.Expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", item.Expects)
}
}
}
func TestAuth(t *testing.T) {
// bcrypt likes doing stupid things, so this test will probably fail
var realPassword string
var hashedPassword string
var password string
var salt string
var err error
/* No extra salt tests, we might not need this extra salt, as bcrypt has it's own? */
realPassword = "Madame Cassandra's Mystic Orb"
t.Log("Set real_password to '" + realPassword + "'")
t.Log("Hashing the real password")
hashedPassword, err = BcryptGeneratePasswordNoSalt(realPassword)
if err != nil {
t.Error(err)
}
password = realPassword
t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt)
if err == ErrMismatchedHashAndPassword {
t.Error("The two don't match")
} else if err == ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long")
} else if err != nil {
t.Error(err)
}
password = "hahaha"
t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long")
} else if err == nil {
t.Error("The two shouldn't match!")
}
password = "Madame Cassandra's Mystic"
t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long")
} else if err == nil {
t.Error("The two shouldn't match!")
}
}