diff options
Diffstat (limited to 'tests/cracha.go')
-rw-r--r-- | tests/cracha.go | 935 |
1 files changed, 935 insertions, 0 deletions
diff --git a/tests/cracha.go b/tests/cracha.go new file mode 100644 index 0000000..905733c --- /dev/null +++ b/tests/cracha.go @@ -0,0 +1,935 @@ +package cracha + +import ( + "database/sql" + "fmt" + "os" + "time" + + // "q" + "golite" + "guuid" + "scrypt" + g "gobang" +) + + + +type userDataT struct{ + userID guuid.UUID + email string + salt []byte + pwhash []byte + token string +} + + + +func mksalt() []byte { + salt, err := scrypt.Salt() + g.TErrorIf(err) + return salt +} + +func newUser() userDataT { + return userDataT{ + userID: guuid.New(), + email: string(mksalt()), + salt: mksalt(), + pwhash: mksalt(), + token: string(mksalt()), + } +} + + +func test_defaultPrefix() { + g.TestStart("defaultPrefix") + + g.Testing("the defaultPrefix is valid", func() { + g.TErrorIf(g.ValidateSQLTablePrefix(defaultPrefix)) + }) +} + +func test_tryRollback() { + // FIXME +} + +func test_inTx() { + // FIXME +} + +func test_createTables() { + g.TestStart("createTables()") + + db, err := sql.Open(golite.DriverName, ":memory:") + g.TErrorIf(err) + defer db.Close() + + + g.Testing("tables exist afterwards", func() { + const tmpl_read = ` + SELECT id FROM "%s_users" LIMIT 1; + ` + qRead := fmt.Sprintf(tmpl_read, defaultPrefix) + + _, err := db.Exec(qRead) + g.TErrorNil(err) + + err = createTables(db, defaultPrefix) + g.TErrorIf(err) + + _, err = db.Exec(qRead) + g.TErrorIf(err) + }) + + g.Testing("we can do it multiple times", func() { + g.TErrorIf(g.SomeError( + createTables(db, defaultPrefix), + createTables(db, defaultPrefix), + createTables(db, defaultPrefix), + )) + }) +} + +func test_registerStmt() { + g.TestStart("registerStmt()") + + const ( + prefix = defaultPrefix + ) + + db, err := sql.Open(golite.DriverName, ":memory:") + g.TErrorIf(err) + g.TErrorIf(createTables(db, prefix)) + + register, registerClose, registerErr := registerStmt(db, prefix) + g.TErrorIf(registerErr) + defer g.SomeFnError( + registerClose, + db.Close, + ) + + + g.Testing("we can register a user", func() { + u := newUser() + user, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + g.TAssertEqual(user.timestamp == time.Time{}, false) + g.TAssertEqual(user.id, int64(1)) + g.TAssertEqual(user.uuid, u.userID) + g.TAssertEqual(user.email, u.email) + g.TAssertEqual(user.salt, u.salt) + g.TAssertEqual(user.pwhash, u.pwhash) + }) + + g.Testing("users can't have the same uuid", func() { + u1 := newUser() + u2 := newUser() + userID := guuid.New() + + _, err1 := register(userID, u1.email, u1.salt, u1.pwhash) + _, err2 := register(userID, u2.email, u2.salt, u2.pwhash) + + g.TErrorIf(err1) + g.TAssertEqual( + err2.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + }) + + g.Testing("users can't have the same email", func() { + u1 := newUser() + u2 := newUser() + email := string(mksalt()) + + _, err1 := register(u1.userID, email, u1.salt, u1.pwhash) + _, err2 := register(u2.userID, email, u2.salt, u2.pwhash) + + g.TErrorIf(err1) + g.TAssertEqual( + err2.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + }) + + g.Testing("users can't have the same salt", func() { + u1 := newUser() + u2 := newUser() + salt := mksalt() + + _, err1 := register(u1.userID, u1.email, salt, u1.pwhash) + _, err2 := register(u2.userID, u2.email, salt, u2.pwhash) + + g.TErrorIf(err1) + g.TAssertEqual( + err2.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + }) + + g.Testing("no error when close()ing more than once", func() { + g.TErrorIf(g.SomeError( + registerClose(), + registerClose(), + registerClose(), + )) + }) +} + +func test_sendTokenStmt() { + g.TestStart("sendToken()") + + const ( + prefix = defaultPrefix + ) + + db, err := sql.Open(golite.DriverName, ":memory:") + g.TErrorIf(err) + g.TErrorIf(createTables(db, prefix)) + + register, registerClose, registerErr := registerStmt(db, prefix) + sendToken, sendTokenClose, sendTokenErr := sendTokenStmt(db, prefix) + g.TErrorIf(g.SomeError( + registerErr, + sendTokenErr, + )) + defer g.SomeFnError( + registerClose, + sendTokenClose, + db.Close, + ) + + + g.Testing("can't send a token to a non-existent user", func() { + err := sendToken(guuid.New(), "some token") + g.TAssertEqual( + err.(golite.Error).ExtendedCode, + golite.ErrConstraintNotNull, + ) + }) + + g.Testing("otherwise creates the confirmation attempt", func() { + u := newUser() + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + err = sendToken(u.userID, u.token) + g.TErrorIf(err) + }) + + g.Testing("token has to be unique globally", func() { + u1 := newUser() + u2 := newUser() + token := string(mksalt()) + + _, err := register(u1.userID, u1.email, u1.salt, u1.pwhash) + g.TErrorIf(err) + _, err = register(u2.userID, u2.email, u2.salt, u2.pwhash) + g.TErrorIf(err) + + err1 := sendToken(u1.userID, token) + err2 := sendToken(u2.userID, token) + g.TErrorIf(err1) + g.TAssertEqual( + err2.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + }) + + g.Testing("a user can have multiple", func() { + u := newUser() + token1 := string(mksalt()) + token2 := string(mksalt()) + token3 := string(mksalt()) + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + g.TErrorIf(g.SomeError( + sendToken(u.userID, token1), + sendToken(u.userID, token2), + sendToken(u.userID, token3), + )) + + tokens := []string{} + const tmpl_read = ` + SELECT token from "%s_confirmation_attempts" + WHERE user_id = ( + SELECT id FROM "%s_users" + WHERE uuid = ? + ) + ORDER BY id ASC; + ` + qRead := fmt.Sprintf(tmpl_read, prefix, prefix) + rows, err := db.Query(qRead, u.userID[:]) + g.TErrorIf(err) + + for rows.Next() { + var token string + err := rows.Scan(&token) + g.TErrorIf(err) + tokens = append(tokens, token) + } + g.TErrorIf(g.SomeFnError(rows.Err, rows.Close)) + + expected := []string{ + token1, + token2, + token3, + } + g.TAssertEqual(tokens, expected) + }) +} + +func test_confirmStmt() { + g.TestStart("confirmStmt()") + + const ( + prefix = defaultPrefix + ) + + db, err := sql.Open(golite.DriverName, ":memory:") + g.TErrorIf(err) + g.TErrorIf(createTables(db, prefix)) + + register, registerClose, registerErr := registerStmt(db, prefix) + sendToken, sendTokenClose, sendTokenErr := sendTokenStmt(db, prefix) + confirm, confirmClose, confirmErr := confirmStmt(db, prefix) + g.TErrorIf(g.SomeError( + registerErr, + sendTokenErr, + confirmErr, + )) + defer g.SomeFnError( + registerClose, + sendTokenClose, + confirmClose, + db.Close, + ) + + + g.Testing("can't confirm a token that doesn't exist", func() { + _, err := confirm(string(mksalt()), guuid.New()) + g.TAssertEqual(err, sql.ErrNoRows) + }) + + g.Testing("otherwise it creates a confirmation and a session", func() { + u := newUser() + sessionID := guuid.New() + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + g.TErrorIf(sendToken(u.userID, u.token)) + + session, err := confirm(u.token, sessionID) + g.TErrorIf(err) + + g.TAssertEqual(session.timestamp == time.Time{}, false) + g.TAssertEqual(session.uuid, sessionID) + g.TAssertEqual(session.userID, u.userID) + }) + + g.Testing("can't confirm the same token twice", func() { + u := newUser() + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + g.TErrorIf(sendToken(u.userID, u.token)) + + _, err1 := confirm(u.token, guuid.New()) + _, err2 := confirm(u.token, guuid.New()) + g.TErrorIf(err1) + g.TAssertEqual( + err2.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + }) + + g.Testing("a user can't have 2 confirmations", func() { + u := newUser() + token1 := string(mksalt()) + token2 := string(mksalt()) + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + g.TErrorIf(g.SomeError( + sendToken(u.userID, token1), + sendToken(u.userID, token2), + )) + + _, err1 := confirm(token1, guuid.New()) + _, err2 := confirm(token2, guuid.New()) + g.TErrorIf(err1) + g.TAssertEqual( + err2.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + }) +} + +func test_byEmailStmt() { + g.TestStart("byEmailStmt()") + + const ( + prefix = defaultPrefix + ) + + db, err := sql.Open(golite.DriverName, ":memory:") + g.TErrorIf(err) + g.TErrorIf(createTables(db, prefix)) + + register, registerClose, registerErr := registerStmt(db, prefix) + sendToken, sendTokenClose, sendTokenErr := sendTokenStmt(db, prefix) + confirm, confirmClose, confirmErr := confirmStmt(db, prefix) + byEmail, byEmailClose, byEmailErr := byEmailStmt(db, prefix) + g.TErrorIf(g.SomeError( + registerErr, + sendTokenErr, + confirmErr, + byEmailErr, + )) + defer g.SomeFnError( + registerClose, + sendTokenClose, + confirmClose, + byEmailClose, + db.Close, + ) + + + g.Testing("error when not found", func() { + email := string(mksalt()) + _, err := byEmail(email) + g.TAssertEqual(err, sql.ErrNoRows) + }) + + g.Testing("full user otherwise, confirmed or not", func() { + u := newUser() + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + user1, err := byEmail(u.email) + g.TErrorIf(err) + + g.TErrorIf(sendToken(u.userID, u.token)) + + user2, err := byEmail(u.email) + g.TErrorIf(err) + + _, err = confirm(u.token, guuid.New()) + g.TErrorIf(err) + + user3, err := byEmail(u.email) + g.TErrorIf(err) + + g.TAssertEqual(user1, user2) + user2.confirmed = true + g.TAssertEqual(user2, user3) + }) +} + +func test_loginStmt() { + g.TestStart("loginStmt()") + + const ( + prefix = defaultPrefix + ) + + db, err := sql.Open(golite.DriverName, ":memory:") + g.TErrorIf(err) + g.TErrorIf(createTables(db, prefix)) + + register, registerClose, registerErr := registerStmt(db, prefix) + sendToken, sendTokenClose, sendTokenErr := sendTokenStmt(db, prefix) + confirm, confirmClose, confirmErr := confirmStmt(db, prefix) + byEmail, byEmailClose, byEmailErr := byEmailStmt(db, prefix) + login, loginClose, loginErr := loginStmt(db, prefix) + g.TErrorIf(g.SomeError( + registerErr, + sendTokenErr, + confirmErr, + byEmailErr, + loginErr, + )) + defer g.SomeFnError( + registerClose, + sendTokenClose, + confirmClose, + byEmailClose, + loginClose, + db.Close, + ) + + + g.Testing("a user must exist to login", func() { + _, err := login(guuid.New(), guuid.New()) + g.TAssertEqual( + err.(golite.Error).ExtendedCode, + golite.ErrConstraintNotNull, + ) + }) + + g.Testing("sessionID must be unique globally", func() { + u1 := newUser() + u2 := newUser() + sessionID := guuid.New() + + _, err := register(u1.userID, u1.email, u1.salt, u1.pwhash) + g.TErrorIf(err) + _, err = register(u2.userID, u2.email, u2.salt, u2.pwhash) + g.TErrorIf(err) + + _, err1 := login(u1.userID, sessionID) + _, err2 := login(u1.userID, sessionID) + _, err3 := login(u2.userID, sessionID) + + g.TErrorIf(err1) + g.TAssertEqual( + err2.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + g.TAssertEqual( + err3.(golite.Error).ExtendedCode, + golite.ErrConstraintUnique, + ) + }) + + g.Testing("a user can have multiple active sessions", func() { + u := newUser() + sessionID1 := guuid.New() + sessionID2 := guuid.New() + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + session1, err := login(u.userID, sessionID1) + g.TErrorIf(err) + + session2, err := login(u.userID, sessionID2) + g.TErrorIf(err) + + g.TAssertEqual(session1.uuid, sessionID1) + g.TAssertEqual(session2.uuid, sessionID2) + g.TAssertEqual(session1.userID, u.userID) + g.TAssertEqual(session2.userID, u.userID) + }) + + g.Testing("multiple users can be logged in", func() { + u1 := newUser() + u2 := newUser() + sessionID1 := guuid.New() + sessionID2 := guuid.New() + + _, err := register(u1.userID, u1.email, u1.salt, u1.pwhash) + g.TErrorIf(err) + _, err = register(u2.userID, u2.email, u2.salt, u2.pwhash) + g.TErrorIf(err) + + session1, err := login(u1.userID, sessionID1) + g.TErrorIf(err) + session2, err := login(u2.userID, sessionID2) + g.TErrorIf(err) + + g.TAssertEqual(session1.uuid, sessionID1) + g.TAssertEqual(session2.uuid, sessionID2) + g.TAssertEqual(session1.userID, u1.userID) + g.TAssertEqual(session2.userID, u2.userID) + }) + + g.Testing("an unconfirmed user is allowed to login", func() { + u := newUser() + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + _, err = login(u.userID, guuid.New()) + g.TErrorIf(err) + }) + + g.Testing("a confirmed user is allowed to login, too", func() { + u := newUser() + + _, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + + g.TErrorIf(sendToken(u.userID, u.token)) + + _, err = confirm(u.token, guuid.New()) + g.TErrorIf(err) + + user, err := byEmail(u.email) + g.TErrorIf(err) + g.TAssertEqual(user.confirmed, true) + + _, err = login(u.userID, guuid.New()) + g.TErrorIf(err) + }) +} + +func test_refreshStmt() { + g.TestStart("refreshStmt()") + + const ( + prefix = defaultPrefix + ) + + db, err := sql.Open(golite.DriverName, ":memory:") + g.TErrorIf(err) + g.TErrorIf(createTables(db, prefix)) + + register, registerClose, registerErr := registerStmt(db, prefix) + sendToken, sendTokenClose, sendTokenErr := sendTokenStmt(db, prefix) + confirm, confirmClose, confirmErr := confirmStmt(db, prefix) + byEmail, byEmailClose, byEmailErr := byEmailStmt(db, prefix) + login, loginClose, loginErr := loginStmt(db, prefix) + refresh, refreshClose, refreshErr := refreshStmt(db, prefix) + g.TErrorIf(g.SomeError( + registerErr, + sendTokenErr, + confirmErr, + byEmailErr, + loginErr, + refreshErr, + )) + defer g.SomeFnError( + registerClose, + sendTokenClose, + confirmClose, + byEmailClose, + loginClose, + refreshClose, + db.Close, + ) + + reg := func(u userDataT) userT { + user, err := register(u.userID, u.email, u.salt, u.pwhash) + g.TErrorIf(err) + return user + } + + conf := func(u userDataT) sessionT { + err := sendToken(u.userID, u.token) + g.TErrorIf(err) + + session, err := confirm(u.token, guuid.New()) + g.TErrorIf(err) + return session + } + + + g.Testing("a session needs to exist be be refreshed", func() { + _, err := refresh(guuid.New(), guuid.New()) + g.TAssertEqual( + err.(golite.Error).ExtendedCode, + golite.ErrConstraintNotNull, + ) + }) + + g.Testing("we can refresh the session of an unconfirmed user", func() { + u := newUser() + sessionID1 := guuid.New() + sessionID2 := guuid.New() + + reg(u) + + session1, err := login(u.userID, sessionID1) + g.TErrorIf(err) + + user, err := byEmail(u.email) + g.TErrorIf(err) + g.TAssertEqual(user.confirmed, false) + + session2, err := refresh(sessionID1, sessionID2) + g.TErrorIf(err) + + g.TAssertEqual(session1.userID, u.userID) + g.TAssertEqual(session1.userID, session2.userID) + g.TAssertEqual(session1.uuid, sessionID1) + g.TAssertEqual(session2.uuid, sessionID2) + g.TAssertEqual(session1.timestamp == time.Time{}, false) + g.TAssertEqual(session2.timestamp == time.Time{}, false) + }) + + g.Testing("we can refresh the session of a confirmed user", func() { + u := newUser() + sessionID1 := guuid.New() + sessionID2 := guuid.New() + + reg(u) + session1 := conf(u) + + user, err := byEmail(u.email) + g.TErrorIf(err) + g.TAssertEqual(user.confirmed, true) + + // FIXME + return + + session2, err := refresh(sessionID1, sessionID2) + g.TErrorIf(err) + + g.TAssertEqual(session1.userID, u.userID) + g.TAssertEqual(session1.userID, session2.userID) + g.TAssertEqual(session1.uuid, sessionID1) + g.TAssertEqual(session2.uuid, sessionID2) + }) + + g.Testing("we can't refresh an expired session", func() { + }) + + g.Testing("the sessionID can't be reused, even across users", func() { + }) + // FIXME +} + +func test_resetStmt() { + // FIXME +} + +func test_changeStmt() { + // FIXME +} + +func test_byUUIDStmt() { + // FIXME +} + +func test_logoutStmt() { + // FIXME +} + +func test_outOthersStmt() { + // FIXME +} + +func test_outAllStmt() { + // FIXME +} + +func test_initDB() { + // FIXME +} + +func test_queriesTclose() { + // FIXME +} + +func test_newUserHandler() { + // FIXME +} + +func test_sendConfirmationRequestHandler() { + // FIXME +} + +func test_forgotPasswordRequestHandler() { + // FIXME +} + +func test_registerConsumers() { + // FIXME +} + +func test_unregisterConsumers() { + // FIXME +} + +func test_startRunner() { + // FIXME +} + +func test_makePoolRunner() { + // FIXME +} + +func test_asResult() { + // FIXME +} + +func test_unwrapResult() { + // FIXME +} + +func test_NewWithPrefix() { + // FIXME +} + +func test_New() { + // FIXME +} + +func test_newUserPayload() { + // FIXME +} + +func test_authT_Register() { + // FIXME +} + +func test_sendConfirmationMessage() { + // FIXME +} + +func test_authT_ResentConfirmation() { + // FIXME +} + +func test_authT_ConfirmEmail() { + // FIXME +} + +func test_authT_LoginEmail() { + // FIXME +} + +func test_forgotPasswordMessage() { + // FIXME +} + +func test_authT_ForgotPassword() { + // FIXME +} + +func test_checkSession() { + // FIXME +} + +func test_validateSession() { + // FIXME +} + +func test_authT_Refresh() { + // FIXME +} + +func test_authT_ResetPassword() { + // FIXME +} + +func test_authT_ChangePassword() { + // FIXME +} + +func test_runLogout() { + // FIXME +} + +func test_authT_Logout() { + // FIXME +} + +func test_authT_LogoutOthers() { + // FIXME +} + +func test_authT_LogoutAll() { + // FIXME +} + +func test_authT_Close() { + // FIXME +} + +func test_usage() { + // FIXME +} + +func test_getopt() { + // FIXME +} + +func test_runCommand() { + // FIXME +} + + +func dumpQueries() { + queries := []struct{name string; fn func(string) queryT}{ + { "createTables", createTablesSQL }, + { "byEmail", byEmailSQL }, + { "register", registerSQL }, + { "sendToken", sendTokenSQL }, + { "confirm", confirmSQL }, + { "login", loginSQL }, + { "refresh", refreshSQL }, + { "reset", resetSQL }, + { "change", changeSQL }, + { "byUUID", byUUIDSQL }, + { "logout", logoutSQL }, + { "outOthers", outOthersSQL }, + { "outAll", outAllSQL }, + } + for _, query := range queries { + q := query.fn(defaultPrefix) + fmt.Printf("\n-- %s.sql:", query.name) + fmt.Printf("\n-- write:%s\n", q.write) + fmt.Printf("\n-- read:%s\n", q.read) + } +} + + + +func MainTest() { + if os.Getenv("TESTING_DUMP_SQL_QUERIES") != "" { + dumpQueries() + return + } + + g.Init() + test_defaultPrefix() + test_tryRollback() + test_inTx() + test_createTables() + test_registerStmt() + test_sendTokenStmt() + test_confirmStmt() + test_byEmailStmt() + test_loginStmt() + test_refreshStmt() + test_resetStmt() + test_changeStmt() + test_byUUIDStmt() + test_logoutStmt() + test_outOthersStmt() + test_outAllStmt() + test_initDB() + test_queriesTclose() + test_newUserHandler() + test_sendConfirmationRequestHandler() + test_forgotPasswordRequestHandler() + test_registerConsumers() + test_unregisterConsumers() + test_startRunner() + test_makePoolRunner() + test_asResult() + test_unwrapResult() + test_NewWithPrefix() + test_New() + test_newUserPayload() + test_authT_Register() + test_sendConfirmationMessage() + test_authT_ResentConfirmation() + test_authT_ConfirmEmail() + test_authT_LoginEmail() + test_forgotPasswordMessage() + test_authT_ForgotPassword() + test_checkSession() + test_validateSession() + test_authT_Refresh() + test_authT_ResetPassword() + test_authT_ChangePassword() + test_runLogout() + test_authT_Logout() + test_authT_LogoutOthers() + test_authT_LogoutAll() + test_authT_Close() + test_usage() + test_getopt() + test_runCommand() +} |