2019-11-11 06:20:33 -05:00
package routers
import (
2019-11-12 01:45:27 -05:00
"bytes"
2019-11-12 03:18:58 -05:00
"encoding/json"
"errors"
2019-11-12 01:45:27 -05:00
"github.com/DATA-DOG/go-sqlmock"
2019-11-16 03:11:37 -05:00
"github.com/HFO4/cloudreve/middleware"
"github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/serializer"
2019-11-12 01:45:27 -05:00
"github.com/jinzhu/gorm"
2019-11-13 05:34:29 -05:00
"github.com/mojocn/base64Captcha"
2019-11-11 06:20:33 -05:00
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
2019-11-26 01:52:54 -05:00
"strings"
2019-11-11 06:20:33 -05:00
"testing"
)
func TestPing ( t * testing . T ) {
asserts := assert . New ( t )
router := InitRouter ( )
w := httptest . NewRecorder ( )
2019-11-23 03:58:56 -05:00
req , _ := http . NewRequest ( "GET" , "/api/v3/site/ping" , nil )
2019-11-11 06:20:33 -05:00
router . ServeHTTP ( w , req )
assert . Equal ( t , 200 , w . Code )
asserts . Contains ( w . Body . String ( ) , "Pong" )
}
2019-11-12 01:45:27 -05:00
2019-11-13 05:34:29 -05:00
func TestCaptcha ( t * testing . T ) {
asserts := assert . New ( t )
router := InitRouter ( )
w := httptest . NewRecorder ( )
req , _ := http . NewRequest (
"GET" ,
2019-11-23 03:58:56 -05:00
"/api/v3/captcha" ,
2019-11-13 05:34:29 -05:00
nil ,
)
router . ServeHTTP ( w , req )
asserts . Equal ( 200 , w . Code )
asserts . Contains ( w . Body . String ( ) , "base64" )
}
2019-11-12 01:45:27 -05:00
func TestUserSession ( t * testing . T ) {
asserts := assert . New ( t )
router := InitRouter ( )
w := httptest . NewRecorder ( )
2019-11-13 05:34:29 -05:00
// 创建测试用验证码
var configD = base64Captcha . ConfigDigit {
Height : 80 ,
Width : 240 ,
MaxSkew : 0.7 ,
DotCount : 80 ,
CaptchaLen : 1 ,
}
idKeyD , _ := base64Captcha . GenerateCaptcha ( "" , configD )
middleware . ContextMock = map [ string ] interface { } {
"captchaID" : idKeyD ,
}
2019-11-12 01:45:27 -05:00
testCases := [ ] struct {
settingRows * sqlmock . Rows
userRows * sqlmock . Rows
2019-11-14 01:51:59 -05:00
policyRows * sqlmock . Rows
2019-11-12 01:45:27 -05:00
reqBody string
2019-11-12 03:18:58 -05:00
expected interface { }
2019-11-12 01:45:27 -05:00
} {
// 登录信息正确,不需要验证码
{
settingRows : sqlmock . NewRows ( [ ] string { "name" , "value" , "type" } ) .
AddRow ( "login_captcha" , "0" , "login" ) ,
userRows : sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" } ) .
2019-11-14 01:51:59 -05:00
AddRow ( "admin@cloudreve.org" , "admin" , "CKLmDKa1C9SD64vU:76adadd4fd4bad86959155f6f7bc8993c94e7adf" , "{}" ) , policyRows : sqlmock . NewRows ( [ ] string { "name" , "type" , "options" } ) .
AddRow ( "默认上传策略" , "local" , "{\"op_name\":\"123\"}" ) ,
2019-11-12 03:18:58 -05:00
reqBody : ` { "userName":"admin@cloudreve.org","captchaCode":"captchaCode","Password":"admin"} ` ,
expected : serializer . BuildUserResponse ( model . User {
Email : "admin@cloudreve.org" ,
Nick : "admin" ,
} ) ,
2019-11-12 01:45:27 -05:00
} ,
2019-11-13 05:34:29 -05:00
// 登录信息正确,需要验证码,验证码错误
{
settingRows : sqlmock . NewRows ( [ ] string { "name" , "value" , "type" } ) .
AddRow ( "login_captcha" , "1" , "login" ) ,
userRows : sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" } ) .
AddRow ( "admin@cloudreve.org" , "admin" , "CKLmDKa1C9SD64vU:76adadd4fd4bad86959155f6f7bc8993c94e7adf" , "{}" ) ,
2019-11-14 01:51:59 -05:00
policyRows : sqlmock . NewRows ( [ ] string { "name" , "type" , "options" } ) .
AddRow ( "默认上传策略" , "local" , "{\"op_name\":\"123\"}" ) ,
2019-11-13 05:34:29 -05:00
reqBody : ` { "userName":"admin@cloudreve.org","captchaCode":"captchaCode","Password":"admin"} ` ,
expected : serializer . ParamErr ( "验证码错误" , nil ) ,
} ,
2019-11-12 01:45:27 -05:00
// 邮箱正确密码错误
{
settingRows : sqlmock . NewRows ( [ ] string { "name" , "value" , "type" } ) .
AddRow ( "login_captcha" , "0" , "login" ) ,
userRows : sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" } ) .
AddRow ( "admin@cloudreve.org" , "admin" , "CKLmDKa1C9SD64vU:76adadd4fd4bad86959155f6f7bc8993c94e7adf" , "{}" ) ,
2019-11-14 01:51:59 -05:00
policyRows : sqlmock . NewRows ( [ ] string { "name" , "type" , "options" } ) .
AddRow ( "默认上传策略" , "local" , "{\"op_name\":\"123\"}" ) ,
2019-11-12 01:45:27 -05:00
reqBody : ` { "userName":"admin@cloudreve.org","captchaCode":"captchaCode","Password":"admin123"} ` ,
2019-11-12 03:18:58 -05:00
expected : serializer . Err ( 401 , "用户邮箱或密码错误" , nil ) ,
2019-11-12 01:45:27 -05:00
} ,
//邮箱格式不正确
{
reqBody : ` { "userName":"admin@cloudreve","captchaCode":"captchaCode","Password":"admin123"} ` ,
2019-11-12 03:18:58 -05:00
expected : serializer . Err ( 40001 , "邮箱格式不正确" , errors . New ( "Key: 'UserLoginService.UserName' Error:Field validation for 'UserName' failed on the 'email' tag" ) ) ,
2019-11-12 01:45:27 -05:00
} ,
// 用户被Ban
{
settingRows : sqlmock . NewRows ( [ ] string { "name" , "value" , "type" } ) .
AddRow ( "login_captcha" , "0" , "login" ) ,
userRows : sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" , "status" } ) .
AddRow ( "admin@cloudreve.org" , "admin" , "CKLmDKa1C9SD64vU:76adadd4fd4bad86959155f6f7bc8993c94e7adf" , "{}" , model . Baned ) ,
2019-11-14 01:51:59 -05:00
policyRows : sqlmock . NewRows ( [ ] string { "name" , "type" , "options" } ) .
AddRow ( "默认上传策略" , "local" , "{\"op_name\":\"123\"}" ) ,
2019-11-12 01:45:27 -05:00
reqBody : ` { "userName":"admin@cloudreve.org","captchaCode":"captchaCode","Password":"admin"} ` ,
2019-11-12 03:18:58 -05:00
expected : serializer . Err ( 403 , "该账号已被封禁" , nil ) ,
2019-11-12 01:45:27 -05:00
} ,
// 用户未激活
{
settingRows : sqlmock . NewRows ( [ ] string { "name" , "value" , "type" } ) .
AddRow ( "login_captcha" , "0" , "login" ) ,
userRows : sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" , "status" } ) .
AddRow ( "admin@cloudreve.org" , "admin" , "CKLmDKa1C9SD64vU:76adadd4fd4bad86959155f6f7bc8993c94e7adf" , "{}" , model . NotActivicated ) ,
2019-11-14 01:51:59 -05:00
policyRows : sqlmock . NewRows ( [ ] string { "name" , "type" , "options" } ) .
AddRow ( "默认上传策略" , "local" , "{\"op_name\":\"123\"}" ) ,
2019-11-12 01:45:27 -05:00
reqBody : ` { "userName":"admin@cloudreve.org","captchaCode":"captchaCode","Password":"admin"} ` ,
2019-11-12 03:18:58 -05:00
expected : serializer . Err ( 403 , "该账号未激活" , nil ) ,
2019-11-12 01:45:27 -05:00
} ,
}
2019-11-13 05:34:29 -05:00
for k , testCase := range testCases {
2019-11-12 01:45:27 -05:00
if testCase . settingRows != nil {
mock . ExpectQuery ( "^SELECT (.+)" ) . WillReturnRows ( testCase . settingRows )
}
if testCase . userRows != nil {
mock . ExpectQuery ( "^SELECT (.+)" ) . WillReturnRows ( testCase . userRows )
}
2019-11-14 01:51:59 -05:00
if testCase . policyRows != nil {
mock . ExpectQuery ( "^SELECT \\* FROM `(.+)` WHERE `(.+)`\\.`deleted_at` IS NULL AND \\(\\(`policies`.`id` = 1\\)\\)(.+)$" ) . WillReturnRows ( testCase . policyRows )
}
2019-11-12 01:45:27 -05:00
req , _ := http . NewRequest (
"POST" ,
2019-11-23 03:58:56 -05:00
"/api/v3/user/session" ,
2019-11-12 01:45:27 -05:00
bytes . NewReader ( [ ] byte ( testCase . reqBody ) ) ,
)
router . ServeHTTP ( w , req )
2019-11-12 03:53:32 -05:00
asserts . Equal ( 200 , w . Code )
expectedJSON , _ := json . Marshal ( testCase . expected )
2019-11-13 05:34:29 -05:00
asserts . JSONEq ( string ( expectedJSON ) , w . Body . String ( ) , "测试用例:%d" , k )
2019-11-12 03:18:58 -05:00
2019-11-12 01:45:27 -05:00
w . Body . Reset ( )
asserts . NoError ( mock . ExpectationsWereMet ( ) )
model . ClearCache ( )
}
}
2019-11-12 03:53:32 -05:00
func TestSessionAuthCheck ( t * testing . T ) {
asserts := assert . New ( t )
router := InitRouter ( )
w := httptest . NewRecorder ( )
mock . ExpectQuery ( "^SELECT (.+)" ) . WillReturnRows ( sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" } ) .
AddRow ( "admin@cloudreve.org" , "admin" , "CKLmDKa1C9SD64vU:76adadd4fd4bad86959155f6f7bc8993c94e7adf" , "{}" ) )
expectedUser , _ := model . GetUserByID ( 1 )
testCases := [ ] struct {
userRows * sqlmock . Rows
sessionMock map [ string ] interface { }
contextMock map [ string ] interface { }
expected interface { }
} {
// 未登录
{
expected : serializer . CheckLogin ( ) ,
} ,
// 登录正常
{
userRows : sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" } ) .
AddRow ( "admin@cloudreve.org" , "admin" , "CKLmDKa1C9SD64vU:76adadd4fd4bad86959155f6f7bc8993c94e7adf" , "{}" ) ,
sessionMock : map [ string ] interface { } { "user_id" : 1 } ,
expected : serializer . BuildUserResponse ( expectedUser ) ,
} ,
// UID不存在
{
userRows : sqlmock . NewRows ( [ ] string { "email" , "nick" , "password" , "options" } ) ,
sessionMock : map [ string ] interface { } { "user_id" : - 1 } ,
expected : serializer . CheckLogin ( ) ,
} ,
}
for _ , testCase := range testCases {
req , _ := http . NewRequest (
"GET" ,
2019-11-23 03:58:56 -05:00
"/api/v3/user/me" ,
2019-11-12 03:53:32 -05:00
nil ,
)
if testCase . userRows != nil {
mock . ExpectQuery ( "^SELECT (.+)" ) . WillReturnRows ( testCase . userRows )
}
middleware . ContextMock = testCase . contextMock
middleware . SessionMock = testCase . sessionMock
router . ServeHTTP ( w , req )
expectedJSON , _ := json . Marshal ( testCase . expected )
asserts . Equal ( 200 , w . Code )
asserts . JSONEq ( string ( expectedJSON ) , w . Body . String ( ) )
asserts . NoError ( mock . ExpectationsWereMet ( ) )
w . Body . Reset ( )
}
}
2019-11-23 02:09:46 -05:00
func TestSiteConfigRoute ( t * testing . T ) {
switchToMemDB ( )
asserts := assert . New ( t )
router := InitRouter ( )
w := httptest . NewRecorder ( )
req , _ := http . NewRequest (
"GET" ,
2019-11-23 03:58:56 -05:00
"/api/v3/site/config" ,
2019-11-23 02:09:46 -05:00
nil ,
)
router . ServeHTTP ( w , req )
asserts . Equal ( 200 , w . Code )
asserts . Contains ( w . Body . String ( ) , "Cloudreve" )
w . Body . Reset ( )
// 消除无效值
model . DB . Model ( & model . Setting {
Model : gorm . Model {
ID : 2 ,
} ,
} ) . UpdateColumn ( "name" , "siteName_b" )
req , _ = http . NewRequest (
"GET" ,
2019-11-23 03:58:56 -05:00
"/api/v3/site/config" ,
2019-11-23 02:09:46 -05:00
nil ,
)
router . ServeHTTP ( w , req )
asserts . Equal ( 200 , w . Code )
asserts . Contains ( w . Body . String ( ) , "\"title\":\"\"" )
model . DB . Model ( & model . Setting {
Model : gorm . Model {
ID : 2 ,
} ,
} ) . UpdateColumn ( "name" , "siteName" )
}
2019-11-24 03:28:41 -05:00
func TestListDirectoryRoute ( t * testing . T ) {
switchToMemDB ( )
asserts := assert . New ( t )
router := InitRouter ( )
w := httptest . NewRecorder ( )
// 成功
req , _ := http . NewRequest (
"GET" ,
"/api/v3/directory?path=/" ,
nil ,
)
middleware . SessionMock = map [ string ] interface { } { "user_id" : 1 }
router . ServeHTTP ( w , req )
asserts . Equal ( 200 , w . Code )
resJSON := & serializer . Response { }
err := json . Unmarshal ( w . Body . Bytes ( ) , resJSON )
asserts . NoError ( err )
asserts . Equal ( 0 , resJSON . Code )
w . Body . Reset ( )
// 缺少参数
req , _ = http . NewRequest (
"GET" ,
"/api/v3/directory" ,
nil ,
)
middleware . SessionMock = map [ string ] interface { } { "user_id" : 1 }
router . ServeHTTP ( w , req )
asserts . Equal ( 200 , w . Code )
resJSON = & serializer . Response { }
err = json . Unmarshal ( w . Body . Bytes ( ) , resJSON )
asserts . NoError ( err )
asserts . NotEqual ( 0 , resJSON . Code )
}
2019-11-26 01:52:54 -05:00
func TestLocalFileUpload ( t * testing . T ) {
switchToMemDB ( )
asserts := assert . New ( t )
router := InitRouter ( )
w := httptest . NewRecorder ( )
middleware . SessionMock = map [ string ] interface { } { "user_id" : 1 }
testCases := [ ] struct {
GetRequest func ( ) * http . Request
ExpectCode int
RollBack func ( )
} {
// 文件大小指定错误
{
GetRequest : func ( ) * http . Request {
req , _ := http . NewRequest (
"POST" ,
"/api/v3/file/upload" ,
nil ,
)
req . Header . Add ( "Content-Length" , "ddf" )
return req
} ,
ExpectCode : 40001 ,
} ,
// 返回错误
{
GetRequest : func ( ) * http . Request {
req , _ := http . NewRequest (
"POST" ,
"/api/v3/file/upload" ,
strings . NewReader ( "2333" ) ,
)
req . Header . Add ( "Content-Length" , "4" )
req . Header . Add ( "X-FileName" , "大地的%sfsf" )
return req
} ,
ExpectCode : 40002 ,
} ,
// 成功
{
GetRequest : func ( ) * http . Request {
req , _ := http . NewRequest (
"POST" ,
"/api/v3/file/upload" ,
strings . NewReader ( "2333" ) ,
)
req . Header . Add ( "Content-Length" , "4" )
req . Header . Add ( "X-FileName" , "TestFileUploadRoute.txt" )
return req
} ,
ExpectCode : 0 ,
} ,
}
for key , testCase := range testCases {
req := testCase . GetRequest ( )
router . ServeHTTP ( w , req )
asserts . Equal ( 200 , w . Code )
resJSON := & serializer . Response { }
err := json . Unmarshal ( w . Body . Bytes ( ) , resJSON )
asserts . NoError ( err , "测试用例%d" , key )
asserts . Equal ( testCase . ExpectCode , resJSON . Code , "测试用例%d" , key )
if testCase . RollBack != nil {
testCase . RollBack ( )
}
w . Body . Reset ( )
}
}