user_store_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. package state
  2. import (
  3. "os"
  4. "reflect"
  5. "testing"
  6. "github.com/mk6i/retro-aim-server/wire"
  7. "github.com/stretchr/testify/assert"
  8. )
  9. const testFile string = "aim_test.db"
  10. func TestUserStore(t *testing.T) {
  11. const screenName = "sn2day"
  12. defer func() {
  13. assert.NoError(t, os.Remove(testFile))
  14. }()
  15. f, err := NewSQLiteUserStore(testFile)
  16. assert.NoError(t, err)
  17. itemsIn := []wire.FeedbagItem{
  18. {
  19. GroupID: 0,
  20. ItemID: 1805,
  21. ClassID: 3,
  22. Name: "spimmer1234",
  23. TLVLBlock: wire.TLVLBlock{},
  24. },
  25. {
  26. GroupID: 0x0A,
  27. ItemID: 0,
  28. ClassID: 1,
  29. Name: "Friends",
  30. },
  31. }
  32. if err := f.FeedbagUpsert(screenName, itemsIn); err != nil {
  33. t.Fatalf("failed to upsert: %s", err.Error())
  34. }
  35. itemsOut, err := f.Feedbag(screenName)
  36. if err != nil {
  37. t.Fatalf("failed to retrieve: %s", err.Error())
  38. }
  39. if !reflect.DeepEqual(itemsIn, itemsOut) {
  40. t.Fatalf("items did not match:\n in: %v\n out: %v", itemsIn, itemsOut)
  41. }
  42. }
  43. func TestFeedbagDelete(t *testing.T) {
  44. const screenName = "sn2day"
  45. defer func() {
  46. assert.NoError(t, os.Remove(testFile))
  47. }()
  48. f, err := NewSQLiteUserStore(testFile)
  49. assert.NoError(t, err)
  50. itemsIn := []wire.FeedbagItem{
  51. {
  52. GroupID: 0,
  53. ItemID: 1805,
  54. ClassID: 3,
  55. Name: "spimmer1234",
  56. TLVLBlock: wire.TLVLBlock{
  57. TLVList: wire.TLVList{
  58. wire.NewTLV(0x01, uint16(1000)),
  59. },
  60. },
  61. },
  62. {
  63. GroupID: 0x0A,
  64. ItemID: 0,
  65. ClassID: 1,
  66. Name: "Friends",
  67. },
  68. {
  69. GroupID: 0x0B,
  70. ItemID: 100,
  71. ClassID: 1,
  72. Name: "co-workers",
  73. },
  74. }
  75. if err := f.FeedbagUpsert(screenName, itemsIn); err != nil {
  76. t.Fatalf("failed to upsert: %s", err.Error())
  77. }
  78. if err := f.FeedbagDelete(screenName, []wire.FeedbagItem{itemsIn[0]}); err != nil {
  79. t.Fatalf("failed to delete: %s", err.Error())
  80. }
  81. itemsOut, err := f.Feedbag(screenName)
  82. if err != nil {
  83. t.Fatalf("failed to retrieve: %s", err.Error())
  84. }
  85. expect := itemsIn[1:]
  86. if !reflect.DeepEqual(expect, itemsOut) {
  87. t.Fatalf("items did not match:\n in: %v\n out: %v", expect, itemsOut)
  88. }
  89. }
  90. func TestLastModifiedEmpty(t *testing.T) {
  91. const screenName = "sn2day"
  92. defer func() {
  93. assert.NoError(t, os.Remove(testFile))
  94. }()
  95. f, err := NewSQLiteUserStore(testFile)
  96. assert.NoError(t, err)
  97. _, err = f.FeedbagLastModified(screenName)
  98. if err != nil {
  99. t.Fatalf("get error from last modified: %s", err.Error())
  100. }
  101. }
  102. func TestLastModifiedNotEmpty(t *testing.T) {
  103. const screenName = "sn2day"
  104. defer func() {
  105. assert.NoError(t, os.Remove(testFile))
  106. }()
  107. f, err := NewSQLiteUserStore(testFile)
  108. assert.NoError(t, err)
  109. itemsIn := []wire.FeedbagItem{
  110. {
  111. GroupID: 0x0A,
  112. ItemID: 0,
  113. ClassID: 1,
  114. Name: "Friends",
  115. },
  116. }
  117. if err := f.FeedbagUpsert(screenName, itemsIn); err != nil {
  118. t.Fatalf("failed to upsert: %s", err.Error())
  119. }
  120. _, err = f.FeedbagLastModified(screenName)
  121. if err != nil {
  122. t.Fatalf("get error from last modified: %s", err.Error())
  123. }
  124. }
  125. func TestProfile(t *testing.T) {
  126. const screenName = "sn2day"
  127. defer func() {
  128. assert.NoError(t, os.Remove(testFile))
  129. }()
  130. f, err := NewSQLiteUserStore(testFile)
  131. assert.NoError(t, err)
  132. u := User{
  133. ScreenName: screenName,
  134. }
  135. if err := f.InsertUser(u); err != nil {
  136. t.Fatalf("failed to upsert new user: %s", err.Error())
  137. }
  138. profile, err := f.Profile(screenName)
  139. if err != nil {
  140. t.Fatalf("failed to retrieve profile: %s", err.Error())
  141. }
  142. if profile != "" {
  143. t.Fatalf("expected empty profile for %s", screenName)
  144. }
  145. newProfile := "here is my profile"
  146. if err := f.SetProfile(screenName, newProfile); err != nil {
  147. t.Fatalf("failed to create new profile: %s", err.Error())
  148. }
  149. profile, err = f.Profile(screenName)
  150. if err != nil {
  151. t.Fatalf("failed to retrieve profile: %s", err.Error())
  152. }
  153. if !reflect.DeepEqual(newProfile, profile) {
  154. t.Fatalf("profiles did not match:\n expected: %v\n actual: %v", newProfile, profile)
  155. }
  156. updatedProfile := "here is my profile [updated]"
  157. if err := f.SetProfile(screenName, updatedProfile); err != nil {
  158. t.Fatalf("failed to create new profile: %s", err.Error())
  159. }
  160. profile, err = f.Profile(screenName)
  161. if err != nil {
  162. t.Fatalf("failed to retrieve profile: %s", err.Error())
  163. }
  164. if !reflect.DeepEqual(updatedProfile, profile) {
  165. t.Fatalf("updated profiles did not match:\n expected: %v\n actual: %v", newProfile, profile)
  166. }
  167. }
  168. func TestProfileNonExistent(t *testing.T) {
  169. const screenName = "sn2day"
  170. defer func() {
  171. assert.NoError(t, os.Remove(testFile))
  172. }()
  173. f, err := NewSQLiteUserStore(testFile)
  174. assert.NoError(t, err)
  175. prof, err := f.Profile(screenName)
  176. assert.NoError(t, err)
  177. assert.Empty(t, prof)
  178. }
  179. func TestAdjacentUsers(t *testing.T) {
  180. defer func() {
  181. assert.NoError(t, os.Remove(testFile))
  182. }()
  183. f, err := NewSQLiteUserStore(testFile)
  184. assert.NoError(t, err)
  185. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',0,13852,3,'userB',NULL,1691286176)`)
  186. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
  187. f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
  188. users, err := f.AdjacentUsers("userA")
  189. if len(users) != 0 {
  190. t.Fatalf("expected no interested users, got %v", users)
  191. }
  192. users, err = f.AdjacentUsers("userB")
  193. if len(users) != 0 {
  194. t.Fatalf("expected no interested users, got %v", users)
  195. }
  196. }
  197. func TestUserStoreBuddiesBlockedUser(t *testing.T) {
  198. defer func() {
  199. assert.NoError(t, os.Remove(testFile))
  200. }()
  201. f, err := NewSQLiteUserStore(testFile)
  202. assert.NoError(t, err)
  203. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',0,13852,3,'userB',NULL,1691286176)`)
  204. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
  205. f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
  206. users, err := f.Buddies("userA")
  207. if len(users) != 0 {
  208. t.Fatalf("expected no buddies, got %v", users)
  209. }
  210. users, err = f.Buddies("userB")
  211. if len(users) != 0 {
  212. t.Fatalf("expected no buddies, got %v", users)
  213. }
  214. }
  215. func TestUserStoreBlockedA(t *testing.T) {
  216. defer func() {
  217. assert.NoError(t, os.Remove(testFile))
  218. }()
  219. f, err := NewSQLiteUserStore(testFile)
  220. assert.NoError(t, err)
  221. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',0,13852,3,'userB',NULL,1691286176)`)
  222. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
  223. f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
  224. sn1 := "userA"
  225. sn2 := "userB"
  226. blocked, err := f.BlockedState(sn1, sn2)
  227. if err != nil {
  228. t.Fatalf("db err: %s", err.Error())
  229. }
  230. if blocked != BlockedA {
  231. t.Fatalf("expected A to be blocker")
  232. }
  233. }
  234. func TestUserStoreBlockedB(t *testing.T) {
  235. defer func() {
  236. assert.NoError(t, os.Remove(testFile))
  237. }()
  238. f, err := NewSQLiteUserStore(testFile)
  239. assert.NoError(t, err)
  240. f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',0,13852,3,'userA',NULL,1691286176)`)
  241. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
  242. f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
  243. sn1 := "userA"
  244. sn2 := "userB"
  245. blocked, err := f.BlockedState(sn1, sn2)
  246. if err != nil {
  247. t.Fatalf("db err: %s", err.Error())
  248. }
  249. if blocked != BlockedB {
  250. t.Fatalf("expected B to be blocker")
  251. }
  252. }
  253. func TestUserStoreBlockedNoBlocked(t *testing.T) {
  254. defer func() {
  255. assert.NoError(t, os.Remove(testFile))
  256. }()
  257. f, err := NewSQLiteUserStore(testFile)
  258. assert.NoError(t, err)
  259. f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
  260. f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
  261. sn1 := "userA"
  262. sn2 := "userB"
  263. blocked, err := f.BlockedState(sn1, sn2)
  264. if err != nil {
  265. t.Fatalf("db err: %s", err.Error())
  266. }
  267. if blocked != BlockedNo {
  268. t.Fatalf("expected no blocker")
  269. }
  270. }
  271. func TestGetUser(t *testing.T) {
  272. defer func() {
  273. assert.NoError(t, os.Remove(testFile))
  274. }()
  275. f, err := NewSQLiteUserStore(testFile)
  276. assert.NoError(t, err)
  277. expectUser := &User{
  278. ScreenName: "testscreenname",
  279. AuthKey: "theauthkey",
  280. StrongMD5Pass: []byte("thepasshash"),
  281. }
  282. _, err = f.db.Exec(`INSERT INTO user (ScreenName, authKey, strongMD5Pass) VALUES(?, ?, ?)`,
  283. expectUser.ScreenName, expectUser.AuthKey, expectUser.StrongMD5Pass)
  284. if err != nil {
  285. t.Fatalf("failed to insert user: %s", err.Error())
  286. }
  287. actualUser, err := f.User(expectUser.ScreenName)
  288. if err != nil {
  289. t.Fatalf("failed to get user: %s", err.Error())
  290. }
  291. if !reflect.DeepEqual(expectUser, actualUser) {
  292. t.Fatalf("users are not equal. expect: %v actual: %v", expectUser, actualUser)
  293. }
  294. }
  295. func TestGetUserNotFound(t *testing.T) {
  296. defer func() {
  297. assert.NoError(t, os.Remove(testFile))
  298. }()
  299. f, err := NewSQLiteUserStore(testFile)
  300. assert.NoError(t, err)
  301. actualUser, err := f.User("testscreenname")
  302. if err != nil {
  303. t.Fatalf("failed to get user: %s", err.Error())
  304. }
  305. if actualUser != nil {
  306. t.Fatal("expected user to not be found")
  307. }
  308. }
  309. func TestSQLiteUserStore_Users(t *testing.T) {
  310. defer func() {
  311. assert.NoError(t, os.Remove(testFile))
  312. }()
  313. f, err := NewSQLiteUserStore(testFile)
  314. if err != nil {
  315. assert.NoError(t, err)
  316. }
  317. want := []User{
  318. {ScreenName: "userA"},
  319. {ScreenName: "userB"},
  320. {ScreenName: "userC"},
  321. }
  322. for _, u := range want {
  323. err := f.InsertUser(u)
  324. assert.NoError(t, err)
  325. }
  326. have, err := f.AllUsers()
  327. assert.NoError(t, err)
  328. assert.Equal(t, want, have)
  329. }
  330. func TestSQLiteUserStore_Buddies(t *testing.T) {
  331. defer func() {
  332. assert.NoError(t, os.Remove(testFile))
  333. }()
  334. feedbagStore, err := NewSQLiteUserStore(testFile)
  335. assert.NoError(t, err)
  336. assert.NoError(t, feedbagStore.FeedbagUpsert("userA", []wire.FeedbagItem{
  337. {Name: "userB", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
  338. {Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
  339. {Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
  340. }))
  341. assert.NoError(t, feedbagStore.FeedbagUpsert("userB", []wire.FeedbagItem{
  342. {Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
  343. {Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
  344. {Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
  345. }))
  346. want := []string{"userB", "userC", "userD"}
  347. have, err := feedbagStore.Buddies("userA")
  348. assert.NoError(t, err)
  349. assert.Equal(t, want, have)
  350. }
  351. func TestNewStubUser(t *testing.T) {
  352. have, err := NewStubUser("userA")
  353. assert.NoError(t, err)
  354. want := User{
  355. ScreenName: "userA",
  356. AuthKey: have.AuthKey,
  357. }
  358. assert.NoError(t, want.HashPassword("welcome1"))
  359. assert.Equal(t, want, have)
  360. }
  361. func TestSQLiteUserStore_AdjacentUsers(t *testing.T) {
  362. defer func() {
  363. assert.NoError(t, os.Remove(testFile))
  364. }()
  365. feedbagStore, err := NewSQLiteUserStore(testFile)
  366. assert.NoError(t, err)
  367. assert.NoError(t, feedbagStore.FeedbagUpsert("userA", []wire.FeedbagItem{
  368. {Name: "userB", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
  369. {Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
  370. {Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
  371. }))
  372. assert.NoError(t, feedbagStore.FeedbagUpsert("userB", []wire.FeedbagItem{
  373. {Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
  374. {Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
  375. {Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
  376. }))
  377. assert.NoError(t, feedbagStore.FeedbagUpsert("userC", []wire.FeedbagItem{
  378. {Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
  379. {Name: "userB", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
  380. {Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
  381. }))
  382. want := []string{"userB", "userC"}
  383. have, err := feedbagStore.AdjacentUsers("userA")
  384. assert.NoError(t, err)
  385. assert.Equal(t, want, have)
  386. }
  387. func TestSQLiteUserStore_BARTUpsertAndRetrieve(t *testing.T) {
  388. defer func() {
  389. assert.NoError(t, os.Remove(testFile))
  390. }()
  391. feedbagStore, err := NewSQLiteUserStore(testFile)
  392. assert.NoError(t, err)
  393. hash := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
  394. item := []byte{'a', 'b', 'c', 'd'}
  395. b, err := feedbagStore.BARTRetrieve(hash)
  396. assert.NoError(t, err)
  397. assert.Empty(t, b)
  398. err = feedbagStore.BARTUpsert(hash, item)
  399. assert.NoError(t, err)
  400. b, err = feedbagStore.BARTRetrieve(hash)
  401. assert.NoError(t, err)
  402. assert.Equal(t, item, b)
  403. }