eventmanager_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package common
  15. import (
  16. "fmt"
  17. "net/http"
  18. "os"
  19. "path"
  20. "path/filepath"
  21. "testing"
  22. "time"
  23. "github.com/sftpgo/sdk"
  24. sdkkms "github.com/sftpgo/sdk/kms"
  25. "github.com/stretchr/testify/assert"
  26. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  27. "github.com/drakkan/sftpgo/v2/internal/kms"
  28. "github.com/drakkan/sftpgo/v2/internal/util"
  29. "github.com/drakkan/sftpgo/v2/internal/vfs"
  30. )
  31. func TestEventRuleMatch(t *testing.T) {
  32. conditions := dataprovider.EventConditions{
  33. ProviderEvents: []string{"add", "update"},
  34. Options: dataprovider.ConditionOptions{
  35. Names: []dataprovider.ConditionPattern{
  36. {
  37. Pattern: "user1",
  38. InverseMatch: true,
  39. },
  40. },
  41. },
  42. }
  43. res := eventManager.checkProviderEventMatch(conditions, EventParams{
  44. Name: "user1",
  45. Event: "add",
  46. })
  47. assert.False(t, res)
  48. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  49. Name: "user2",
  50. Event: "update",
  51. })
  52. assert.True(t, res)
  53. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  54. Name: "user2",
  55. Event: "delete",
  56. })
  57. assert.False(t, res)
  58. conditions.Options.ProviderObjects = []string{"api_key"}
  59. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  60. Name: "user2",
  61. Event: "update",
  62. ObjectType: "share",
  63. })
  64. assert.False(t, res)
  65. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  66. Name: "user2",
  67. Event: "update",
  68. ObjectType: "api_key",
  69. })
  70. assert.True(t, res)
  71. // now test fs events
  72. conditions = dataprovider.EventConditions{
  73. FsEvents: []string{operationUpload, operationDownload},
  74. Options: dataprovider.ConditionOptions{
  75. Names: []dataprovider.ConditionPattern{
  76. {
  77. Pattern: "user*",
  78. },
  79. {
  80. Pattern: "tester*",
  81. },
  82. },
  83. FsPaths: []dataprovider.ConditionPattern{
  84. {
  85. Pattern: "*.txt",
  86. },
  87. },
  88. Protocols: []string{ProtocolSFTP},
  89. MinFileSize: 10,
  90. MaxFileSize: 30,
  91. },
  92. }
  93. params := EventParams{
  94. Name: "tester4",
  95. Event: operationDelete,
  96. VirtualPath: "/path.txt",
  97. Protocol: ProtocolSFTP,
  98. ObjectName: "path.txt",
  99. FileSize: 20,
  100. }
  101. res = eventManager.checkFsEventMatch(conditions, params)
  102. assert.False(t, res)
  103. params.Event = operationDownload
  104. res = eventManager.checkFsEventMatch(conditions, params)
  105. assert.True(t, res)
  106. params.Name = "name"
  107. res = eventManager.checkFsEventMatch(conditions, params)
  108. assert.False(t, res)
  109. params.Name = "user5"
  110. res = eventManager.checkFsEventMatch(conditions, params)
  111. assert.True(t, res)
  112. params.VirtualPath = "/sub/f.jpg"
  113. params.ObjectName = path.Base(params.VirtualPath)
  114. res = eventManager.checkFsEventMatch(conditions, params)
  115. assert.False(t, res)
  116. params.VirtualPath = "/sub/f.txt"
  117. params.ObjectName = path.Base(params.VirtualPath)
  118. res = eventManager.checkFsEventMatch(conditions, params)
  119. assert.True(t, res)
  120. params.Protocol = ProtocolHTTP
  121. res = eventManager.checkFsEventMatch(conditions, params)
  122. assert.False(t, res)
  123. params.Protocol = ProtocolSFTP
  124. params.FileSize = 5
  125. res = eventManager.checkFsEventMatch(conditions, params)
  126. assert.False(t, res)
  127. params.FileSize = 50
  128. res = eventManager.checkFsEventMatch(conditions, params)
  129. assert.False(t, res)
  130. params.FileSize = 25
  131. res = eventManager.checkFsEventMatch(conditions, params)
  132. assert.True(t, res)
  133. // bad pattern
  134. conditions.Options.Names = []dataprovider.ConditionPattern{
  135. {
  136. Pattern: "[-]",
  137. },
  138. }
  139. res = eventManager.checkFsEventMatch(conditions, params)
  140. assert.False(t, res)
  141. }
  142. func TestEventManager(t *testing.T) {
  143. startEventScheduler()
  144. action := &dataprovider.BaseEventAction{
  145. Name: "test_action",
  146. Type: dataprovider.ActionTypeHTTP,
  147. Options: dataprovider.BaseEventActionOptions{
  148. HTTPConfig: dataprovider.EventActionHTTPConfig{
  149. Endpoint: "http://localhost",
  150. Timeout: 20,
  151. Method: http.MethodGet,
  152. },
  153. },
  154. }
  155. err := dataprovider.AddEventAction(action, "", "")
  156. assert.NoError(t, err)
  157. rule := &dataprovider.EventRule{
  158. Name: "rule",
  159. Trigger: dataprovider.EventTriggerFsEvent,
  160. Conditions: dataprovider.EventConditions{
  161. FsEvents: []string{operationUpload},
  162. },
  163. Actions: []dataprovider.EventAction{
  164. {
  165. BaseEventAction: dataprovider.BaseEventAction{
  166. Name: action.Name,
  167. },
  168. Order: 1,
  169. },
  170. },
  171. }
  172. err = dataprovider.AddEventRule(rule, "", "")
  173. assert.NoError(t, err)
  174. eventManager.RLock()
  175. assert.Len(t, eventManager.FsEvents, 1)
  176. assert.Len(t, eventManager.ProviderEvents, 0)
  177. assert.Len(t, eventManager.Schedules, 0)
  178. assert.Len(t, eventManager.schedulesMapping, 0)
  179. eventManager.RUnlock()
  180. rule.Trigger = dataprovider.EventTriggerProviderEvent
  181. rule.Conditions = dataprovider.EventConditions{
  182. ProviderEvents: []string{"add"},
  183. }
  184. err = dataprovider.UpdateEventRule(rule, "", "")
  185. assert.NoError(t, err)
  186. eventManager.RLock()
  187. assert.Len(t, eventManager.FsEvents, 0)
  188. assert.Len(t, eventManager.ProviderEvents, 1)
  189. assert.Len(t, eventManager.Schedules, 0)
  190. assert.Len(t, eventManager.schedulesMapping, 0)
  191. eventManager.RUnlock()
  192. rule.Trigger = dataprovider.EventTriggerSchedule
  193. rule.Conditions = dataprovider.EventConditions{
  194. Schedules: []dataprovider.Schedule{
  195. {
  196. Hours: "0",
  197. DayOfWeek: "*",
  198. DayOfMonth: "*",
  199. Month: "*",
  200. },
  201. },
  202. }
  203. rule.DeletedAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-12 * time.Hour))
  204. eventManager.addUpdateRuleInternal(*rule)
  205. eventManager.RLock()
  206. assert.Len(t, eventManager.FsEvents, 0)
  207. assert.Len(t, eventManager.ProviderEvents, 0)
  208. assert.Len(t, eventManager.Schedules, 0)
  209. assert.Len(t, eventManager.schedulesMapping, 0)
  210. eventManager.RUnlock()
  211. assert.Eventually(t, func() bool {
  212. _, err = dataprovider.EventRuleExists(rule.Name)
  213. _, ok := err.(*util.RecordNotFoundError)
  214. return ok
  215. }, 2*time.Second, 100*time.Millisecond)
  216. rule.DeletedAt = 0
  217. err = dataprovider.AddEventRule(rule, "", "")
  218. assert.NoError(t, err)
  219. eventManager.RLock()
  220. assert.Len(t, eventManager.FsEvents, 0)
  221. assert.Len(t, eventManager.ProviderEvents, 0)
  222. assert.Len(t, eventManager.Schedules, 1)
  223. assert.Len(t, eventManager.schedulesMapping, 1)
  224. eventManager.RUnlock()
  225. err = dataprovider.DeleteEventRule(rule.Name, "", "")
  226. assert.NoError(t, err)
  227. eventManager.RLock()
  228. assert.Len(t, eventManager.FsEvents, 0)
  229. assert.Len(t, eventManager.ProviderEvents, 0)
  230. assert.Len(t, eventManager.Schedules, 0)
  231. assert.Len(t, eventManager.schedulesMapping, 0)
  232. eventManager.RUnlock()
  233. err = dataprovider.DeleteEventAction(action.Name, "", "")
  234. assert.NoError(t, err)
  235. stopEventScheduler()
  236. }
  237. func TestEventManagerErrors(t *testing.T) {
  238. startEventScheduler()
  239. providerConf := dataprovider.GetProviderConfig()
  240. err := dataprovider.Close()
  241. assert.NoError(t, err)
  242. err = executeUsersQuotaResetRuleAction(dataprovider.ConditionOptions{})
  243. assert.Error(t, err)
  244. err = executeFoldersQuotaResetRuleAction(dataprovider.ConditionOptions{})
  245. assert.Error(t, err)
  246. err = executeTransferQuotaResetRuleAction(dataprovider.ConditionOptions{})
  247. assert.Error(t, err)
  248. err = executeQuotaResetForUser(dataprovider.User{
  249. Groups: []sdk.GroupMapping{
  250. {
  251. Name: "agroup",
  252. Type: sdk.GroupTypePrimary,
  253. },
  254. },
  255. })
  256. assert.Error(t, err)
  257. err = executeDataRetentionCheckForUser(dataprovider.User{
  258. Groups: []sdk.GroupMapping{
  259. {
  260. Name: "agroup",
  261. Type: sdk.GroupTypePrimary,
  262. },
  263. },
  264. }, nil)
  265. assert.Error(t, err)
  266. dataRetentionAction := dataprovider.BaseEventAction{
  267. Type: dataprovider.ActionTypeDataRetentionCheck,
  268. Options: dataprovider.BaseEventActionOptions{
  269. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  270. Folders: []dataprovider.FolderRetention{
  271. {
  272. Path: "/",
  273. Retention: 24,
  274. },
  275. },
  276. },
  277. },
  278. }
  279. err = executeRuleAction(dataRetentionAction, EventParams{}, dataprovider.ConditionOptions{
  280. Names: []dataprovider.ConditionPattern{
  281. {
  282. Pattern: "username1",
  283. },
  284. },
  285. })
  286. if assert.Error(t, err) {
  287. assert.Contains(t, err.Error(), "unable to get users")
  288. }
  289. eventManager.loadRules()
  290. eventManager.RLock()
  291. assert.Len(t, eventManager.FsEvents, 0)
  292. assert.Len(t, eventManager.ProviderEvents, 0)
  293. assert.Len(t, eventManager.Schedules, 0)
  294. eventManager.RUnlock()
  295. // rule with invalid trigger
  296. eventManager.addUpdateRuleInternal(dataprovider.EventRule{
  297. Name: "test rule",
  298. Trigger: -1,
  299. })
  300. eventManager.RLock()
  301. assert.Len(t, eventManager.FsEvents, 0)
  302. assert.Len(t, eventManager.ProviderEvents, 0)
  303. assert.Len(t, eventManager.Schedules, 0)
  304. eventManager.RUnlock()
  305. // rule with invalid cronspec
  306. eventManager.addUpdateRuleInternal(dataprovider.EventRule{
  307. Name: "test rule",
  308. Trigger: dataprovider.EventTriggerSchedule,
  309. Conditions: dataprovider.EventConditions{
  310. Schedules: []dataprovider.Schedule{
  311. {
  312. Hours: "1000",
  313. },
  314. },
  315. },
  316. })
  317. eventManager.RLock()
  318. assert.Len(t, eventManager.FsEvents, 0)
  319. assert.Len(t, eventManager.ProviderEvents, 0)
  320. assert.Len(t, eventManager.Schedules, 0)
  321. eventManager.RUnlock()
  322. err = dataprovider.Initialize(providerConf, configDir, true)
  323. assert.NoError(t, err)
  324. stopEventScheduler()
  325. }
  326. func TestEventRuleActions(t *testing.T) {
  327. actionName := "test rule action"
  328. action := dataprovider.BaseEventAction{
  329. Name: actionName,
  330. Type: dataprovider.ActionTypeBackup,
  331. }
  332. err := executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{})
  333. assert.NoError(t, err)
  334. action.Type = -1
  335. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{})
  336. assert.Error(t, err)
  337. action = dataprovider.BaseEventAction{
  338. Name: actionName,
  339. Type: dataprovider.ActionTypeHTTP,
  340. Options: dataprovider.BaseEventActionOptions{
  341. HTTPConfig: dataprovider.EventActionHTTPConfig{
  342. Endpoint: "http://foo\x7f.com/", // invalid URL
  343. SkipTLSVerify: true,
  344. Body: "{{ObjectData}}",
  345. Method: http.MethodPost,
  346. QueryParameters: []dataprovider.KeyValue{
  347. {
  348. Key: "param",
  349. Value: "value",
  350. },
  351. },
  352. Timeout: 5,
  353. Headers: []dataprovider.KeyValue{
  354. {
  355. Key: "Content-Type",
  356. Value: "application/json",
  357. },
  358. },
  359. Username: "httpuser",
  360. },
  361. },
  362. }
  363. action.Options.SetEmptySecretsIfNil()
  364. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{})
  365. if assert.Error(t, err) {
  366. assert.Contains(t, err.Error(), "invalid endpoint")
  367. }
  368. action.Options.HTTPConfig.Endpoint = fmt.Sprintf("http://%v", httpAddr)
  369. params := EventParams{
  370. Name: "a",
  371. Object: &dataprovider.User{
  372. BaseUser: sdk.BaseUser{
  373. Username: "test user",
  374. },
  375. },
  376. }
  377. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  378. assert.NoError(t, err)
  379. action.Options.HTTPConfig.Endpoint = fmt.Sprintf("http://%v/404", httpAddr)
  380. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  381. if assert.Error(t, err) {
  382. assert.Equal(t, err.Error(), "unexpected status code: 404")
  383. }
  384. action.Options.HTTPConfig.Endpoint = "http://invalid:1234"
  385. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  386. assert.Error(t, err)
  387. action.Options.HTTPConfig.QueryParameters = nil
  388. action.Options.HTTPConfig.Endpoint = "http://bar\x7f.com/"
  389. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  390. assert.Error(t, err)
  391. action.Options.HTTPConfig.Password = kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", "data")
  392. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  393. if assert.Error(t, err) {
  394. assert.Contains(t, err.Error(), "unable to decrypt password")
  395. }
  396. // test disk and transfer quota reset
  397. username1 := "user1"
  398. username2 := "user2"
  399. user1 := dataprovider.User{
  400. BaseUser: sdk.BaseUser{
  401. Username: username1,
  402. HomeDir: filepath.Join(os.TempDir(), username1),
  403. Status: 1,
  404. Permissions: map[string][]string{
  405. "/": {dataprovider.PermAny},
  406. },
  407. },
  408. }
  409. user2 := dataprovider.User{
  410. BaseUser: sdk.BaseUser{
  411. Username: username2,
  412. HomeDir: filepath.Join(os.TempDir(), username2),
  413. Status: 1,
  414. Permissions: map[string][]string{
  415. "/": {dataprovider.PermAny},
  416. },
  417. },
  418. }
  419. err = dataprovider.AddUser(&user1, "", "")
  420. assert.NoError(t, err)
  421. err = dataprovider.AddUser(&user2, "", "")
  422. assert.NoError(t, err)
  423. action = dataprovider.BaseEventAction{
  424. Type: dataprovider.ActionTypeUserQuotaReset,
  425. }
  426. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{
  427. Names: []dataprovider.ConditionPattern{
  428. {
  429. Pattern: username1,
  430. },
  431. },
  432. })
  433. assert.Error(t, err) // no home dir
  434. // create the home dir
  435. err = os.MkdirAll(user1.GetHomeDir(), os.ModePerm)
  436. assert.NoError(t, err)
  437. err = os.WriteFile(filepath.Join(user1.GetHomeDir(), "file.txt"), []byte("user"), 0666)
  438. assert.NoError(t, err)
  439. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{
  440. Names: []dataprovider.ConditionPattern{
  441. {
  442. Pattern: username1,
  443. },
  444. },
  445. })
  446. assert.NoError(t, err)
  447. userGet, err := dataprovider.UserExists(username1)
  448. assert.NoError(t, err)
  449. assert.Equal(t, 1, userGet.UsedQuotaFiles)
  450. assert.Equal(t, int64(4), userGet.UsedQuotaSize)
  451. // simulate another quota scan in progress
  452. assert.True(t, QuotaScans.AddUserQuotaScan(username1))
  453. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{
  454. Names: []dataprovider.ConditionPattern{
  455. {
  456. Pattern: username1,
  457. },
  458. },
  459. })
  460. assert.Error(t, err)
  461. assert.True(t, QuotaScans.RemoveUserQuotaScan(username1))
  462. dataRetentionAction := dataprovider.BaseEventAction{
  463. Type: dataprovider.ActionTypeDataRetentionCheck,
  464. Options: dataprovider.BaseEventActionOptions{
  465. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  466. Folders: []dataprovider.FolderRetention{
  467. {
  468. Path: "",
  469. Retention: 24,
  470. },
  471. },
  472. },
  473. },
  474. }
  475. err = executeRuleAction(dataRetentionAction, EventParams{}, dataprovider.ConditionOptions{
  476. Names: []dataprovider.ConditionPattern{
  477. {
  478. Pattern: username1,
  479. },
  480. },
  481. })
  482. assert.Error(t, err) // invalid config, no folder path specified
  483. retentionDir := "testretention"
  484. dataRetentionAction = dataprovider.BaseEventAction{
  485. Type: dataprovider.ActionTypeDataRetentionCheck,
  486. Options: dataprovider.BaseEventActionOptions{
  487. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  488. Folders: []dataprovider.FolderRetention{
  489. {
  490. Path: path.Join("/", retentionDir),
  491. Retention: 24,
  492. DeleteEmptyDirs: true,
  493. },
  494. },
  495. },
  496. },
  497. }
  498. // create some test files
  499. file1 := filepath.Join(user1.GetHomeDir(), "file1.txt")
  500. file2 := filepath.Join(user1.GetHomeDir(), retentionDir, "file2.txt")
  501. file3 := filepath.Join(user1.GetHomeDir(), retentionDir, "file3.txt")
  502. file4 := filepath.Join(user1.GetHomeDir(), retentionDir, "sub", "file4.txt")
  503. err = os.MkdirAll(filepath.Dir(file4), os.ModePerm)
  504. assert.NoError(t, err)
  505. for _, f := range []string{file1, file2, file3, file4} {
  506. err = os.WriteFile(f, []byte(""), 0666)
  507. assert.NoError(t, err)
  508. }
  509. timeBeforeRetention := time.Now().Add(-48 * time.Hour)
  510. err = os.Chtimes(file1, timeBeforeRetention, timeBeforeRetention)
  511. assert.NoError(t, err)
  512. err = os.Chtimes(file2, timeBeforeRetention, timeBeforeRetention)
  513. assert.NoError(t, err)
  514. err = os.Chtimes(file4, timeBeforeRetention, timeBeforeRetention)
  515. assert.NoError(t, err)
  516. err = executeRuleAction(dataRetentionAction, EventParams{}, dataprovider.ConditionOptions{
  517. Names: []dataprovider.ConditionPattern{
  518. {
  519. Pattern: username1,
  520. },
  521. },
  522. })
  523. assert.NoError(t, err)
  524. assert.FileExists(t, file1)
  525. assert.NoFileExists(t, file2)
  526. assert.FileExists(t, file3)
  527. assert.NoDirExists(t, filepath.Dir(file4))
  528. // simulate another check in progress
  529. c := RetentionChecks.Add(RetentionCheck{}, &user1)
  530. assert.NotNil(t, c)
  531. err = executeRuleAction(dataRetentionAction, EventParams{}, dataprovider.ConditionOptions{
  532. Names: []dataprovider.ConditionPattern{
  533. {
  534. Pattern: username1,
  535. },
  536. },
  537. })
  538. assert.Error(t, err)
  539. RetentionChecks.remove(user1.Username)
  540. err = os.RemoveAll(user1.GetHomeDir())
  541. assert.NoError(t, err)
  542. err = dataprovider.UpdateUserTransferQuota(&user1, 100, 100, true)
  543. assert.NoError(t, err)
  544. action.Type = dataprovider.ActionTypeTransferQuotaReset
  545. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{
  546. Names: []dataprovider.ConditionPattern{
  547. {
  548. Pattern: username1,
  549. },
  550. },
  551. })
  552. assert.NoError(t, err)
  553. userGet, err = dataprovider.UserExists(username1)
  554. assert.NoError(t, err)
  555. assert.Equal(t, int64(0), userGet.UsedDownloadDataTransfer)
  556. assert.Equal(t, int64(0), userGet.UsedUploadDataTransfer)
  557. err = dataprovider.DeleteUser(username1, "", "")
  558. assert.NoError(t, err)
  559. err = dataprovider.DeleteUser(username2, "", "")
  560. assert.NoError(t, err)
  561. // test folder quota reset
  562. foldername1 := "f1"
  563. foldername2 := "f2"
  564. folder1 := vfs.BaseVirtualFolder{
  565. Name: foldername1,
  566. MappedPath: filepath.Join(os.TempDir(), foldername1),
  567. }
  568. folder2 := vfs.BaseVirtualFolder{
  569. Name: foldername2,
  570. MappedPath: filepath.Join(os.TempDir(), foldername2),
  571. }
  572. err = dataprovider.AddFolder(&folder1, "", "")
  573. assert.NoError(t, err)
  574. err = dataprovider.AddFolder(&folder2, "", "")
  575. assert.NoError(t, err)
  576. action = dataprovider.BaseEventAction{
  577. Type: dataprovider.ActionTypeFolderQuotaReset,
  578. }
  579. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{
  580. Names: []dataprovider.ConditionPattern{
  581. {
  582. Pattern: foldername1,
  583. },
  584. },
  585. })
  586. assert.Error(t, err) // no home dir
  587. err = os.MkdirAll(folder1.MappedPath, os.ModePerm)
  588. assert.NoError(t, err)
  589. err = os.WriteFile(filepath.Join(folder1.MappedPath, "file.txt"), []byte("folder"), 0666)
  590. assert.NoError(t, err)
  591. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{
  592. Names: []dataprovider.ConditionPattern{
  593. {
  594. Pattern: foldername1,
  595. },
  596. },
  597. })
  598. assert.NoError(t, err)
  599. folderGet, err := dataprovider.GetFolderByName(foldername1)
  600. assert.NoError(t, err)
  601. assert.Equal(t, 1, folderGet.UsedQuotaFiles)
  602. assert.Equal(t, int64(6), folderGet.UsedQuotaSize)
  603. // simulate another quota scan in progress
  604. assert.True(t, QuotaScans.AddVFolderQuotaScan(foldername1))
  605. err = executeRuleAction(action, EventParams{}, dataprovider.ConditionOptions{
  606. Names: []dataprovider.ConditionPattern{
  607. {
  608. Pattern: foldername1,
  609. },
  610. },
  611. })
  612. assert.Error(t, err)
  613. assert.True(t, QuotaScans.RemoveVFolderQuotaScan(foldername1))
  614. err = os.RemoveAll(folder1.MappedPath)
  615. assert.NoError(t, err)
  616. err = dataprovider.DeleteFolder(foldername1, "", "")
  617. assert.NoError(t, err)
  618. err = dataprovider.DeleteFolder(foldername2, "", "")
  619. assert.NoError(t, err)
  620. }
  621. func TestQuotaActionsWithQuotaTrackDisabled(t *testing.T) {
  622. oldProviderConf := dataprovider.GetProviderConfig()
  623. providerConf := dataprovider.GetProviderConfig()
  624. providerConf.TrackQuota = 0
  625. err := dataprovider.Close()
  626. assert.NoError(t, err)
  627. err = dataprovider.Initialize(providerConf, configDir, true)
  628. assert.NoError(t, err)
  629. username := "u1"
  630. user := dataprovider.User{
  631. BaseUser: sdk.BaseUser{
  632. Username: username,
  633. HomeDir: filepath.Join(os.TempDir(), username),
  634. Status: 1,
  635. Permissions: map[string][]string{
  636. "/": {dataprovider.PermAny},
  637. },
  638. },
  639. FsConfig: vfs.Filesystem{
  640. Provider: sdk.LocalFilesystemProvider,
  641. },
  642. }
  643. err = dataprovider.AddUser(&user, "", "")
  644. assert.NoError(t, err)
  645. err = os.MkdirAll(user.GetHomeDir(), os.ModePerm)
  646. assert.NoError(t, err)
  647. err = executeRuleAction(dataprovider.BaseEventAction{Type: dataprovider.ActionTypeUserQuotaReset},
  648. EventParams{}, dataprovider.ConditionOptions{
  649. Names: []dataprovider.ConditionPattern{
  650. {
  651. Pattern: username,
  652. },
  653. },
  654. })
  655. assert.Error(t, err)
  656. err = executeRuleAction(dataprovider.BaseEventAction{Type: dataprovider.ActionTypeTransferQuotaReset},
  657. EventParams{}, dataprovider.ConditionOptions{
  658. Names: []dataprovider.ConditionPattern{
  659. {
  660. Pattern: username,
  661. },
  662. },
  663. })
  664. assert.Error(t, err)
  665. err = os.RemoveAll(user.GetHomeDir())
  666. assert.NoError(t, err)
  667. err = dataprovider.DeleteUser(username, "", "")
  668. assert.NoError(t, err)
  669. foldername := "f1"
  670. folder := vfs.BaseVirtualFolder{
  671. Name: foldername,
  672. MappedPath: filepath.Join(os.TempDir(), foldername),
  673. }
  674. err = dataprovider.AddFolder(&folder, "", "")
  675. assert.NoError(t, err)
  676. err = os.MkdirAll(folder.MappedPath, os.ModePerm)
  677. assert.NoError(t, err)
  678. err = executeRuleAction(dataprovider.BaseEventAction{Type: dataprovider.ActionTypeFolderQuotaReset},
  679. EventParams{}, dataprovider.ConditionOptions{
  680. Names: []dataprovider.ConditionPattern{
  681. {
  682. Pattern: foldername,
  683. },
  684. },
  685. })
  686. assert.Error(t, err)
  687. err = os.RemoveAll(folder.MappedPath)
  688. assert.NoError(t, err)
  689. err = dataprovider.DeleteFolder(foldername, "", "")
  690. assert.NoError(t, err)
  691. err = dataprovider.Close()
  692. assert.NoError(t, err)
  693. err = dataprovider.Initialize(oldProviderConf, configDir, true)
  694. assert.NoError(t, err)
  695. }
  696. func TestScheduledActions(t *testing.T) {
  697. startEventScheduler()
  698. backupsPath := filepath.Join(os.TempDir(), "backups")
  699. err := os.RemoveAll(backupsPath)
  700. assert.NoError(t, err)
  701. action := &dataprovider.BaseEventAction{
  702. Name: "action",
  703. Type: dataprovider.ActionTypeBackup,
  704. }
  705. err = dataprovider.AddEventAction(action, "", "")
  706. assert.NoError(t, err)
  707. rule := &dataprovider.EventRule{
  708. Name: "rule",
  709. Trigger: dataprovider.EventTriggerSchedule,
  710. Conditions: dataprovider.EventConditions{
  711. Schedules: []dataprovider.Schedule{
  712. {
  713. Hours: "11",
  714. DayOfWeek: "*",
  715. DayOfMonth: "*",
  716. Month: "*",
  717. },
  718. },
  719. },
  720. Actions: []dataprovider.EventAction{
  721. {
  722. BaseEventAction: dataprovider.BaseEventAction{
  723. Name: action.Name,
  724. },
  725. Order: 1,
  726. },
  727. },
  728. }
  729. job := eventCronJob{
  730. ruleName: rule.Name,
  731. }
  732. job.Run() // rule not found
  733. assert.NoDirExists(t, backupsPath)
  734. err = dataprovider.AddEventRule(rule, "", "")
  735. assert.NoError(t, err)
  736. job.Run()
  737. assert.DirExists(t, backupsPath)
  738. err = dataprovider.DeleteEventRule(rule.Name, "", "")
  739. assert.NoError(t, err)
  740. err = dataprovider.DeleteEventAction(action.Name, "", "")
  741. assert.NoError(t, err)
  742. err = os.RemoveAll(backupsPath)
  743. assert.NoError(t, err)
  744. stopEventScheduler()
  745. }